@@ -689,6 +698,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
unsigned int arg)
{
- struct file *file, *old_file;
+ struct file *file = NULL, *old_file;
+ struct file *f, *virt_file = NULL, *old_virt_file;
int error;
@@ -704,12 +714,19 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
file = fget(arg);
if (!file)
- goto out;
+ goto out_err;
+ f = loop_real_file(file);
+ if (f) {
+ virt_file = file;
error = loop_validate_file(file, bdev);
if (error)
- goto out_putf;
+ goto out_err;
old_file = lo->lo_backing_file;
+ old_virt_file = lo->lo_backing_virt_file;
lo->old_gfp_mask = mapping_gfp_mask(file->f_mapping);
mapping_set_gfp_mask(file->f_mapping,
lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
-@@ -728,12 +746,16 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
- blk_mq_unfreeze_queue(lo->lo_queue);
-
+@@ -728,14 +746,18 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
+ * dependency.
+ */
fput(old_file);
+ if (old_virt_file)
+ fput(old_virt_file);
- if (lo->lo_flags & LO_FLAGS_PARTSCAN)
+ if (partscan)
loop_reread_partitions(lo, bdev);
return 0;
- out_putf:
- fput(file);
+ out_err:
+ mutex_unlock(&loop_ctl_mutex);
+ if (file)
+ fput(file);
+ if (virt_file)
+ fput(virt_file);
- out:
return error;
}
+
@@ -921,7 +943,7 @@ static int loop_prepare_queue(struct loop_device *lo)
static int loop_set_fd(struct loop_device *lo, fmode_t mode,
struct block_device *bdev, unsigned int arg)
lo->lo_sizelimit = 0;
@@ -1000,6 +1029,8 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
- out_putf:
+ out_putf:
fput(file);
+ if (virt_file)
+ fput(virt_file);
- out:
+ out:
/* This is safe: open() is still holding a reference. */
module_put(THIS_MODULE);
@@ -1046,6 +1077,7 @@ loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer,
static int loop_clr_fd(struct loop_device *lo)
{
- struct file *filp = lo->lo_backing_file;
+ struct file *filp = NULL;
+ struct file *virt_filp = lo->lo_backing_virt_file;
gfp_t gfp = lo->old_gfp_mask;
struct block_device *bdev = lo->lo_device;
loop_release_xfer(lo);
@@ -1125,6 +1158,8 @@ static int loop_clr_fd(struct loop_device *lo)
- * bd_mutex which is usually taken before lo_ctl_mutex.
*/
- fput(filp);
+ if (filp)
+ fput(filp);
+ if (virt_filp)
+ fput(virt_filp);
- return 0;
+ return err;
}
diff --git a/drivers/block/loop.h b/drivers/block/loop.h