diff options
author | David Howells <dhowells@redhat.com> | 2016-08-30 15:42:14 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-09-01 19:43:27 -0400 |
commit | d001648ec7cf8b21ae9eec8b9ba4a18295adfb14 (patch) | |
tree | 830a6ec7dbc683675ba088750caeb5eafb4c8012 /fs/afs/cmservice.c | |
parent | 95ac3994514015823634ef1f7116dce24f26aa97 (diff) |
rxrpc: Don't expose skbs to in-kernel users [ver #2]
Don't expose skbs to in-kernel users, such as the AFS filesystem, but
instead provide a notification hook the indicates that a call needs
attention and another that indicates that there's a new call to be
collected.
This makes the following possibilities more achievable:
(1) Call refcounting can be made simpler if skbs don't hold refs to calls.
(2) skbs referring to non-data events will be able to be freed much sooner
rather than being queued for AFS to pick up as rxrpc_kernel_recv_data
will be able to consult the call state.
(3) We can shortcut the receive phase when a call is remotely aborted
because we don't have to go through all the packets to get to the one
cancelling the operation.
(4) It makes it easier to do encryption/decryption directly between AFS's
buffers and sk_buffs.
(5) Encryption/decryption can more easily be done in the AFS's thread
contexts - usually that of the userspace process that issued a syscall
- rather than in one of rxrpc's background threads on a workqueue.
(6) AFS will be able to wait synchronously on a call inside AF_RXRPC.
To make this work, the following interface function has been added:
int rxrpc_kernel_recv_data(
struct socket *sock, struct rxrpc_call *call,
void *buffer, size_t bufsize, size_t *_offset,
bool want_more, u32 *_abort_code);
This is the recvmsg equivalent. It allows the caller to find out about the
state of a specific call and to transfer received data into a buffer
piecemeal.
afs_extract_data() and rxrpc_kernel_recv_data() now do all the extraction
logic between them. They don't wait synchronously yet because the socket
lock needs to be dealt with.
Five interface functions have been removed:
rxrpc_kernel_is_data_last()
rxrpc_kernel_get_abort_code()
rxrpc_kernel_get_error_number()
rxrpc_kernel_free_skb()
rxrpc_kernel_data_consumed()
As a temporary hack, sk_buffs going to an in-kernel call are queued on the
rxrpc_call struct (->knlrecv_queue) rather than being handed over to the
in-kernel user. To process the queue internally, a temporary function,
temp_deliver_data() has been added. This will be replaced with common code
between the rxrpc_recvmsg() path and the kernel_rxrpc_recv_data() path in a
future patch.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'fs/afs/cmservice.c')
-rw-r--r-- | fs/afs/cmservice.c | 142 |
1 files changed, 77 insertions, 65 deletions
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index 77ee481059ac..2037e7a77a37 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c | |||
@@ -17,15 +17,12 @@ | |||
17 | #include "internal.h" | 17 | #include "internal.h" |
18 | #include "afs_cm.h" | 18 | #include "afs_cm.h" |
19 | 19 | ||
20 | static int afs_deliver_cb_init_call_back_state(struct afs_call *, | 20 | static int afs_deliver_cb_init_call_back_state(struct afs_call *); |
21 | struct sk_buff *, bool); | 21 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *); |
22 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *, | 22 | static int afs_deliver_cb_probe(struct afs_call *); |
23 | struct sk_buff *, bool); | 23 | static int afs_deliver_cb_callback(struct afs_call *); |
24 | static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool); | 24 | static int afs_deliver_cb_probe_uuid(struct afs_call *); |
25 | static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool); | 25 | static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *); |
26 | static int afs_deliver_cb_probe_uuid(struct afs_call *, struct sk_buff *, bool); | ||
27 | static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *, | ||
28 | struct sk_buff *, bool); | ||
29 | static void afs_cm_destructor(struct afs_call *); | 26 | static void afs_cm_destructor(struct afs_call *); |
30 | 27 | ||
31 | /* | 28 | /* |
@@ -130,7 +127,7 @@ static void afs_cm_destructor(struct afs_call *call) | |||
130 | * received. The step number here must match the final number in | 127 | * received. The step number here must match the final number in |
131 | * afs_deliver_cb_callback(). | 128 | * afs_deliver_cb_callback(). |
132 | */ | 129 | */ |
133 | if (call->unmarshall == 6) { | 130 | if (call->unmarshall == 5) { |
134 | ASSERT(call->server && call->count && call->request); | 131 | ASSERT(call->server && call->count && call->request); |
135 | afs_break_callbacks(call->server, call->count, call->request); | 132 | afs_break_callbacks(call->server, call->count, call->request); |
136 | } | 133 | } |
@@ -164,8 +161,7 @@ static void SRXAFSCB_CallBack(struct work_struct *work) | |||
164 | /* | 161 | /* |
165 | * deliver request data to a CB.CallBack call | 162 | * deliver request data to a CB.CallBack call |
166 | */ | 163 | */ |
167 | static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb, | 164 | static int afs_deliver_cb_callback(struct afs_call *call) |
168 | bool last) | ||
169 | { | 165 | { |
170 | struct sockaddr_rxrpc srx; | 166 | struct sockaddr_rxrpc srx; |
171 | struct afs_callback *cb; | 167 | struct afs_callback *cb; |
@@ -174,7 +170,7 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb, | |||
174 | u32 tmp; | 170 | u32 tmp; |
175 | int ret, loop; | 171 | int ret, loop; |
176 | 172 | ||
177 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | 173 | _enter("{%u}", call->unmarshall); |
178 | 174 | ||
179 | switch (call->unmarshall) { | 175 | switch (call->unmarshall) { |
180 | case 0: | 176 | case 0: |
@@ -185,7 +181,7 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb, | |||
185 | /* extract the FID array and its count in two steps */ | 181 | /* extract the FID array and its count in two steps */ |
186 | case 1: | 182 | case 1: |
187 | _debug("extract FID count"); | 183 | _debug("extract FID count"); |
188 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | 184 | ret = afs_extract_data(call, &call->tmp, 4, true); |
189 | if (ret < 0) | 185 | if (ret < 0) |
190 | return ret; | 186 | return ret; |
191 | 187 | ||
@@ -202,8 +198,8 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb, | |||
202 | 198 | ||
203 | case 2: | 199 | case 2: |
204 | _debug("extract FID array"); | 200 | _debug("extract FID array"); |
205 | ret = afs_extract_data(call, skb, last, call->buffer, | 201 | ret = afs_extract_data(call, call->buffer, |
206 | call->count * 3 * 4); | 202 | call->count * 3 * 4, true); |
207 | if (ret < 0) | 203 | if (ret < 0) |
208 | return ret; | 204 | return ret; |
209 | 205 | ||
@@ -229,7 +225,7 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb, | |||
229 | /* extract the callback array and its count in two steps */ | 225 | /* extract the callback array and its count in two steps */ |
230 | case 3: | 226 | case 3: |
231 | _debug("extract CB count"); | 227 | _debug("extract CB count"); |
232 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | 228 | ret = afs_extract_data(call, &call->tmp, 4, true); |
233 | if (ret < 0) | 229 | if (ret < 0) |
234 | return ret; | 230 | return ret; |
235 | 231 | ||
@@ -239,13 +235,11 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb, | |||
239 | return -EBADMSG; | 235 | return -EBADMSG; |
240 | call->offset = 0; | 236 | call->offset = 0; |
241 | call->unmarshall++; | 237 | call->unmarshall++; |
242 | if (tmp == 0) | ||
243 | goto empty_cb_array; | ||
244 | 238 | ||
245 | case 4: | 239 | case 4: |
246 | _debug("extract CB array"); | 240 | _debug("extract CB array"); |
247 | ret = afs_extract_data(call, skb, last, call->request, | 241 | ret = afs_extract_data(call, call->buffer, |
248 | call->count * 3 * 4); | 242 | call->count * 3 * 4, false); |
249 | if (ret < 0) | 243 | if (ret < 0) |
250 | return ret; | 244 | return ret; |
251 | 245 | ||
@@ -258,15 +252,9 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb, | |||
258 | cb->type = ntohl(*bp++); | 252 | cb->type = ntohl(*bp++); |
259 | } | 253 | } |
260 | 254 | ||
261 | empty_cb_array: | ||
262 | call->offset = 0; | 255 | call->offset = 0; |
263 | call->unmarshall++; | 256 | call->unmarshall++; |
264 | 257 | ||
265 | case 5: | ||
266 | ret = afs_data_complete(call, skb, last); | ||
267 | if (ret < 0) | ||
268 | return ret; | ||
269 | |||
270 | /* Record that the message was unmarshalled successfully so | 258 | /* Record that the message was unmarshalled successfully so |
271 | * that the call destructor can know do the callback breaking | 259 | * that the call destructor can know do the callback breaking |
272 | * work, even if the final ACK isn't received. | 260 | * work, even if the final ACK isn't received. |
@@ -275,7 +263,7 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb, | |||
275 | * updated also. | 263 | * updated also. |
276 | */ | 264 | */ |
277 | call->unmarshall++; | 265 | call->unmarshall++; |
278 | case 6: | 266 | case 5: |
279 | break; | 267 | break; |
280 | } | 268 | } |
281 | 269 | ||
@@ -310,19 +298,17 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work) | |||
310 | /* | 298 | /* |
311 | * deliver request data to a CB.InitCallBackState call | 299 | * deliver request data to a CB.InitCallBackState call |
312 | */ | 300 | */ |
313 | static int afs_deliver_cb_init_call_back_state(struct afs_call *call, | 301 | static int afs_deliver_cb_init_call_back_state(struct afs_call *call) |
314 | struct sk_buff *skb, | ||
315 | bool last) | ||
316 | { | 302 | { |
317 | struct sockaddr_rxrpc srx; | 303 | struct sockaddr_rxrpc srx; |
318 | struct afs_server *server; | 304 | struct afs_server *server; |
319 | int ret; | 305 | int ret; |
320 | 306 | ||
321 | _enter(",{%u},%d", skb->len, last); | 307 | _enter(""); |
322 | 308 | ||
323 | rxrpc_kernel_get_peer(afs_socket, call->rxcall, &srx); | 309 | rxrpc_kernel_get_peer(afs_socket, call->rxcall, &srx); |
324 | 310 | ||
325 | ret = afs_data_complete(call, skb, last); | 311 | ret = afs_extract_data(call, NULL, 0, false); |
326 | if (ret < 0) | 312 | if (ret < 0) |
327 | return ret; | 313 | return ret; |
328 | 314 | ||
@@ -344,21 +330,61 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call, | |||
344 | /* | 330 | /* |
345 | * deliver request data to a CB.InitCallBackState3 call | 331 | * deliver request data to a CB.InitCallBackState3 call |
346 | */ | 332 | */ |
347 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *call, | 333 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) |
348 | struct sk_buff *skb, | ||
349 | bool last) | ||
350 | { | 334 | { |
351 | struct sockaddr_rxrpc srx; | 335 | struct sockaddr_rxrpc srx; |
352 | struct afs_server *server; | 336 | struct afs_server *server; |
337 | struct afs_uuid *r; | ||
338 | unsigned loop; | ||
339 | __be32 *b; | ||
340 | int ret; | ||
353 | 341 | ||
354 | _enter(",{%u},%d", skb->len, last); | 342 | _enter(""); |
355 | 343 | ||
356 | rxrpc_kernel_get_peer(afs_socket, call->rxcall, &srx); | 344 | rxrpc_kernel_get_peer(afs_socket, call->rxcall, &srx); |
357 | 345 | ||
358 | /* There are some arguments that we ignore */ | 346 | _enter("{%u}", call->unmarshall); |
359 | afs_data_consumed(call, skb); | 347 | |
360 | if (!last) | 348 | switch (call->unmarshall) { |
361 | return -EAGAIN; | 349 | case 0: |
350 | call->offset = 0; | ||
351 | call->buffer = kmalloc(11 * sizeof(__be32), GFP_KERNEL); | ||
352 | if (!call->buffer) | ||
353 | return -ENOMEM; | ||
354 | call->unmarshall++; | ||
355 | |||
356 | case 1: | ||
357 | _debug("extract UUID"); | ||
358 | ret = afs_extract_data(call, call->buffer, | ||
359 | 11 * sizeof(__be32), false); | ||
360 | switch (ret) { | ||
361 | case 0: break; | ||
362 | case -EAGAIN: return 0; | ||
363 | default: return ret; | ||
364 | } | ||
365 | |||
366 | _debug("unmarshall UUID"); | ||
367 | call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL); | ||
368 | if (!call->request) | ||
369 | return -ENOMEM; | ||
370 | |||
371 | b = call->buffer; | ||
372 | r = call->request; | ||
373 | r->time_low = ntohl(b[0]); | ||
374 | r->time_mid = ntohl(b[1]); | ||
375 | r->time_hi_and_version = ntohl(b[2]); | ||
376 | r->clock_seq_hi_and_reserved = ntohl(b[3]); | ||
377 | r->clock_seq_low = ntohl(b[4]); | ||
378 | |||
379 | for (loop = 0; loop < 6; loop++) | ||
380 | r->node[loop] = ntohl(b[loop + 5]); | ||
381 | |||
382 | call->offset = 0; | ||
383 | call->unmarshall++; | ||
384 | |||
385 | case 2: | ||
386 | break; | ||
387 | } | ||
362 | 388 | ||
363 | /* no unmarshalling required */ | 389 | /* no unmarshalling required */ |
364 | call->state = AFS_CALL_REPLYING; | 390 | call->state = AFS_CALL_REPLYING; |
@@ -390,14 +416,13 @@ static void SRXAFSCB_Probe(struct work_struct *work) | |||
390 | /* | 416 | /* |
391 | * deliver request data to a CB.Probe call | 417 | * deliver request data to a CB.Probe call |
392 | */ | 418 | */ |
393 | static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb, | 419 | static int afs_deliver_cb_probe(struct afs_call *call) |
394 | bool last) | ||
395 | { | 420 | { |
396 | int ret; | 421 | int ret; |
397 | 422 | ||
398 | _enter(",{%u},%d", skb->len, last); | 423 | _enter(""); |
399 | 424 | ||
400 | ret = afs_data_complete(call, skb, last); | 425 | ret = afs_extract_data(call, NULL, 0, false); |
401 | if (ret < 0) | 426 | if (ret < 0) |
402 | return ret; | 427 | return ret; |
403 | 428 | ||
@@ -435,19 +460,14 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work) | |||
435 | /* | 460 | /* |
436 | * deliver request data to a CB.ProbeUuid call | 461 | * deliver request data to a CB.ProbeUuid call |
437 | */ | 462 | */ |
438 | static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb, | 463 | static int afs_deliver_cb_probe_uuid(struct afs_call *call) |
439 | bool last) | ||
440 | { | 464 | { |
441 | struct afs_uuid *r; | 465 | struct afs_uuid *r; |
442 | unsigned loop; | 466 | unsigned loop; |
443 | __be32 *b; | 467 | __be32 *b; |
444 | int ret; | 468 | int ret; |
445 | 469 | ||
446 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | 470 | _enter("{%u}", call->unmarshall); |
447 | |||
448 | ret = afs_data_complete(call, skb, last); | ||
449 | if (ret < 0) | ||
450 | return ret; | ||
451 | 471 | ||
452 | switch (call->unmarshall) { | 472 | switch (call->unmarshall) { |
453 | case 0: | 473 | case 0: |
@@ -459,8 +479,8 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb, | |||
459 | 479 | ||
460 | case 1: | 480 | case 1: |
461 | _debug("extract UUID"); | 481 | _debug("extract UUID"); |
462 | ret = afs_extract_data(call, skb, last, call->buffer, | 482 | ret = afs_extract_data(call, call->buffer, |
463 | 11 * sizeof(__be32)); | 483 | 11 * sizeof(__be32), false); |
464 | switch (ret) { | 484 | switch (ret) { |
465 | case 0: break; | 485 | case 0: break; |
466 | case -EAGAIN: return 0; | 486 | case -EAGAIN: return 0; |
@@ -487,16 +507,9 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb, | |||
487 | call->unmarshall++; | 507 | call->unmarshall++; |
488 | 508 | ||
489 | case 2: | 509 | case 2: |
490 | _debug("trailer"); | ||
491 | if (skb->len != 0) | ||
492 | return -EBADMSG; | ||
493 | break; | 510 | break; |
494 | } | 511 | } |
495 | 512 | ||
496 | ret = afs_data_complete(call, skb, last); | ||
497 | if (ret < 0) | ||
498 | return ret; | ||
499 | |||
500 | call->state = AFS_CALL_REPLYING; | 513 | call->state = AFS_CALL_REPLYING; |
501 | 514 | ||
502 | INIT_WORK(&call->work, SRXAFSCB_ProbeUuid); | 515 | INIT_WORK(&call->work, SRXAFSCB_ProbeUuid); |
@@ -570,14 +583,13 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work) | |||
570 | /* | 583 | /* |
571 | * deliver request data to a CB.TellMeAboutYourself call | 584 | * deliver request data to a CB.TellMeAboutYourself call |
572 | */ | 585 | */ |
573 | static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call, | 586 | static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call) |
574 | struct sk_buff *skb, bool last) | ||
575 | { | 587 | { |
576 | int ret; | 588 | int ret; |
577 | 589 | ||
578 | _enter(",{%u},%d", skb->len, last); | 590 | _enter(""); |
579 | 591 | ||
580 | ret = afs_data_complete(call, skb, last); | 592 | ret = afs_extract_data(call, NULL, 0, false); |
581 | if (ret < 0) | 593 | if (ret < 0) |
582 | return ret; | 594 | return ret; |
583 | 595 | ||