summaryrefslogtreecommitdiff
path: root/drivers/md/dm-table.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-table.c')
-rw-r--r--drivers/md/dm-table.c32
1 files changed, 24 insertions, 8 deletions
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 7d208b2b1a19..37b48f63ae6a 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -135,6 +135,7 @@ int dm_table_create(struct dm_table **result, blk_mode_t mode,
return -ENOMEM;
INIT_LIST_HEAD(&t->devices);
+ init_rwsem(&t->devices_lock);
if (!num_targets)
num_targets = KEYS_PER_NODE;
@@ -359,16 +360,20 @@ int __ref dm_get_device(struct dm_target *ti, const char *path, blk_mode_t mode,
if (dev == disk_devt(t->md->disk))
return -EINVAL;
+ down_write(&t->devices_lock);
+
dd = find_device(&t->devices, dev);
if (!dd) {
dd = kmalloc(sizeof(*dd), GFP_KERNEL);
- if (!dd)
- return -ENOMEM;
+ if (!dd) {
+ r = -ENOMEM;
+ goto unlock_ret_r;
+ }
r = dm_get_table_device(t->md, dev, mode, &dd->dm_dev);
if (r) {
kfree(dd);
- return r;
+ goto unlock_ret_r;
}
refcount_set(&dd->count, 1);
@@ -378,12 +383,17 @@ int __ref dm_get_device(struct dm_target *ti, const char *path, blk_mode_t mode,
} else if (dd->dm_dev->mode != (mode | dd->dm_dev->mode)) {
r = upgrade_mode(dd, mode, t->md);
if (r)
- return r;
+ goto unlock_ret_r;
}
refcount_inc(&dd->count);
out:
+ up_write(&t->devices_lock);
*result = dd->dm_dev;
return 0;
+
+unlock_ret_r:
+ up_write(&t->devices_lock);
+ return r;
}
EXPORT_SYMBOL(dm_get_device);
@@ -419,9 +429,12 @@ static int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
void dm_put_device(struct dm_target *ti, struct dm_dev *d)
{
int found = 0;
- struct list_head *devices = &ti->table->devices;
+ struct dm_table *t = ti->table;
+ struct list_head *devices = &t->devices;
struct dm_dev_internal *dd;
+ down_write(&t->devices_lock);
+
list_for_each_entry(dd, devices, list) {
if (dd->dm_dev == d) {
found = 1;
@@ -430,14 +443,17 @@ void dm_put_device(struct dm_target *ti, struct dm_dev *d)
}
if (!found) {
DMERR("%s: device %s not in table devices list",
- dm_device_name(ti->table->md), d->name);
- return;
+ dm_device_name(t->md), d->name);
+ goto unlock_ret;
}
if (refcount_dec_and_test(&dd->count)) {
- dm_put_table_device(ti->table->md, d);
+ dm_put_table_device(t->md, d);
list_del(&dd->list);
kfree(dd);
}
+
+unlock_ret:
+ up_write(&t->devices_lock);
}
EXPORT_SYMBOL(dm_put_device);