aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/md/dm-ioctl.c122
-rw-r--r--drivers/md/dm-table.c35
-rw-r--r--drivers/md/dm.c160
-rw-r--r--include/linux/device-mapper.h6
-rw-r--r--include/uapi/linux/dm-ioctl.h4
5 files changed, 180 insertions, 147 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;