aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/dm-ioctl.c15
-rw-r--r--drivers/md/dm.c62
-rw-r--r--drivers/md/dm.h5
3 files changed, 62 insertions, 20 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 6a6d475f8e80..feb64d65fbfb 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -274,6 +274,10 @@ retry:
274 up_write(&_hash_lock); 274 up_write(&_hash_lock);
275 275
276 dm_put(md); 276 dm_put(md);
277 if (likely(keep_open_devices))
278 dm_destroy(md);
279 else
280 dm_destroy_immediate(md);
277 281
278 /* 282 /*
279 * Some mapped devices may be using other mapped 283 * Some mapped devices may be using other mapped
@@ -644,17 +648,19 @@ static int dev_create(struct dm_ioctl *param, size_t param_size)
644 return r; 648 return r;
645 649
646 r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); 650 r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
647 if (r) 651 if (r) {
648 goto out; 652 dm_put(md);
653 dm_destroy(md);
654 return r;
655 }
649 656
650 param->flags &= ~DM_INACTIVE_PRESENT_FLAG; 657 param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
651 658
652 __dev_status(md, param); 659 __dev_status(md, param);
653 660
654out:
655 dm_put(md); 661 dm_put(md);
656 662
657 return r; 663 return 0;
658} 664}
659 665
660/* 666/*
@@ -748,6 +754,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
748 param->flags |= DM_UEVENT_GENERATED_FLAG; 754 param->flags |= DM_UEVENT_GENERATED_FLAG;
749 755
750 dm_put(md); 756 dm_put(md);
757 dm_destroy(md);
751 return 0; 758 return 0;
752} 759}
753 760
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index ba6934c3e2c5..a503b95ecbfb 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -20,6 +20,7 @@
20#include <linux/slab.h> 20#include <linux/slab.h>
21#include <linux/idr.h> 21#include <linux/idr.h>
22#include <linux/hdreg.h> 22#include <linux/hdreg.h>
23#include <linux/delay.h>
23 24
24#include <trace/events/block.h> 25#include <trace/events/block.h>
25 26
@@ -2171,6 +2172,7 @@ void dm_set_mdptr(struct mapped_device *md, void *ptr)
2171void dm_get(struct mapped_device *md) 2172void dm_get(struct mapped_device *md)
2172{ 2173{
2173 atomic_inc(&md->holders); 2174 atomic_inc(&md->holders);
2175 BUG_ON(test_bit(DMF_FREEING, &md->flags));
2174} 2176}
2175 2177
2176const char *dm_device_name(struct mapped_device *md) 2178const char *dm_device_name(struct mapped_device *md)
@@ -2179,27 +2181,55 @@ const char *dm_device_name(struct mapped_device *md)
2179} 2181}
2180EXPORT_SYMBOL_GPL(dm_device_name); 2182EXPORT_SYMBOL_GPL(dm_device_name);
2181 2183
2182void dm_put(struct mapped_device *md) 2184static void __dm_destroy(struct mapped_device *md, bool wait)
2183{ 2185{
2184 struct dm_table *map; 2186 struct dm_table *map;
2185 2187
2186 BUG_ON(test_bit(DMF_FREEING, &md->flags)); 2188 might_sleep();
2187 2189
2188 if (atomic_dec_and_lock(&md->holders, &_minor_lock)) { 2190 spin_lock(&_minor_lock);
2189 map = dm_get_live_table(md); 2191 map = dm_get_live_table(md);
2190 idr_replace(&_minor_idr, MINOR_ALLOCED, 2192 idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md))));
2191 MINOR(disk_devt(dm_disk(md)))); 2193 set_bit(DMF_FREEING, &md->flags);
2192 set_bit(DMF_FREEING, &md->flags); 2194 spin_unlock(&_minor_lock);
2193 spin_unlock(&_minor_lock); 2195
2194 if (!dm_suspended_md(md)) { 2196 if (!dm_suspended_md(md)) {
2195 dm_table_presuspend_targets(map); 2197 dm_table_presuspend_targets(map);
2196 dm_table_postsuspend_targets(map); 2198 dm_table_postsuspend_targets(map);
2197 }
2198 dm_sysfs_exit(md);
2199 dm_table_put(map);
2200 dm_table_destroy(__unbind(md));
2201 free_dev(md);
2202 } 2199 }
2200
2201 /*
2202 * Rare, but there may be I/O requests still going to complete,
2203 * for example. Wait for all references to disappear.
2204 * No one should increment the reference count of the mapped_device,
2205 * after the mapped_device state becomes DMF_FREEING.
2206 */
2207 if (wait)
2208 while (atomic_read(&md->holders))
2209 msleep(1);
2210 else if (atomic_read(&md->holders))
2211 DMWARN("%s: Forcibly removing mapped_device still in use! (%d users)",
2212 dm_device_name(md), atomic_read(&md->holders));
2213
2214 dm_sysfs_exit(md);
2215 dm_table_put(map);
2216 dm_table_destroy(__unbind(md));
2217 free_dev(md);
2218}
2219
2220void dm_destroy(struct mapped_device *md)
2221{
2222 __dm_destroy(md, true);
2223}
2224
2225void dm_destroy_immediate(struct mapped_device *md)
2226{
2227 __dm_destroy(md, false);
2228}
2229
2230void dm_put(struct mapped_device *md)
2231{
2232 atomic_dec(&md->holders);
2203} 2233}
2204EXPORT_SYMBOL_GPL(dm_put); 2234EXPORT_SYMBOL_GPL(dm_put);
2205 2235
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index bad1724d4869..8223671e4901 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -122,6 +122,11 @@ void dm_linear_exit(void);
122int dm_stripe_init(void); 122int dm_stripe_init(void);
123void dm_stripe_exit(void); 123void dm_stripe_exit(void);
124 124
125/*
126 * mapped_device operations
127 */
128void dm_destroy(struct mapped_device *md);
129void dm_destroy_immediate(struct mapped_device *md);
125int dm_open_count(struct mapped_device *md); 130int dm_open_count(struct mapped_device *md);
126int dm_lock_for_deletion(struct mapped_device *md); 131int dm_lock_for_deletion(struct mapped_device *md);
127 132