aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-ioctl.c')
-rw-r--r--drivers/md/dm-ioctl.c139
1 files changed, 74 insertions, 65 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 8edd6435414d..d13bb15a8a02 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. 2 * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
3 * Copyright (C) 2004 - 2005 Red Hat, Inc. All rights reserved. 3 * Copyright (C) 2004 - 2006 Red Hat, Inc. All rights reserved.
4 * 4 *
5 * This file is released under the GPL. 5 * This file is released under the GPL.
6 */ 6 */
@@ -13,12 +13,12 @@
13#include <linux/init.h> 13#include <linux/init.h>
14#include <linux/wait.h> 14#include <linux/wait.h>
15#include <linux/slab.h> 15#include <linux/slab.h>
16#include <linux/devfs_fs_kernel.h>
17#include <linux/dm-ioctl.h> 16#include <linux/dm-ioctl.h>
18#include <linux/hdreg.h> 17#include <linux/hdreg.h>
19 18
20#include <asm/uaccess.h> 19#include <asm/uaccess.h>
21 20
21#define DM_MSG_PREFIX "ioctl"
22#define DM_DRIVER_EMAIL "dm-devel@redhat.com" 22#define DM_DRIVER_EMAIL "dm-devel@redhat.com"
23 23
24/*----------------------------------------------------------------- 24/*-----------------------------------------------------------------
@@ -48,7 +48,7 @@ struct vers_iter {
48static struct list_head _name_buckets[NUM_BUCKETS]; 48static struct list_head _name_buckets[NUM_BUCKETS];
49static struct list_head _uuid_buckets[NUM_BUCKETS]; 49static struct list_head _uuid_buckets[NUM_BUCKETS];
50 50
51static void dm_hash_remove_all(void); 51static void dm_hash_remove_all(int keep_open_devices);
52 52
53/* 53/*
54 * Guards access to both hash tables. 54 * Guards access to both hash tables.
@@ -67,14 +67,12 @@ static int dm_hash_init(void)
67{ 67{
68 init_buckets(_name_buckets); 68 init_buckets(_name_buckets);
69 init_buckets(_uuid_buckets); 69 init_buckets(_uuid_buckets);
70 devfs_mk_dir(DM_DIR);
71 return 0; 70 return 0;
72} 71}
73 72
74static void dm_hash_exit(void) 73static void dm_hash_exit(void)
75{ 74{
76 dm_hash_remove_all(); 75 dm_hash_remove_all(0);
77 devfs_remove(DM_DIR);
78} 76}
79 77
80/*----------------------------------------------------------------- 78/*-----------------------------------------------------------------
@@ -102,8 +100,10 @@ static struct hash_cell *__get_name_cell(const char *str)
102 unsigned int h = hash_str(str); 100 unsigned int h = hash_str(str);
103 101
104 list_for_each_entry (hc, _name_buckets + h, name_list) 102 list_for_each_entry (hc, _name_buckets + h, name_list)
105 if (!strcmp(hc->name, str)) 103 if (!strcmp(hc->name, str)) {
104 dm_get(hc->md);
106 return hc; 105 return hc;
106 }
107 107
108 return NULL; 108 return NULL;
109} 109}
@@ -114,8 +114,10 @@ static struct hash_cell *__get_uuid_cell(const char *str)
114 unsigned int h = hash_str(str); 114 unsigned int h = hash_str(str);
115 115
116 list_for_each_entry (hc, _uuid_buckets + h, uuid_list) 116 list_for_each_entry (hc, _uuid_buckets + h, uuid_list)
117 if (!strcmp(hc->uuid, str)) 117 if (!strcmp(hc->uuid, str)) {
118 dm_get(hc->md);
118 return hc; 119 return hc;
120 }
119 121
120 return NULL; 122 return NULL;
121} 123}
@@ -167,31 +169,12 @@ static void free_cell(struct hash_cell *hc)
167} 169}
168 170
169/* 171/*
170 * devfs stuff.
171 */
172static int register_with_devfs(struct hash_cell *hc)
173{
174 struct gendisk *disk = dm_disk(hc->md);
175
176 devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
177 S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
178 DM_DIR "/%s", hc->name);
179 return 0;
180}
181
182static int unregister_with_devfs(struct hash_cell *hc)
183{
184 devfs_remove(DM_DIR"/%s", hc->name);
185 return 0;
186}
187
188/*
189 * The kdev_t and uuid of a device can never change once it is 172 * The kdev_t and uuid of a device can never change once it is
190 * initially inserted. 173 * initially inserted.
191 */ 174 */
192static int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) 175static int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
193{ 176{
194 struct hash_cell *cell; 177 struct hash_cell *cell, *hc;
195 178
196 /* 179 /*
197 * Allocate the new cells. 180 * Allocate the new cells.
@@ -204,19 +187,23 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi
204 * Insert the cell into both hash tables. 187 * Insert the cell into both hash tables.
205 */ 188 */
206 down_write(&_hash_lock); 189 down_write(&_hash_lock);
207 if (__get_name_cell(name)) 190 hc = __get_name_cell(name);
191 if (hc) {
192 dm_put(hc->md);
208 goto bad; 193 goto bad;
194 }
209 195
210 list_add(&cell->name_list, _name_buckets + hash_str(name)); 196 list_add(&cell->name_list, _name_buckets + hash_str(name));
211 197
212 if (uuid) { 198 if (uuid) {
213 if (__get_uuid_cell(uuid)) { 199 hc = __get_uuid_cell(uuid);
200 if (hc) {
214 list_del(&cell->name_list); 201 list_del(&cell->name_list);
202 dm_put(hc->md);
215 goto bad; 203 goto bad;
216 } 204 }
217 list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); 205 list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
218 } 206 }
219 register_with_devfs(cell);
220 dm_get(md); 207 dm_get(md);
221 dm_set_mdptr(md, cell); 208 dm_set_mdptr(md, cell);
222 up_write(&_hash_lock); 209 up_write(&_hash_lock);
@@ -236,7 +223,6 @@ static void __hash_remove(struct hash_cell *hc)
236 /* remove from the dev hash */ 223 /* remove from the dev hash */
237 list_del(&hc->uuid_list); 224 list_del(&hc->uuid_list);
238 list_del(&hc->name_list); 225 list_del(&hc->name_list);
239 unregister_with_devfs(hc);
240 dm_set_mdptr(hc->md, NULL); 226 dm_set_mdptr(hc->md, NULL);
241 227
242 table = dm_get_table(hc->md); 228 table = dm_get_table(hc->md);
@@ -251,19 +237,41 @@ static void __hash_remove(struct hash_cell *hc)
251 free_cell(hc); 237 free_cell(hc);
252} 238}
253 239
254static void dm_hash_remove_all(void) 240static void dm_hash_remove_all(int keep_open_devices)
255{ 241{
256 int i; 242 int i, dev_skipped, dev_removed;
257 struct hash_cell *hc; 243 struct hash_cell *hc;
258 struct list_head *tmp, *n; 244 struct list_head *tmp, *n;
259 245
260 down_write(&_hash_lock); 246 down_write(&_hash_lock);
247
248retry:
249 dev_skipped = dev_removed = 0;
261 for (i = 0; i < NUM_BUCKETS; i++) { 250 for (i = 0; i < NUM_BUCKETS; i++) {
262 list_for_each_safe (tmp, n, _name_buckets + i) { 251 list_for_each_safe (tmp, n, _name_buckets + i) {
263 hc = list_entry(tmp, struct hash_cell, name_list); 252 hc = list_entry(tmp, struct hash_cell, name_list);
253
254 if (keep_open_devices &&
255 dm_lock_for_deletion(hc->md)) {
256 dev_skipped++;
257 continue;
258 }
264 __hash_remove(hc); 259 __hash_remove(hc);
260 dev_removed = 1;
265 } 261 }
266 } 262 }
263
264 /*
265 * Some mapped devices may be using other mapped devices, so if any
266 * still exist, repeat until we make no further progress.
267 */
268 if (dev_skipped) {
269 if (dev_removed)
270 goto retry;
271
272 DMWARN("remove_all left %d open device(s)", dev_skipped);
273 }
274
267 up_write(&_hash_lock); 275 up_write(&_hash_lock);
268} 276}
269 277
@@ -289,6 +297,7 @@ static int dm_hash_rename(const char *old, const char *new)
289 if (hc) { 297 if (hc) {
290 DMWARN("asked to rename to an already existing name %s -> %s", 298 DMWARN("asked to rename to an already existing name %s -> %s",
291 old, new); 299 old, new);
300 dm_put(hc->md);
292 up_write(&_hash_lock); 301 up_write(&_hash_lock);
293 kfree(new_name); 302 kfree(new_name);
294 return -EBUSY; 303 return -EBUSY;
@@ -309,16 +318,11 @@ static int dm_hash_rename(const char *old, const char *new)
309 /* 318 /*
310 * rename and move the name cell. 319 * rename and move the name cell.
311 */ 320 */
312 unregister_with_devfs(hc);
313
314 list_del(&hc->name_list); 321 list_del(&hc->name_list);
315 old_name = hc->name; 322 old_name = hc->name;
316 hc->name = new_name; 323 hc->name = new_name;
317 list_add(&hc->name_list, _name_buckets + hash_str(new_name)); 324 list_add(&hc->name_list, _name_buckets + hash_str(new_name));
318 325
319 /* rename the device node in devfs */
320 register_with_devfs(hc);
321
322 /* 326 /*
323 * Wake up any dm event waiters. 327 * Wake up any dm event waiters.
324 */ 328 */
@@ -328,6 +332,7 @@ static int dm_hash_rename(const char *old, const char *new)
328 dm_table_put(table); 332 dm_table_put(table);
329 } 333 }
330 334
335 dm_put(hc->md);
331 up_write(&_hash_lock); 336 up_write(&_hash_lock);
332 kfree(old_name); 337 kfree(old_name);
333 return 0; 338 return 0;
@@ -344,7 +349,7 @@ typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size);
344 349
345static int remove_all(struct dm_ioctl *param, size_t param_size) 350static int remove_all(struct dm_ioctl *param, size_t param_size)
346{ 351{
347 dm_hash_remove_all(); 352 dm_hash_remove_all(1);
348 param->data_size = 0; 353 param->data_size = 0;
349 return 0; 354 return 0;
350} 355}
@@ -524,7 +529,6 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
524{ 529{
525 struct gendisk *disk = dm_disk(md); 530 struct gendisk *disk = dm_disk(md);
526 struct dm_table *table; 531 struct dm_table *table;
527 struct block_device *bdev;
528 532
529 param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | 533 param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
530 DM_ACTIVE_PRESENT_FLAG); 534 DM_ACTIVE_PRESENT_FLAG);
@@ -534,20 +538,12 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
534 538
535 param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor)); 539 param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));
536 540
537 if (!(param->flags & DM_SKIP_BDGET_FLAG)) { 541 /*
538 bdev = bdget_disk(disk, 0); 542 * Yes, this will be out of date by the time it gets back
539 if (!bdev) 543 * to userland, but it is still very useful for
540 return -ENXIO; 544 * debugging.
541 545 */
542 /* 546 param->open_count = dm_open_count(md);
543 * Yes, this will be out of date by the time it gets back
544 * to userland, but it is still very useful for
545 * debugging.
546 */
547 param->open_count = bdev->bd_openers;
548 bdput(bdev);
549 } else
550 param->open_count = -1;
551 547
552 if (disk->policy) 548 if (disk->policy)
553 param->flags |= DM_READONLY_FLAG; 549 param->flags |= DM_READONLY_FLAG;
@@ -567,7 +563,7 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
567 563
568static int dev_create(struct dm_ioctl *param, size_t param_size) 564static int dev_create(struct dm_ioctl *param, size_t param_size)
569{ 565{
570 int r; 566 int r, m = DM_ANY_MINOR;
571 struct mapped_device *md; 567 struct mapped_device *md;
572 568
573 r = check_name(param->name); 569 r = check_name(param->name);
@@ -575,10 +571,9 @@ static int dev_create(struct dm_ioctl *param, size_t param_size)
575 return r; 571 return r;
576 572
577 if (param->flags & DM_PERSISTENT_DEV_FLAG) 573 if (param->flags & DM_PERSISTENT_DEV_FLAG)
578 r = dm_create_with_minor(MINOR(huge_decode_dev(param->dev)), &md); 574 m = MINOR(huge_decode_dev(param->dev));
579 else
580 r = dm_create(&md);
581 575
576 r = dm_create(m, &md);
582 if (r) 577 if (r)
583 return r; 578 return r;
584 579
@@ -611,10 +606,8 @@ static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
611 return __get_name_cell(param->name); 606 return __get_name_cell(param->name);
612 607
613 md = dm_get_md(huge_decode_dev(param->dev)); 608 md = dm_get_md(huge_decode_dev(param->dev));
614 if (md) { 609 if (md)
615 mdptr = dm_get_mdptr(md); 610 mdptr = dm_get_mdptr(md);
616 dm_put(md);
617 }
618 611
619 return mdptr; 612 return mdptr;
620} 613}
@@ -628,7 +621,6 @@ static struct mapped_device *find_device(struct dm_ioctl *param)
628 hc = __find_device_hash_cell(param); 621 hc = __find_device_hash_cell(param);
629 if (hc) { 622 if (hc) {
630 md = hc->md; 623 md = hc->md;
631 dm_get(md);
632 624
633 /* 625 /*
634 * Sneakily write in both the name and the uuid 626 * Sneakily write in both the name and the uuid
@@ -653,6 +645,8 @@ static struct mapped_device *find_device(struct dm_ioctl *param)
653static int dev_remove(struct dm_ioctl *param, size_t param_size) 645static int dev_remove(struct dm_ioctl *param, size_t param_size)
654{ 646{
655 struct hash_cell *hc; 647 struct hash_cell *hc;
648 struct mapped_device *md;
649 int r;
656 650
657 down_write(&_hash_lock); 651 down_write(&_hash_lock);
658 hc = __find_device_hash_cell(param); 652 hc = __find_device_hash_cell(param);
@@ -663,8 +657,22 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
663 return -ENXIO; 657 return -ENXIO;
664 } 658 }
665 659
660 md = hc->md;
661
662 /*
663 * Ensure the device is not open and nothing further can open it.
664 */
665 r = dm_lock_for_deletion(md);
666 if (r) {
667 DMWARN("unable to remove open device %s", hc->name);
668 up_write(&_hash_lock);
669 dm_put(md);
670 return r;
671 }
672
666 __hash_remove(hc); 673 __hash_remove(hc);
667 up_write(&_hash_lock); 674 up_write(&_hash_lock);
675 dm_put(md);
668 param->data_size = 0; 676 param->data_size = 0;
669 return 0; 677 return 0;
670} 678}
@@ -790,7 +798,6 @@ static int do_resume(struct dm_ioctl *param)
790 } 798 }
791 799
792 md = hc->md; 800 md = hc->md;
793 dm_get(md);
794 801
795 new_map = hc->new_map; 802 new_map = hc->new_map;
796 hc->new_map = NULL; 803 hc->new_map = NULL;
@@ -1078,6 +1085,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
1078{ 1085{
1079 int r; 1086 int r;
1080 struct hash_cell *hc; 1087 struct hash_cell *hc;
1088 struct mapped_device *md;
1081 1089
1082 down_write(&_hash_lock); 1090 down_write(&_hash_lock);
1083 1091
@@ -1096,7 +1104,9 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
1096 param->flags &= ~DM_INACTIVE_PRESENT_FLAG; 1104 param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
1097 1105
1098 r = __dev_status(hc->md, param); 1106 r = __dev_status(hc->md, param);
1107 md = hc->md;
1099 up_write(&_hash_lock); 1108 up_write(&_hash_lock);
1109 dm_put(md);
1100 return r; 1110 return r;
1101} 1111}
1102 1112
@@ -1462,7 +1472,6 @@ static struct file_operations _ctl_fops = {
1462static struct miscdevice _dm_misc = { 1472static struct miscdevice _dm_misc = {
1463 .minor = MISC_DYNAMIC_MINOR, 1473 .minor = MISC_DYNAMIC_MINOR,
1464 .name = DM_NAME, 1474 .name = DM_NAME,
1465 .devfs_name = "mapper/control",
1466 .fops = &_ctl_fops 1475 .fops = &_ctl_fops
1467}; 1476};
1468 1477