aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--block/blk-core.c25
-rw-r--r--drivers/block/umem.c35
-rw-r--r--drivers/md/md.c56
-rw-r--r--drivers/md/md.h8
-rw-r--r--include/linux/blkdev.h8
5 files changed, 49 insertions, 83 deletions
diff --git a/block/blk-core.c b/block/blk-core.c
index dd134d834d58..177ddcf356e6 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -2927,6 +2927,31 @@ static void flush_plug_callbacks(struct blk_plug *plug)
2927 } 2927 }
2928} 2928}
2929 2929
2930struct blk_plug_cb *blk_check_plugged(blk_plug_cb_fn unplug, void *data,
2931 int size)
2932{
2933 struct blk_plug *plug = current->plug;
2934 struct blk_plug_cb *cb;
2935
2936 if (!plug)
2937 return NULL;
2938
2939 list_for_each_entry(cb, &plug->cb_list, list)
2940 if (cb->callback == unplug && cb->data == data)
2941 return cb;
2942
2943 /* Not currently on the callback list */
2944 BUG_ON(size < sizeof(*cb));
2945 cb = kzalloc(size, GFP_ATOMIC);
2946 if (cb) {
2947 cb->data = data;
2948 cb->callback = unplug;
2949 list_add(&cb->list, &plug->cb_list);
2950 }
2951 return cb;
2952}
2953EXPORT_SYMBOL(blk_check_plugged);
2954
2930void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) 2955void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
2931{ 2956{
2932 struct request_queue *q; 2957 struct request_queue *q;
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 */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 3816ce8a08fc..607ca228f47e 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -922,11 +922,15 @@ struct blk_plug {
922}; 922};
923#define BLK_MAX_REQUEST_COUNT 16 923#define BLK_MAX_REQUEST_COUNT 16
924 924
925struct blk_plug_cb;
926typedef void (*blk_plug_cb_fn)(struct blk_plug_cb *);
925struct blk_plug_cb { 927struct blk_plug_cb {
926 struct list_head list; 928 struct list_head list;
927 void (*callback)(struct blk_plug_cb *); 929 blk_plug_cb_fn callback;
930 void *data;
928}; 931};
929 932extern struct blk_plug_cb *blk_check_plugged(blk_plug_cb_fn unplug,
933 void *data, int size);
930extern void blk_start_plug(struct blk_plug *); 934extern void blk_start_plug(struct blk_plug *);
931extern void blk_finish_plug(struct blk_plug *); 935extern void blk_finish_plug(struct blk_plug *);
932extern void blk_flush_plug_list(struct blk_plug *, bool); 936extern void blk_flush_plug_list(struct blk_plug *, bool);