diff options
Diffstat (limited to 'drivers/block/xen-blkback/blkback.c')
| -rw-r--r-- | drivers/block/xen-blkback/blkback.c | 81 |
1 files changed, 52 insertions, 29 deletions
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index da18046d0e07..64c60edcdfbc 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c | |||
| @@ -285,7 +285,8 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, | |||
| 285 | 285 | ||
| 286 | if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST || | 286 | if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST || |
| 287 | !rb_next(&persistent_gnt->node)) { | 287 | !rb_next(&persistent_gnt->node)) { |
| 288 | ret = gnttab_unmap_refs(unmap, pages, segs_to_unmap); | 288 | ret = gnttab_unmap_refs(unmap, NULL, pages, |
| 289 | segs_to_unmap); | ||
| 289 | BUG_ON(ret); | 290 | BUG_ON(ret); |
| 290 | put_free_pages(blkif, pages, segs_to_unmap); | 291 | put_free_pages(blkif, pages, segs_to_unmap); |
| 291 | segs_to_unmap = 0; | 292 | segs_to_unmap = 0; |
| @@ -298,7 +299,7 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, | |||
| 298 | BUG_ON(num != 0); | 299 | BUG_ON(num != 0); |
| 299 | } | 300 | } |
| 300 | 301 | ||
| 301 | static void unmap_purged_grants(struct work_struct *work) | 302 | void xen_blkbk_unmap_purged_grants(struct work_struct *work) |
| 302 | { | 303 | { |
| 303 | struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; | 304 | struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; |
| 304 | struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; | 305 | struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; |
| @@ -320,7 +321,8 @@ static void unmap_purged_grants(struct work_struct *work) | |||
| 320 | pages[segs_to_unmap] = persistent_gnt->page; | 321 | pages[segs_to_unmap] = persistent_gnt->page; |
| 321 | 322 | ||
| 322 | if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST) { | 323 | if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST) { |
| 323 | ret = gnttab_unmap_refs(unmap, pages, segs_to_unmap); | 324 | ret = gnttab_unmap_refs(unmap, NULL, pages, |
| 325 | segs_to_unmap); | ||
| 324 | BUG_ON(ret); | 326 | BUG_ON(ret); |
| 325 | put_free_pages(blkif, pages, segs_to_unmap); | 327 | put_free_pages(blkif, pages, segs_to_unmap); |
| 326 | segs_to_unmap = 0; | 328 | segs_to_unmap = 0; |
| @@ -328,7 +330,7 @@ static void unmap_purged_grants(struct work_struct *work) | |||
| 328 | kfree(persistent_gnt); | 330 | kfree(persistent_gnt); |
| 329 | } | 331 | } |
| 330 | if (segs_to_unmap > 0) { | 332 | if (segs_to_unmap > 0) { |
| 331 | ret = gnttab_unmap_refs(unmap, pages, segs_to_unmap); | 333 | ret = gnttab_unmap_refs(unmap, NULL, pages, segs_to_unmap); |
| 332 | BUG_ON(ret); | 334 | BUG_ON(ret); |
| 333 | put_free_pages(blkif, pages, segs_to_unmap); | 335 | put_free_pages(blkif, pages, segs_to_unmap); |
| 334 | } | 336 | } |
| @@ -373,7 +375,7 @@ static void purge_persistent_gnt(struct xen_blkif *blkif) | |||
| 373 | 375 | ||
| 374 | pr_debug(DRV_PFX "Going to purge %u persistent grants\n", num_clean); | 376 | pr_debug(DRV_PFX "Going to purge %u persistent grants\n", num_clean); |
| 375 | 377 | ||
| 376 | INIT_LIST_HEAD(&blkif->persistent_purge_list); | 378 | BUG_ON(!list_empty(&blkif->persistent_purge_list)); |
| 377 | root = &blkif->persistent_gnts; | 379 | root = &blkif->persistent_gnts; |
| 378 | purge_list: | 380 | purge_list: |
| 379 | foreach_grant_safe(persistent_gnt, n, root, node) { | 381 | foreach_grant_safe(persistent_gnt, n, root, node) { |
| @@ -418,7 +420,6 @@ finished: | |||
| 418 | blkif->vbd.overflow_max_grants = 0; | 420 | blkif->vbd.overflow_max_grants = 0; |
| 419 | 421 | ||
| 420 | /* We can defer this work */ | 422 | /* We can defer this work */ |
| 421 | INIT_WORK(&blkif->persistent_purge_work, unmap_purged_grants); | ||
| 422 | schedule_work(&blkif->persistent_purge_work); | 423 | schedule_work(&blkif->persistent_purge_work); |
| 423 | pr_debug(DRV_PFX "Purged %u/%u\n", (total - num_clean), total); | 424 | pr_debug(DRV_PFX "Purged %u/%u\n", (total - num_clean), total); |
| 424 | return; | 425 | return; |
| @@ -623,9 +624,23 @@ purge_gnt_list: | |||
| 623 | print_stats(blkif); | 624 | print_stats(blkif); |
| 624 | } | 625 | } |
| 625 | 626 | ||
| 626 | /* Since we are shutting down remove all pages from the buffer */ | 627 | /* Drain pending purge work */ |
| 627 | shrink_free_pagepool(blkif, 0 /* All */); | 628 | flush_work(&blkif->persistent_purge_work); |
| 628 | 629 | ||
| 630 | if (log_stats) | ||
| 631 | print_stats(blkif); | ||
| 632 | |||
| 633 | blkif->xenblkd = NULL; | ||
| 634 | xen_blkif_put(blkif); | ||
| 635 | |||
| 636 | return 0; | ||
| 637 | } | ||
| 638 | |||
| 639 | /* | ||
| 640 | * Remove persistent grants and empty the pool of free pages | ||
| 641 | */ | ||
| 642 | void xen_blkbk_free_caches(struct xen_blkif *blkif) | ||
| 643 | { | ||
| 629 | /* Free all persistent grant pages */ | 644 | /* Free all persistent grant pages */ |
| 630 | if (!RB_EMPTY_ROOT(&blkif->persistent_gnts)) | 645 | if (!RB_EMPTY_ROOT(&blkif->persistent_gnts)) |
| 631 | free_persistent_gnts(blkif, &blkif->persistent_gnts, | 646 | free_persistent_gnts(blkif, &blkif->persistent_gnts, |
| @@ -634,13 +649,8 @@ purge_gnt_list: | |||
| 634 | BUG_ON(!RB_EMPTY_ROOT(&blkif->persistent_gnts)); | 649 | BUG_ON(!RB_EMPTY_ROOT(&blkif->persistent_gnts)); |
| 635 | blkif->persistent_gnt_c = 0; | 650 | blkif->persistent_gnt_c = 0; |
| 636 | 651 | ||
| 637 | if (log_stats) | 652 | /* Since we are shutting down remove all pages from the buffer */ |
| 638 | print_stats(blkif); | 653 | shrink_free_pagepool(blkif, 0 /* All */); |
| 639 | |||
| 640 | blkif->xenblkd = NULL; | ||
| 641 | xen_blkif_put(blkif); | ||
| 642 | |||
| 643 | return 0; | ||
| 644 | } | 654 | } |
| 645 | 655 | ||
| 646 | /* | 656 | /* |
| @@ -668,14 +678,15 @@ static void xen_blkbk_unmap(struct xen_blkif *blkif, | |||
| 668 | GNTMAP_host_map, pages[i]->handle); | 678 | GNTMAP_host_map, pages[i]->handle); |
| 669 | pages[i]->handle = BLKBACK_INVALID_HANDLE; | 679 | pages[i]->handle = BLKBACK_INVALID_HANDLE; |
| 670 | if (++invcount == BLKIF_MAX_SEGMENTS_PER_REQUEST) { | 680 | if (++invcount == BLKIF_MAX_SEGMENTS_PER_REQUEST) { |
| 671 | ret = gnttab_unmap_refs(unmap, unmap_pages, invcount); | 681 | ret = gnttab_unmap_refs(unmap, NULL, unmap_pages, |
| 682 | invcount); | ||
| 672 | BUG_ON(ret); | 683 | BUG_ON(ret); |
| 673 | put_free_pages(blkif, unmap_pages, invcount); | 684 | put_free_pages(blkif, unmap_pages, invcount); |
| 674 | invcount = 0; | 685 | invcount = 0; |
| 675 | } | 686 | } |
| 676 | } | 687 | } |
| 677 | if (invcount) { | 688 | if (invcount) { |
| 678 | ret = gnttab_unmap_refs(unmap, unmap_pages, invcount); | 689 | ret = gnttab_unmap_refs(unmap, NULL, unmap_pages, invcount); |
| 679 | BUG_ON(ret); | 690 | BUG_ON(ret); |
| 680 | put_free_pages(blkif, unmap_pages, invcount); | 691 | put_free_pages(blkif, unmap_pages, invcount); |
| 681 | } | 692 | } |
| @@ -737,7 +748,7 @@ again: | |||
| 737 | } | 748 | } |
| 738 | 749 | ||
| 739 | if (segs_to_map) { | 750 | if (segs_to_map) { |
| 740 | ret = gnttab_map_refs(map, pages_to_gnt, segs_to_map); | 751 | ret = gnttab_map_refs(map, NULL, pages_to_gnt, segs_to_map); |
| 741 | BUG_ON(ret); | 752 | BUG_ON(ret); |
| 742 | } | 753 | } |
| 743 | 754 | ||
| @@ -835,7 +846,7 @@ static int xen_blkbk_parse_indirect(struct blkif_request *req, | |||
| 835 | struct grant_page **pages = pending_req->indirect_pages; | 846 | struct grant_page **pages = pending_req->indirect_pages; |
| 836 | struct xen_blkif *blkif = pending_req->blkif; | 847 | struct xen_blkif *blkif = pending_req->blkif; |
| 837 | int indirect_grefs, rc, n, nseg, i; | 848 | int indirect_grefs, rc, n, nseg, i; |
| 838 | struct blkif_request_segment_aligned *segments = NULL; | 849 | struct blkif_request_segment *segments = NULL; |
| 839 | 850 | ||
| 840 | nseg = pending_req->nr_pages; | 851 | nseg = pending_req->nr_pages; |
| 841 | indirect_grefs = INDIRECT_PAGES(nseg); | 852 | indirect_grefs = INDIRECT_PAGES(nseg); |
| @@ -931,9 +942,7 @@ static void xen_blk_drain_io(struct xen_blkif *blkif) | |||
| 931 | { | 942 | { |
| 932 | atomic_set(&blkif->drain, 1); | 943 | atomic_set(&blkif->drain, 1); |
| 933 | do { | 944 | do { |
| 934 | /* The initial value is one, and one refcnt taken at the | 945 | if (atomic_read(&blkif->inflight) == 0) |
| 935 | * start of the xen_blkif_schedule thread. */ | ||
| 936 | if (atomic_read(&blkif->refcnt) <= 2) | ||
| 937 | break; | 946 | break; |
| 938 | wait_for_completion_interruptible_timeout( | 947 | wait_for_completion_interruptible_timeout( |
| 939 | &blkif->drain_complete, HZ); | 948 | &blkif->drain_complete, HZ); |
| @@ -973,17 +982,30 @@ static void __end_block_io_op(struct pending_req *pending_req, int error) | |||
| 973 | * the proper response on the ring. | 982 | * the proper response on the ring. |
| 974 | */ | 983 | */ |
| 975 | if (atomic_dec_and_test(&pending_req->pendcnt)) { | 984 | if (atomic_dec_and_test(&pending_req->pendcnt)) { |
| 976 | xen_blkbk_unmap(pending_req->blkif, | 985 | struct xen_blkif *blkif = pending_req->blkif; |
| 986 | |||
| 987 | xen_blkbk_unmap(blkif, | ||
| 977 | pending_req->segments, | 988 | pending_req->segments, |
| 978 | pending_req->nr_pages); | 989 | pending_req->nr_pages); |
| 979 | make_response(pending_req->blkif, pending_req->id, | 990 | make_response(blkif, pending_req->id, |
| 980 | pending_req->operation, pending_req->status); | 991 | pending_req->operation, pending_req->status); |
| 981 | xen_blkif_put(pending_req->blkif); | 992 | free_req(blkif, pending_req); |
| 982 | if (atomic_read(&pending_req->blkif->refcnt) <= 2) { | 993 | /* |
| 983 | if (atomic_read(&pending_req->blkif->drain)) | 994 | * Make sure the request is freed before releasing blkif, |
| 984 | complete(&pending_req->blkif->drain_complete); | 995 | * or there could be a race between free_req and the |
| 996 | * cleanup done in xen_blkif_free during shutdown. | ||
| 997 | * | ||
| 998 | * NB: The fact that we might try to wake up pending_free_wq | ||
| 999 | * before drain_complete (in case there's a drain going on) | ||
| 1000 | * it's not a problem with our current implementation | ||
| 1001 | * because we can assure there's no thread waiting on | ||
| 1002 | * pending_free_wq if there's a drain going on, but it has | ||
| 1003 | * to be taken into account if the current model is changed. | ||
| 1004 | */ | ||
| 1005 | if (atomic_dec_and_test(&blkif->inflight) && atomic_read(&blkif->drain)) { | ||
| 1006 | complete(&blkif->drain_complete); | ||
| 985 | } | 1007 | } |
| 986 | free_req(pending_req->blkif, pending_req); | 1008 | xen_blkif_put(blkif); |
| 987 | } | 1009 | } |
| 988 | } | 1010 | } |
| 989 | 1011 | ||
| @@ -1237,6 +1259,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, | |||
| 1237 | * below (in "!bio") if we are handling a BLKIF_OP_DISCARD. | 1259 | * below (in "!bio") if we are handling a BLKIF_OP_DISCARD. |
| 1238 | */ | 1260 | */ |
| 1239 | xen_blkif_get(blkif); | 1261 | xen_blkif_get(blkif); |
| 1262 | atomic_inc(&blkif->inflight); | ||
| 1240 | 1263 | ||
| 1241 | for (i = 0; i < nseg; i++) { | 1264 | for (i = 0; i < nseg; i++) { |
| 1242 | while ((bio == NULL) || | 1265 | while ((bio == NULL) || |
