1
2#include "ceph_debug.h"
3
4#include <linux/slab.h>
5
6#include "buffer.h"
7#include "decode.h"
8
9struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp)
10{
11	struct ceph_buffer *b;
12
13	b = kmalloc(sizeof(*b), gfp);
14	if (!b)
15		return NULL;
16
17	b->vec.iov_base = kmalloc(len, gfp | __GFP_NOWARN);
18	if (b->vec.iov_base) {
19		b->is_vmalloc = false;
20	} else {
21		b->vec.iov_base = __vmalloc(len, gfp, PAGE_KERNEL);
22		if (!b->vec.iov_base) {
23			kfree(b);
24			return NULL;
25		}
26		b->is_vmalloc = true;
27	}
28
29	kref_init(&b->kref);
30	b->alloc_len = len;
31	b->vec.iov_len = len;
32	dout("buffer_new %p\n", b);
33	return b;
34}
35
36void ceph_buffer_release(struct kref *kref)
37{
38	struct ceph_buffer *b = container_of(kref, struct ceph_buffer, kref);
39
40	dout("buffer_release %p\n", b);
41	if (b->vec.iov_base) {
42		if (b->is_vmalloc)
43			vfree(b->vec.iov_base);
44		else
45			kfree(b->vec.iov_base);
46	}
47	kfree(b);
48}
49
50int ceph_decode_buffer(struct ceph_buffer **b, void **p, void *end)
51{
52	size_t len;
53
54	ceph_decode_need(p, end, sizeof(u32), bad);
55	len = ceph_decode_32(p);
56	dout("decode_buffer len %d\n", (int)len);
57	ceph_decode_need(p, end, len, bad);
58	*b = ceph_buffer_new(len, GFP_NOFS);
59	if (!*b)
60		return -ENOMEM;
61	ceph_decode_copy(p, (*b)->vec.iov_base, len);
62	return 0;
63bad:
64	return -EINVAL;
65}
66