libceph: add ceph_kv{malloc,free}() and switch to them
authorIlya Dryomov <ilya.dryomov@inktank.com>
Thu, 9 Jan 2014 18:08:21 +0000 (20:08 +0200)
committerIlya Dryomov <ilya.dryomov@inktank.com>
Sun, 26 Jan 2014 10:34:23 +0000 (12:34 +0200)
Encapsulate kmalloc vs vmalloc memory allocation and freeing logic into
two helpers, ceph_kvmalloc() and ceph_kvfree(), and switch to them.

ceph_kvmalloc() kmalloc()'s a maximum of 8 pages, anything bigger is
vmalloc()'ed with __GFP_HIGHMEM set.  This changes the existing
behaviour:

- for buffers (ceph_buffer_new()), from trying to kmalloc() everything
  and using vmalloc() just as a fallback

- for messages (ceph_msg_new()), from going to vmalloc() for anything
  bigger than a page

- for messages (ceph_msg_new()), from disallowing vmalloc() to use high
  memory

Signed-off-by: Ilya Dryomov <ilya.dryomov@inktank.com>
Reviewed-by: Sage Weil <sage@inktank.com>
include/linux/ceph/buffer.h
include/linux/ceph/libceph.h
include/linux/ceph/messenger.h
net/ceph/buffer.c
net/ceph/ceph_common.c
net/ceph/messenger.c

index 58d1901..07ad423 100644 (file)
@@ -17,7 +17,6 @@ struct ceph_buffer {
        struct kref kref;
        struct kvec vec;
        size_t alloc_len;
-       bool is_vmalloc;
 };
 
 extern struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp);
index 7d704db..2f49aa4 100644 (file)
@@ -173,15 +173,18 @@ static inline int calc_pages_for(u64 off, u64 len)
                (off >> PAGE_CACHE_SHIFT);
 }
 
+extern struct kmem_cache *ceph_inode_cachep;
+extern struct kmem_cache *ceph_cap_cachep;
+extern struct kmem_cache *ceph_dentry_cachep;
+extern struct kmem_cache *ceph_file_cachep;
+
 /* ceph_common.c */
 extern bool libceph_compatible(void *data);
 
 extern const char *ceph_msg_type_name(int type);
 extern int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid);
-extern struct kmem_cache *ceph_inode_cachep;
-extern struct kmem_cache *ceph_cap_cachep;
-extern struct kmem_cache *ceph_dentry_cachep;
-extern struct kmem_cache *ceph_file_cachep;
+extern void *ceph_kvmalloc(size_t size, gfp_t flags);
+extern void ceph_kvfree(const void *ptr);
 
 extern struct ceph_options *ceph_parse_options(char *options,
                              const char *dev_name, const char *dev_name_end,
index 861138f..20ee8b6 100644 (file)
@@ -154,7 +154,6 @@ struct ceph_msg {
        struct list_head list_head;     /* links for connection lists */
 
        struct kref kref;
-       bool front_is_vmalloc;
        bool more_to_follow;
        bool needs_out_seq;
        int front_alloc_len;
index bf3e6a1..621b5f6 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/ceph/buffer.h>
 #include <linux/ceph/decode.h>
+#include <linux/ceph/libceph.h> /* for ceph_kv{malloc,free} */
 
 struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp)
 {
@@ -15,16 +16,10 @@ struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp)
        if (!b)
                return NULL;
 
-       b->vec.iov_base = kmalloc(len, gfp | __GFP_NOWARN);
-       if (b->vec.iov_base) {
-               b->is_vmalloc = false;
-       } else {
-               b->vec.iov_base = __vmalloc(len, gfp | __GFP_HIGHMEM, PAGE_KERNEL);
-               if (!b->vec.iov_base) {
-                       kfree(b);
-                       return NULL;
-               }
-               b->is_vmalloc = true;
+       b->vec.iov_base = ceph_kvmalloc(len, gfp);
+       if (!b->vec.iov_base) {
+               kfree(b);
+               return NULL;
        }
 
        kref_init(&b->kref);
@@ -40,12 +35,7 @@ void ceph_buffer_release(struct kref *kref)
        struct ceph_buffer *b = container_of(kref, struct ceph_buffer, kref);
 
        dout("buffer_release %p\n", b);
-       if (b->vec.iov_base) {
-               if (b->is_vmalloc)
-                       vfree(b->vec.iov_base);
-               else
-                       kfree(b->vec.iov_base);
-       }
+       ceph_kvfree(b->vec.iov_base);
        kfree(b);
 }
 EXPORT_SYMBOL(ceph_buffer_release);
index 43d8177..67d7721 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/statfs.h>
 #include <linux/string.h>
+#include <linux/vmalloc.h>
 #include <linux/nsproxy.h>
 #include <net/net_namespace.h>
 
@@ -170,6 +171,25 @@ int ceph_compare_options(struct ceph_options *new_opt,
 }
 EXPORT_SYMBOL(ceph_compare_options);
 
+void *ceph_kvmalloc(size_t size, gfp_t flags)
+{
+       if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
+               void *ptr = kmalloc(size, flags | __GFP_NOWARN);
+               if (ptr)
+                       return ptr;
+       }
+
+       return __vmalloc(size, flags | __GFP_HIGHMEM, PAGE_KERNEL);
+}
+
+void ceph_kvfree(const void *ptr)
+{
+       if (is_vmalloc_addr(ptr))
+               vfree(ptr);
+       else
+               kfree(ptr);
+}
+
 
 static int parse_fsid(const char *str, struct ceph_fsid *fsid)
 {
index 252ad4e..2ed1304 100644 (file)
@@ -3131,13 +3131,7 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags,
 
        /* front */
        if (front_len) {
-               if (front_len > PAGE_CACHE_SIZE) {
-                       m->front.iov_base = __vmalloc(front_len, flags,
-                                                     PAGE_KERNEL);
-                       m->front_is_vmalloc = true;
-               } else {
-                       m->front.iov_base = kmalloc(front_len, flags);
-               }
+               m->front.iov_base = ceph_kvmalloc(front_len, flags);
                if (m->front.iov_base == NULL) {
                        dout("ceph_msg_new can't allocate %d bytes\n",
                             front_len);
@@ -3259,10 +3253,7 @@ static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip)
 void ceph_msg_kfree(struct ceph_msg *m)
 {
        dout("msg_kfree %p\n", m);
-       if (m->front_is_vmalloc)
-               vfree(m->front.iov_base);
-       else
-               kfree(m->front.iov_base);
+       ceph_kvfree(m->front.iov_base);
        kmem_cache_free(ceph_msg_cache, m);
 }