1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/ceph/ceph_debug.h> |
3 | |
4 | #include <linux/err.h> |
5 | #include <linux/sched.h> |
6 | #include <linux/types.h> |
7 | #include <linux/vmalloc.h> |
8 | |
9 | #include <linux/ceph/messenger.h> |
10 | #include <linux/ceph/msgpool.h> |
11 | |
12 | static void *msgpool_alloc(gfp_t gfp_mask, void *arg) |
13 | { |
14 | struct ceph_msgpool *pool = arg; |
15 | struct ceph_msg *msg; |
16 | |
17 | msg = ceph_msg_new2(type: pool->type, front_len: pool->front_len, max_data_items: pool->max_data_items, |
18 | flags: gfp_mask, can_fail: true); |
19 | if (!msg) { |
20 | dout("msgpool_alloc %s failed\n" , pool->name); |
21 | } else { |
22 | dout("msgpool_alloc %s %p\n" , pool->name, msg); |
23 | msg->pool = pool; |
24 | } |
25 | return msg; |
26 | } |
27 | |
28 | static void msgpool_free(void *element, void *arg) |
29 | { |
30 | struct ceph_msgpool *pool = arg; |
31 | struct ceph_msg *msg = element; |
32 | |
33 | dout("msgpool_release %s %p\n" , pool->name, msg); |
34 | msg->pool = NULL; |
35 | ceph_msg_put(msg); |
36 | } |
37 | |
38 | int ceph_msgpool_init(struct ceph_msgpool *pool, int type, |
39 | int front_len, int max_data_items, int size, |
40 | const char *name) |
41 | { |
42 | dout("msgpool %s init\n" , name); |
43 | pool->type = type; |
44 | pool->front_len = front_len; |
45 | pool->max_data_items = max_data_items; |
46 | pool->pool = mempool_create(min_nr: size, alloc_fn: msgpool_alloc, free_fn: msgpool_free, pool_data: pool); |
47 | if (!pool->pool) |
48 | return -ENOMEM; |
49 | pool->name = name; |
50 | return 0; |
51 | } |
52 | |
53 | void ceph_msgpool_destroy(struct ceph_msgpool *pool) |
54 | { |
55 | dout("msgpool %s destroy\n" , pool->name); |
56 | mempool_destroy(pool: pool->pool); |
57 | } |
58 | |
59 | struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool, int front_len, |
60 | int max_data_items) |
61 | { |
62 | struct ceph_msg *msg; |
63 | |
64 | if (front_len > pool->front_len || |
65 | max_data_items > pool->max_data_items) { |
66 | pr_warn_ratelimited("%s need %d/%d, pool %s has %d/%d\n" , |
67 | __func__, front_len, max_data_items, pool->name, |
68 | pool->front_len, pool->max_data_items); |
69 | WARN_ON_ONCE(1); |
70 | |
71 | /* try to alloc a fresh message */ |
72 | return ceph_msg_new2(type: pool->type, front_len, max_data_items, |
73 | GFP_NOFS, can_fail: false); |
74 | } |
75 | |
76 | msg = mempool_alloc(pool: pool->pool, GFP_NOFS); |
77 | dout("msgpool_get %s %p\n" , pool->name, msg); |
78 | return msg; |
79 | } |
80 | |
81 | void ceph_msgpool_put(struct ceph_msgpool *pool, struct ceph_msg *msg) |
82 | { |
83 | dout("msgpool_put %s %p\n" , pool->name, msg); |
84 | |
85 | /* reset msg front_len; user may have changed it */ |
86 | msg->front.iov_len = pool->front_len; |
87 | msg->hdr.front_len = cpu_to_le32(pool->front_len); |
88 | |
89 | msg->data_length = 0; |
90 | msg->num_data_items = 0; |
91 | |
92 | kref_init(kref: &msg->kref); /* retake single ref */ |
93 | mempool_free(element: msg, pool: pool->pool); |
94 | } |
95 | |