diff options
-rw-r--r-- | drivers/block/xen-blkback/blkback.c | 169 | ||||
-rw-r--r-- | drivers/block/xen-blkback/common.h | 3 |
2 files changed, 122 insertions, 50 deletions
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 908e630240bd..2a04d341e598 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <asm/xen/hypervisor.h> | 47 | #include <asm/xen/hypervisor.h> |
48 | #include <asm/xen/hypercall.h> | 48 | #include <asm/xen/hypercall.h> |
49 | #include <xen/balloon.h> | 49 | #include <xen/balloon.h> |
50 | #include <xen/grant_table.h> | ||
50 | #include "common.h" | 51 | #include "common.h" |
51 | 52 | ||
52 | /* | 53 | /* |
@@ -262,6 +263,17 @@ static void put_persistent_gnt(struct xen_blkif *blkif, | |||
262 | atomic_dec(&blkif->persistent_gnt_in_use); | 263 | atomic_dec(&blkif->persistent_gnt_in_use); |
263 | } | 264 | } |
264 | 265 | ||
266 | static void free_persistent_gnts_unmap_callback(int result, | ||
267 | struct gntab_unmap_queue_data *data) | ||
268 | { | ||
269 | struct completion *c = data->data; | ||
270 | |||
271 | /* BUG_ON used to reproduce existing behaviour, | ||
272 | but is this the best way to deal with this? */ | ||
273 | BUG_ON(result); | ||
274 | complete(c); | ||
275 | } | ||
276 | |||
265 | static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, | 277 | static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, |
266 | unsigned int num) | 278 | unsigned int num) |
267 | { | 279 | { |
@@ -269,8 +281,17 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, | |||
269 | struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; | 281 | struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; |
270 | struct persistent_gnt *persistent_gnt; | 282 | struct persistent_gnt *persistent_gnt; |
271 | struct rb_node *n; | 283 | struct rb_node *n; |
272 | int ret = 0; | ||
273 | int segs_to_unmap = 0; | 284 | int segs_to_unmap = 0; |
285 | struct gntab_unmap_queue_data unmap_data; | ||
286 | struct completion unmap_completion; | ||
287 | |||
288 | init_completion(&unmap_completion); | ||
289 | |||
290 | unmap_data.data = &unmap_completion; | ||
291 | unmap_data.done = &free_persistent_gnts_unmap_callback; | ||
292 | unmap_data.pages = pages; | ||
293 | unmap_data.unmap_ops = unmap; | ||
294 | unmap_data.kunmap_ops = NULL; | ||
274 | 295 | ||
275 | foreach_grant_safe(persistent_gnt, n, root, node) { | 296 | foreach_grant_safe(persistent_gnt, n, root, node) { |
276 | BUG_ON(persistent_gnt->handle == | 297 | BUG_ON(persistent_gnt->handle == |
@@ -285,9 +306,11 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, | |||
285 | 306 | ||
286 | if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST || | 307 | if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST || |
287 | !rb_next(&persistent_gnt->node)) { | 308 | !rb_next(&persistent_gnt->node)) { |
288 | ret = gnttab_unmap_refs(unmap, NULL, pages, | 309 | |
289 | segs_to_unmap); | 310 | unmap_data.count = segs_to_unmap; |
290 | BUG_ON(ret); | 311 | gnttab_unmap_refs_async(&unmap_data); |
312 | wait_for_completion(&unmap_completion); | ||
313 | |||
291 | put_free_pages(blkif, pages, segs_to_unmap); | 314 | put_free_pages(blkif, pages, segs_to_unmap); |
292 | segs_to_unmap = 0; | 315 | segs_to_unmap = 0; |
293 | } | 316 | } |
@@ -653,18 +676,14 @@ void xen_blkbk_free_caches(struct xen_blkif *blkif) | |||
653 | shrink_free_pagepool(blkif, 0 /* All */); | 676 | shrink_free_pagepool(blkif, 0 /* All */); |
654 | } | 677 | } |
655 | 678 | ||
656 | /* | 679 | static unsigned int xen_blkbk_unmap_prepare( |
657 | * Unmap the grant references, and also remove the M2P over-rides | 680 | struct xen_blkif *blkif, |
658 | * used in the 'pending_req'. | 681 | struct grant_page **pages, |
659 | */ | 682 | unsigned int num, |
660 | static void xen_blkbk_unmap(struct xen_blkif *blkif, | 683 | struct gnttab_unmap_grant_ref *unmap_ops, |
661 | struct grant_page *pages[], | 684 | struct page **unmap_pages) |
662 | int num) | ||
663 | { | 685 | { |
664 | struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; | ||
665 | struct page *unmap_pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; | ||
666 | unsigned int i, invcount = 0; | 686 | unsigned int i, invcount = 0; |
667 | int ret; | ||
668 | 687 | ||
669 | for (i = 0; i < num; i++) { | 688 | for (i = 0; i < num; i++) { |
670 | if (pages[i]->persistent_gnt != NULL) { | 689 | if (pages[i]->persistent_gnt != NULL) { |
@@ -674,21 +693,95 @@ static void xen_blkbk_unmap(struct xen_blkif *blkif, | |||
674 | if (pages[i]->handle == BLKBACK_INVALID_HANDLE) | 693 | if (pages[i]->handle == BLKBACK_INVALID_HANDLE) |
675 | continue; | 694 | continue; |
676 | unmap_pages[invcount] = pages[i]->page; | 695 | unmap_pages[invcount] = pages[i]->page; |
677 | gnttab_set_unmap_op(&unmap[invcount], vaddr(pages[i]->page), | 696 | gnttab_set_unmap_op(&unmap_ops[invcount], vaddr(pages[i]->page), |
678 | GNTMAP_host_map, pages[i]->handle); | 697 | GNTMAP_host_map, pages[i]->handle); |
679 | pages[i]->handle = BLKBACK_INVALID_HANDLE; | 698 | pages[i]->handle = BLKBACK_INVALID_HANDLE; |
680 | if (++invcount == BLKIF_MAX_SEGMENTS_PER_REQUEST) { | 699 | invcount++; |
681 | ret = gnttab_unmap_refs(unmap, NULL, unmap_pages, | 700 | } |
682 | invcount); | 701 | |
702 | return invcount; | ||
703 | } | ||
704 | |||
705 | static void xen_blkbk_unmap_and_respond_callback(int result, struct gntab_unmap_queue_data *data) | ||
706 | { | ||
707 | struct pending_req* pending_req = (struct pending_req*) (data->data); | ||
708 | struct xen_blkif *blkif = pending_req->blkif; | ||
709 | |||
710 | /* BUG_ON used to reproduce existing behaviour, | ||
711 | but is this the best way to deal with this? */ | ||
712 | BUG_ON(result); | ||
713 | |||
714 | put_free_pages(blkif, data->pages, data->count); | ||
715 | make_response(blkif, pending_req->id, | ||
716 | pending_req->operation, pending_req->status); | ||
717 | free_req(blkif, pending_req); | ||
718 | /* | ||
719 | * Make sure the request is freed before releasing blkif, | ||
720 | * or there could be a race between free_req and the | ||
721 | * cleanup done in xen_blkif_free during shutdown. | ||
722 | * | ||
723 | * NB: The fact that we might try to wake up pending_free_wq | ||
724 | * before drain_complete (in case there's a drain going on) | ||
725 | * it's not a problem with our current implementation | ||
726 | * because we can assure there's no thread waiting on | ||
727 | * pending_free_wq if there's a drain going on, but it has | ||
728 | * to be taken into account if the current model is changed. | ||
729 | */ | ||
730 | if (atomic_dec_and_test(&blkif->inflight) && atomic_read(&blkif->drain)) { | ||
731 | complete(&blkif->drain_complete); | ||
732 | } | ||
733 | xen_blkif_put(blkif); | ||
734 | } | ||
735 | |||
736 | static void xen_blkbk_unmap_and_respond(struct pending_req *req) | ||
737 | { | ||
738 | struct gntab_unmap_queue_data* work = &req->gnttab_unmap_data; | ||
739 | struct xen_blkif *blkif = req->blkif; | ||
740 | struct grant_page **pages = req->segments; | ||
741 | unsigned int invcount; | ||
742 | |||
743 | invcount = xen_blkbk_unmap_prepare(blkif, pages, req->nr_pages, | ||
744 | req->unmap, req->unmap_pages); | ||
745 | |||
746 | work->data = req; | ||
747 | work->done = xen_blkbk_unmap_and_respond_callback; | ||
748 | work->unmap_ops = req->unmap; | ||
749 | work->kunmap_ops = NULL; | ||
750 | work->pages = req->unmap_pages; | ||
751 | work->count = invcount; | ||
752 | |||
753 | gnttab_unmap_refs_async(&req->gnttab_unmap_data); | ||
754 | } | ||
755 | |||
756 | |||
757 | /* | ||
758 | * Unmap the grant references. | ||
759 | * | ||
760 | * This could accumulate ops up to the batch size to reduce the number | ||
761 | * of hypercalls, but since this is only used in error paths there's | ||
762 | * no real need. | ||
763 | */ | ||
764 | static void xen_blkbk_unmap(struct xen_blkif *blkif, | ||
765 | struct grant_page *pages[], | ||
766 | int num) | ||
767 | { | ||
768 | struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; | ||
769 | struct page *unmap_pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; | ||
770 | unsigned int invcount = 0; | ||
771 | int ret; | ||
772 | |||
773 | while (num) { | ||
774 | unsigned int batch = min(num, BLKIF_MAX_SEGMENTS_PER_REQUEST); | ||
775 | |||
776 | invcount = xen_blkbk_unmap_prepare(blkif, pages, batch, | ||
777 | unmap, unmap_pages); | ||
778 | if (invcount) { | ||
779 | ret = gnttab_unmap_refs(unmap, NULL, unmap_pages, invcount); | ||
683 | BUG_ON(ret); | 780 | BUG_ON(ret); |
684 | put_free_pages(blkif, unmap_pages, invcount); | 781 | put_free_pages(blkif, unmap_pages, invcount); |
685 | invcount = 0; | ||
686 | } | 782 | } |
687 | } | 783 | pages += batch; |
688 | if (invcount) { | 784 | num -= batch; |
689 | ret = gnttab_unmap_refs(unmap, NULL, unmap_pages, invcount); | ||
690 | BUG_ON(ret); | ||
691 | put_free_pages(blkif, unmap_pages, invcount); | ||
692 | } | 785 | } |
693 | } | 786 | } |
694 | 787 | ||
@@ -982,32 +1075,8 @@ static void __end_block_io_op(struct pending_req *pending_req, int error) | |||
982 | * the grant references associated with 'request' and provide | 1075 | * the grant references associated with 'request' and provide |
983 | * the proper response on the ring. | 1076 | * the proper response on the ring. |
984 | */ | 1077 | */ |
985 | if (atomic_dec_and_test(&pending_req->pendcnt)) { | 1078 | if (atomic_dec_and_test(&pending_req->pendcnt)) |
986 | struct xen_blkif *blkif = pending_req->blkif; | 1079 | xen_blkbk_unmap_and_respond(pending_req); |
987 | |||
988 | xen_blkbk_unmap(blkif, | ||
989 | pending_req->segments, | ||
990 | pending_req->nr_pages); | ||
991 | make_response(blkif, pending_req->id, | ||
992 | pending_req->operation, pending_req->status); | ||
993 | free_req(blkif, pending_req); | ||
994 | /* | ||
995 | * Make sure the request is freed before releasing blkif, | ||
996 | * or there could be a race between free_req and the | ||
997 | * cleanup done in xen_blkif_free during shutdown. | ||
998 | * | ||
999 | * NB: The fact that we might try to wake up pending_free_wq | ||
1000 | * before drain_complete (in case there's a drain going on) | ||
1001 | * it's not a problem with our current implementation | ||
1002 | * because we can assure there's no thread waiting on | ||
1003 | * pending_free_wq if there's a drain going on, but it has | ||
1004 | * to be taken into account if the current model is changed. | ||
1005 | */ | ||
1006 | if (atomic_dec_and_test(&blkif->inflight) && atomic_read(&blkif->drain)) { | ||
1007 | complete(&blkif->drain_complete); | ||
1008 | } | ||
1009 | xen_blkif_put(blkif); | ||
1010 | } | ||
1011 | } | 1080 | } |
1012 | 1081 | ||
1013 | /* | 1082 | /* |
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index f65b807e3236..cc90a840e616 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h | |||
@@ -350,6 +350,9 @@ struct pending_req { | |||
350 | struct grant_page *indirect_pages[MAX_INDIRECT_PAGES]; | 350 | struct grant_page *indirect_pages[MAX_INDIRECT_PAGES]; |
351 | struct seg_buf seg[MAX_INDIRECT_SEGMENTS]; | 351 | struct seg_buf seg[MAX_INDIRECT_SEGMENTS]; |
352 | struct bio *biolist[MAX_INDIRECT_SEGMENTS]; | 352 | struct bio *biolist[MAX_INDIRECT_SEGMENTS]; |
353 | struct gnttab_unmap_grant_ref unmap[MAX_INDIRECT_SEGMENTS]; | ||
354 | struct page *unmap_pages[MAX_INDIRECT_SEGMENTS]; | ||
355 | struct gntab_unmap_queue_data gnttab_unmap_data; | ||
353 | }; | 356 | }; |
354 | 357 | ||
355 | 358 | ||