diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 20:30:47 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 20:30:47 -0500 |
commit | f6bcfd94c0a97c11ce9197ade93a08bc8af6e057 (patch) | |
tree | 83d867565b4f2a7627b3288f9e000eaf2b217be9 /drivers/md/dm-log-userspace-base.c | |
parent | 509e4aef44eb10e4aef1f81c3c3ff1214671503b (diff) | |
parent | 9d09e663d5502c46f2d9481c04c1087e1c2da698 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm
* git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm: (32 commits)
dm: raid456 basic support
dm: per target unplug callback support
dm: introduce target callbacks and congestion callback
dm mpath: delay activate_path retry on SCSI_DH_RETRY
dm: remove superfluous irq disablement in dm_request_fn
dm log: use PTR_ERR value instead of ENOMEM
dm snapshot: avoid storing private suspended state
dm snapshot: persistent make metadata_wq multithreaded
dm: use non reentrant workqueues if equivalent
dm: convert workqueues to alloc_ordered
dm stripe: switch from local workqueue to system_wq
dm: dont use flush_scheduled_work
dm snapshot: remove unused dm_snapshot queued_bios_work
dm ioctl: suppress needless warning messages
dm crypt: add loop aes iv generator
dm crypt: add multi key capability
dm crypt: add post iv call to iv generator
dm crypt: use io thread for reads only if mempool exhausted
dm crypt: scale to multiple cpus
dm crypt: simplify compatible table output
...
Diffstat (limited to 'drivers/md/dm-log-userspace-base.c')
-rw-r--r-- | drivers/md/dm-log-userspace-base.c | 139 |
1 files changed, 111 insertions, 28 deletions
diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c index 1ed0094f064b..aa2e0c374ab3 100644 --- a/drivers/md/dm-log-userspace-base.c +++ b/drivers/md/dm-log-userspace-base.c | |||
@@ -12,12 +12,22 @@ | |||
12 | 12 | ||
13 | #include "dm-log-userspace-transfer.h" | 13 | #include "dm-log-userspace-transfer.h" |
14 | 14 | ||
15 | #define DM_LOG_USERSPACE_VSN "1.1.0" | ||
16 | |||
15 | struct flush_entry { | 17 | struct flush_entry { |
16 | int type; | 18 | int type; |
17 | region_t region; | 19 | region_t region; |
18 | struct list_head list; | 20 | struct list_head list; |
19 | }; | 21 | }; |
20 | 22 | ||
23 | /* | ||
24 | * This limit on the number of mark and clear request is, to a degree, | ||
25 | * arbitrary. However, there is some basis for the choice in the limits | ||
26 | * imposed on the size of data payload by dm-log-userspace-transfer.c: | ||
27 | * dm_consult_userspace(). | ||
28 | */ | ||
29 | #define MAX_FLUSH_GROUP_COUNT 32 | ||
30 | |||
21 | struct log_c { | 31 | struct log_c { |
22 | struct dm_target *ti; | 32 | struct dm_target *ti; |
23 | uint32_t region_size; | 33 | uint32_t region_size; |
@@ -37,8 +47,15 @@ struct log_c { | |||
37 | */ | 47 | */ |
38 | uint64_t in_sync_hint; | 48 | uint64_t in_sync_hint; |
39 | 49 | ||
50 | /* | ||
51 | * Mark and clear requests are held until a flush is issued | ||
52 | * so that we can group, and thereby limit, the amount of | ||
53 | * network traffic between kernel and userspace. The 'flush_lock' | ||
54 | * is used to protect these lists. | ||
55 | */ | ||
40 | spinlock_t flush_lock; | 56 | spinlock_t flush_lock; |
41 | struct list_head flush_list; /* only for clear and mark requests */ | 57 | struct list_head mark_list; |
58 | struct list_head clear_list; | ||
42 | }; | 59 | }; |
43 | 60 | ||
44 | static mempool_t *flush_entry_pool; | 61 | static mempool_t *flush_entry_pool; |
@@ -169,7 +186,8 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, | |||
169 | 186 | ||
170 | strncpy(lc->uuid, argv[0], DM_UUID_LEN); | 187 | strncpy(lc->uuid, argv[0], DM_UUID_LEN); |
171 | spin_lock_init(&lc->flush_lock); | 188 | spin_lock_init(&lc->flush_lock); |
172 | INIT_LIST_HEAD(&lc->flush_list); | 189 | INIT_LIST_HEAD(&lc->mark_list); |
190 | INIT_LIST_HEAD(&lc->clear_list); | ||
173 | 191 | ||
174 | str_size = build_constructor_string(ti, argc - 1, argv + 1, &ctr_str); | 192 | str_size = build_constructor_string(ti, argc - 1, argv + 1, &ctr_str); |
175 | if (str_size < 0) { | 193 | if (str_size < 0) { |
@@ -181,8 +199,11 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, | |||
181 | r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_CTR, | 199 | r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_CTR, |
182 | ctr_str, str_size, NULL, NULL); | 200 | ctr_str, str_size, NULL, NULL); |
183 | 201 | ||
184 | if (r == -ESRCH) { | 202 | if (r < 0) { |
185 | DMERR("Userspace log server not found"); | 203 | if (r == -ESRCH) |
204 | DMERR("Userspace log server not found"); | ||
205 | else | ||
206 | DMERR("Userspace log server failed to create log"); | ||
186 | goto out; | 207 | goto out; |
187 | } | 208 | } |
188 | 209 | ||
@@ -214,10 +235,9 @@ out: | |||
214 | 235 | ||
215 | static void userspace_dtr(struct dm_dirty_log *log) | 236 | static void userspace_dtr(struct dm_dirty_log *log) |
216 | { | 237 | { |
217 | int r; | ||
218 | struct log_c *lc = log->context; | 238 | struct log_c *lc = log->context; |
219 | 239 | ||
220 | r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_DTR, | 240 | (void) dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_DTR, |
221 | NULL, 0, | 241 | NULL, 0, |
222 | NULL, NULL); | 242 | NULL, NULL); |
223 | 243 | ||
@@ -338,6 +358,71 @@ static int userspace_in_sync(struct dm_dirty_log *log, region_t region, | |||
338 | return (r) ? 0 : (int)in_sync; | 358 | return (r) ? 0 : (int)in_sync; |
339 | } | 359 | } |
340 | 360 | ||
361 | static int flush_one_by_one(struct log_c *lc, struct list_head *flush_list) | ||
362 | { | ||
363 | int r = 0; | ||
364 | struct flush_entry *fe; | ||
365 | |||
366 | list_for_each_entry(fe, flush_list, list) { | ||
367 | r = userspace_do_request(lc, lc->uuid, fe->type, | ||
368 | (char *)&fe->region, | ||
369 | sizeof(fe->region), | ||
370 | NULL, NULL); | ||
371 | if (r) | ||
372 | break; | ||
373 | } | ||
374 | |||
375 | return r; | ||
376 | } | ||
377 | |||
378 | static int flush_by_group(struct log_c *lc, struct list_head *flush_list) | ||
379 | { | ||
380 | int r = 0; | ||
381 | int count; | ||
382 | uint32_t type = 0; | ||
383 | struct flush_entry *fe, *tmp_fe; | ||
384 | LIST_HEAD(tmp_list); | ||
385 | uint64_t group[MAX_FLUSH_GROUP_COUNT]; | ||
386 | |||
387 | /* | ||
388 | * Group process the requests | ||
389 | */ | ||
390 | while (!list_empty(flush_list)) { | ||
391 | count = 0; | ||
392 | |||
393 | list_for_each_entry_safe(fe, tmp_fe, flush_list, list) { | ||
394 | group[count] = fe->region; | ||
395 | count++; | ||
396 | |||
397 | list_del(&fe->list); | ||
398 | list_add(&fe->list, &tmp_list); | ||
399 | |||
400 | type = fe->type; | ||
401 | if (count >= MAX_FLUSH_GROUP_COUNT) | ||
402 | break; | ||
403 | } | ||
404 | |||
405 | r = userspace_do_request(lc, lc->uuid, type, | ||
406 | (char *)(group), | ||
407 | count * sizeof(uint64_t), | ||
408 | NULL, NULL); | ||
409 | if (r) { | ||
410 | /* Group send failed. Attempt one-by-one. */ | ||
411 | list_splice_init(&tmp_list, flush_list); | ||
412 | r = flush_one_by_one(lc, flush_list); | ||
413 | break; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | /* | ||
418 | * Must collect flush_entrys that were successfully processed | ||
419 | * as a group so that they will be free'd by the caller. | ||
420 | */ | ||
421 | list_splice_init(&tmp_list, flush_list); | ||
422 | |||
423 | return r; | ||
424 | } | ||
425 | |||
341 | /* | 426 | /* |
342 | * userspace_flush | 427 | * userspace_flush |
343 | * | 428 | * |
@@ -360,31 +445,25 @@ static int userspace_flush(struct dm_dirty_log *log) | |||
360 | int r = 0; | 445 | int r = 0; |
361 | unsigned long flags; | 446 | unsigned long flags; |
362 | struct log_c *lc = log->context; | 447 | struct log_c *lc = log->context; |
363 | LIST_HEAD(flush_list); | 448 | LIST_HEAD(mark_list); |
449 | LIST_HEAD(clear_list); | ||
364 | struct flush_entry *fe, *tmp_fe; | 450 | struct flush_entry *fe, *tmp_fe; |
365 | 451 | ||
366 | spin_lock_irqsave(&lc->flush_lock, flags); | 452 | spin_lock_irqsave(&lc->flush_lock, flags); |
367 | list_splice_init(&lc->flush_list, &flush_list); | 453 | list_splice_init(&lc->mark_list, &mark_list); |
454 | list_splice_init(&lc->clear_list, &clear_list); | ||
368 | spin_unlock_irqrestore(&lc->flush_lock, flags); | 455 | spin_unlock_irqrestore(&lc->flush_lock, flags); |
369 | 456 | ||
370 | if (list_empty(&flush_list)) | 457 | if (list_empty(&mark_list) && list_empty(&clear_list)) |
371 | return 0; | 458 | return 0; |
372 | 459 | ||
373 | /* | 460 | r = flush_by_group(lc, &mark_list); |
374 | * FIXME: Count up requests, group request types, | 461 | if (r) |
375 | * allocate memory to stick all requests in and | 462 | goto fail; |
376 | * send to server in one go. Failing the allocation, | ||
377 | * do it one by one. | ||
378 | */ | ||
379 | 463 | ||
380 | list_for_each_entry(fe, &flush_list, list) { | 464 | r = flush_by_group(lc, &clear_list); |
381 | r = userspace_do_request(lc, lc->uuid, fe->type, | 465 | if (r) |
382 | (char *)&fe->region, | 466 | goto fail; |
383 | sizeof(fe->region), | ||
384 | NULL, NULL); | ||
385 | if (r) | ||
386 | goto fail; | ||
387 | } | ||
388 | 467 | ||
389 | r = userspace_do_request(lc, lc->uuid, DM_ULOG_FLUSH, | 468 | r = userspace_do_request(lc, lc->uuid, DM_ULOG_FLUSH, |
390 | NULL, 0, NULL, NULL); | 469 | NULL, 0, NULL, NULL); |
@@ -395,7 +474,11 @@ fail: | |||
395 | * Calling code will receive an error and will know that | 474 | * Calling code will receive an error and will know that |
396 | * the log facility has failed. | 475 | * the log facility has failed. |
397 | */ | 476 | */ |
398 | list_for_each_entry_safe(fe, tmp_fe, &flush_list, list) { | 477 | list_for_each_entry_safe(fe, tmp_fe, &mark_list, list) { |
478 | list_del(&fe->list); | ||
479 | mempool_free(fe, flush_entry_pool); | ||
480 | } | ||
481 | list_for_each_entry_safe(fe, tmp_fe, &clear_list, list) { | ||
399 | list_del(&fe->list); | 482 | list_del(&fe->list); |
400 | mempool_free(fe, flush_entry_pool); | 483 | mempool_free(fe, flush_entry_pool); |
401 | } | 484 | } |
@@ -425,7 +508,7 @@ static void userspace_mark_region(struct dm_dirty_log *log, region_t region) | |||
425 | spin_lock_irqsave(&lc->flush_lock, flags); | 508 | spin_lock_irqsave(&lc->flush_lock, flags); |
426 | fe->type = DM_ULOG_MARK_REGION; | 509 | fe->type = DM_ULOG_MARK_REGION; |
427 | fe->region = region; | 510 | fe->region = region; |
428 | list_add(&fe->list, &lc->flush_list); | 511 | list_add(&fe->list, &lc->mark_list); |
429 | spin_unlock_irqrestore(&lc->flush_lock, flags); | 512 | spin_unlock_irqrestore(&lc->flush_lock, flags); |
430 | 513 | ||
431 | return; | 514 | return; |
@@ -462,7 +545,7 @@ static void userspace_clear_region(struct dm_dirty_log *log, region_t region) | |||
462 | spin_lock_irqsave(&lc->flush_lock, flags); | 545 | spin_lock_irqsave(&lc->flush_lock, flags); |
463 | fe->type = DM_ULOG_CLEAR_REGION; | 546 | fe->type = DM_ULOG_CLEAR_REGION; |
464 | fe->region = region; | 547 | fe->region = region; |
465 | list_add(&fe->list, &lc->flush_list); | 548 | list_add(&fe->list, &lc->clear_list); |
466 | spin_unlock_irqrestore(&lc->flush_lock, flags); | 549 | spin_unlock_irqrestore(&lc->flush_lock, flags); |
467 | 550 | ||
468 | return; | 551 | return; |
@@ -684,7 +767,7 @@ static int __init userspace_dirty_log_init(void) | |||
684 | return r; | 767 | return r; |
685 | } | 768 | } |
686 | 769 | ||
687 | DMINFO("version 1.0.0 loaded"); | 770 | DMINFO("version " DM_LOG_USERSPACE_VSN " loaded"); |
688 | return 0; | 771 | return 0; |
689 | } | 772 | } |
690 | 773 | ||
@@ -694,7 +777,7 @@ static void __exit userspace_dirty_log_exit(void) | |||
694 | dm_ulog_tfr_exit(); | 777 | dm_ulog_tfr_exit(); |
695 | mempool_destroy(flush_entry_pool); | 778 | mempool_destroy(flush_entry_pool); |
696 | 779 | ||
697 | DMINFO("version 1.0.0 unloaded"); | 780 | DMINFO("version " DM_LOG_USERSPACE_VSN " unloaded"); |
698 | return; | 781 | return; |
699 | } | 782 | } |
700 | 783 | ||