aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2006-06-26 03:27:24 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 12:58:35 -0400
commit7ec75f254742766eb729f1d1024a5b4e6692fc5f (patch)
tree67cf98f49397c4f7a71e12afc82c04c7dedbe17f /drivers/md
parentfba9f90e568e17c326257ee293207b75880b39d6 (diff)
[PATCH] dm: fix mapped device ref counting
To avoid races, _minor_lock must be held while changing mapped device reference counts. There are a few paths where a mapped_device pointer is returned before a reference is taken. This patch fixes them. [akpm: too late for 2.6.17 - suitable for 2.6.17.x after it has settled] Signed-off-by: Jeff Mahoney <jeffm@suse.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/dm-ioctl.c34
1 files changed, 24 insertions, 10 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 8edd6435414d..f7e743691aa8 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -102,8 +102,10 @@ static struct hash_cell *__get_name_cell(const char *str)
102 unsigned int h = hash_str(str); 102 unsigned int h = hash_str(str);
103 103
104 list_for_each_entry (hc, _name_buckets + h, name_list) 104 list_for_each_entry (hc, _name_buckets + h, name_list)
105 if (!strcmp(hc->name, str)) 105 if (!strcmp(hc->name, str)) {
106 dm_get(hc->md);
106 return hc; 107 return hc;
108 }
107 109
108 return NULL; 110 return NULL;
109} 111}
@@ -114,8 +116,10 @@ static struct hash_cell *__get_uuid_cell(const char *str)
114 unsigned int h = hash_str(str); 116 unsigned int h = hash_str(str);
115 117
116 list_for_each_entry (hc, _uuid_buckets + h, uuid_list) 118 list_for_each_entry (hc, _uuid_buckets + h, uuid_list)
117 if (!strcmp(hc->uuid, str)) 119 if (!strcmp(hc->uuid, str)) {
120 dm_get(hc->md);
118 return hc; 121 return hc;
122 }
119 123
120 return NULL; 124 return NULL;
121} 125}
@@ -191,7 +195,7 @@ static int unregister_with_devfs(struct hash_cell *hc)
191 */ 195 */
192static int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) 196static int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
193{ 197{
194 struct hash_cell *cell; 198 struct hash_cell *cell, *hc;
195 199
196 /* 200 /*
197 * Allocate the new cells. 201 * Allocate the new cells.
@@ -204,14 +208,19 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi
204 * Insert the cell into both hash tables. 208 * Insert the cell into both hash tables.
205 */ 209 */
206 down_write(&_hash_lock); 210 down_write(&_hash_lock);
207 if (__get_name_cell(name)) 211 hc = __get_name_cell(name);
212 if (hc) {
213 dm_put(hc->md);
208 goto bad; 214 goto bad;
215 }
209 216
210 list_add(&cell->name_list, _name_buckets + hash_str(name)); 217 list_add(&cell->name_list, _name_buckets + hash_str(name));
211 218
212 if (uuid) { 219 if (uuid) {
213 if (__get_uuid_cell(uuid)) { 220 hc = __get_uuid_cell(uuid);
221 if (hc) {
214 list_del(&cell->name_list); 222 list_del(&cell->name_list);
223 dm_put(hc->md);
215 goto bad; 224 goto bad;
216 } 225 }
217 list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); 226 list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
@@ -289,6 +298,7 @@ static int dm_hash_rename(const char *old, const char *new)
289 if (hc) { 298 if (hc) {
290 DMWARN("asked to rename to an already existing name %s -> %s", 299 DMWARN("asked to rename to an already existing name %s -> %s",
291 old, new); 300 old, new);
301 dm_put(hc->md);
292 up_write(&_hash_lock); 302 up_write(&_hash_lock);
293 kfree(new_name); 303 kfree(new_name);
294 return -EBUSY; 304 return -EBUSY;
@@ -328,6 +338,7 @@ static int dm_hash_rename(const char *old, const char *new)
328 dm_table_put(table); 338 dm_table_put(table);
329 } 339 }
330 340
341 dm_put(hc->md);
331 up_write(&_hash_lock); 342 up_write(&_hash_lock);
332 kfree(old_name); 343 kfree(old_name);
333 return 0; 344 return 0;
@@ -611,10 +622,8 @@ static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
611 return __get_name_cell(param->name); 622 return __get_name_cell(param->name);
612 623
613 md = dm_get_md(huge_decode_dev(param->dev)); 624 md = dm_get_md(huge_decode_dev(param->dev));
614 if (md) { 625 if (md)
615 mdptr = dm_get_mdptr(md); 626 mdptr = dm_get_mdptr(md);
616 dm_put(md);
617 }
618 627
619 return mdptr; 628 return mdptr;
620} 629}
@@ -628,7 +637,6 @@ static struct mapped_device *find_device(struct dm_ioctl *param)
628 hc = __find_device_hash_cell(param); 637 hc = __find_device_hash_cell(param);
629 if (hc) { 638 if (hc) {
630 md = hc->md; 639 md = hc->md;
631 dm_get(md);
632 640
633 /* 641 /*
634 * Sneakily write in both the name and the uuid 642 * Sneakily write in both the name and the uuid
@@ -653,6 +661,7 @@ static struct mapped_device *find_device(struct dm_ioctl *param)
653static int dev_remove(struct dm_ioctl *param, size_t param_size) 661static int dev_remove(struct dm_ioctl *param, size_t param_size)
654{ 662{
655 struct hash_cell *hc; 663 struct hash_cell *hc;
664 struct mapped_device *md;
656 665
657 down_write(&_hash_lock); 666 down_write(&_hash_lock);
658 hc = __find_device_hash_cell(param); 667 hc = __find_device_hash_cell(param);
@@ -663,8 +672,11 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
663 return -ENXIO; 672 return -ENXIO;
664 } 673 }
665 674
675 md = hc->md;
676
666 __hash_remove(hc); 677 __hash_remove(hc);
667 up_write(&_hash_lock); 678 up_write(&_hash_lock);
679 dm_put(md);
668 param->data_size = 0; 680 param->data_size = 0;
669 return 0; 681 return 0;
670} 682}
@@ -790,7 +802,6 @@ static int do_resume(struct dm_ioctl *param)
790 } 802 }
791 803
792 md = hc->md; 804 md = hc->md;
793 dm_get(md);
794 805
795 new_map = hc->new_map; 806 new_map = hc->new_map;
796 hc->new_map = NULL; 807 hc->new_map = NULL;
@@ -1078,6 +1089,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
1078{ 1089{
1079 int r; 1090 int r;
1080 struct hash_cell *hc; 1091 struct hash_cell *hc;
1092 struct mapped_device *md;
1081 1093
1082 down_write(&_hash_lock); 1094 down_write(&_hash_lock);
1083 1095
@@ -1096,7 +1108,9 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
1096 param->flags &= ~DM_INACTIVE_PRESENT_FLAG; 1108 param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
1097 1109
1098 r = __dev_status(hc->md, param); 1110 r = __dev_status(hc->md, param);
1111 md = hc->md;
1099 up_write(&_hash_lock); 1112 up_write(&_hash_lock);
1113 dm_put(md);
1100 return r; 1114 return r;
1101} 1115}
1102 1116