summaryrefslogtreecommitdiff
path: root/drivers/block/loop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/loop.c')
-rw-r--r--drivers/block/loop.c169
1 files changed, 70 insertions, 99 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index cc0e8c39a48b..f37b9e3d833c 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -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);