aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/ccid.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp/ccid.c')
-rw-r--r--net/dccp/ccid.c189
1 files changed, 153 insertions, 36 deletions
diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c
index 9d8fc0e289ea..ff05e59043cd 100644
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -13,7 +13,7 @@
13 13
14#include "ccid.h" 14#include "ccid.h"
15 15
16static struct ccid *ccids[CCID_MAX]; 16static struct ccid_operations *ccids[CCID_MAX];
17#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) 17#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
18static atomic_t ccids_lockct = ATOMIC_INIT(0); 18static atomic_t ccids_lockct = ATOMIC_INIT(0);
19static DEFINE_SPINLOCK(ccids_lock); 19static DEFINE_SPINLOCK(ccids_lock);
@@ -55,85 +55,202 @@ static inline void ccids_read_unlock(void)
55#define ccids_read_unlock() do { } while(0) 55#define ccids_read_unlock() do { } while(0)
56#endif 56#endif
57 57
58int ccid_register(struct ccid *ccid) 58static kmem_cache_t *ccid_kmem_cache_create(int obj_size, const char *fmt,...)
59{ 59{
60 int err; 60 kmem_cache_t *slab;
61 char slab_name_fmt[32], *slab_name;
62 va_list args;
61 63
62 if (ccid->ccid_init == NULL) 64 va_start(args, fmt);
63 return -1; 65 vsnprintf(slab_name_fmt, sizeof(slab_name_fmt), fmt, args);
66 va_end(args);
67
68 slab_name = kstrdup(slab_name_fmt, GFP_KERNEL);
69 if (slab_name == NULL)
70 return NULL;
71 slab = kmem_cache_create(slab_name, sizeof(struct ccid) + obj_size, 0,
72 SLAB_HWCACHE_ALIGN, NULL, NULL);
73 if (slab == NULL)
74 kfree(slab_name);
75 return slab;
76}
77
78static void ccid_kmem_cache_destroy(kmem_cache_t *slab)
79{
80 if (slab != NULL) {
81 const char *name = kmem_cache_name(slab);
82
83 kmem_cache_destroy(slab);
84 kfree(name);
85 }
86}
87
88int ccid_register(struct ccid_operations *ccid_ops)
89{
90 int err = -ENOBUFS;
91
92 ccid_ops->ccid_hc_rx_slab =
93 ccid_kmem_cache_create(ccid_ops->ccid_hc_rx_obj_size,
94 "%s_hc_rx_sock",
95 ccid_ops->ccid_name);
96 if (ccid_ops->ccid_hc_rx_slab == NULL)
97 goto out;
98
99 ccid_ops->ccid_hc_tx_slab =
100 ccid_kmem_cache_create(ccid_ops->ccid_hc_tx_obj_size,
101 "%s_hc_tx_sock",
102 ccid_ops->ccid_name);
103 if (ccid_ops->ccid_hc_tx_slab == NULL)
104 goto out_free_rx_slab;
64 105
65 ccids_write_lock(); 106 ccids_write_lock();
66 err = -EEXIST; 107 err = -EEXIST;
67 if (ccids[ccid->ccid_id] == NULL) { 108 if (ccids[ccid_ops->ccid_id] == NULL) {
68 ccids[ccid->ccid_id] = ccid; 109 ccids[ccid_ops->ccid_id] = ccid_ops;
69 err = 0; 110 err = 0;
70 } 111 }
71 ccids_write_unlock(); 112 ccids_write_unlock();
72 if (err == 0) 113 if (err != 0)
73 pr_info("CCID: Registered CCID %d (%s)\n", 114 goto out_free_tx_slab;
74 ccid->ccid_id, ccid->ccid_name); 115
116 pr_info("CCID: Registered CCID %d (%s)\n",
117 ccid_ops->ccid_id, ccid_ops->ccid_name);
118out:
75 return err; 119 return err;
120out_free_tx_slab:
121 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab);
122 ccid_ops->ccid_hc_tx_slab = NULL;
123 goto out;
124out_free_rx_slab:
125 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
126 ccid_ops->ccid_hc_rx_slab = NULL;
127 goto out;
76} 128}
77 129
78EXPORT_SYMBOL_GPL(ccid_register); 130EXPORT_SYMBOL_GPL(ccid_register);
79 131
80int ccid_unregister(struct ccid *ccid) 132int ccid_unregister(struct ccid_operations *ccid_ops)
81{ 133{
82 ccids_write_lock(); 134 ccids_write_lock();
83 ccids[ccid->ccid_id] = NULL; 135 ccids[ccid_ops->ccid_id] = NULL;
84 ccids_write_unlock(); 136 ccids_write_unlock();
137
138 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab);
139 ccid_ops->ccid_hc_tx_slab = NULL;
140 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
141 ccid_ops->ccid_hc_rx_slab = NULL;
142
85 pr_info("CCID: Unregistered CCID %d (%s)\n", 143 pr_info("CCID: Unregistered CCID %d (%s)\n",
86 ccid->ccid_id, ccid->ccid_name); 144 ccid_ops->ccid_id, ccid_ops->ccid_name);
87 return 0; 145 return 0;
88} 146}
89 147
90EXPORT_SYMBOL_GPL(ccid_unregister); 148EXPORT_SYMBOL_GPL(ccid_unregister);
91 149
92struct ccid *ccid_init(unsigned char id, struct sock *sk) 150struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
93{ 151{
94 struct ccid *ccid; 152 struct ccid_operations *ccid_ops;
153 struct ccid *ccid = NULL;
95 154
155 ccids_read_lock();
96#ifdef CONFIG_KMOD 156#ifdef CONFIG_KMOD
97 if (ccids[id] == NULL) 157 if (ccids[id] == NULL) {
158 /* We only try to load if in process context */
159 ccids_read_unlock();
160 if (gfp & GFP_ATOMIC)
161 goto out;
98 request_module("net-dccp-ccid-%d", id); 162 request_module("net-dccp-ccid-%d", id);
163 ccids_read_lock();
164 }
99#endif 165#endif
100 ccids_read_lock(); 166 ccid_ops = ccids[id];
167 if (ccid_ops == NULL)
168 goto out_unlock;
101 169
102 ccid = ccids[id]; 170 if (!try_module_get(ccid_ops->ccid_owner))
103 if (ccid == NULL) 171 goto out_unlock;
104 goto out;
105 172
106 if (!try_module_get(ccid->ccid_owner)) 173 ccids_read_unlock();
107 goto out_err;
108 174
109 if (ccid->ccid_init(sk) != 0) 175 ccid = kmem_cache_alloc(rx ? ccid_ops->ccid_hc_rx_slab :
176 ccid_ops->ccid_hc_tx_slab, gfp);
177 if (ccid == NULL)
110 goto out_module_put; 178 goto out_module_put;
179 ccid->ccid_ops = ccid_ops;
180 if (rx) {
181 memset(ccid + 1, 0, ccid_ops->ccid_hc_rx_obj_size);
182 if (ccid->ccid_ops->ccid_hc_rx_init != NULL &&
183 ccid->ccid_ops->ccid_hc_rx_init(ccid, sk) != 0)
184 goto out_free_ccid;
185 } else {
186 memset(ccid + 1, 0, ccid_ops->ccid_hc_tx_obj_size);
187 if (ccid->ccid_ops->ccid_hc_tx_init != NULL &&
188 ccid->ccid_ops->ccid_hc_tx_init(ccid, sk) != 0)
189 goto out_free_ccid;
190 }
111out: 191out:
112 ccids_read_unlock();
113 return ccid; 192 return ccid;
114out_module_put: 193out_unlock:
115 module_put(ccid->ccid_owner); 194 ccids_read_unlock();
116out_err: 195 goto out;
196out_free_ccid:
197 kmem_cache_free(rx ? ccid_ops->ccid_hc_rx_slab :
198 ccid_ops->ccid_hc_tx_slab, ccid);
117 ccid = NULL; 199 ccid = NULL;
200out_module_put:
201 module_put(ccid_ops->ccid_owner);
118 goto out; 202 goto out;
119} 203}
120 204
121EXPORT_SYMBOL_GPL(ccid_init); 205EXPORT_SYMBOL_GPL(ccid_new);
206
207struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk, gfp_t gfp)
208{
209 return ccid_new(id, sk, 1, gfp);
210}
211
212EXPORT_SYMBOL_GPL(ccid_hc_rx_new);
213
214struct ccid *ccid_hc_tx_new(unsigned char id,struct sock *sk, gfp_t gfp)
215{
216 return ccid_new(id, sk, 0, gfp);
217}
218
219EXPORT_SYMBOL_GPL(ccid_hc_tx_new);
122 220
123void ccid_exit(struct ccid *ccid, struct sock *sk) 221static void ccid_delete(struct ccid *ccid, struct sock *sk, int rx)
124{ 222{
223 struct ccid_operations *ccid_ops;
224
125 if (ccid == NULL) 225 if (ccid == NULL)
126 return; 226 return;
127 227
228 ccid_ops = ccid->ccid_ops;
229 if (rx) {
230 if (ccid_ops->ccid_hc_rx_exit != NULL)
231 ccid_ops->ccid_hc_rx_exit(sk);
232 kmem_cache_free(ccid_ops->ccid_hc_rx_slab, ccid);
233 } else {
234 if (ccid_ops->ccid_hc_tx_exit != NULL)
235 ccid_ops->ccid_hc_tx_exit(sk);
236 kmem_cache_free(ccid_ops->ccid_hc_tx_slab, ccid);
237 }
128 ccids_read_lock(); 238 ccids_read_lock();
239 if (ccids[ccid_ops->ccid_id] != NULL)
240 module_put(ccid_ops->ccid_owner);
241 ccids_read_unlock();
242}
129 243
130 if (ccids[ccid->ccid_id] != NULL) { 244void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk)
131 if (ccid->ccid_exit != NULL) 245{
132 ccid->ccid_exit(sk); 246 ccid_delete(ccid, sk, 1);
133 module_put(ccid->ccid_owner); 247}
134 }
135 248
136 ccids_read_unlock(); 249EXPORT_SYMBOL_GPL(ccid_hc_rx_delete);
250
251void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk)
252{
253 ccid_delete(ccid, sk, 0);
137} 254}
138 255
139EXPORT_SYMBOL_GPL(ccid_exit); 256EXPORT_SYMBOL_GPL(ccid_hc_tx_delete);