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.c188
1 files changed, 154 insertions, 34 deletions
diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c
index 06b191a5740b..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,82 +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;
63
64 va_start(args, fmt);
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;
61 105
62 ccids_write_lock(); 106 ccids_write_lock();
63 err = -EEXIST; 107 err = -EEXIST;
64 if (ccids[ccid->ccid_id] == NULL) { 108 if (ccids[ccid_ops->ccid_id] == NULL) {
65 ccids[ccid->ccid_id] = ccid; 109 ccids[ccid_ops->ccid_id] = ccid_ops;
66 err = 0; 110 err = 0;
67 } 111 }
68 ccids_write_unlock(); 112 ccids_write_unlock();
69 if (err == 0) 113 if (err != 0)
70 pr_info("CCID: Registered CCID %d (%s)\n", 114 goto out_free_tx_slab;
71 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:
72 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;
73} 128}
74 129
75EXPORT_SYMBOL_GPL(ccid_register); 130EXPORT_SYMBOL_GPL(ccid_register);
76 131
77int ccid_unregister(struct ccid *ccid) 132int ccid_unregister(struct ccid_operations *ccid_ops)
78{ 133{
79 ccids_write_lock(); 134 ccids_write_lock();
80 ccids[ccid->ccid_id] = NULL; 135 ccids[ccid_ops->ccid_id] = NULL;
81 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
82 pr_info("CCID: Unregistered CCID %d (%s)\n", 143 pr_info("CCID: Unregistered CCID %d (%s)\n",
83 ccid->ccid_id, ccid->ccid_name); 144 ccid_ops->ccid_id, ccid_ops->ccid_name);
84 return 0; 145 return 0;
85} 146}
86 147
87EXPORT_SYMBOL_GPL(ccid_unregister); 148EXPORT_SYMBOL_GPL(ccid_unregister);
88 149
89struct ccid *ccid_init(unsigned char id, struct sock *sk) 150struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
90{ 151{
91 struct ccid *ccid; 152 struct ccid_operations *ccid_ops;
153 struct ccid *ccid = NULL;
92 154
155 ccids_read_lock();
93#ifdef CONFIG_KMOD 156#ifdef CONFIG_KMOD
94 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;
95 request_module("net-dccp-ccid-%d", id); 162 request_module("net-dccp-ccid-%d", id);
163 ccids_read_lock();
164 }
96#endif 165#endif
97 ccids_read_lock(); 166 ccid_ops = ccids[id];
167 if (ccid_ops == NULL)
168 goto out_unlock;
98 169
99 ccid = ccids[id]; 170 if (!try_module_get(ccid_ops->ccid_owner))
100 if (ccid == NULL) 171 goto out_unlock;
101 goto out;
102 172
103 if (!try_module_get(ccid->ccid_owner)) 173 ccids_read_unlock();
104 goto out_err;
105 174
106 if (ccid->ccid_init != NULL && 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)
107 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 }
108out: 191out:
109 ccids_read_unlock();
110 return ccid; 192 return ccid;
111out_module_put: 193out_unlock:
112 module_put(ccid->ccid_owner); 194 ccids_read_unlock();
113out_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);
114 ccid = NULL; 199 ccid = NULL;
200out_module_put:
201 module_put(ccid_ops->ccid_owner);
115 goto out; 202 goto out;
116} 203}
117 204
118EXPORT_SYMBOL_GPL(ccid_init); 205EXPORT_SYMBOL_GPL(ccid_new);
119 206
120void ccid_exit(struct ccid *ccid, struct sock *sk) 207struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk, gfp_t gfp)
121{ 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);
220
221static void ccid_delete(struct ccid *ccid, struct sock *sk, int rx)
222{
223 struct ccid_operations *ccid_ops;
224
122 if (ccid == NULL) 225 if (ccid == NULL)
123 return; 226 return;
124 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 }
125 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}
126 243
127 if (ccids[ccid->ccid_id] != NULL) { 244void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk)
128 if (ccid->ccid_exit != NULL) 245{
129 ccid->ccid_exit(sk); 246 ccid_delete(ccid, sk, 1);
130 module_put(ccid->ccid_owner); 247}
131 }
132 248
133 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);
134} 254}
135 255
136EXPORT_SYMBOL_GPL(ccid_exit); 256EXPORT_SYMBOL_GPL(ccid_hc_tx_delete);