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.c123
1 files changed, 92 insertions, 31 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index a67942931582..1d669322b27c 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);
@@ -321,13 +330,15 @@ static int dm_hash_rename(uint32_t cookie, const char *old, const char *new)
321 */ 330 */
322 list_del(&hc->name_list); 331 list_del(&hc->name_list);
323 old_name = hc->name; 332 old_name = hc->name;
333 mutex_lock(&dm_hash_cells_mutex);
324 hc->name = new_name; 334 hc->name = new_name;
335 mutex_unlock(&dm_hash_cells_mutex);
325 list_add(&hc->name_list, _name_buckets + hash_str(new_name)); 336 list_add(&hc->name_list, _name_buckets + hash_str(new_name));
326 337
327 /* 338 /*
328 * Wake up any dm event waiters. 339 * Wake up any dm event waiters.
329 */ 340 */
330 table = dm_get_table(hc->md); 341 table = dm_get_live_table(hc->md);
331 if (table) { 342 if (table) {
332 dm_table_event(table); 343 dm_table_event(table);
333 dm_table_put(table); 344 dm_table_put(table);
@@ -512,8 +523,6 @@ static int list_versions(struct dm_ioctl *param, size_t param_size)
512 return 0; 523 return 0;
513} 524}
514 525
515
516
517static int check_name(const char *name) 526static int check_name(const char *name)
518{ 527{
519 if (strchr(name, '/')) { 528 if (strchr(name, '/')) {
@@ -525,6 +534,40 @@ static int check_name(const char *name)
525} 534}
526 535
527/* 536/*
537 * On successful return, the caller must not attempt to acquire
538 * _hash_lock without first calling dm_table_put, because dm_table_destroy
539 * waits for this dm_table_put and could be called under this lock.
540 */
541static struct dm_table *dm_get_inactive_table(struct mapped_device *md)
542{
543 struct hash_cell *hc;
544 struct dm_table *table = NULL;
545
546 down_read(&_hash_lock);
547 hc = dm_get_mdptr(md);
548 if (!hc || hc->md != md) {
549 DMWARN("device has been removed from the dev hash table.");
550 goto out;
551 }
552
553 table = hc->new_map;
554 if (table)
555 dm_table_get(table);
556
557out:
558 up_read(&_hash_lock);
559
560 return table;
561}
562
563static struct dm_table *dm_get_live_or_inactive_table(struct mapped_device *md,
564 struct dm_ioctl *param)
565{
566 return (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) ?
567 dm_get_inactive_table(md) : dm_get_live_table(md);
568}
569
570/*
528 * Fills in a dm_ioctl structure, ready for sending back to 571 * Fills in a dm_ioctl structure, ready for sending back to
529 * userland. 572 * userland.
530 */ 573 */
@@ -536,7 +579,7 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
536 param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | 579 param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
537 DM_ACTIVE_PRESENT_FLAG); 580 DM_ACTIVE_PRESENT_FLAG);
538 581
539 if (dm_suspended(md)) 582 if (dm_suspended_md(md))
540 param->flags |= DM_SUSPEND_FLAG; 583 param->flags |= DM_SUSPEND_FLAG;
541 584
542 param->dev = huge_encode_dev(disk_devt(disk)); 585 param->dev = huge_encode_dev(disk_devt(disk));
@@ -548,18 +591,30 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
548 */ 591 */
549 param->open_count = dm_open_count(md); 592 param->open_count = dm_open_count(md);
550 593
551 if (get_disk_ro(disk))
552 param->flags |= DM_READONLY_FLAG;
553
554 param->event_nr = dm_get_event_nr(md); 594 param->event_nr = dm_get_event_nr(md);
595 param->target_count = 0;
555 596
556 table = dm_get_table(md); 597 table = dm_get_live_table(md);
557 if (table) { 598 if (table) {
558 param->flags |= DM_ACTIVE_PRESENT_FLAG; 599 if (!(param->flags & DM_QUERY_INACTIVE_TABLE_FLAG)) {
559 param->target_count = dm_table_get_num_targets(table); 600 if (get_disk_ro(disk))
601 param->flags |= DM_READONLY_FLAG;
602 param->target_count = dm_table_get_num_targets(table);
603 }
560 dm_table_put(table); 604 dm_table_put(table);
561 } else 605
562 param->target_count = 0; 606 param->flags |= DM_ACTIVE_PRESENT_FLAG;
607 }
608
609 if (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) {
610 table = dm_get_inactive_table(md);
611 if (table) {
612 if (!(dm_table_get_mode(table) & FMODE_WRITE))
613 param->flags |= DM_READONLY_FLAG;
614 param->target_count = dm_table_get_num_targets(table);
615 dm_table_put(table);
616 }
617 }
563 618
564 return 0; 619 return 0;
565} 620}
@@ -634,9 +689,9 @@ static struct mapped_device *find_device(struct dm_ioctl *param)
634 * Sneakily write in both the name and the uuid 689 * Sneakily write in both the name and the uuid
635 * while we have the cell. 690 * while we have the cell.
636 */ 691 */
637 strncpy(param->name, hc->name, sizeof(param->name)); 692 strlcpy(param->name, hc->name, sizeof(param->name));
638 if (hc->uuid) 693 if (hc->uuid)
639 strncpy(param->uuid, hc->uuid, sizeof(param->uuid)-1); 694 strlcpy(param->uuid, hc->uuid, sizeof(param->uuid));
640 else 695 else
641 param->uuid[0] = '\0'; 696 param->uuid[0] = '\0';
642 697
@@ -784,7 +839,7 @@ static int do_suspend(struct dm_ioctl *param)
784 if (param->flags & DM_NOFLUSH_FLAG) 839 if (param->flags & DM_NOFLUSH_FLAG)
785 suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG; 840 suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;
786 841
787 if (!dm_suspended(md)) 842 if (!dm_suspended_md(md))
788 r = dm_suspend(md, suspend_flags); 843 r = dm_suspend(md, suspend_flags);
789 844
790 if (!r) 845 if (!r)
@@ -800,7 +855,7 @@ static int do_resume(struct dm_ioctl *param)
800 unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG; 855 unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG;
801 struct hash_cell *hc; 856 struct hash_cell *hc;
802 struct mapped_device *md; 857 struct mapped_device *md;
803 struct dm_table *new_map; 858 struct dm_table *new_map, *old_map = NULL;
804 859
805 down_write(&_hash_lock); 860 down_write(&_hash_lock);
806 861
@@ -826,14 +881,14 @@ static int do_resume(struct dm_ioctl *param)
826 suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG; 881 suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
827 if (param->flags & DM_NOFLUSH_FLAG) 882 if (param->flags & DM_NOFLUSH_FLAG)
828 suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG; 883 suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;
829 if (!dm_suspended(md)) 884 if (!dm_suspended_md(md))
830 dm_suspend(md, suspend_flags); 885 dm_suspend(md, suspend_flags);
831 886
832 r = dm_swap_table(md, new_map); 887 old_map = dm_swap_table(md, new_map);
833 if (r) { 888 if (IS_ERR(old_map)) {
834 dm_table_destroy(new_map); 889 dm_table_destroy(new_map);
835 dm_put(md); 890 dm_put(md);
836 return r; 891 return PTR_ERR(old_map);
837 } 892 }
838 893
839 if (dm_table_get_mode(new_map) & FMODE_WRITE) 894 if (dm_table_get_mode(new_map) & FMODE_WRITE)
@@ -842,9 +897,11 @@ static int do_resume(struct dm_ioctl *param)
842 set_disk_ro(dm_disk(md), 1); 897 set_disk_ro(dm_disk(md), 1);
843 } 898 }
844 899
845 if (dm_suspended(md)) 900 if (dm_suspended_md(md))
846 r = dm_resume(md); 901 r = dm_resume(md);
847 902
903 if (old_map)
904 dm_table_destroy(old_map);
848 905
849 if (!r) { 906 if (!r) {
850 dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr); 907 dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr);
@@ -982,7 +1039,7 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
982 if (r) 1039 if (r)
983 goto out; 1040 goto out;
984 1041
985 table = dm_get_table(md); 1042 table = dm_get_live_or_inactive_table(md, param);
986 if (table) { 1043 if (table) {
987 retrieve_status(table, param, param_size); 1044 retrieve_status(table, param, param_size);
988 dm_table_put(table); 1045 dm_table_put(table);
@@ -1215,7 +1272,7 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
1215 if (r) 1272 if (r)
1216 goto out; 1273 goto out;
1217 1274
1218 table = dm_get_table(md); 1275 table = dm_get_live_or_inactive_table(md, param);
1219 if (table) { 1276 if (table) {
1220 retrieve_deps(table, param, param_size); 1277 retrieve_deps(table, param, param_size);
1221 dm_table_put(table); 1278 dm_table_put(table);
@@ -1244,13 +1301,13 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
1244 if (r) 1301 if (r)
1245 goto out; 1302 goto out;
1246 1303
1247 table = dm_get_table(md); 1304 table = dm_get_live_or_inactive_table(md, param);
1248 if (table) { 1305 if (table) {
1249 retrieve_status(table, param, param_size); 1306 retrieve_status(table, param, param_size);
1250 dm_table_put(table); 1307 dm_table_put(table);
1251 } 1308 }
1252 1309
1253 out: 1310out:
1254 dm_put(md); 1311 dm_put(md);
1255 return r; 1312 return r;
1256} 1313}
@@ -1288,10 +1345,15 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
1288 goto out; 1345 goto out;
1289 } 1346 }
1290 1347
1291 table = dm_get_table(md); 1348 table = dm_get_live_table(md);
1292 if (!table) 1349 if (!table)
1293 goto out_argv; 1350 goto out_argv;
1294 1351
1352 if (dm_deleting_md(md)) {
1353 r = -ENXIO;
1354 goto out_table;
1355 }
1356
1295 ti = dm_table_find_target(table, tmsg->sector); 1357 ti = dm_table_find_target(table, tmsg->sector);
1296 if (!dm_target_is_valid(ti)) { 1358 if (!dm_target_is_valid(ti)) {
1297 DMWARN("Target message sector outside device."); 1359 DMWARN("Target message sector outside device.");
@@ -1303,6 +1365,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
1303 r = -EINVAL; 1365 r = -EINVAL;
1304 } 1366 }
1305 1367
1368 out_table:
1306 dm_table_put(table); 1369 dm_table_put(table);
1307 out_argv: 1370 out_argv:
1308 kfree(argv); 1371 kfree(argv);
@@ -1582,8 +1645,7 @@ int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid)
1582 if (!md) 1645 if (!md)
1583 return -ENXIO; 1646 return -ENXIO;
1584 1647
1585 dm_get(md); 1648 mutex_lock(&dm_hash_cells_mutex);
1586 down_read(&_hash_lock);
1587 hc = dm_get_mdptr(md); 1649 hc = dm_get_mdptr(md);
1588 if (!hc || hc->md != md) { 1650 if (!hc || hc->md != md) {
1589 r = -ENXIO; 1651 r = -ENXIO;
@@ -1596,8 +1658,7 @@ int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid)
1596 strcpy(uuid, hc->uuid ? : ""); 1658 strcpy(uuid, hc->uuid ? : "");
1597 1659
1598out: 1660out:
1599 up_read(&_hash_lock); 1661 mutex_unlock(&dm_hash_cells_mutex);
1600 dm_put(md);
1601 1662
1602 return r; 1663 return r;
1603} 1664}