diff options
Diffstat (limited to 'net/rxrpc/af_rxrpc.c')
-rw-r--r-- | net/rxrpc/af_rxrpc.c | 141 |
1 files changed, 133 insertions, 8 deletions
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index bfa8822e2286..2c57df9c131b 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c | |||
@@ -41,6 +41,8 @@ atomic_t rxrpc_debug_id; | |||
41 | /* count of skbs currently in use */ | 41 | /* count of skbs currently in use */ |
42 | atomic_t rxrpc_n_skbs; | 42 | atomic_t rxrpc_n_skbs; |
43 | 43 | ||
44 | struct workqueue_struct *rxrpc_workqueue; | ||
45 | |||
44 | static void rxrpc_sock_destructor(struct sock *); | 46 | static void rxrpc_sock_destructor(struct sock *); |
45 | 47 | ||
46 | /* | 48 | /* |
@@ -214,7 +216,8 @@ static int rxrpc_listen(struct socket *sock, int backlog) | |||
214 | */ | 216 | */ |
215 | static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock, | 217 | static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock, |
216 | struct sockaddr *addr, | 218 | struct sockaddr *addr, |
217 | int addr_len, int flags) | 219 | int addr_len, int flags, |
220 | gfp_t gfp) | ||
218 | { | 221 | { |
219 | struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) addr; | 222 | struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) addr; |
220 | struct rxrpc_transport *trans; | 223 | struct rxrpc_transport *trans; |
@@ -232,17 +235,129 @@ static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock, | |||
232 | return ERR_PTR(-EAFNOSUPPORT); | 235 | return ERR_PTR(-EAFNOSUPPORT); |
233 | 236 | ||
234 | /* find a remote transport endpoint from the local one */ | 237 | /* find a remote transport endpoint from the local one */ |
235 | peer = rxrpc_get_peer(srx, GFP_KERNEL); | 238 | peer = rxrpc_get_peer(srx, gfp); |
236 | if (IS_ERR(peer)) | 239 | if (IS_ERR(peer)) |
237 | return ERR_PTR(PTR_ERR(peer)); | 240 | return ERR_PTR(PTR_ERR(peer)); |
238 | 241 | ||
239 | /* find a transport */ | 242 | /* find a transport */ |
240 | trans = rxrpc_get_transport(rx->local, peer, GFP_KERNEL); | 243 | trans = rxrpc_get_transport(rx->local, peer, gfp); |
241 | rxrpc_put_peer(peer); | 244 | rxrpc_put_peer(peer); |
242 | _leave(" = %p", trans); | 245 | _leave(" = %p", trans); |
243 | return trans; | 246 | return trans; |
244 | } | 247 | } |
245 | 248 | ||
249 | /** | ||
250 | * rxrpc_kernel_begin_call - Allow a kernel service to begin a call | ||
251 | * @sock: The socket on which to make the call | ||
252 | * @srx: The address of the peer to contact (defaults to socket setting) | ||
253 | * @key: The security context to use (defaults to socket setting) | ||
254 | * @user_call_ID: The ID to use | ||
255 | * | ||
256 | * Allow a kernel service to begin a call on the nominated socket. This just | ||
257 | * sets up all the internal tracking structures and allocates connection and | ||
258 | * call IDs as appropriate. The call to be used is returned. | ||
259 | * | ||
260 | * The default socket destination address and security may be overridden by | ||
261 | * supplying @srx and @key. | ||
262 | */ | ||
263 | struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, | ||
264 | struct sockaddr_rxrpc *srx, | ||
265 | struct key *key, | ||
266 | unsigned long user_call_ID, | ||
267 | gfp_t gfp) | ||
268 | { | ||
269 | struct rxrpc_conn_bundle *bundle; | ||
270 | struct rxrpc_transport *trans; | ||
271 | struct rxrpc_call *call; | ||
272 | struct rxrpc_sock *rx = rxrpc_sk(sock->sk); | ||
273 | __be16 service_id; | ||
274 | |||
275 | _enter(",,%x,%lx", key_serial(key), user_call_ID); | ||
276 | |||
277 | lock_sock(&rx->sk); | ||
278 | |||
279 | if (srx) { | ||
280 | trans = rxrpc_name_to_transport(sock, (struct sockaddr *) srx, | ||
281 | sizeof(*srx), 0, gfp); | ||
282 | if (IS_ERR(trans)) { | ||
283 | call = ERR_PTR(PTR_ERR(trans)); | ||
284 | trans = NULL; | ||
285 | goto out; | ||
286 | } | ||
287 | } else { | ||
288 | trans = rx->trans; | ||
289 | if (!trans) { | ||
290 | call = ERR_PTR(-ENOTCONN); | ||
291 | goto out; | ||
292 | } | ||
293 | atomic_inc(&trans->usage); | ||
294 | } | ||
295 | |||
296 | service_id = rx->service_id; | ||
297 | if (srx) | ||
298 | service_id = htons(srx->srx_service); | ||
299 | |||
300 | if (!key) | ||
301 | key = rx->key; | ||
302 | if (key && !key->payload.data) | ||
303 | key = NULL; /* a no-security key */ | ||
304 | |||
305 | bundle = rxrpc_get_bundle(rx, trans, key, service_id, gfp); | ||
306 | if (IS_ERR(bundle)) { | ||
307 | call = ERR_PTR(PTR_ERR(bundle)); | ||
308 | goto out; | ||
309 | } | ||
310 | |||
311 | call = rxrpc_get_client_call(rx, trans, bundle, user_call_ID, true, | ||
312 | gfp); | ||
313 | rxrpc_put_bundle(trans, bundle); | ||
314 | out: | ||
315 | rxrpc_put_transport(trans); | ||
316 | release_sock(&rx->sk); | ||
317 | _leave(" = %p", call); | ||
318 | return call; | ||
319 | } | ||
320 | |||
321 | EXPORT_SYMBOL(rxrpc_kernel_begin_call); | ||
322 | |||
323 | /** | ||
324 | * rxrpc_kernel_end_call - Allow a kernel service to end a call it was using | ||
325 | * @call: The call to end | ||
326 | * | ||
327 | * Allow a kernel service to end a call it was using. The call must be | ||
328 | * complete before this is called (the call should be aborted if necessary). | ||
329 | */ | ||
330 | void rxrpc_kernel_end_call(struct rxrpc_call *call) | ||
331 | { | ||
332 | _enter("%d{%d}", call->debug_id, atomic_read(&call->usage)); | ||
333 | rxrpc_remove_user_ID(call->socket, call); | ||
334 | rxrpc_put_call(call); | ||
335 | } | ||
336 | |||
337 | EXPORT_SYMBOL(rxrpc_kernel_end_call); | ||
338 | |||
339 | /** | ||
340 | * rxrpc_kernel_intercept_rx_messages - Intercept received RxRPC messages | ||
341 | * @sock: The socket to intercept received messages on | ||
342 | * @interceptor: The function to pass the messages to | ||
343 | * | ||
344 | * Allow a kernel service to intercept messages heading for the Rx queue on an | ||
345 | * RxRPC socket. They get passed to the specified function instead. | ||
346 | * @interceptor should free the socket buffers it is given. @interceptor is | ||
347 | * called with the socket receive queue spinlock held and softirqs disabled - | ||
348 | * this ensures that the messages will be delivered in the right order. | ||
349 | */ | ||
350 | void rxrpc_kernel_intercept_rx_messages(struct socket *sock, | ||
351 | rxrpc_interceptor_t interceptor) | ||
352 | { | ||
353 | struct rxrpc_sock *rx = rxrpc_sk(sock->sk); | ||
354 | |||
355 | _enter(""); | ||
356 | rx->interceptor = interceptor; | ||
357 | } | ||
358 | |||
359 | EXPORT_SYMBOL(rxrpc_kernel_intercept_rx_messages); | ||
360 | |||
246 | /* | 361 | /* |
247 | * connect an RxRPC socket | 362 | * connect an RxRPC socket |
248 | * - this just targets it at a specific destination; no actual connection | 363 | * - this just targets it at a specific destination; no actual connection |
@@ -294,7 +409,8 @@ static int rxrpc_connect(struct socket *sock, struct sockaddr *addr, | |||
294 | return -EBUSY; /* server sockets can't connect as well */ | 409 | return -EBUSY; /* server sockets can't connect as well */ |
295 | } | 410 | } |
296 | 411 | ||
297 | trans = rxrpc_name_to_transport(sock, addr, addr_len, flags); | 412 | trans = rxrpc_name_to_transport(sock, addr, addr_len, flags, |
413 | GFP_KERNEL); | ||
298 | if (IS_ERR(trans)) { | 414 | if (IS_ERR(trans)) { |
299 | release_sock(&rx->sk); | 415 | release_sock(&rx->sk); |
300 | _leave(" = %ld", PTR_ERR(trans)); | 416 | _leave(" = %ld", PTR_ERR(trans)); |
@@ -344,7 +460,7 @@ static int rxrpc_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
344 | if (m->msg_name) { | 460 | if (m->msg_name) { |
345 | ret = -EISCONN; | 461 | ret = -EISCONN; |
346 | trans = rxrpc_name_to_transport(sock, m->msg_name, | 462 | trans = rxrpc_name_to_transport(sock, m->msg_name, |
347 | m->msg_namelen, 0); | 463 | m->msg_namelen, 0, GFP_KERNEL); |
348 | if (IS_ERR(trans)) { | 464 | if (IS_ERR(trans)) { |
349 | ret = PTR_ERR(trans); | 465 | ret = PTR_ERR(trans); |
350 | trans = NULL; | 466 | trans = NULL; |
@@ -576,7 +692,7 @@ static int rxrpc_release_sock(struct sock *sk) | |||
576 | 692 | ||
577 | /* try to flush out this socket */ | 693 | /* try to flush out this socket */ |
578 | rxrpc_release_calls_on_socket(rx); | 694 | rxrpc_release_calls_on_socket(rx); |
579 | flush_scheduled_work(); | 695 | flush_workqueue(rxrpc_workqueue); |
580 | rxrpc_purge_queue(&sk->sk_receive_queue); | 696 | rxrpc_purge_queue(&sk->sk_receive_queue); |
581 | 697 | ||
582 | if (rx->conn) { | 698 | if (rx->conn) { |
@@ -673,15 +789,21 @@ static int __init af_rxrpc_init(void) | |||
673 | 789 | ||
674 | rxrpc_epoch = htonl(xtime.tv_sec); | 790 | rxrpc_epoch = htonl(xtime.tv_sec); |
675 | 791 | ||
792 | ret = -ENOMEM; | ||
676 | rxrpc_call_jar = kmem_cache_create( | 793 | rxrpc_call_jar = kmem_cache_create( |
677 | "rxrpc_call_jar", sizeof(struct rxrpc_call), 0, | 794 | "rxrpc_call_jar", sizeof(struct rxrpc_call), 0, |
678 | SLAB_HWCACHE_ALIGN, NULL, NULL); | 795 | SLAB_HWCACHE_ALIGN, NULL, NULL); |
679 | if (!rxrpc_call_jar) { | 796 | if (!rxrpc_call_jar) { |
680 | printk(KERN_NOTICE "RxRPC: Failed to allocate call jar\n"); | 797 | printk(KERN_NOTICE "RxRPC: Failed to allocate call jar\n"); |
681 | ret = -ENOMEM; | ||
682 | goto error_call_jar; | 798 | goto error_call_jar; |
683 | } | 799 | } |
684 | 800 | ||
801 | rxrpc_workqueue = create_workqueue("krxrpcd"); | ||
802 | if (!rxrpc_workqueue) { | ||
803 | printk(KERN_NOTICE "RxRPC: Failed to allocate work queue\n"); | ||
804 | goto error_work_queue; | ||
805 | } | ||
806 | |||
685 | ret = proto_register(&rxrpc_proto, 1); | 807 | ret = proto_register(&rxrpc_proto, 1); |
686 | if (ret < 0) { | 808 | if (ret < 0) { |
687 | printk(KERN_CRIT "RxRPC: Cannot register protocol\n"); | 809 | printk(KERN_CRIT "RxRPC: Cannot register protocol\n"); |
@@ -719,6 +841,8 @@ error_key_type: | |||
719 | error_sock: | 841 | error_sock: |
720 | proto_unregister(&rxrpc_proto); | 842 | proto_unregister(&rxrpc_proto); |
721 | error_proto: | 843 | error_proto: |
844 | destroy_workqueue(rxrpc_workqueue); | ||
845 | error_work_queue: | ||
722 | kmem_cache_destroy(rxrpc_call_jar); | 846 | kmem_cache_destroy(rxrpc_call_jar); |
723 | error_call_jar: | 847 | error_call_jar: |
724 | return ret; | 848 | return ret; |
@@ -743,9 +867,10 @@ static void __exit af_rxrpc_exit(void) | |||
743 | ASSERTCMP(atomic_read(&rxrpc_n_skbs), ==, 0); | 867 | ASSERTCMP(atomic_read(&rxrpc_n_skbs), ==, 0); |
744 | 868 | ||
745 | _debug("flush scheduled work"); | 869 | _debug("flush scheduled work"); |
746 | flush_scheduled_work(); | 870 | flush_workqueue(rxrpc_workqueue); |
747 | proc_net_remove("rxrpc_conns"); | 871 | proc_net_remove("rxrpc_conns"); |
748 | proc_net_remove("rxrpc_calls"); | 872 | proc_net_remove("rxrpc_calls"); |
873 | destroy_workqueue(rxrpc_workqueue); | ||
749 | kmem_cache_destroy(rxrpc_call_jar); | 874 | kmem_cache_destroy(rxrpc_call_jar); |
750 | _leave(""); | 875 | _leave(""); |
751 | } | 876 | } |