Merge tag 'for-4.17/block-20180402' of git://git.kernel.dk/linux-block
[sfrench/cifs-2.6.git] / drivers / block / loop.c
index ee62d2d517bf4537c60cdd83c70363382403fc57..264abaaff662e32e93f375bb94a8830874491020 100644 (file)
@@ -214,10 +214,10 @@ static void __loop_update_dio(struct loop_device *lo, bool dio)
        blk_mq_freeze_queue(lo->lo_queue);
        lo->use_dio = use_dio;
        if (use_dio) {
-               queue_flag_clear_unlocked(QUEUE_FLAG_NOMERGES, lo->lo_queue);
+               blk_queue_flag_clear(QUEUE_FLAG_NOMERGES, lo->lo_queue);
                lo->lo_flags |= LO_FLAGS_DIRECT_IO;
        } else {
-               queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, lo->lo_queue);
+               blk_queue_flag_set(QUEUE_FLAG_NOMERGES, lo->lo_queue);
                lo->lo_flags &= ~LO_FLAGS_DIRECT_IO;
        }
        blk_mq_unfreeze_queue(lo->lo_queue);
@@ -817,7 +817,7 @@ static void loop_config_discard(struct loop_device *lo)
                q->limits.discard_alignment = 0;
                blk_queue_max_discard_sectors(q, 0);
                blk_queue_max_write_zeroes_sectors(q, 0);
-               queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q);
+               blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
                return;
        }
 
@@ -826,7 +826,7 @@ static void loop_config_discard(struct loop_device *lo)
 
        blk_queue_max_discard_sectors(q, UINT_MAX >> 9);
        blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9);
-       queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
+       blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
 }
 
 static void loop_unprepare_queue(struct loop_device *lo)
@@ -1167,21 +1167,17 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 static int
 loop_get_status(struct loop_device *lo, struct loop_info64 *info)
 {
-       struct file *file = lo->lo_backing_file;
+       struct file *file;
        struct kstat stat;
-       int error;
+       int ret;
 
-       if (lo->lo_state != Lo_bound)
+       if (lo->lo_state != Lo_bound) {
+               mutex_unlock(&lo->lo_ctl_mutex);
                return -ENXIO;
-       error = vfs_getattr(&file->f_path, &stat,
-                           STATX_INO, AT_STATX_SYNC_AS_STAT);
-       if (error)
-               return error;
+       }
+
        memset(info, 0, sizeof(*info));
        info->lo_number = lo->lo_number;
-       info->lo_device = huge_encode_dev(stat.dev);
-       info->lo_inode = stat.ino;
-       info->lo_rdevice = huge_encode_dev(lo->lo_device ? stat.rdev : stat.dev);
        info->lo_offset = lo->lo_offset;
        info->lo_sizelimit = lo->lo_sizelimit;
        info->lo_flags = lo->lo_flags;
@@ -1194,7 +1190,19 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info)
                memcpy(info->lo_encrypt_key, lo->lo_encrypt_key,
                       lo->lo_encrypt_key_size);
        }
-       return 0;
+
+       /* Drop lo_ctl_mutex while we call into the filesystem. */
+       file = get_file(lo->lo_backing_file);
+       mutex_unlock(&lo->lo_ctl_mutex);
+       ret = vfs_getattr(&file->f_path, &stat, STATX_INO,
+                         AT_STATX_SYNC_AS_STAT);
+       if (!ret) {
+               info->lo_device = huge_encode_dev(stat.dev);
+               info->lo_inode = stat.ino;
+               info->lo_rdevice = huge_encode_dev(stat.rdev);
+       }
+       fput(file);
+       return ret;
 }
 
 static void
@@ -1352,7 +1360,10 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
        struct loop_device *lo = bdev->bd_disk->private_data;
        int err;
 
-       mutex_lock_nested(&lo->lo_ctl_mutex, 1);
+       err = mutex_lock_killable_nested(&lo->lo_ctl_mutex, 1);
+       if (err)
+               goto out_unlocked;
+
        switch (cmd) {
        case LOOP_SET_FD:
                err = loop_set_fd(lo, mode, bdev, arg);
@@ -1374,7 +1385,8 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
                break;
        case LOOP_GET_STATUS:
                err = loop_get_status_old(lo, (struct loop_info __user *) arg);
-               break;
+               /* loop_get_status() unlocks lo_ctl_mutex */
+               goto out_unlocked;
        case LOOP_SET_STATUS64:
                err = -EPERM;
                if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
@@ -1383,7 +1395,8 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
                break;
        case LOOP_GET_STATUS64:
                err = loop_get_status64(lo, (struct loop_info64 __user *) arg);
-               break;
+               /* loop_get_status() unlocks lo_ctl_mutex */
+               goto out_unlocked;
        case LOOP_SET_CAPACITY:
                err = -EPERM;
                if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
@@ -1535,16 +1548,20 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
 
        switch(cmd) {
        case LOOP_SET_STATUS:
-               mutex_lock(&lo->lo_ctl_mutex);
-               err = loop_set_status_compat(
-                       lo, (const struct compat_loop_info __user *) arg);
-               mutex_unlock(&lo->lo_ctl_mutex);
+               err = mutex_lock_killable(&lo->lo_ctl_mutex);
+               if (!err) {
+                       err = loop_set_status_compat(lo,
+                                                    (const struct compat_loop_info __user *)arg);
+                       mutex_unlock(&lo->lo_ctl_mutex);
+               }
                break;
        case LOOP_GET_STATUS:
-               mutex_lock(&lo->lo_ctl_mutex);
-               err = loop_get_status_compat(
-                       lo, (struct compat_loop_info __user *) arg);
-               mutex_unlock(&lo->lo_ctl_mutex);
+               err = mutex_lock_killable(&lo->lo_ctl_mutex);
+               if (!err) {
+                       err = loop_get_status_compat(lo,
+                                                    (struct compat_loop_info __user *)arg);
+                       /* loop_get_status() unlocks lo_ctl_mutex */
+               }
                break;
        case LOOP_SET_CAPACITY:
        case LOOP_CLR_FD:
@@ -1808,7 +1825,7 @@ static int loop_add(struct loop_device **l, int i)
         * page. For directio mode, merge does help to dispatch bigger request
         * to underlayer disk. We will enable merge once directio is enabled.
         */
-       queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, lo->lo_queue);
+       blk_queue_flag_set(QUEUE_FLAG_NOMERGES, lo->lo_queue);
 
        err = -ENOMEM;
        disk = lo->lo_disk = alloc_disk(1 << part_shift);
@@ -1864,8 +1881,8 @@ out:
 
 static void loop_remove(struct loop_device *lo)
 {
-       blk_cleanup_queue(lo->lo_queue);
        del_gendisk(lo->lo_disk);
+       blk_cleanup_queue(lo->lo_queue);
        blk_mq_free_tag_set(&lo->tag_set);
        put_disk(lo->lo_disk);
        kfree(lo);
@@ -1949,7 +1966,9 @@ static long loop_control_ioctl(struct file *file, unsigned int cmd,
                ret = loop_lookup(&lo, parm);
                if (ret < 0)
                        break;
-               mutex_lock(&lo->lo_ctl_mutex);
+               ret = mutex_lock_killable(&lo->lo_ctl_mutex);
+               if (ret)
+                       break;
                if (lo->lo_state != Lo_unbound) {
                        ret = -EBUSY;
                        mutex_unlock(&lo->lo_ctl_mutex);