Merge tag 'linux-kselftest-kunit-fixes-5.14-rc2' of git://git.kernel.org/pub/scm...
[linux-2.6-microblaze.git] / drivers / block / loop.c
index cc0e8c3..f37b9e3 100644 (file)
@@ -1434,7 +1434,6 @@ static int
 loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 {
        int err;
-       struct block_device *bdev;
        kuid_t uid = current_uid();
        int prev_lo_flags;
        bool partscan = false;
@@ -1503,7 +1502,6 @@ out_unfreeze:
        if (!err && (lo->lo_flags & LO_FLAGS_PARTSCAN) &&
             !(prev_lo_flags & LO_FLAGS_PARTSCAN)) {
                lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN;
-               bdev = lo->lo_device;
                partscan = true;
        }
 out_unlock:
@@ -2237,7 +2235,7 @@ static const struct blk_mq_ops loop_mq_ops = {
        .complete       = lo_complete_rq,
 };
 
-static int loop_add(struct loop_device **l, int i)
+static int loop_add(int i)
 {
        struct loop_device *lo;
        struct gendisk *disk;
@@ -2247,9 +2245,12 @@ static int loop_add(struct loop_device **l, int i)
        lo = kzalloc(sizeof(*lo), GFP_KERNEL);
        if (!lo)
                goto out;
-
        lo->lo_state = Lo_unbound;
 
+       err = mutex_lock_killable(&loop_ctl_mutex);
+       if (err)
+               goto out_free_dev;
+
        /* allocate id, if @id >= 0, we're requesting that specific id */
        if (i >= 0) {
                err = idr_alloc(&loop_index_idr, lo, i, i + 1, GFP_KERNEL);
@@ -2259,7 +2260,7 @@ static int loop_add(struct loop_device **l, int i)
                err = idr_alloc(&loop_index_idr, lo, 0, 0, GFP_KERNEL);
        }
        if (err < 0)
-               goto out_free_dev;
+               goto out_unlock;
        i = err;
 
        err = -ENOMEM;
@@ -2326,13 +2327,15 @@ static int loop_add(struct loop_device **l, int i)
        disk->queue             = lo->lo_queue;
        sprintf(disk->disk_name, "loop%d", i);
        add_disk(disk);
-       *l = lo;
-       return lo->lo_number;
+       mutex_unlock(&loop_ctl_mutex);
+       return i;
 
 out_cleanup_tags:
        blk_mq_free_tag_set(&lo->tag_set);
 out_free_idr:
        idr_remove(&loop_index_idr, i);
+out_unlock:
+       mutex_unlock(&loop_ctl_mutex);
 out_free_dev:
        kfree(lo);
 out:
@@ -2348,109 +2351,86 @@ static void loop_remove(struct loop_device *lo)
        kfree(lo);
 }
 
-static int find_free_cb(int id, void *ptr, void *data)
+static void loop_probe(dev_t dev)
 {
-       struct loop_device *lo = ptr;
-       struct loop_device **l = data;
+       int idx = MINOR(dev) >> part_shift;
 
-       if (lo->lo_state == Lo_unbound) {
-               *l = lo;
-               return 1;
-       }
-       return 0;
+       if (max_loop && idx >= max_loop)
+               return;
+       loop_add(idx);
 }
 
-static int loop_lookup(struct loop_device **l, int i)
+static int loop_control_remove(int idx)
 {
        struct loop_device *lo;
-       int ret = -ENODEV;
+       int ret;
 
-       if (i < 0) {
-               int err;
+       if (idx < 0) {
+               pr_warn("deleting an unspecified loop device is not supported.\n");
+               return -EINVAL;
+       }
+               
+       ret = mutex_lock_killable(&loop_ctl_mutex);
+       if (ret)
+               return ret;
 
-               err = idr_for_each(&loop_index_idr, &find_free_cb, &lo);
-               if (err == 1) {
-                       *l = lo;
-                       ret = lo->lo_number;
-               }
-               goto out;
+       lo = idr_find(&loop_index_idr, idx);
+       if (!lo) {
+               ret = -ENODEV;
+               goto out_unlock_ctrl;
        }
 
-       /* lookup and return a specific i */
-       lo = idr_find(&loop_index_idr, i);
-       if (lo) {
-               *l = lo;
-               ret = lo->lo_number;
+       ret = mutex_lock_killable(&lo->lo_mutex);
+       if (ret)
+               goto out_unlock_ctrl;
+       if (lo->lo_state != Lo_unbound ||
+           atomic_read(&lo->lo_refcnt) > 0) {
+               mutex_unlock(&lo->lo_mutex);
+               ret = -EBUSY;
+               goto out_unlock_ctrl;
        }
-out:
+       lo->lo_state = Lo_deleting;
+       mutex_unlock(&lo->lo_mutex);
+
+       idr_remove(&loop_index_idr, lo->lo_number);
+       loop_remove(lo);
+out_unlock_ctrl:
+       mutex_unlock(&loop_ctl_mutex);
        return ret;
 }
 
-static void loop_probe(dev_t dev)
+static int loop_control_get_free(int idx)
 {
-       int idx = MINOR(dev) >> part_shift;
        struct loop_device *lo;
+       int id, ret;
 
-       if (max_loop && idx >= max_loop)
-               return;
-
-       mutex_lock(&loop_ctl_mutex);
-       if (loop_lookup(&lo, idx) < 0)
-               loop_add(&lo, idx);
+       ret = mutex_lock_killable(&loop_ctl_mutex);
+       if (ret)
+               return ret;
+       idr_for_each_entry(&loop_index_idr, lo, id) {
+               if (lo->lo_state == Lo_unbound)
+                       goto found;
+       }
        mutex_unlock(&loop_ctl_mutex);
+       return loop_add(-1);
+found:
+       mutex_unlock(&loop_ctl_mutex);
+       return id;
 }
 
 static long loop_control_ioctl(struct file *file, unsigned int cmd,
                               unsigned long parm)
 {
-       struct loop_device *lo;
-       int ret;
-
-       ret = mutex_lock_killable(&loop_ctl_mutex);
-       if (ret)
-               return ret;
-
-       ret = -ENOSYS;
        switch (cmd) {
        case LOOP_CTL_ADD:
-               ret = loop_lookup(&lo, parm);
-               if (ret >= 0) {
-                       ret = -EEXIST;
-                       break;
-               }
-               ret = loop_add(&lo, parm);
-               break;
+               return loop_add(parm);
        case LOOP_CTL_REMOVE:
-               ret = loop_lookup(&lo, parm);
-               if (ret < 0)
-                       break;
-               ret = mutex_lock_killable(&lo->lo_mutex);
-               if (ret)
-                       break;
-               if (lo->lo_state != Lo_unbound) {
-                       ret = -EBUSY;
-                       mutex_unlock(&lo->lo_mutex);
-                       break;
-               }
-               if (atomic_read(&lo->lo_refcnt) > 0) {
-                       ret = -EBUSY;
-                       mutex_unlock(&lo->lo_mutex);
-                       break;
-               }
-               lo->lo_state = Lo_deleting;
-               mutex_unlock(&lo->lo_mutex);
-               idr_remove(&loop_index_idr, lo->lo_number);
-               loop_remove(lo);
-               break;
+               return loop_control_remove(parm);
        case LOOP_CTL_GET_FREE:
-               ret = loop_lookup(&lo, -1);
-               if (ret >= 0)
-                       break;
-               ret = loop_add(&lo, -1);
+               return loop_control_get_free(parm);
+       default:
+               return -ENOSYS;
        }
-       mutex_unlock(&loop_ctl_mutex);
-
-       return ret;
 }
 
 static const struct file_operations loop_ctl_fops = {
@@ -2473,7 +2453,6 @@ MODULE_ALIAS("devname:loop-control");
 static int __init loop_init(void)
 {
        int i, nr;
-       struct loop_device *lo;
        int err;
 
        part_shift = 0;
@@ -2525,10 +2504,8 @@ static int __init loop_init(void)
        }
 
        /* pre-create number of devices given by config or max_loop */
-       mutex_lock(&loop_ctl_mutex);
        for (i = 0; i < nr; i++)
-               loop_add(&lo, i);
-       mutex_unlock(&loop_ctl_mutex);
+               loop_add(i);
 
        printk(KERN_INFO "loop: module loaded\n");
        return 0;
@@ -2539,26 +2516,20 @@ err_out:
        return err;
 }
 
-static int loop_exit_cb(int id, void *ptr, void *data)
-{
-       struct loop_device *lo = ptr;
-
-       loop_remove(lo);
-       return 0;
-}
-
 static void __exit loop_exit(void)
 {
-       mutex_lock(&loop_ctl_mutex);
-
-       idr_for_each(&loop_index_idr, &loop_exit_cb, NULL);
-       idr_destroy(&loop_index_idr);
+       struct loop_device *lo;
+       int id;
 
        unregister_blkdev(LOOP_MAJOR, "loop");
-
        misc_deregister(&loop_misc);
 
+       mutex_lock(&loop_ctl_mutex);
+       idr_for_each_entry(&loop_index_idr, lo, id)
+               loop_remove(lo);
        mutex_unlock(&loop_ctl_mutex);
+
+       idr_destroy(&loop_index_idr);
 }
 
 module_init(loop_init);