Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

w1/masters/ds2490: queue up found IDs during scan

Queue up found IDs in a buffer and run the callback once for each found ID
at the end. This is necessary because we hold the bus_mutex during the
whole scan, and some of the "add-device" callbacks deadlock as they
themselves want to mutex_lock(bus_mutex).

Acked-by: Evgeniy Polyakov <zbr@ioremap.net>
Signed-off-by: Christian Vogel <vogelchr@vogel.cx>
Link: https://lore.kernel.org/r/20210113195018.7498-3-vogelchr@vogel.cx
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Christian Vogel and committed by
Greg Kroah-Hartman
e3fe0e89 48b7de66

+20 -5
+20 -5
drivers/w1/masters/ds2490.c
··· 688 688 * packet size. 689 689 */ 690 690 const size_t bufsize = 2 * 64; 691 - u64 *buf; 691 + u64 *buf, *found_ids; 692 692 693 693 buf = kmalloc(bufsize, GFP_KERNEL); 694 694 if (!buf) 695 695 return; 696 + 697 + /* 698 + * We are holding the bus mutex during the scan, but adding devices via the 699 + * callback needs the bus to be unlocked. So we queue up found ids here. 700 + */ 701 + found_ids = kmalloc_array(master->max_slave_count, sizeof(u64), GFP_KERNEL); 702 + if (!found_ids) { 703 + kfree(buf); 704 + return; 705 + } 696 706 697 707 mutex_lock(&master->bus_mutex); 698 708 ··· 739 729 if (err < 0) 740 730 break; 741 731 for (i = 0; i < err/8; ++i) { 742 - ++found; 743 - if (found <= search_limit) 744 - callback(master, buf[i]); 732 + found_ids[found++] = buf[i]; 745 733 /* can't know if there will be a discrepancy 746 734 * value after until the next id */ 747 - if (found == search_limit) 735 + if (found == search_limit) { 748 736 master->search_id = buf[i]; 737 + break; 738 + } 749 739 } 750 740 } 751 741 ··· 769 759 master->max_slave_count); 770 760 set_bit(W1_WARN_MAX_COUNT, &master->flags); 771 761 } 762 + 772 763 search_out: 773 764 mutex_unlock(&master->bus_mutex); 774 765 kfree(buf); 766 + 767 + for (i = 0; i < found; i++) /* run callback for all queued up IDs */ 768 + callback(master, found_ids[i]); 769 + kfree(found_ids); 775 770 } 776 771 777 772 #if 0