aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-ioctl.c
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2013-07-10 18:41:18 -0400
committerAlasdair G Kergon <agk@redhat.com>2013-07-10 18:41:18 -0400
commit83d5e5b0af907d46d241a86d9e44003b3f0accbd (patch)
tree46349d07c2090da15c250af3bac40833eb96e9f0 /drivers/md/dm-ioctl.c
parent2480945cd44b50ba8b1646544eec2db21f064f12 (diff)
dm: optimize use SRCU and RCU
This patch removes "io_lock" and "map_lock" in struct mapped_device and "holders" in struct dm_table and replaces these mechanisms with sleepable-rcu. Previously, the code would call "dm_get_live_table" and "dm_table_put" to get and release table. Now, the code is changed to call "dm_get_live_table" and "dm_put_live_table". dm_get_live_table locks sleepable-rcu and dm_put_live_table unlocks it. dm_get_live_table_fast/dm_put_live_table_fast can be used instead of dm_get_live_table/dm_put_live_table. These *_fast functions use non-sleepable RCU, so the caller must not block between them. If the code changes active or inactive dm table, it must call dm_sync_table before destroying the old table. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md/dm-ioctl.c')
-rw-r--r--drivers/md/dm-ioctl.c122
1 files changed, 82 insertions, 40 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 12f04868e899..f1b758675ec7 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -36,6 +36,14 @@ struct hash_cell {
36 struct dm_table *new_map; 36 struct dm_table *new_map;
37}; 37};
38 38
39/*
40 * A dummy definition to make RCU happy.
41 * struct dm_table should never be dereferenced in this file.
42 */
43struct dm_table {
44 int undefined__;
45};
46
39struct vers_iter { 47struct vers_iter {
40 size_t param_size; 48 size_t param_size;
41 struct dm_target_versions *vers, *old_vers; 49 struct dm_target_versions *vers, *old_vers;
@@ -242,9 +250,10 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi
242 return -EBUSY; 250 return -EBUSY;
243} 251}
244 252
245static void __hash_remove(struct hash_cell *hc) 253static struct dm_table *__hash_remove(struct hash_cell *hc)
246{ 254{
247 struct dm_table *table; 255 struct dm_table *table;
256 int srcu_idx;
248 257
249 /* remove from the dev hash */ 258 /* remove from the dev hash */
250 list_del(&hc->uuid_list); 259 list_del(&hc->uuid_list);
@@ -253,16 +262,18 @@ static void __hash_remove(struct hash_cell *hc)
253 dm_set_mdptr(hc->md, NULL); 262 dm_set_mdptr(hc->md, NULL);
254 mutex_unlock(&dm_hash_cells_mutex); 263 mutex_unlock(&dm_hash_cells_mutex);
255 264
256 table = dm_get_live_table(hc->md); 265 table = dm_get_live_table(hc->md, &srcu_idx);
257 if (table) { 266 if (table)
258 dm_table_event(table); 267 dm_table_event(table);
259 dm_table_put(table); 268 dm_put_live_table(hc->md, srcu_idx);
260 }
261 269
270 table = NULL;
262 if (hc->new_map) 271 if (hc->new_map)
263 dm_table_destroy(hc->new_map); 272 table = hc->new_map;
264 dm_put(hc->md); 273 dm_put(hc->md);
265 free_cell(hc); 274 free_cell(hc);
275
276 return table;
266} 277}
267 278
268static void dm_hash_remove_all(int keep_open_devices) 279static void dm_hash_remove_all(int keep_open_devices)
@@ -270,6 +281,7 @@ static void dm_hash_remove_all(int keep_open_devices)
270 int i, dev_skipped; 281 int i, dev_skipped;
271 struct hash_cell *hc; 282 struct hash_cell *hc;
272 struct mapped_device *md; 283 struct mapped_device *md;
284 struct dm_table *t;
273 285
274retry: 286retry:
275 dev_skipped = 0; 287 dev_skipped = 0;
@@ -287,10 +299,14 @@ retry:
287 continue; 299 continue;
288 } 300 }
289 301
290 __hash_remove(hc); 302 t = __hash_remove(hc);
291 303
292 up_write(&_hash_lock); 304 up_write(&_hash_lock);
293 305
306 if (t) {
307 dm_sync_table(md);
308 dm_table_destroy(t);
309 }
294 dm_put(md); 310 dm_put(md);
295 if (likely(keep_open_devices)) 311 if (likely(keep_open_devices))
296 dm_destroy(md); 312 dm_destroy(md);
@@ -356,6 +372,7 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
356 struct dm_table *table; 372 struct dm_table *table;
357 struct mapped_device *md; 373 struct mapped_device *md;
358 unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0; 374 unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
375 int srcu_idx;
359 376
360 /* 377 /*
361 * duplicate new. 378 * duplicate new.
@@ -418,11 +435,10 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
418 /* 435 /*
419 * Wake up any dm event waiters. 436 * Wake up any dm event waiters.
420 */ 437 */
421 table = dm_get_live_table(hc->md); 438 table = dm_get_live_table(hc->md, &srcu_idx);
422 if (table) { 439 if (table)
423 dm_table_event(table); 440 dm_table_event(table);
424 dm_table_put(table); 441 dm_put_live_table(hc->md, srcu_idx);
425 }
426 442
427 if (!dm_kobject_uevent(hc->md, KOBJ_CHANGE, param->event_nr)) 443 if (!dm_kobject_uevent(hc->md, KOBJ_CHANGE, param->event_nr))
428 param->flags |= DM_UEVENT_GENERATED_FLAG; 444 param->flags |= DM_UEVENT_GENERATED_FLAG;
@@ -620,11 +636,14 @@ static int check_name(const char *name)
620 * _hash_lock without first calling dm_table_put, because dm_table_destroy 636 * _hash_lock without first calling dm_table_put, because dm_table_destroy
621 * waits for this dm_table_put and could be called under this lock. 637 * waits for this dm_table_put and could be called under this lock.
622 */ 638 */
623static struct dm_table *dm_get_inactive_table(struct mapped_device *md) 639static struct dm_table *dm_get_inactive_table(struct mapped_device *md, int *srcu_idx)
624{ 640{
625 struct hash_cell *hc; 641 struct hash_cell *hc;
626 struct dm_table *table = NULL; 642 struct dm_table *table = NULL;
627 643
644 /* increment rcu count, we don't care about the table pointer */
645 dm_get_live_table(md, srcu_idx);
646
628 down_read(&_hash_lock); 647 down_read(&_hash_lock);
629 hc = dm_get_mdptr(md); 648 hc = dm_get_mdptr(md);
630 if (!hc || hc->md != md) { 649 if (!hc || hc->md != md) {
@@ -633,8 +652,6 @@ static struct dm_table *dm_get_inactive_table(struct mapped_device *md)
633 } 652 }
634 653
635 table = hc->new_map; 654 table = hc->new_map;
636 if (table)
637 dm_table_get(table);
638 655
639out: 656out:
640 up_read(&_hash_lock); 657 up_read(&_hash_lock);
@@ -643,10 +660,11 @@ out:
643} 660}
644 661
645static struct dm_table *dm_get_live_or_inactive_table(struct mapped_device *md, 662static struct dm_table *dm_get_live_or_inactive_table(struct mapped_device *md,
646 struct dm_ioctl *param) 663 struct dm_ioctl *param,
664 int *srcu_idx)
647{ 665{
648 return (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) ? 666 return (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) ?
649 dm_get_inactive_table(md) : dm_get_live_table(md); 667 dm_get_inactive_table(md, srcu_idx) : dm_get_live_table(md, srcu_idx);
650} 668}
651 669
652/* 670/*
@@ -657,6 +675,7 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
657{ 675{
658 struct gendisk *disk = dm_disk(md); 676 struct gendisk *disk = dm_disk(md);
659 struct dm_table *table; 677 struct dm_table *table;
678 int srcu_idx;
660 679
661 param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | 680 param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
662 DM_ACTIVE_PRESENT_FLAG); 681 DM_ACTIVE_PRESENT_FLAG);
@@ -676,26 +695,27 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
676 param->event_nr = dm_get_event_nr(md); 695 param->event_nr = dm_get_event_nr(md);
677 param->target_count = 0; 696 param->target_count = 0;
678 697
679 table = dm_get_live_table(md); 698 table = dm_get_live_table(md, &srcu_idx);
680 if (table) { 699 if (table) {
681 if (!(param->flags & DM_QUERY_INACTIVE_TABLE_FLAG)) { 700 if (!(param->flags & DM_QUERY_INACTIVE_TABLE_FLAG)) {
682 if (get_disk_ro(disk)) 701 if (get_disk_ro(disk))
683 param->flags |= DM_READONLY_FLAG; 702 param->flags |= DM_READONLY_FLAG;
684 param->target_count = dm_table_get_num_targets(table); 703 param->target_count = dm_table_get_num_targets(table);
685 } 704 }
686 dm_table_put(table);
687 705
688 param->flags |= DM_ACTIVE_PRESENT_FLAG; 706 param->flags |= DM_ACTIVE_PRESENT_FLAG;
689 } 707 }
708 dm_put_live_table(md, srcu_idx);
690 709
691 if (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) { 710 if (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) {
692 table = dm_get_inactive_table(md); 711 int srcu_idx;
712 table = dm_get_inactive_table(md, &srcu_idx);
693 if (table) { 713 if (table) {
694 if (!(dm_table_get_mode(table) & FMODE_WRITE)) 714 if (!(dm_table_get_mode(table) & FMODE_WRITE))
695 param->flags |= DM_READONLY_FLAG; 715 param->flags |= DM_READONLY_FLAG;
696 param->target_count = dm_table_get_num_targets(table); 716 param->target_count = dm_table_get_num_targets(table);
697 dm_table_put(table);
698 } 717 }
718 dm_put_live_table(md, srcu_idx);
699 } 719 }
700} 720}
701 721
@@ -796,6 +816,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
796 struct hash_cell *hc; 816 struct hash_cell *hc;
797 struct mapped_device *md; 817 struct mapped_device *md;
798 int r; 818 int r;
819 struct dm_table *t;
799 820
800 down_write(&_hash_lock); 821 down_write(&_hash_lock);
801 hc = __find_device_hash_cell(param); 822 hc = __find_device_hash_cell(param);
@@ -819,9 +840,14 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
819 return r; 840 return r;
820 } 841 }
821 842
822 __hash_remove(hc); 843 t = __hash_remove(hc);
823 up_write(&_hash_lock); 844 up_write(&_hash_lock);
824 845
846 if (t) {
847 dm_sync_table(md);
848 dm_table_destroy(t);
849 }
850
825 if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr)) 851 if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr))
826 param->flags |= DM_UEVENT_GENERATED_FLAG; 852 param->flags |= DM_UEVENT_GENERATED_FLAG;
827 853
@@ -986,6 +1012,7 @@ static int do_resume(struct dm_ioctl *param)
986 1012
987 old_map = dm_swap_table(md, new_map); 1013 old_map = dm_swap_table(md, new_map);
988 if (IS_ERR(old_map)) { 1014 if (IS_ERR(old_map)) {
1015 dm_sync_table(md);
989 dm_table_destroy(new_map); 1016 dm_table_destroy(new_map);
990 dm_put(md); 1017 dm_put(md);
991 return PTR_ERR(old_map); 1018 return PTR_ERR(old_map);
@@ -1003,6 +1030,10 @@ static int do_resume(struct dm_ioctl *param)
1003 param->flags |= DM_UEVENT_GENERATED_FLAG; 1030 param->flags |= DM_UEVENT_GENERATED_FLAG;
1004 } 1031 }
1005 1032
1033 /*
1034 * Since dm_swap_table synchronizes RCU, nobody should be in
1035 * read-side critical section already.
1036 */
1006 if (old_map) 1037 if (old_map)
1007 dm_table_destroy(old_map); 1038 dm_table_destroy(old_map);
1008 1039
@@ -1125,6 +1156,7 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
1125 int r = 0; 1156 int r = 0;
1126 struct mapped_device *md; 1157 struct mapped_device *md;
1127 struct dm_table *table; 1158 struct dm_table *table;
1159 int srcu_idx;
1128 1160
1129 md = find_device(param); 1161 md = find_device(param);
1130 if (!md) 1162 if (!md)
@@ -1145,11 +1177,10 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
1145 */ 1177 */
1146 __dev_status(md, param); 1178 __dev_status(md, param);
1147 1179
1148 table = dm_get_live_or_inactive_table(md, param); 1180 table = dm_get_live_or_inactive_table(md, param, &srcu_idx);
1149 if (table) { 1181 if (table)
1150 retrieve_status(table, param, param_size); 1182 retrieve_status(table, param, param_size);
1151 dm_table_put(table); 1183 dm_put_live_table(md, srcu_idx);
1152 }
1153 1184
1154out: 1185out:
1155 dm_put(md); 1186 dm_put(md);
@@ -1221,7 +1252,7 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
1221{ 1252{
1222 int r; 1253 int r;
1223 struct hash_cell *hc; 1254 struct hash_cell *hc;
1224 struct dm_table *t; 1255 struct dm_table *t, *old_map = NULL;
1225 struct mapped_device *md; 1256 struct mapped_device *md;
1226 struct target_type *immutable_target_type; 1257 struct target_type *immutable_target_type;
1227 1258
@@ -1277,14 +1308,14 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
1277 hc = dm_get_mdptr(md); 1308 hc = dm_get_mdptr(md);
1278 if (!hc || hc->md != md) { 1309 if (!hc || hc->md != md) {
1279 DMWARN("device has been removed from the dev hash table."); 1310 DMWARN("device has been removed from the dev hash table.");
1280 dm_table_destroy(t);
1281 up_write(&_hash_lock); 1311 up_write(&_hash_lock);
1312 dm_table_destroy(t);
1282 r = -ENXIO; 1313 r = -ENXIO;
1283 goto out; 1314 goto out;
1284 } 1315 }
1285 1316
1286 if (hc->new_map) 1317 if (hc->new_map)
1287 dm_table_destroy(hc->new_map); 1318 old_map = hc->new_map;
1288 hc->new_map = t; 1319 hc->new_map = t;
1289 up_write(&_hash_lock); 1320 up_write(&_hash_lock);
1290 1321
@@ -1292,6 +1323,11 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
1292 __dev_status(md, param); 1323 __dev_status(md, param);
1293 1324
1294out: 1325out:
1326 if (old_map) {
1327 dm_sync_table(md);
1328 dm_table_destroy(old_map);
1329 }
1330
1295 dm_put(md); 1331 dm_put(md);
1296 1332
1297 return r; 1333 return r;
@@ -1301,6 +1337,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
1301{ 1337{
1302 struct hash_cell *hc; 1338 struct hash_cell *hc;
1303 struct mapped_device *md; 1339 struct mapped_device *md;
1340 struct dm_table *old_map = NULL;
1304 1341
1305 down_write(&_hash_lock); 1342 down_write(&_hash_lock);
1306 1343
@@ -1312,7 +1349,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
1312 } 1349 }
1313 1350
1314 if (hc->new_map) { 1351 if (hc->new_map) {
1315 dm_table_destroy(hc->new_map); 1352 old_map = hc->new_map;
1316 hc->new_map = NULL; 1353 hc->new_map = NULL;
1317 } 1354 }
1318 1355
@@ -1321,6 +1358,10 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
1321 __dev_status(hc->md, param); 1358 __dev_status(hc->md, param);
1322 md = hc->md; 1359 md = hc->md;
1323 up_write(&_hash_lock); 1360 up_write(&_hash_lock);
1361 if (old_map) {
1362 dm_sync_table(md);
1363 dm_table_destroy(old_map);
1364 }
1324 dm_put(md); 1365 dm_put(md);
1325 1366
1326 return 0; 1367 return 0;
@@ -1370,6 +1411,7 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
1370{ 1411{
1371 struct mapped_device *md; 1412 struct mapped_device *md;
1372 struct dm_table *table; 1413 struct dm_table *table;
1414 int srcu_idx;
1373 1415
1374 md = find_device(param); 1416 md = find_device(param);
1375 if (!md) 1417 if (!md)
@@ -1377,11 +1419,10 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
1377 1419
1378 __dev_status(md, param); 1420 __dev_status(md, param);
1379 1421
1380 table = dm_get_live_or_inactive_table(md, param); 1422 table = dm_get_live_or_inactive_table(md, param, &srcu_idx);
1381 if (table) { 1423 if (table)
1382 retrieve_deps(table, param, param_size); 1424 retrieve_deps(table, param, param_size);
1383 dm_table_put(table); 1425 dm_put_live_table(md, srcu_idx);
1384 }
1385 1426
1386 dm_put(md); 1427 dm_put(md);
1387 1428
@@ -1396,6 +1437,7 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
1396{ 1437{
1397 struct mapped_device *md; 1438 struct mapped_device *md;
1398 struct dm_table *table; 1439 struct dm_table *table;
1440 int srcu_idx;
1399 1441
1400 md = find_device(param); 1442 md = find_device(param);
1401 if (!md) 1443 if (!md)
@@ -1403,11 +1445,10 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
1403 1445
1404 __dev_status(md, param); 1446 __dev_status(md, param);
1405 1447
1406 table = dm_get_live_or_inactive_table(md, param); 1448 table = dm_get_live_or_inactive_table(md, param, &srcu_idx);
1407 if (table) { 1449 if (table)
1408 retrieve_status(table, param, param_size); 1450 retrieve_status(table, param, param_size);
1409 dm_table_put(table); 1451 dm_put_live_table(md, srcu_idx);
1410 }
1411 1452
1412 dm_put(md); 1453 dm_put(md);
1413 1454
@@ -1443,6 +1484,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
1443 struct dm_target_msg *tmsg = (void *) param + param->data_start; 1484 struct dm_target_msg *tmsg = (void *) param + param->data_start;
1444 size_t maxlen; 1485 size_t maxlen;
1445 char *result = get_result_buffer(param, param_size, &maxlen); 1486 char *result = get_result_buffer(param, param_size, &maxlen);
1487 int srcu_idx;
1446 1488
1447 md = find_device(param); 1489 md = find_device(param);
1448 if (!md) 1490 if (!md)
@@ -1470,9 +1512,9 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
1470 if (r <= 1) 1512 if (r <= 1)
1471 goto out_argv; 1513 goto out_argv;
1472 1514
1473 table = dm_get_live_table(md); 1515 table = dm_get_live_table(md, &srcu_idx);
1474 if (!table) 1516 if (!table)
1475 goto out_argv; 1517 goto out_table;
1476 1518
1477 if (dm_deleting_md(md)) { 1519 if (dm_deleting_md(md)) {
1478 r = -ENXIO; 1520 r = -ENXIO;
@@ -1491,7 +1533,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
1491 } 1533 }
1492 1534
1493 out_table: 1535 out_table:
1494 dm_table_put(table); 1536 dm_put_live_table(md, srcu_idx);
1495 out_argv: 1537 out_argv:
1496 kfree(argv); 1538 kfree(argv);
1497 out: 1539 out: