aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2012-07-31 03:08:14 -0400
committerJens Axboe <axboe@kernel.dk>2012-07-31 03:08:14 -0400
commit9cbb17508808f8a6bdd83354b61e126ac4fa6fed (patch)
treebc797d1b5cd829751a333115e6e6d52799fb6df2 /drivers
parent0021b7bc045e4b0b85d8c53614342aaf84ca96a5 (diff)
blk: centralize non-request unplug handling.
Both md and umem has similar code for getting notified on an blk_finish_plug event. Centralize this code in block/ and allow each driver to provide its distinctive difference. Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/umem.c35
-rw-r--r--drivers/md/md.c56
-rw-r--r--drivers/md/md.h8
3 files changed, 18 insertions, 81 deletions
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index 9a72277a31df..6ef3489568e3 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -513,42 +513,19 @@ static void process_page(unsigned long data)
513 } 513 }
514} 514}
515 515
516struct mm_plug_cb {
517 struct blk_plug_cb cb;
518 struct cardinfo *card;
519};
520
521static void mm_unplug(struct blk_plug_cb *cb) 516static void mm_unplug(struct blk_plug_cb *cb)
522{ 517{
523 struct mm_plug_cb *mmcb = container_of(cb, struct mm_plug_cb, cb); 518 struct cardinfo *card = cb->data;
524 519
525 spin_lock_irq(&mmcb->card->lock); 520 spin_lock_irq(&card->lock);
526 activate(mmcb->card); 521 activate(card);
527 spin_unlock_irq(&mmcb->card->lock); 522 spin_unlock_irq(&card->lock);
528 kfree(mmcb); 523 kfree(cb);
529} 524}
530 525
531static int mm_check_plugged(struct cardinfo *card) 526static int mm_check_plugged(struct cardinfo *card)
532{ 527{
533 struct blk_plug *plug = current->plug; 528 return !!blk_check_plugged(mm_unplug, card, sizeof(struct blk_plug_cb));
534 struct mm_plug_cb *mmcb;
535
536 if (!plug)
537 return 0;
538
539 list_for_each_entry(mmcb, &plug->cb_list, cb.list) {
540 if (mmcb->cb.callback == mm_unplug && mmcb->card == card)
541 return 1;
542 }
543 /* Not currently on the callback list */
544 mmcb = kmalloc(sizeof(*mmcb), GFP_ATOMIC);
545 if (!mmcb)
546 return 0;
547
548 mmcb->card = card;
549 mmcb->cb.callback = mm_unplug;
550 list_add(&mmcb->cb.list, &plug->cb_list);
551 return 1;
552} 529}
553 530
554static void mm_make_request(struct request_queue *q, struct bio *bio) 531static void mm_make_request(struct request_queue *q, struct bio *bio)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 34381172a947..b493fa417387 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -498,59 +498,13 @@ void md_flush_request(struct mddev *mddev, struct bio *bio)
498} 498}
499EXPORT_SYMBOL(md_flush_request); 499EXPORT_SYMBOL(md_flush_request);
500 500
501/* Support for plugging. 501void md_unplug(struct blk_plug_cb *cb)
502 * This mirrors the plugging support in request_queue, but does not
503 * require having a whole queue or request structures.
504 * We allocate an md_plug_cb for each md device and each thread it gets
505 * plugged on. This links tot the private plug_handle structure in the
506 * personality data where we keep a count of the number of outstanding
507 * plugs so other code can see if a plug is active.
508 */
509struct md_plug_cb {
510 struct blk_plug_cb cb;
511 struct mddev *mddev;
512};
513
514static void plugger_unplug(struct blk_plug_cb *cb)
515{ 502{
516 struct md_plug_cb *mdcb = container_of(cb, struct md_plug_cb, cb); 503 struct mddev *mddev = cb->data;
517 md_wakeup_thread(mdcb->mddev->thread); 504 md_wakeup_thread(mddev->thread);
518 kfree(mdcb); 505 kfree(cb);
519}
520
521/* Check that an unplug wakeup will come shortly.
522 * If not, wakeup the md thread immediately
523 */
524int mddev_check_plugged(struct mddev *mddev)
525{
526 struct blk_plug *plug = current->plug;
527 struct md_plug_cb *mdcb;
528
529 if (!plug)
530 return 0;
531
532 list_for_each_entry(mdcb, &plug->cb_list, cb.list) {
533 if (mdcb->cb.callback == plugger_unplug &&
534 mdcb->mddev == mddev) {
535 /* Already on the list, move to top */
536 if (mdcb != list_first_entry(&plug->cb_list,
537 struct md_plug_cb,
538 cb.list))
539 list_move(&mdcb->cb.list, &plug->cb_list);
540 return 1;
541 }
542 }
543 /* Not currently on the callback list */
544 mdcb = kmalloc(sizeof(*mdcb), GFP_ATOMIC);
545 if (!mdcb)
546 return 0;
547
548 mdcb->mddev = mddev;
549 mdcb->cb.callback = plugger_unplug;
550 list_add(&mdcb->cb.list, &plug->cb_list);
551 return 1;
552} 506}
553EXPORT_SYMBOL_GPL(mddev_check_plugged); 507EXPORT_SYMBOL(md_unplug);
554 508
555static inline struct mddev *mddev_get(struct mddev *mddev) 509static inline struct mddev *mddev_get(struct mddev *mddev)
556{ 510{
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 91786c46b85c..8f998e08fb87 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -627,6 +627,12 @@ extern struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask,
627 struct mddev *mddev); 627 struct mddev *mddev);
628extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, 628extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,
629 struct mddev *mddev); 629 struct mddev *mddev);
630extern int mddev_check_plugged(struct mddev *mddev);
631extern void md_trim_bio(struct bio *bio, int offset, int size); 630extern void md_trim_bio(struct bio *bio, int offset, int size);
631
632extern void md_unplug(struct blk_plug_cb *cb);
633static inline int mddev_check_plugged(struct mddev *mddev)
634{
635 return !!blk_check_plugged(md_unplug, mddev,
636 sizeof(struct blk_plug_cb));
637}
632#endif /* _MD_MD_H */ 638#endif /* _MD_MD_H */