diff --git a/block/bdev.c b/block/bdev.c index ed022f8c48c7..96520fac7b2f 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -860,10 +860,12 @@ void blkdev_put_no_open(struct block_device *bdev) put_device(&bdev->bd_device); } -static bool bdev_writes_blocked(struct block_device *bdev) +bool bdev_writes_blocked(struct block_device *bdev) { return bdev->bd_writers < 0; } +EXPORT_SYMBOL_GPL(bdev_writes_blocked); + static void bdev_block_writes(struct block_device *bdev) { diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 0000913f7efc..3f3a29abad1f 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1239,6 +1239,18 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) goto out_unlock; } + /* + * Changing lo_offset or lo_sizelimit on a mounted device is + * equivalent to modifying the block device contents, block + * this if writes are blocked on the device. + */ + if ((lo->lo_offset != info->lo_offset || + lo->lo_sizelimit != info->lo_sizelimit) && + bdev_writes_blocked(lo->lo_device)) { + err = -EBUSY; + goto out_unlock; + } + if (lo->lo_offset != info->lo_offset || lo->lo_sizelimit != info->lo_sizelimit) { size_changed = true; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index d463b9b5a0a5..6b908e9dd035 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -820,6 +820,7 @@ static inline bool bdev_read_only(struct block_device *bdev) return bdev_test_flag(bdev, BD_READ_ONLY) || get_disk_ro(bdev->bd_disk); } +bool bdev_writes_blocked(struct block_device *bdev); bool set_capacity_and_notify(struct gendisk *disk, sector_t size); void disk_force_media_change(struct gendisk *disk); void bdev_mark_dead(struct block_device *bdev, bool surprise);