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 | ||
