xen: add helpers for caching grant mapping pages
[sfrench/cifs-2.6.git] / drivers / xen / xen-scsiback.c
index 4acc4e899600cf09bc91af36463fc8c4940aa114..862162dca33cf4221f81008a6214479dbfb4dbc9 100644 (file)
@@ -99,6 +99,8 @@ struct vscsibk_info {
        struct list_head v2p_entry_lists;
 
        wait_queue_head_t waiting_to_free;
+
+       struct gnttab_page_cache free_pages;
 };
 
 /* theoretical maximum of grants for one request */
@@ -188,10 +190,6 @@ module_param_named(max_buffer_pages, scsiback_max_buffer_pages, int, 0644);
 MODULE_PARM_DESC(max_buffer_pages,
 "Maximum number of free pages to keep in backend buffer");
 
-static DEFINE_SPINLOCK(free_pages_lock);
-static int free_pages_num;
-static LIST_HEAD(scsiback_free_pages);
-
 /* Global spinlock to protect scsiback TPG list */
 static DEFINE_MUTEX(scsiback_mutex);
 static LIST_HEAD(scsiback_list);
@@ -207,41 +205,6 @@ static void scsiback_put(struct vscsibk_info *info)
                wake_up(&info->waiting_to_free);
 }
 
-static void put_free_pages(struct page **page, int num)
-{
-       unsigned long flags;
-       int i = free_pages_num + num, n = num;
-
-       if (num == 0)
-               return;
-       if (i > scsiback_max_buffer_pages) {
-               n = min(num, i - scsiback_max_buffer_pages);
-               gnttab_free_pages(n, page + num - n);
-               n = num - n;
-       }
-       spin_lock_irqsave(&free_pages_lock, flags);
-       for (i = 0; i < n; i++)
-               list_add(&page[i]->lru, &scsiback_free_pages);
-       free_pages_num += n;
-       spin_unlock_irqrestore(&free_pages_lock, flags);
-}
-
-static int get_free_page(struct page **page)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&free_pages_lock, flags);
-       if (list_empty(&scsiback_free_pages)) {
-               spin_unlock_irqrestore(&free_pages_lock, flags);
-               return gnttab_alloc_pages(1, page);
-       }
-       page[0] = list_first_entry(&scsiback_free_pages, struct page, lru);
-       list_del(&page[0]->lru);
-       free_pages_num--;
-       spin_unlock_irqrestore(&free_pages_lock, flags);
-       return 0;
-}
-
 static unsigned long vaddr_page(struct page *page)
 {
        unsigned long pfn = page_to_pfn(page);
@@ -302,7 +265,8 @@ static void scsiback_fast_flush_area(struct vscsibk_pend *req)
                BUG_ON(err);
        }
 
-       put_free_pages(req->pages, req->n_grants);
+       gnttab_page_cache_put(&req->info->free_pages, req->pages,
+                             req->n_grants);
        req->n_grants = 0;
 }
 
@@ -445,8 +409,8 @@ static int scsiback_gnttab_data_map_list(struct vscsibk_pend *pending_req,
        struct vscsibk_info *info = pending_req->info;
 
        for (i = 0; i < cnt; i++) {
-               if (get_free_page(pg + mapcount)) {
-                       put_free_pages(pg, mapcount);
+               if (gnttab_page_cache_get(&info->free_pages, pg + mapcount)) {
+                       gnttab_page_cache_put(&info->free_pages, pg, mapcount);
                        pr_err("no grant page\n");
                        return -ENOMEM;
                }
@@ -796,6 +760,8 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info,
                cond_resched();
        }
 
+       gnttab_page_cache_shrink(&info->free_pages, scsiback_max_buffer_pages);
+
        RING_FINAL_CHECK_FOR_REQUESTS(&info->ring, more_to_do);
        return more_to_do;
 }
@@ -1233,6 +1199,8 @@ static int scsiback_remove(struct xenbus_device *dev)
 
        scsiback_release_translation_entry(info);
 
+       gnttab_page_cache_shrink(&info->free_pages, 0);
+
        dev_set_drvdata(&dev->dev, NULL);
 
        return 0;
@@ -1263,6 +1231,7 @@ static int scsiback_probe(struct xenbus_device *dev,
        info->irq = 0;
        INIT_LIST_HEAD(&info->v2p_entry_lists);
        spin_lock_init(&info->v2p_lock);
+       gnttab_page_cache_init(&info->free_pages);
 
        err = xenbus_printf(XBT_NIL, dev->nodename, "feature-sg-grant", "%u",
                            SG_ALL);
@@ -1879,13 +1848,6 @@ out:
 
 static void __exit scsiback_exit(void)
 {
-       struct page *page;
-
-       while (free_pages_num) {
-               if (get_free_page(&page))
-                       BUG();
-               gnttab_free_pages(1, &page);
-       }
        target_unregister_template(&scsiback_ops);
        xenbus_unregister_driver(&scsiback_driver);
 }