aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/md.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2011-04-18 04:25:42 -0400
committerNeilBrown <neilb@suse.de>2011-04-18 04:25:42 -0400
commit97658cdd3af7d01461874c93b89afa4a2465e7c6 (patch)
treed4e2f930850eb3981307a3eec8c86399dcebf68a /drivers/md/md.c
parent482c083492ddaa32ef5864bae3d143dc8bcdf7d1 (diff)
md: provide generic support for handling unplug callbacks.
When an md device adds a request to a queue, it can call mddev_check_plugged. If this succeeds then we know that the md thread will be woken up shortly, and ->plug_cnt will be non-zero until then, so some processing can be delayed. If it fails, then no unplug callback is expected and the make_request function needs to do whatever is required to make the request happen. Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r--drivers/md/md.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index fb11170c717e..6e853c61d87e 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -445,6 +445,61 @@ void md_flush_request(mddev_t *mddev, struct bio *bio)
445} 445}
446EXPORT_SYMBOL(md_flush_request); 446EXPORT_SYMBOL(md_flush_request);
447 447
448/* Support for plugging.
449 * This mirrors the plugging support in request_queue, but does not
450 * require having a whole queue or request structures.
451 * We allocate an md_plug_cb for each md device and each thread it gets
452 * plugged on. This links tot the private plug_handle structure in the
453 * personality data where we keep a count of the number of outstanding
454 * plugs so other code can see if a plug is active.
455 */
456struct md_plug_cb {
457 struct blk_plug_cb cb;
458 mddev_t *mddev;
459};
460
461static void plugger_unplug(struct blk_plug_cb *cb)
462{
463 struct md_plug_cb *mdcb = container_of(cb, struct md_plug_cb, cb);
464 if (atomic_dec_and_test(&mdcb->mddev->plug_cnt))
465 md_wakeup_thread(mdcb->mddev->thread);
466 kfree(mdcb);
467}
468
469/* Check that an unplug wakeup will come shortly.
470 * If not, wakeup the md thread immediately
471 */
472int mddev_check_plugged(mddev_t *mddev)
473{
474 struct blk_plug *plug = current->plug;
475 struct md_plug_cb *mdcb;
476
477 if (!plug)
478 return 0;
479
480 list_for_each_entry(mdcb, &plug->cb_list, cb.list) {
481 if (mdcb->cb.callback == plugger_unplug &&
482 mdcb->mddev == mddev) {
483 /* Already on the list, move to top */
484 if (mdcb != list_first_entry(&plug->cb_list,
485 struct md_plug_cb,
486 cb.list))
487 list_move(&mdcb->cb.list, &plug->cb_list);
488 return 1;
489 }
490 }
491 /* Not currently on the callback list */
492 mdcb = kmalloc(sizeof(*mdcb), GFP_ATOMIC);
493 if (!mdcb)
494 return 0;
495
496 mdcb->mddev = mddev;
497 mdcb->cb.callback = plugger_unplug;
498 atomic_inc(&mddev->plug_cnt);
499 list_add(&mdcb->cb.list, &plug->cb_list);
500 return 1;
501}
502EXPORT_SYMBOL_GPL(mddev_check_plugged);
448 503
449static inline mddev_t *mddev_get(mddev_t *mddev) 504static inline mddev_t *mddev_get(mddev_t *mddev)
450{ 505{
@@ -494,6 +549,7 @@ void mddev_init(mddev_t *mddev)
494 atomic_set(&mddev->active, 1); 549 atomic_set(&mddev->active, 1);
495 atomic_set(&mddev->openers, 0); 550 atomic_set(&mddev->openers, 0);
496 atomic_set(&mddev->active_io, 0); 551 atomic_set(&mddev->active_io, 0);
552 atomic_set(&mddev->plug_cnt, 0);
497 spin_lock_init(&mddev->write_lock); 553 spin_lock_init(&mddev->write_lock);
498 atomic_set(&mddev->flush_pending, 0); 554 atomic_set(&mddev->flush_pending, 0);
499 init_waitqueue_head(&mddev->sb_wait); 555 init_waitqueue_head(&mddev->sb_wait);