aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIlya Dryomov <ilya.dryomov@inktank.com>2014-01-09 13:08:21 -0500
committerIlya Dryomov <ilya.dryomov@inktank.com>2014-01-26 05:34:23 -0500
commiteeb0bed5572b1282009dfc2635604df5a35d1a02 (patch)
tree6b90792affac20b326daa59a59227766f746ee2f
parent80213a84a96c3040f5824bce646a184d5dd3dd2b (diff)
libceph: add ceph_kv{malloc,free}() and switch to them
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>
-rw-r--r--include/linux/ceph/buffer.h1
-rw-r--r--include/linux/ceph/libceph.h11
-rw-r--r--include/linux/ceph/messenger.h1
-rw-r--r--net/ceph/buffer.c22
-rw-r--r--net/ceph/ceph_common.c20
-rw-r--r--net/ceph/messenger.c13
6 files changed, 35 insertions, 33 deletions
diff --git a/include/linux/ceph/buffer.h b/include/linux/ceph/buffer.h
index 58d19014068f..07ad423cc37f 100644
--- a/include/linux/ceph/buffer.h
+++ b/include/linux/ceph/buffer.h
@@ -17,7 +17,6 @@ struct ceph_buffer {
17 struct kref kref; 17 struct kref kref;
18 struct kvec vec; 18 struct kvec vec;
19 size_t alloc_len; 19 size_t alloc_len;
20 bool is_vmalloc;
21}; 20};
22 21
23extern struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp); 22extern struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp);
diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h
index 7d704db60cbb..2f49aa4c4f7f 100644
--- a/include/linux/ceph/libceph.h
+++ b/include/linux/ceph/libceph.h
@@ -173,15 +173,18 @@ static inline int calc_pages_for(u64 off, u64 len)
173 (off >> PAGE_CACHE_SHIFT); 173 (off >> PAGE_CACHE_SHIFT);
174} 174}
175 175
176extern struct kmem_cache *ceph_inode_cachep;
177extern struct kmem_cache *ceph_cap_cachep;
178extern struct kmem_cache *ceph_dentry_cachep;
179extern struct kmem_cache *ceph_file_cachep;
180
176/* ceph_common.c */ 181/* ceph_common.c */
177extern bool libceph_compatible(void *data); 182extern bool libceph_compatible(void *data);
178 183
179extern const char *ceph_msg_type_name(int type); 184extern const char *ceph_msg_type_name(int type);
180extern int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid); 185extern int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid);
181extern struct kmem_cache *ceph_inode_cachep; 186extern void *ceph_kvmalloc(size_t size, gfp_t flags);
182extern struct kmem_cache *ceph_cap_cachep; 187extern void ceph_kvfree(const void *ptr);
183extern struct kmem_cache *ceph_dentry_cachep;
184extern struct kmem_cache *ceph_file_cachep;
185 188
186extern struct ceph_options *ceph_parse_options(char *options, 189extern struct ceph_options *ceph_parse_options(char *options,
187 const char *dev_name, const char *dev_name_end, 190 const char *dev_name, const char *dev_name_end,
diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h
index 861138f7c161..20ee8b63a968 100644
--- a/include/linux/ceph/messenger.h
+++ b/include/linux/ceph/messenger.h
@@ -154,7 +154,6 @@ struct ceph_msg {
154 struct list_head list_head; /* links for connection lists */ 154 struct list_head list_head; /* links for connection lists */
155 155
156 struct kref kref; 156 struct kref kref;
157 bool front_is_vmalloc;
158 bool more_to_follow; 157 bool more_to_follow;
159 bool needs_out_seq; 158 bool needs_out_seq;
160 int front_alloc_len; 159 int front_alloc_len;
diff --git a/net/ceph/buffer.c b/net/ceph/buffer.c
index bf3e6a13c215..621b5f65407f 100644
--- a/net/ceph/buffer.c
+++ b/net/ceph/buffer.c
@@ -6,6 +6,7 @@
6 6
7#include <linux/ceph/buffer.h> 7#include <linux/ceph/buffer.h>
8#include <linux/ceph/decode.h> 8#include <linux/ceph/decode.h>
9#include <linux/ceph/libceph.h> /* for ceph_kv{malloc,free} */
9 10
10struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp) 11struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp)
11{ 12{
@@ -15,16 +16,10 @@ struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp)
15 if (!b) 16 if (!b)
16 return NULL; 17 return NULL;
17 18
18 b->vec.iov_base = kmalloc(len, gfp | __GFP_NOWARN); 19 b->vec.iov_base = ceph_kvmalloc(len, gfp);
19 if (b->vec.iov_base) { 20 if (!b->vec.iov_base) {
20 b->is_vmalloc = false; 21 kfree(b);
21 } else { 22 return NULL;
22 b->vec.iov_base = __vmalloc(len, gfp | __GFP_HIGHMEM, PAGE_KERNEL);
23 if (!b->vec.iov_base) {
24 kfree(b);
25 return NULL;
26 }
27 b->is_vmalloc = true;
28 } 23 }
29 24
30 kref_init(&b->kref); 25 kref_init(&b->kref);
@@ -40,12 +35,7 @@ void ceph_buffer_release(struct kref *kref)
40 struct ceph_buffer *b = container_of(kref, struct ceph_buffer, kref); 35 struct ceph_buffer *b = container_of(kref, struct ceph_buffer, kref);
41 36
42 dout("buffer_release %p\n", b); 37 dout("buffer_release %p\n", b);
43 if (b->vec.iov_base) { 38 ceph_kvfree(b->vec.iov_base);
44 if (b->is_vmalloc)
45 vfree(b->vec.iov_base);
46 else
47 kfree(b->vec.iov_base);
48 }
49 kfree(b); 39 kfree(b);
50} 40}
51EXPORT_SYMBOL(ceph_buffer_release); 41EXPORT_SYMBOL(ceph_buffer_release);
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index 43d8177a52e1..67d7721d237e 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -15,6 +15,7 @@
15#include <linux/slab.h> 15#include <linux/slab.h>
16#include <linux/statfs.h> 16#include <linux/statfs.h>
17#include <linux/string.h> 17#include <linux/string.h>
18#include <linux/vmalloc.h>
18#include <linux/nsproxy.h> 19#include <linux/nsproxy.h>
19#include <net/net_namespace.h> 20#include <net/net_namespace.h>
20 21
@@ -170,6 +171,25 @@ int ceph_compare_options(struct ceph_options *new_opt,
170} 171}
171EXPORT_SYMBOL(ceph_compare_options); 172EXPORT_SYMBOL(ceph_compare_options);
172 173
174void *ceph_kvmalloc(size_t size, gfp_t flags)
175{
176 if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
177 void *ptr = kmalloc(size, flags | __GFP_NOWARN);
178 if (ptr)
179 return ptr;
180 }
181
182 return __vmalloc(size, flags | __GFP_HIGHMEM, PAGE_KERNEL);
183}
184
185void ceph_kvfree(const void *ptr)
186{
187 if (is_vmalloc_addr(ptr))
188 vfree(ptr);
189 else
190 kfree(ptr);
191}
192
173 193
174static int parse_fsid(const char *str, struct ceph_fsid *fsid) 194static int parse_fsid(const char *str, struct ceph_fsid *fsid)
175{ 195{
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index 252ad4e01cf8..2ed1304d22a7 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -3131,13 +3131,7 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags,
3131 3131
3132 /* front */ 3132 /* front */
3133 if (front_len) { 3133 if (front_len) {
3134 if (front_len > PAGE_CACHE_SIZE) { 3134 m->front.iov_base = ceph_kvmalloc(front_len, flags);
3135 m->front.iov_base = __vmalloc(front_len, flags,
3136 PAGE_KERNEL);
3137 m->front_is_vmalloc = true;
3138 } else {
3139 m->front.iov_base = kmalloc(front_len, flags);
3140 }
3141 if (m->front.iov_base == NULL) { 3135 if (m->front.iov_base == NULL) {
3142 dout("ceph_msg_new can't allocate %d bytes\n", 3136 dout("ceph_msg_new can't allocate %d bytes\n",
3143 front_len); 3137 front_len);
@@ -3259,10 +3253,7 @@ static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip)
3259void ceph_msg_kfree(struct ceph_msg *m) 3253void ceph_msg_kfree(struct ceph_msg *m)
3260{ 3254{
3261 dout("msg_kfree %p\n", m); 3255 dout("msg_kfree %p\n", m);
3262 if (m->front_is_vmalloc) 3256 ceph_kvfree(m->front.iov_base);
3263 vfree(m->front.iov_base);
3264 else
3265 kfree(m->front.iov_base);
3266 kmem_cache_free(ceph_msg_cache, m); 3257 kmem_cache_free(ceph_msg_cache, m);
3267} 3258}
3268 3259