diff options
author | Ming Lei <ming.lei@canonical.com> | 2015-05-06 00:26:24 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-05-20 11:06:11 -0400 |
commit | 06f0e9e68c0d81c7d822a405f6e35686a711c1fe (patch) | |
tree | edeba14fd08414b99402b9b2d94a6faf34f1cded /drivers/block | |
parent | f8933667953e8e61bb6104f5ca88e32e85656a93 (diff) |
block: loop: fix another reread part failure
loop_clr_fd() can be run piggyback with lo_release(), and
under this situation, reread partition may always fail because
bd_mutex has been held already.
This patch detects the situation by the reference count, and
call __blkdev_reread_part() to avoid acquiring the lock again.
In the meantime, this patch switches to new kernel APIs
of blkdev_reread_part() and __blkdev_reread_part().
Reviewed-by: Christoph Hellwig <hch@lst.de>
Tested-by: Jarod Wilson <jarod@redhat.com>
Acked-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/loop.c | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index b3e294e529ec..2b99e34f4253 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
@@ -474,6 +474,28 @@ static int loop_flush(struct loop_device *lo) | |||
474 | return loop_switch(lo, NULL); | 474 | return loop_switch(lo, NULL); |
475 | } | 475 | } |
476 | 476 | ||
477 | static void loop_reread_partitions(struct loop_device *lo, | ||
478 | struct block_device *bdev) | ||
479 | { | ||
480 | int rc; | ||
481 | |||
482 | /* | ||
483 | * bd_mutex has been held already in release path, so don't | ||
484 | * acquire it if this function is called in such case. | ||
485 | * | ||
486 | * If the reread partition isn't from release path, lo_refcnt | ||
487 | * must be at least one and it can only become zero when the | ||
488 | * current holder is released. | ||
489 | */ | ||
490 | if (!atomic_read(&lo->lo_refcnt)) | ||
491 | rc = __blkdev_reread_part(bdev); | ||
492 | else | ||
493 | rc = blkdev_reread_part(bdev); | ||
494 | if (rc) | ||
495 | pr_warn("%s: partition scan of loop%d (%s) failed (rc=%d)\n", | ||
496 | __func__, lo->lo_number, lo->lo_file_name, rc); | ||
497 | } | ||
498 | |||
477 | /* | 499 | /* |
478 | * loop_change_fd switched the backing store of a loopback device to | 500 | * loop_change_fd switched the backing store of a loopback device to |
479 | * a new file. This is useful for operating system installers to free up | 501 | * a new file. This is useful for operating system installers to free up |
@@ -522,7 +544,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, | |||
522 | 544 | ||
523 | fput(old_file); | 545 | fput(old_file); |
524 | if (lo->lo_flags & LO_FLAGS_PARTSCAN) | 546 | if (lo->lo_flags & LO_FLAGS_PARTSCAN) |
525 | ioctl_by_bdev(bdev, BLKRRPART, 0); | 547 | loop_reread_partitions(lo, bdev); |
526 | return 0; | 548 | return 0; |
527 | 549 | ||
528 | out_putf: | 550 | out_putf: |
@@ -759,7 +781,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, | |||
759 | if (part_shift) | 781 | if (part_shift) |
760 | lo->lo_flags |= LO_FLAGS_PARTSCAN; | 782 | lo->lo_flags |= LO_FLAGS_PARTSCAN; |
761 | if (lo->lo_flags & LO_FLAGS_PARTSCAN) | 783 | if (lo->lo_flags & LO_FLAGS_PARTSCAN) |
762 | ioctl_by_bdev(bdev, BLKRRPART, 0); | 784 | loop_reread_partitions(lo, bdev); |
763 | 785 | ||
764 | /* Grab the block_device to prevent its destruction after we | 786 | /* Grab the block_device to prevent its destruction after we |
765 | * put /dev/loopXX inode. Later in loop_clr_fd() we bdput(bdev). | 787 | * put /dev/loopXX inode. Later in loop_clr_fd() we bdput(bdev). |
@@ -877,7 +899,7 @@ static int loop_clr_fd(struct loop_device *lo) | |||
877 | blk_mq_unfreeze_queue(lo->lo_queue); | 899 | blk_mq_unfreeze_queue(lo->lo_queue); |
878 | 900 | ||
879 | if (lo->lo_flags & LO_FLAGS_PARTSCAN && bdev) | 901 | if (lo->lo_flags & LO_FLAGS_PARTSCAN && bdev) |
880 | ioctl_by_bdev(bdev, BLKRRPART, 0); | 902 | loop_reread_partitions(lo, bdev); |
881 | lo->lo_flags = 0; | 903 | lo->lo_flags = 0; |
882 | if (!part_shift) | 904 | if (!part_shift) |
883 | lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN; | 905 | lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN; |
@@ -954,7 +976,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) | |||
954 | !(lo->lo_flags & LO_FLAGS_PARTSCAN)) { | 976 | !(lo->lo_flags & LO_FLAGS_PARTSCAN)) { |
955 | lo->lo_flags |= LO_FLAGS_PARTSCAN; | 977 | lo->lo_flags |= LO_FLAGS_PARTSCAN; |
956 | lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN; | 978 | lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN; |
957 | ioctl_by_bdev(lo->lo_device, BLKRRPART, 0); | 979 | loop_reread_partitions(lo, lo->lo_device); |
958 | } | 980 | } |
959 | 981 | ||
960 | lo->lo_encrypt_key_size = info->lo_encrypt_key_size; | 982 | lo->lo_encrypt_key_size = info->lo_encrypt_key_size; |