libceph: reference counting pagelist
authorYan, Zheng <zyan@redhat.com>
Tue, 16 Sep 2014 09:50:45 +0000 (17:50 +0800)
committerSage Weil <sage@redhat.com>
Tue, 14 Oct 2014 19:56:48 +0000 (12:56 -0700)
this allow pagelist to present data that may be sent multiple times.

Signed-off-by: Yan, Zheng <zyan@redhat.com>
Reviewed-by: Sage Weil <sage@redhat.com>
fs/ceph/mds_client.c
include/linux/ceph/pagelist.h
net/ceph/messenger.c
net/ceph/pagelist.c

index 5474feb7774348adbc216260e080aba425da0834..b4430ce1b3f6f7b1a913ee2d49e632b35b38c6ee 100644 (file)
@@ -2865,7 +2865,6 @@ fail:
        mutex_unlock(&session->s_mutex);
 fail_nomsg:
        ceph_pagelist_release(pagelist);
-       kfree(pagelist);
 fail_nopagelist:
        pr_err("error %d preparing reconnect for mds%d\n", err, mds);
        return;
index 9660d6b0a35d780dbe0806edf6193d1f7d5ef8f5..5f871d84ddcea591418825f4bf863ea587e3b38d 100644 (file)
@@ -2,6 +2,7 @@
 #define __FS_CEPH_PAGELIST_H
 
 #include <linux/list.h>
+#include <linux/atomic.h>
 
 struct ceph_pagelist {
        struct list_head head;
@@ -10,6 +11,7 @@ struct ceph_pagelist {
        size_t room;
        struct list_head free_list;
        size_t num_pages_free;
+       atomic_t refcnt;
 };
 
 struct ceph_pagelist_cursor {
@@ -26,9 +28,10 @@ static inline void ceph_pagelist_init(struct ceph_pagelist *pl)
        pl->room = 0;
        INIT_LIST_HEAD(&pl->free_list);
        pl->num_pages_free = 0;
+       atomic_set(&pl->refcnt, 1);
 }
 
-extern int ceph_pagelist_release(struct ceph_pagelist *pl);
+extern void ceph_pagelist_release(struct ceph_pagelist *pl);
 
 extern int ceph_pagelist_append(struct ceph_pagelist *pl, const void *d, size_t l);
 
index e7d94113f2d65d1be96952b5ff257354249ef691..9764c771cfb16a50b92e35a8e1ccdfa3ade5a27d 100644 (file)
@@ -3071,10 +3071,8 @@ static void ceph_msg_data_destroy(struct ceph_msg_data *data)
                return;
 
        WARN_ON(!list_empty(&data->links));
-       if (data->type == CEPH_MSG_DATA_PAGELIST) {
+       if (data->type == CEPH_MSG_DATA_PAGELIST)
                ceph_pagelist_release(data->pagelist);
-               kfree(data->pagelist);
-       }
        kmem_cache_free(ceph_msg_data_cache, data);
 }
 
index 92866bebb65fe2ac438a10c068f18da5a1912018..c7c220a736e50bc7ec78c48eb4c6e5a80cf1b500 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
+#include <linux/slab.h>
 #include <linux/pagemap.h>
 #include <linux/highmem.h>
 #include <linux/ceph/pagelist.h>
@@ -13,8 +14,10 @@ static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl)
        }
 }
 
-int ceph_pagelist_release(struct ceph_pagelist *pl)
+void ceph_pagelist_release(struct ceph_pagelist *pl)
 {
+       if (!atomic_dec_and_test(&pl->refcnt))
+               return;
        ceph_pagelist_unmap_tail(pl);
        while (!list_empty(&pl->head)) {
                struct page *page = list_first_entry(&pl->head, struct page,
@@ -23,7 +26,7 @@ int ceph_pagelist_release(struct ceph_pagelist *pl)
                __free_page(page);
        }
        ceph_pagelist_free_reserve(pl);
-       return 0;
+       kfree(pl);
 }
 EXPORT_SYMBOL(ceph_pagelist_release);