aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/xen-blkback
diff options
context:
space:
mode:
authorRoger Pau Monne <roger.pau@citrix.com>2014-02-04 05:26:13 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2014-02-07 12:58:46 -0500
commitef753411339eae46b9a3151906901f8bfd12b0f1 (patch)
treedbc12f7ba93c1d7b1be02202ecb100e2509257e8 /drivers/block/xen-blkback
parent2ed22e3c3bec5b92b9aba4afdef0cc5e6d859a11 (diff)
xen-blkback: fix memory leaks
I've at least identified two possible memory leaks in blkback, both related to the shutdown path of a VBD: - blkback doesn't wait for any pending purge work to finish before cleaning the list of free_pages. The purge work will call put_free_pages and thus we might end up with pages being added to the free_pages list after we have emptied it. Fix this by making sure there's no pending purge work before exiting xen_blkif_schedule, and moving the free_page cleanup code to xen_blkif_free. - blkback doesn't wait for pending requests to end before cleaning persistent grants and the list of free_pages. Again this can add pages to the free_pages list or persistent grants to the persistent_gnts red-black tree. Fixed by moving the persistent grants and free_pages cleanup code to xen_blkif_free. Also, add some checks in xen_blkif_free to make sure we are cleaning everything. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Reviewed-by: David Vrabel <david.vrabel@citrix.com> Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> Tested-by: Matt Rushton <mrushton@amazon.com> Reviewed-by: Matt Rushton <mrushton@amazon.com> Cc: Matt Wilson <msw@amazon.com> Cc: Ian Campbell <Ian.Campbell@citrix.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/block/xen-blkback')
-rw-r--r--drivers/block/xen-blkback/blkback.c27
-rw-r--r--drivers/block/xen-blkback/common.h1
-rw-r--r--drivers/block/xen-blkback/xenbus.c12
3 files changed, 31 insertions, 9 deletions
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
index 30ef7b390df5..dcfe49fd3cb4 100644
--- a/drivers/block/xen-blkback/blkback.c
+++ b/drivers/block/xen-blkback/blkback.c
@@ -375,7 +375,7 @@ static void purge_persistent_gnt(struct xen_blkif *blkif)
375 375
376 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);
377 377
378 INIT_LIST_HEAD(&blkif->persistent_purge_list); 378 BUG_ON(!list_empty(&blkif->persistent_purge_list));
379 root = &blkif->persistent_gnts; 379 root = &blkif->persistent_gnts;
380purge_list: 380purge_list:
381 foreach_grant_safe(persistent_gnt, n, root, node) { 381 foreach_grant_safe(persistent_gnt, n, root, node) {
@@ -625,6 +625,23 @@ purge_gnt_list:
625 print_stats(blkif); 625 print_stats(blkif);
626 } 626 }
627 627
628 /* Drain pending purge work */
629 flush_work(&blkif->persistent_purge_work);
630
631 if (log_stats)
632 print_stats(blkif);
633
634 blkif->xenblkd = NULL;
635 xen_blkif_put(blkif);
636
637 return 0;
638}
639
640/*
641 * Remove persistent grants and empty the pool of free pages
642 */
643void xen_blkbk_free_caches(struct xen_blkif *blkif)
644{
628 /* Free all persistent grant pages */ 645 /* Free all persistent grant pages */
629 if (!RB_EMPTY_ROOT(&blkif->persistent_gnts)) 646 if (!RB_EMPTY_ROOT(&blkif->persistent_gnts))
630 free_persistent_gnts(blkif, &blkif->persistent_gnts, 647 free_persistent_gnts(blkif, &blkif->persistent_gnts,
@@ -635,14 +652,6 @@ purge_gnt_list:
635 652
636 /* Since we are shutting down remove all pages from the buffer */ 653 /* Since we are shutting down remove all pages from the buffer */
637 shrink_free_pagepool(blkif, 0 /* All */); 654 shrink_free_pagepool(blkif, 0 /* All */);
638
639 if (log_stats)
640 print_stats(blkif);
641
642 blkif->xenblkd = NULL;
643 xen_blkif_put(blkif);
644
645 return 0;
646} 655}
647 656
648/* 657/*
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
index 8d8807563d99..f733d7627120 100644
--- a/drivers/block/xen-blkback/common.h
+++ b/drivers/block/xen-blkback/common.h
@@ -376,6 +376,7 @@ int xen_blkif_xenbus_init(void);
376irqreturn_t xen_blkif_be_int(int irq, void *dev_id); 376irqreturn_t xen_blkif_be_int(int irq, void *dev_id);
377int xen_blkif_schedule(void *arg); 377int xen_blkif_schedule(void *arg);
378int xen_blkif_purge_persistent(void *arg); 378int xen_blkif_purge_persistent(void *arg);
379void xen_blkbk_free_caches(struct xen_blkif *blkif);
379 380
380int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt, 381int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
381 struct backend_info *be, int state); 382 struct backend_info *be, int state);
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
index c2014a0aa206..8afef67fecdd 100644
--- a/drivers/block/xen-blkback/xenbus.c
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -125,6 +125,7 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
125 blkif->persistent_gnts.rb_node = NULL; 125 blkif->persistent_gnts.rb_node = NULL;
126 spin_lock_init(&blkif->free_pages_lock); 126 spin_lock_init(&blkif->free_pages_lock);
127 INIT_LIST_HEAD(&blkif->free_pages); 127 INIT_LIST_HEAD(&blkif->free_pages);
128 INIT_LIST_HEAD(&blkif->persistent_purge_list);
128 blkif->free_pages_num = 0; 129 blkif->free_pages_num = 0;
129 atomic_set(&blkif->persistent_gnt_in_use, 0); 130 atomic_set(&blkif->persistent_gnt_in_use, 0);
130 131
@@ -259,6 +260,17 @@ static void xen_blkif_free(struct xen_blkif *blkif)
259 if (!atomic_dec_and_test(&blkif->refcnt)) 260 if (!atomic_dec_and_test(&blkif->refcnt))
260 BUG(); 261 BUG();
261 262
263 /* Remove all persistent grants and the cache of ballooned pages. */
264 xen_blkbk_free_caches(blkif);
265
266 /* Make sure everything is drained before shutting down */
267 BUG_ON(blkif->persistent_gnt_c != 0);
268 BUG_ON(atomic_read(&blkif->persistent_gnt_in_use) != 0);
269 BUG_ON(blkif->free_pages_num != 0);
270 BUG_ON(!list_empty(&blkif->persistent_purge_list));
271 BUG_ON(!list_empty(&blkif->free_pages));
272 BUG_ON(!RB_EMPTY_ROOT(&blkif->persistent_gnts));
273
262 /* Check that there is no request in use */ 274 /* Check that there is no request in use */
263 list_for_each_entry_safe(req, n, &blkif->pending_free, free_list) { 275 list_for_each_entry_safe(req, n, &blkif->pending_free, free_list) {
264 list_del(&req->free_list); 276 list_del(&req->free_list);