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.

block: fix queue freeze vs limits lock order in sysfs store methods

queue_attr_store() always freezes a device queue before calling the
attribute store operation. For attributes that control queue limits, the
store operation will also lock the queue limits with a call to
queue_limits_start_update(). However, some drivers (e.g. SCSI sd) may
need to issue commands to a device to obtain limit values from the
hardware with the queue limits locked. This creates a potential ABBA
deadlock situation if a user attempts to modify a limit (thus freezing
the device queue) while the device driver starts a revalidation of the
device queue limits.

Avoid such deadlock by not freezing the queue before calling the
->store_limit() method in struct queue_sysfs_entry and instead use the
queue_limits_commit_update_frozen helper to freeze the queue after taking
the limits lock.

This also removes taking the sysfs lock for the store_limit method as
it doesn't protect anything here, but creates even more nesting.
Hopefully it will go away from the actual sysfs methods entirely soon.

(commit log adapted from a similar patch from Damien Le Moal)

Fixes: ff956a3be95b ("block: use queue_limits_commit_update in queue_discard_max_store")
Fixes: 0327ca9d53bf ("block: use queue_limits_commit_update in queue_max_sectors_store")
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Ming Lei <ming.lei@redhat.com>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Nilay Shroff <nilay@linux.ibm.com>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Link: https://lore.kernel.org/r/20250110054726.1499538-7-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Christoph Hellwig and committed by
Jens Axboe
c99f66e4 a1623064

+10 -8
+10 -8
block/blk-sysfs.c
··· 694 694 if (entry->load_module) 695 695 entry->load_module(disk, page, length); 696 696 697 - mutex_lock(&q->sysfs_lock); 698 - blk_mq_freeze_queue(q); 699 697 if (entry->store_limit) { 700 698 struct queue_limits lim = queue_limits_start_update(q); 701 699 702 700 res = entry->store_limit(disk, page, length, &lim); 703 701 if (res < 0) { 704 702 queue_limits_cancel_update(q); 705 - } else { 706 - res = queue_limits_commit_update(q, &lim); 707 - if (!res) 708 - res = length; 703 + return res; 709 704 } 710 - } else { 711 - res = entry->store(disk, page, length); 705 + 706 + res = queue_limits_commit_update_frozen(q, &lim); 707 + if (res) 708 + return res; 709 + return length; 712 710 } 711 + 712 + mutex_lock(&q->sysfs_lock); 713 + blk_mq_freeze_queue(q); 714 + res = entry->store(disk, page, length); 713 715 blk_mq_unfreeze_queue(q); 714 716 mutex_unlock(&q->sysfs_lock); 715 717 return res;