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.c145
1 files changed, 106 insertions, 39 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index a67942931582..d7500e1c26f2 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -56,6 +56,11 @@ static void dm_hash_remove_all(int keep_open_devices);
56 */ 56 */
57static DECLARE_RWSEM(_hash_lock); 57static DECLARE_RWSEM(_hash_lock);
58 58
59/*
60 * Protects use of mdptr to obtain hash cell name and uuid from mapped device.
61 */
62static DEFINE_MUTEX(dm_hash_cells_mutex);
63
59static void init_buckets(struct list_head *buckets) 64static void init_buckets(struct list_head *buckets)
60{ 65{
61 unsigned int i; 66 unsigned int i;
@@ -206,7 +211,9 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi
206 list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); 211 list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
207 } 212 }
208 dm_get(md); 213 dm_get(md);
214 mutex_lock(&dm_hash_cells_mutex);
209 dm_set_mdptr(md, cell); 215 dm_set_mdptr(md, cell);
216 mutex_unlock(&dm_hash_cells_mutex);
210 up_write(&_hash_lock); 217 up_write(&_hash_lock);
211 218
212 return 0; 219 return 0;
@@ -224,9 +231,11 @@ static void __hash_remove(struct hash_cell *hc)
224 /* remove from the dev hash */ 231 /* remove from the dev hash */
225 list_del(&hc->uuid_list); 232 list_del(&hc->uuid_list);
226 list_del(&hc->name_list); 233 list_del(&hc->name_list);
234 mutex_lock(&dm_hash_cells_mutex);
227 dm_set_mdptr(hc->md, NULL); 235 dm_set_mdptr(hc->md, NULL);
236 mutex_unlock(&dm_hash_cells_mutex);
228 237
229 table = dm_get_table(hc->md); 238 table = dm_get_live_table(hc->md);
230 if (table) { 239 if (table) {
231 dm_table_event(table); 240 dm_table_event(table);
232 dm_table_put(table); 241 dm_table_put(table);
@@ -276,7 +285,8 @@ retry:
276 up_write(&_hash_lock); 285 up_write(&_hash_lock);
277} 286}
278 287
279static int dm_hash_rename(uint32_t cookie, const char *old, const char *new) 288static int dm_hash_rename(uint32_t cookie, uint32_t *flags, const char *old,
289 const char *new)
280{ 290{
281 char *new_name, *old_name; 291 char *new_name, *old_name;
282 struct hash_cell *hc; 292 struct hash_cell *hc;
@@ -321,19 +331,22 @@ static int dm_hash_rename(uint32_t cookie, const char *old, const char *new)
321 */ 331 */
322 list_del(&hc->name_list); 332 list_del(&hc->name_list);
323 old_name = hc->name; 333 old_name = hc->name;
334 mutex_lock(&dm_hash_cells_mutex);
324 hc->name = new_name; 335 hc->name = new_name;
336 mutex_unlock(&dm_hash_cells_mutex);
325 list_add(&hc->name_list, _name_buckets + hash_str(new_name)); 337 list_add(&hc->name_list, _name_buckets + hash_str(new_name));
326 338
327 /* 339 /*
328 * Wake up any dm event waiters. 340 * Wake up any dm event waiters.
329 */ 341 */
330 table = dm_get_table(hc->md); 342 table = dm_get_live_table(hc->md);
331 if (table) { 343 if (table) {
332 dm_table_event(table); 344 dm_table_event(table);
333 dm_table_put(table); 345 dm_table_put(table);
334 } 346 }
335 347
336 dm_kobject_uevent(hc->md, KOBJ_CHANGE, cookie); 348 if (!dm_kobject_uevent(hc->md, KOBJ_CHANGE, cookie))
349 *flags |= DM_UEVENT_GENERATED_FLAG;
337 350
338 dm_put(hc->md); 351 dm_put(hc->md);
339 up_write(&_hash_lock); 352 up_write(&_hash_lock);
@@ -512,8 +525,6 @@ static int list_versions(struct dm_ioctl *param, size_t param_size)
512 return 0; 525 return 0;
513} 526}
514 527
515
516
517static int check_name(const char *name) 528static int check_name(const char *name)
518{ 529{
519 if (strchr(name, '/')) { 530 if (strchr(name, '/')) {
@@ -525,6 +536,40 @@ static int check_name(const char *name)
525} 536}
526 537
527/* 538/*
539 * On successful return, the caller must not attempt to acquire
540 * _hash_lock without first calling dm_table_put, because dm_table_destroy
541 * waits for this dm_table_put and could be called under this lock.
542 */
543static struct dm_table *dm_get_inactive_table(struct mapped_device *md)
544{
545 struct hash_cell *hc;
546 struct dm_table *table = NULL;
547
548 down_read(&_hash_lock);
549 hc = dm_get_mdptr(md);
550 if (!hc || hc->md != md) {
551 DMWARN("device has been removed from the dev hash table.");
552 goto out;
553 }
554
555 table = hc->new_map;
556 if (table)
557 dm_table_get(table);
558
559out:
560 up_read(&_hash_lock);
561
562 return table;
563}
564
565static struct dm_table *dm_get_live_or_inactive_table(struct mapped_device *md,
566 struct dm_ioctl *param)
567{
568 return (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) ?
569 dm_get_inactive_table(md) : dm_get_live_table(md);
570}
571
572/*
528 * Fills in a dm_ioctl structure, ready for sending back to 573 * Fills in a dm_ioctl structure, ready for sending back to
529 * userland. 574 * userland.
530 */ 575 */
@@ -536,7 +581,7 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
536 param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | 581 param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
537 DM_ACTIVE_PRESENT_FLAG); 582 DM_ACTIVE_PRESENT_FLAG);
538 583
539 if (dm_suspended(md)) 584 if (dm_suspended_md(md))
540 param->flags |= DM_SUSPEND_FLAG; 585 param->flags |= DM_SUSPEND_FLAG;
541 586
542 param->dev = huge_encode_dev(disk_devt(disk)); 587 param->dev = huge_encode_dev(disk_devt(disk));
@@ -548,18 +593,30 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
548 */ 593 */
549 param->open_count = dm_open_count(md); 594 param->open_count = dm_open_count(md);
550 595
551 if (get_disk_ro(disk))
552 param->flags |= DM_READONLY_FLAG;
553
554 param->event_nr = dm_get_event_nr(md); 596 param->event_nr = dm_get_event_nr(md);
597 param->target_count = 0;
555 598
556 table = dm_get_table(md); 599 table = dm_get_live_table(md);
557 if (table) { 600 if (table) {
558 param->flags |= DM_ACTIVE_PRESENT_FLAG; 601 if (!(param->flags & DM_QUERY_INACTIVE_TABLE_FLAG)) {
559 param->target_count = dm_table_get_num_targets(table); 602 if (get_disk_ro(disk))
603 param->flags |= DM_READONLY_FLAG;
604 param->target_count = dm_table_get_num_targets(table);
605 }
560 dm_table_put(table); 606 dm_table_put(table);
561 } else 607
562 param->target_count = 0; 608 param->flags |= DM_ACTIVE_PRESENT_FLAG;
609 }
610
611 if (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) {
612 table = dm_get_inactive_table(md);
613 if (table) {
614 if (!(dm_table_get_mode(table) & FMODE_WRITE))
615 param->flags |= DM_READONLY_FLAG;
616 param->target_count = dm_table_get_num_targets(table);
617 dm_table_put(table);
618 }
619 }
563 620
564 return 0; 621 return 0;
565} 622}
@@ -634,9 +691,9 @@ static struct mapped_device *find_device(struct dm_ioctl *param)
634 * Sneakily write in both the name and the uuid 691 * Sneakily write in both the name and the uuid
635 * while we have the cell. 692 * while we have the cell.
636 */ 693 */
637 strncpy(param->name, hc->name, sizeof(param->name)); 694 strlcpy(param->name, hc->name, sizeof(param->name));
638 if (hc->uuid) 695 if (hc->uuid)
639 strncpy(param->uuid, hc->uuid, sizeof(param->uuid)-1); 696 strlcpy(param->uuid, hc->uuid, sizeof(param->uuid));
640 else 697 else
641 param->uuid[0] = '\0'; 698 param->uuid[0] = '\0';
642 699
@@ -681,10 +738,10 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
681 __hash_remove(hc); 738 __hash_remove(hc);
682 up_write(&_hash_lock); 739 up_write(&_hash_lock);
683 740
684 dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr); 741 if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr))
742 param->flags |= DM_UEVENT_GENERATED_FLAG;
685 743
686 dm_put(md); 744 dm_put(md);
687 param->data_size = 0;
688 return 0; 745 return 0;
689} 746}
690 747
@@ -718,7 +775,9 @@ static int dev_rename(struct dm_ioctl *param, size_t param_size)
718 return r; 775 return r;
719 776
720 param->data_size = 0; 777 param->data_size = 0;
721 return dm_hash_rename(param->event_nr, param->name, new_name); 778
779 return dm_hash_rename(param->event_nr, &param->flags, param->name,
780 new_name);
722} 781}
723 782
724static int dev_set_geometry(struct dm_ioctl *param, size_t param_size) 783static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
@@ -784,7 +843,7 @@ static int do_suspend(struct dm_ioctl *param)
784 if (param->flags & DM_NOFLUSH_FLAG) 843 if (param->flags & DM_NOFLUSH_FLAG)
785 suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG; 844 suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;
786 845
787 if (!dm_suspended(md)) 846 if (!dm_suspended_md(md))
788 r = dm_suspend(md, suspend_flags); 847 r = dm_suspend(md, suspend_flags);
789 848
790 if (!r) 849 if (!r)
@@ -800,7 +859,7 @@ static int do_resume(struct dm_ioctl *param)
800 unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG; 859 unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG;
801 struct hash_cell *hc; 860 struct hash_cell *hc;
802 struct mapped_device *md; 861 struct mapped_device *md;
803 struct dm_table *new_map; 862 struct dm_table *new_map, *old_map = NULL;
804 863
805 down_write(&_hash_lock); 864 down_write(&_hash_lock);
806 865
@@ -826,14 +885,14 @@ static int do_resume(struct dm_ioctl *param)
826 suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG; 885 suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
827 if (param->flags & DM_NOFLUSH_FLAG) 886 if (param->flags & DM_NOFLUSH_FLAG)
828 suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG; 887 suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;
829 if (!dm_suspended(md)) 888 if (!dm_suspended_md(md))
830 dm_suspend(md, suspend_flags); 889 dm_suspend(md, suspend_flags);
831 890
832 r = dm_swap_table(md, new_map); 891 old_map = dm_swap_table(md, new_map);
833 if (r) { 892 if (IS_ERR(old_map)) {
834 dm_table_destroy(new_map); 893 dm_table_destroy(new_map);
835 dm_put(md); 894 dm_put(md);
836 return r; 895 return PTR_ERR(old_map);
837 } 896 }
838 897
839 if (dm_table_get_mode(new_map) & FMODE_WRITE) 898 if (dm_table_get_mode(new_map) & FMODE_WRITE)
@@ -842,14 +901,17 @@ static int do_resume(struct dm_ioctl *param)
842 set_disk_ro(dm_disk(md), 1); 901 set_disk_ro(dm_disk(md), 1);
843 } 902 }
844 903
845 if (dm_suspended(md)) 904 if (dm_suspended_md(md)) {
846 r = dm_resume(md); 905 r = dm_resume(md);
906 if (!r && !dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr))
907 param->flags |= DM_UEVENT_GENERATED_FLAG;
908 }
847 909
910 if (old_map)
911 dm_table_destroy(old_map);
848 912
849 if (!r) { 913 if (!r)
850 dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr);
851 r = __dev_status(md, param); 914 r = __dev_status(md, param);
852 }
853 915
854 dm_put(md); 916 dm_put(md);
855 return r; 917 return r;
@@ -982,7 +1044,7 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
982 if (r) 1044 if (r)
983 goto out; 1045 goto out;
984 1046
985 table = dm_get_table(md); 1047 table = dm_get_live_or_inactive_table(md, param);
986 if (table) { 1048 if (table) {
987 retrieve_status(table, param, param_size); 1049 retrieve_status(table, param, param_size);
988 dm_table_put(table); 1050 dm_table_put(table);
@@ -1215,7 +1277,7 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
1215 if (r) 1277 if (r)
1216 goto out; 1278 goto out;
1217 1279
1218 table = dm_get_table(md); 1280 table = dm_get_live_or_inactive_table(md, param);
1219 if (table) { 1281 if (table) {
1220 retrieve_deps(table, param, param_size); 1282 retrieve_deps(table, param, param_size);
1221 dm_table_put(table); 1283 dm_table_put(table);
@@ -1244,13 +1306,13 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
1244 if (r) 1306 if (r)
1245 goto out; 1307 goto out;
1246 1308
1247 table = dm_get_table(md); 1309 table = dm_get_live_or_inactive_table(md, param);
1248 if (table) { 1310 if (table) {
1249 retrieve_status(table, param, param_size); 1311 retrieve_status(table, param, param_size);
1250 dm_table_put(table); 1312 dm_table_put(table);
1251 } 1313 }
1252 1314
1253 out: 1315out:
1254 dm_put(md); 1316 dm_put(md);
1255 return r; 1317 return r;
1256} 1318}
@@ -1288,10 +1350,15 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
1288 goto out; 1350 goto out;
1289 } 1351 }
1290 1352
1291 table = dm_get_table(md); 1353 table = dm_get_live_table(md);
1292 if (!table) 1354 if (!table)
1293 goto out_argv; 1355 goto out_argv;
1294 1356
1357 if (dm_deleting_md(md)) {
1358 r = -ENXIO;
1359 goto out_table;
1360 }
1361
1295 ti = dm_table_find_target(table, tmsg->sector); 1362 ti = dm_table_find_target(table, tmsg->sector);
1296 if (!dm_target_is_valid(ti)) { 1363 if (!dm_target_is_valid(ti)) {
1297 DMWARN("Target message sector outside device."); 1364 DMWARN("Target message sector outside device.");
@@ -1303,6 +1370,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
1303 r = -EINVAL; 1370 r = -EINVAL;
1304 } 1371 }
1305 1372
1373 out_table:
1306 dm_table_put(table); 1374 dm_table_put(table);
1307 out_argv: 1375 out_argv:
1308 kfree(argv); 1376 kfree(argv);
@@ -1413,6 +1481,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param)
1413{ 1481{
1414 /* Always clear this flag */ 1482 /* Always clear this flag */
1415 param->flags &= ~DM_BUFFER_FULL_FLAG; 1483 param->flags &= ~DM_BUFFER_FULL_FLAG;
1484 param->flags &= ~DM_UEVENT_GENERATED_FLAG;
1416 1485
1417 /* Ignores parameters */ 1486 /* Ignores parameters */
1418 if (cmd == DM_REMOVE_ALL_CMD || 1487 if (cmd == DM_REMOVE_ALL_CMD ||
@@ -1582,8 +1651,7 @@ int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid)
1582 if (!md) 1651 if (!md)
1583 return -ENXIO; 1652 return -ENXIO;
1584 1653
1585 dm_get(md); 1654 mutex_lock(&dm_hash_cells_mutex);
1586 down_read(&_hash_lock);
1587 hc = dm_get_mdptr(md); 1655 hc = dm_get_mdptr(md);
1588 if (!hc || hc->md != md) { 1656 if (!hc || hc->md != md) {
1589 r = -ENXIO; 1657 r = -ENXIO;
@@ -1596,8 +1664,7 @@ int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid)
1596 strcpy(uuid, hc->uuid ? : ""); 1664 strcpy(uuid, hc->uuid ? : "");
1597 1665
1598out: 1666out:
1599 up_read(&_hash_lock); 1667 mutex_unlock(&dm_hash_cells_mutex);
1600 dm_put(md);
1601 1668
1602 return r; 1669 return r;
1603} 1670}