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

Configure Feed

Select the types of activity you want to include in your feed.

scsi: device_handler: alua: Call scsi_device_put() from non-atomic context

Since commit f93ed747e2c7 ("scsi: core: Release SCSI devices
synchronously"), scsi_device_put() might sleep. Avoid calling it from
alua_rtpg_queue() with the pg_lock held. The lock only pretects h->pg,
anyway. To avoid the pg being freed under us, because of a race with
another thread, take a temporary reference. In alua_rtpg_queue(), verify
that the pg still belongs to the sdev being passed before actually queueing
the RTPG.

This patch fixes the following smatch warning:

drivers/scsi/device_handler/scsi_dh_alua.c:1013 alua_rtpg_queue() warn: sleeping in atomic context

alua_check_vpd() <- disables preempt
-> alua_rtpg_queue()
-> scsi_device_put()

Cc: Martin Wilck <mwilck@suse.com>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Sachin Sant <sachinp@linux.ibm.com>
Cc: Benjamin Block <bblock@linux.ibm.com>
Suggested-by: Martin Wilck <mwilck@suse.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Link: https://lore.kernel.org/r/20221117183626.2656196-3-bvanassche@acm.org
Tested-by: Sachin Sant <sachinp@linux.ibm.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Bart Van Assche and committed by
Martin K. Petersen
50759b88 a500c4cc

+19 -8
+19 -8
drivers/scsi/device_handler/scsi_dh_alua.c
··· 354 354 "%s: port group %x rel port %x\n", 355 355 ALUA_DH_NAME, group_id, rel_port); 356 356 357 + kref_get(&pg->kref); 358 + 357 359 /* Check for existing port group references */ 358 360 spin_lock(&h->pg_lock); 359 361 old_pg = rcu_dereference_protected(h->pg, lockdep_is_held(&h->pg_lock)); ··· 375 373 list_add_rcu(&h->node, &pg->dh_list); 376 374 spin_unlock_irqrestore(&pg->lock, flags); 377 375 378 - alua_rtpg_queue(rcu_dereference_protected(h->pg, 379 - lockdep_is_held(&h->pg_lock)), 380 - sdev, NULL, true); 381 376 spin_unlock(&h->pg_lock); 377 + 378 + alua_rtpg_queue(pg, sdev, NULL, true); 379 + kref_put(&pg->kref, release_port_group); 382 380 383 381 if (old_pg) 384 382 kref_put(&old_pg->kref, release_port_group); ··· 988 986 { 989 987 int start_queue = 0; 990 988 unsigned long flags; 989 + 990 + might_sleep(); 991 + 991 992 if (WARN_ON_ONCE(!pg) || scsi_device_get(sdev)) 992 993 return false; 993 994 ··· 1001 996 force = true; 1002 997 } 1003 998 if (pg->rtpg_sdev == NULL) { 1004 - pg->interval = 0; 1005 - pg->flags |= ALUA_PG_RUN_RTPG; 1006 - kref_get(&pg->kref); 1007 - pg->rtpg_sdev = sdev; 1008 - start_queue = 1; 999 + struct alua_dh_data *h = sdev->handler_data; 1000 + 1001 + rcu_read_lock(); 1002 + if (h && rcu_dereference(h->pg) == pg) { 1003 + pg->interval = 0; 1004 + pg->flags |= ALUA_PG_RUN_RTPG; 1005 + kref_get(&pg->kref); 1006 + pg->rtpg_sdev = sdev; 1007 + start_queue = 1; 1008 + } 1009 + rcu_read_unlock(); 1009 1010 } else if (!(pg->flags & ALUA_PG_RUN_RTPG) && force) { 1010 1011 pg->flags |= ALUA_PG_RUN_RTPG; 1011 1012 /* Do not queue if the worker is already running */