diff options
author | Sage Weil <sage@newdream.net> | 2009-10-06 11:31:07 -0700 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2009-10-06 11:31:07 -0700 |
commit | c30dbb9cc7fc75ab1d0ee6fb084ba4684f7a665d (patch) | |
tree | 7e702615046c0c866bb0229c731f86916c526115 /fs/ceph/buffer.h | |
parent | de57606c23afded22202825b3db8a5d61859f198 (diff) |
ceph: ref counted buffer
struct ceph_buffer is a simple ref-counted buffer. We transparently
choose between kmalloc for small buffers and vmalloc for large ones.
This is currently used only for allocating memory for xattr data.
Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'fs/ceph/buffer.h')
-rw-r--r-- | fs/ceph/buffer.h | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/fs/ceph/buffer.h b/fs/ceph/buffer.h new file mode 100644 index 00000000000..16b1930acc4 --- /dev/null +++ b/fs/ceph/buffer.h @@ -0,0 +1,55 @@ +#ifndef __FS_CEPH_BUFFER_H +#define __FS_CEPH_BUFFER_H + +#include <linux/mm.h> +#include <linux/vmalloc.h> +#include <linux/types.h> +#include <linux/uio.h> + +/* + * a simple reference counted buffer. + * + * use kmalloc for small sizes (<= one page), vmalloc for larger + * sizes. + */ +struct ceph_buffer { + atomic_t nref; + struct kvec vec; + size_t alloc_len; + bool is_vmalloc; +}; + +struct ceph_buffer *ceph_buffer_new(gfp_t gfp); +int ceph_buffer_alloc(struct ceph_buffer *b, int len, gfp_t gfp); + +static inline struct ceph_buffer *ceph_buffer_get(struct ceph_buffer *b) +{ + atomic_inc(&b->nref); + return b; +} + +static inline void ceph_buffer_put(struct ceph_buffer *b) +{ + if (b && atomic_dec_and_test(&b->nref)) { + if (b->vec.iov_base) { + if (b->is_vmalloc) + vfree(b->vec.iov_base); + else + kfree(b->vec.iov_base); + } + kfree(b); + } +} + +static inline struct ceph_buffer *ceph_buffer_new_alloc(int len, gfp_t gfp) +{ + struct ceph_buffer *b = ceph_buffer_new(gfp); + + if (b && ceph_buffer_alloc(b, len, gfp) < 0) { + ceph_buffer_put(b); + b = NULL; + } + return b; +} + +#endif |