Commit 14b218a8e4f110206c46e586a3da372f665631e7
1 parent
455a396710
Exists in
master
and in
39 other branches
[PATCH] RPC: Ensure rpc calls respects the RPC_NOINTR flag
For internal purposes, the rpc_clnt_sigmask() call is replaced by a call to rpc_task_sigmask(), which ensures that the current task sigmask respects both the client cl_intr flag and the per-task NOINTR flag. Problem noted by Jiaying Zhang. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Showing 1 changed file with 37 additions and 34 deletions Side-by-side Diff
net/sunrpc/clnt.c
... | ... | @@ -378,38 +378,41 @@ |
378 | 378 | } |
379 | 379 | |
380 | 380 | /* |
381 | - * Export the signal mask handling for aysnchronous code that | |
381 | + * Export the signal mask handling for synchronous code that | |
382 | 382 | * sleeps on RPC calls |
383 | 383 | */ |
384 | +#define RPC_INTR_SIGNALS (sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGKILL)) | |
384 | 385 | |
386 | +static void rpc_save_sigmask(sigset_t *oldset, int intr) | |
387 | +{ | |
388 | + unsigned long sigallow = 0; | |
389 | + sigset_t sigmask; | |
390 | + | |
391 | + /* Block all signals except those listed in sigallow */ | |
392 | + if (intr) | |
393 | + sigallow |= RPC_INTR_SIGNALS; | |
394 | + siginitsetinv(&sigmask, sigallow); | |
395 | + sigprocmask(SIG_BLOCK, &sigmask, oldset); | |
396 | +} | |
397 | + | |
398 | +static inline void rpc_task_sigmask(struct rpc_task *task, sigset_t *oldset) | |
399 | +{ | |
400 | + rpc_save_sigmask(oldset, !RPC_TASK_UNINTERRUPTIBLE(task)); | |
401 | +} | |
402 | + | |
403 | +static inline void rpc_restore_sigmask(sigset_t *oldset) | |
404 | +{ | |
405 | + sigprocmask(SIG_SETMASK, oldset, NULL); | |
406 | +} | |
407 | + | |
385 | 408 | void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset) |
386 | 409 | { |
387 | - unsigned long sigallow = sigmask(SIGKILL); | |
388 | - unsigned long irqflags; | |
389 | - | |
390 | - /* Turn off various signals */ | |
391 | - if (clnt->cl_intr) { | |
392 | - struct k_sigaction *action = current->sighand->action; | |
393 | - if (action[SIGINT-1].sa.sa_handler == SIG_DFL) | |
394 | - sigallow |= sigmask(SIGINT); | |
395 | - if (action[SIGQUIT-1].sa.sa_handler == SIG_DFL) | |
396 | - sigallow |= sigmask(SIGQUIT); | |
397 | - } | |
398 | - spin_lock_irqsave(¤t->sighand->siglock, irqflags); | |
399 | - *oldset = current->blocked; | |
400 | - siginitsetinv(¤t->blocked, sigallow & ~oldset->sig[0]); | |
401 | - recalc_sigpending(); | |
402 | - spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); | |
410 | + rpc_save_sigmask(oldset, clnt->cl_intr); | |
403 | 411 | } |
404 | 412 | |
405 | 413 | void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset) |
406 | 414 | { |
407 | - unsigned long irqflags; | |
408 | - | |
409 | - spin_lock_irqsave(¤t->sighand->siglock, irqflags); | |
410 | - current->blocked = *oldset; | |
411 | - recalc_sigpending(); | |
412 | - spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); | |
415 | + rpc_restore_sigmask(oldset); | |
413 | 416 | } |
414 | 417 | |
415 | 418 | /* |
416 | 419 | |
417 | 420 | |
418 | 421 | |
419 | 422 | |
420 | 423 | |
... | ... | @@ -427,26 +430,26 @@ |
427 | 430 | |
428 | 431 | BUG_ON(flags & RPC_TASK_ASYNC); |
429 | 432 | |
430 | - rpc_clnt_sigmask(clnt, &oldset); | |
431 | - | |
432 | 433 | status = -ENOMEM; |
433 | 434 | task = rpc_new_task(clnt, NULL, flags); |
434 | 435 | if (task == NULL) |
435 | 436 | goto out; |
436 | 437 | |
438 | + /* Mask signals on RPC calls _and_ GSS_AUTH upcalls */ | |
439 | + rpc_task_sigmask(task, &oldset); | |
440 | + | |
437 | 441 | rpc_call_setup(task, msg, 0); |
438 | 442 | |
439 | 443 | /* Set up the call info struct and execute the task */ |
440 | - if (task->tk_status == 0) | |
444 | + if (task->tk_status == 0) { | |
441 | 445 | status = rpc_execute(task); |
442 | - else { | |
446 | + } else { | |
443 | 447 | status = task->tk_status; |
444 | 448 | rpc_release_task(task); |
445 | 449 | } |
446 | 450 | |
451 | + rpc_restore_sigmask(&oldset); | |
447 | 452 | out: |
448 | - rpc_clnt_sigunmask(clnt, &oldset); | |
449 | - | |
450 | 453 | return status; |
451 | 454 | } |
452 | 455 | |
... | ... | @@ -467,8 +470,6 @@ |
467 | 470 | |
468 | 471 | flags |= RPC_TASK_ASYNC; |
469 | 472 | |
470 | - rpc_clnt_sigmask(clnt, &oldset); | |
471 | - | |
472 | 473 | /* Create/initialize a new RPC task */ |
473 | 474 | if (!callback) |
474 | 475 | callback = rpc_default_callback; |
... | ... | @@ -477,6 +478,9 @@ |
477 | 478 | goto out; |
478 | 479 | task->tk_calldata = data; |
479 | 480 | |
481 | + /* Mask signals on GSS_AUTH upcalls */ | |
482 | + rpc_task_sigmask(task, &oldset); | |
483 | + | |
480 | 484 | rpc_call_setup(task, msg, 0); |
481 | 485 | |
482 | 486 | /* Set up the call info struct and execute the task */ |
483 | 487 | |
... | ... | @@ -486,9 +490,8 @@ |
486 | 490 | else |
487 | 491 | rpc_release_task(task); |
488 | 492 | |
493 | + rpc_restore_sigmask(&oldset); | |
489 | 494 | out: |
490 | - rpc_clnt_sigunmask(clnt, &oldset); | |
491 | - | |
492 | 495 | return status; |
493 | 496 | } |
494 | 497 | |
... | ... | @@ -666,7 +669,7 @@ |
666 | 669 | return; |
667 | 670 | printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); |
668 | 671 | |
669 | - if (RPC_IS_ASYNC(task) || !(task->tk_client->cl_intr && signalled())) { | |
672 | + if (RPC_IS_ASYNC(task) || !signalled()) { | |
670 | 673 | xprt_release(task); |
671 | 674 | task->tk_action = call_reserve; |
672 | 675 | rpc_delay(task, HZ>>4); |