]> www.infradead.org Git - users/jedix/linux-maple.git/commit
block: loop: don't hold lo_ctl_mutex in lo_open
authorMing Lei <ming.lei@canonical.com>
Thu, 5 Sep 2019 07:45:49 +0000 (15:45 +0800)
committerBrian Maly <brian.maly@oracle.com>
Tue, 10 Sep 2019 14:48:54 +0000 (10:48 -0400)
commit93204e7b1fa59ea9aa717e9dcd71c08aece6a190
tree4cb4017ee23fa5c9b9b18d56a6b8cd1ee5b33a38
parentcfd20f2eb1cfb5fa5b0f9d3fa29cc620c18fb3ba
block: loop: don't hold lo_ctl_mutex in lo_open

The lo_ctl_mutex is held for running all ioctl handlers, and
in some ioctl handlers, ioctl_by_bdev(BLKRRPART) is called for
rereading partitions, which requires bd_mutex.

So it is easy to cause failure because trylock(bd_mutex) may
fail inside blkdev_reread_part(), and follows the lock context:

blkid or other application:
->open()
->mutex_lock(bd_mutex)
->lo_open()
->mutex_lock(lo_ctl_mutex)

losetup(set fd ioctl):
->mutex_lock(lo_ctl_mutex)
->ioctl_by_bdev(BLKRRPART)
->trylock(bd_mutex)

This patch trys to eliminate the ABBA lock dependency by removing
lo_ctl_mutext in lo_open() with the following approach:

1) make lo_refcnt as atomic_t and avoid acquiring lo_ctl_mutex in lo_open():
- for open vs. add/del loop, no any problem because of loop_index_mutex
- freeze request queue during clr_fd, so I/O can't come until
  clearing fd is completed, like the effect of holding lo_ctl_mutex
  in lo_open
- both open() and release() have been serialized by bd_mutex already

2) don't hold lo_ctl_mutex for decreasing/checking lo_refcnt in
lo_release(), then lo_ctl_mutex is only required for the last release.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Tested-by: Jarod Wilson <jarod@redhat.com>
Acked-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
(cherry-picked from commit f8933667953e8e61bb6104f5ca88e32e85656a93)
Orabug: 30264603
Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com>
Reviewed-by: Joe Jin <joe.jin@oracle.com>
Signed-off-by: Brian Maly <brian.maly@oracle.com>
drivers/block/loop.c
drivers/block/loop.h