Q. block: check bdev_read_only() from blkdev_get()
By the commit 75f1dc0
2010-11-13 block: check bdev_read_only() from blkdev_get()
bdev_read_only() call is added into blkdev_get().
This check makes the loopback block device unable to be mounted as writable once it is set to readonly, even if the corresponding is detached and the device becomes free.
We may need to re-initialize the readonly/writable status flag somewhere?
# simple tests with loopback
# mount as writable, succeed + sudo mount -o loop ./ext2.img /mnt + sudo umount /mnt
# mount as readonly, succeed + sudo mount -o ro,loop ./ext2.img /mnt + sudo umount /mnt
# mount as writable again, fail + sudo mount -o loop ./ext2.img /mnt /dev/loop0: Permission denied
Now /dev/loop0 is fixed as readonly.
J. R. Okajima
Quoted 9 lines · J. R. Okajima
By the commit 75f1dc0
2010-11-13 block: check bdev_read_only() from blkdev_get()
bdev_read_only()call is added intoblkdev_get().This check makes the loopback block device unable to be mounted as writable once it is set to readonly, even if the corresponding is detached and the device becomes free.
We may need to re-initialize the readonly/writable status flag somewhere?
Yeah, it should definitely reset r/w flag on each mount. Interested in fixing it?
Thanks.
Signature · 1 line
tejun
Tejun Heo:
Quoted 2 lines
Yeah, it should definitely reset r/w flag on each mount. Interested in fixing it?
It must be faster and sure that you (or other bdev people) would fix much more than I do.
I don't think you want me to dive into unfamiliar code.
J. R. Okajima
Hello,
Quoted 3 lines · J. R. Okajima
It must be faster and sure that you (or other bdev people) would fix much more than I do.
I don't think you want me to dive into unfamiliar code.
As you already have figured out most of technical details, I don't think it would have been difficult, and, hey, jumping into unfamiliar code is half of the fun when working on the kernel. Anyways, if you aren't interested, I'll give it a shot.
Thanks.
Signature · 1 line
tejun
PATCH 1/2 loop: guarantee lo->lo_device availability while fd is bound
In reply to J. R. Okajimaloop_set_fd() recorded the attached bdev in lo->lo_device; however, the fd may remain attached while the bdev is detached. This causes several problems.
* lo->lo_device may end up pointing to already reclaimed bdev, so loop_clr_fd() can't use it to clear bdev attributes when called from lo_ioctl().
* As lo_open() doesn't fill in @bdev on open, if the bdev is reclaimed and then recreated, the attributes set on the original bdev are lost.
Fix it by making loop_set_fd() hold onto the bdev using bdgrab(). This allows loop_clr_fd() to rely on lo->lo_device to access the attached bdev. Drop @bdev from loop_clr_fd() and always use lo->lo_device. This guarantees that bdev attributes are cleared no matter how the fd is detached.
---
Jens, these two patches fix a regression in loop introduced by block change. Thanks.
drivers/block/loop.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-)
drivers/block/loop.c +11 -12
@@ -901,7 +901,7 @@ static int loop_set_fd(struct loop_devicset_device_ro (bdev, (lo_flags &LO_FLAGS_READ_ONLY ) !=0 ); lo->lo_blocksize = lo_blocksize; - lo->lo_device = bdev; + lo->lo_device =bdgrab (bdev); lo->lo_flags = lo_flags; lo->lo_backing_file = file; lo->transfer = transfer_none;
@@ -1000,8 +1000,9 @@ loop_init_xfer(struct loop_device *lo, sreturn err; } -static int loop_clr_fd (struct loop_device *lo,struct block_device *bdev) +static int loop_clr_fd (struct loop_device *lo) { +struct block_device *bdev = lo->lo_device;struct file *filp = lo->lo_backing_file;gfp_t gfp = lo->old_gfp_mask;
@@ -1036,20 +1037,17 @@ static int loop_clr_fd(struct loop_devicmemset (lo->lo_encrypt_key,0 ,LO_KEY_SIZE );memset (lo->lo_crypt_name,0 ,LO_NAME_SIZE );memset (lo->lo_file_name,0 ,LO_NAME_SIZE ); -if (bdev) -invalidate_bdev (bdev); +invalidate_bdev (bdev);set_capacity (lo->lo_disk,0 );loop_sysfs_exit (lo); -if (bdev) { -bd_set_size (bdev,0 ); -/* let user-space know about this change */ -kobject_uevent (&disk_to_dev (bdev->bd_disk)->kobj,KOBJ_CHANGE ); - } +bd_set_size (bdev,0 ); +/* let user-space know about this change */ +kobject_uevent (&disk_to_dev (bdev->bd_disk)->kobj,KOBJ_CHANGE );mapping_set_gfp_mask (filp->f_mapping, gfp); lo->lo_state = Lo_unbound;/* This is safe: open() is still holding a reference. */ module_put (THIS_MODULE ); -if (max_part >0 && bdev) +if (max_part >0 )ioctl_by_bdev (bdev,BLKRRPART ,0 );mutex_unlock (&lo->lo_ctl_mutex);/*
@@ -1059,6 +1057,7 @@ static int loop_clr_fd(struct loop_devic* bd_mutex which is usually taken before lo_ctl_mutex. */ fput (filp); +bdput (bdev);return 0 ; }
@@ -1312,7 +1311,7 @@ static int lo_ioctl(struct block_devicebreak ;case LOOP_CLR_FD :/* loop_clr_fd would have unlocked lo_ctl_mutex on success */ - err =loop_clr_fd (lo, bdev); + err =loop_clr_fd (lo);if (!err) goto out_unlocked;break ;
@@ -1526,7 +1525,7 @@ static int lo_release(struct gendisk *di* In autoclear mode, stop the loop thread * and remove configuration after last close. */ - err =loop_clr_fd (lo,NULL ); + err =loop_clr_fd (lo);if (!err) goto out_unlocked; }else {
PATCH 2/2 block: clear ro on fd detach fd is bound
Commit 75f1dc0d (block: check bdev_read_only() from blkdev_get()) enforced bdev_read_only() check during blkdev_get(). This had an unfortunate side effect on loop because loop didn't clear ro flag on fd detach, so once a loop device was used ro, it can't be used for rw at all.
Fix it by clearing ro flag on fd detach.
--- drivers/block/loop.c | 1 + 1 file changed, 1 insertion(+)
drivers/block/loop.c +1 -0
@@ -1041,6 +1041,7 @@ static int loop_clr_fd(struct loop_devicset_capacity (lo->lo_disk,0 );loop_sysfs_exit (lo);bd_set_size (bdev,0 ); +set_device_ro (bdev,0 );/* let user-space know about this change */ kobject_uevent (&disk_to_dev (bdev->bd_disk)->kobj,KOBJ_CHANGE );mapping_set_gfp_mask (filp->f_mapping, gfp);
Re: [PATCH 2/2] block: clear ro on fd detach fd is bound
Tejun Heo:
Quoted 7 lines
Commit
75f1dc0d(block: checkbdev_read_only()fromblkdev_get()) enforcedbdev_read_only()check duringblkdev_get(). This had an unfortunate side effect on loop because loop didn't clear ro flag on fd detach, so once a loop device was used ro, it can't be used for rw at all.Fix it by clearing ro flag on fd detach.
Tested and succeeded, thanx.
J. R. Okajima