Commit 14b218a8e4f110206c46e586a3da372f665631e7

Authored by Trond Myklebust
1 parent 455a396710

[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

... ... @@ -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(&current->sighand->siglock, irqflags);
399   - *oldset = current->blocked;
400   - siginitsetinv(&current->blocked, sigallow & ~oldset->sig[0]);
401   - recalc_sigpending();
402   - spin_unlock_irqrestore(&current->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(&current->sighand->siglock, irqflags);
410   - current->blocked = *oldset;
411   - recalc_sigpending();
412   - spin_unlock_irqrestore(&current->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);