From ec1b20e72282d6a9407c350f0328bd4ce74b2352 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 11 Mar 2020 09:01:09 -0400 Subject: [PATCH] LU-9859 libcfs: improve API and implementation of blocking signals. According to comment for set_current_blocked() in kernel/signal.c, changing ->blocked directly is wrong. sigprocmask() should be called instead. So change cfs_block_sigsinv() and cfs_restore_sigs() to use sigprocmask(). For consistency, change them to pass the sigset_t by reference rather than by value. Also fix cfs_block_sigsinv() so that it correctly blocks signals above 32 on a 32bit host. Linux-commit: 84e07b9d0ac8728b1865b23498d746861a8ab4c2 Change-Id: Iffb8b39ee2b988e9909ceaaba50446eecdf7f249 Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Reviewed-on: https://review.whamcloud.com/35411 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Jian Yu Reviewed-by: Shaun Tancheff Reviewed-by: Oleg Drokin --- libcfs/include/libcfs/libcfs.h | 4 ++-- libcfs/include/libcfs/linux/linux-wait.h | 12 ++++++------ libcfs/libcfs/linux/linux-prim.c | 25 ++++++++----------------- lustre/llite/llite_mmap.c | 8 ++++---- lustre/ptlrpc/client.c | 7 ++++--- 5 files changed, 24 insertions(+), 32 deletions(-) diff --git a/libcfs/include/libcfs/libcfs.h b/libcfs/include/libcfs/libcfs.h index 3d17af6..b60343b 100644 --- a/libcfs/include/libcfs/libcfs.h +++ b/libcfs/include/libcfs/libcfs.h @@ -108,8 +108,8 @@ static inline int notifier_from_ioctl_errno(int err) * Defined by platform */ int unshare_fs_struct(void); -sigset_t cfs_block_sigsinv(unsigned long sigs); -void cfs_restore_sigs(sigset_t); +void cfs_block_sigsinv(unsigned long sigs, sigset_t *sigset); +void cfs_restore_sigs(sigset_t *sigset); int libcfs_ioctl_data_adjust(struct libcfs_ioctl_data *data); diff --git a/libcfs/include/libcfs/linux/linux-wait.h b/libcfs/include/libcfs/linux/linux-wait.h index fd154ba..5a3f548 100644 --- a/libcfs/include/libcfs/linux/linux-wait.h +++ b/libcfs/include/libcfs/linux/linux-wait.h @@ -208,9 +208,9 @@ __out: __ret; \ wait_queue_entry_t __wq_entry; \ unsigned long flags; \ long __ret = ret; /* explicit shadow */ \ - sigset_t __blocked; \ + sigset_t __old_blocked; \ \ - __blocked = cfs_block_sigsinv(0); \ + cfs_block_sigsinv(0, &__old_blocked); \ init_wait(&__wq_entry); \ if (exclusive) \ __wq_entry.flags = WQ_FLAG_EXCLUSIVE; \ @@ -238,7 +238,7 @@ __out: __ret; \ cmd; \ } \ finish_wait(&wq_head, &__wq_entry); \ - cfs_restore_sigs(__blocked); \ + cfs_restore_sigs(&__old_blocked); \ __ret; \ }) @@ -473,9 +473,9 @@ do { \ wait_queue_entry_t __wq_entry; \ unsigned long flags; \ long __ret = ret; /* explicit shadow */ \ - sigset_t __blocked; \ + sigset_t __old_blocked; \ \ - __blocked = cfs_block_sigsinv(0); \ + cfs_block_sigsinv(0, &__old_blocked); \ init_wait(&__wq_entry); \ __wq_entry.flags = WQ_FLAG_EXCLUSIVE; \ for (;;) { \ @@ -495,7 +495,7 @@ do { \ } \ cmd; \ } \ - cfs_restore_sigs(__blocked); \ + cfs_restore_sigs(&__old_blocked); \ finish_wait(&wq_head, &__wq_entry); \ __ret; \ }) diff --git a/libcfs/libcfs/linux/linux-prim.c b/libcfs/libcfs/linux/linux-prim.c index a8ca37e..9c65e7e 100644 --- a/libcfs/libcfs/linux/linux-prim.c +++ b/libcfs/libcfs/linux/linux-prim.c @@ -196,28 +196,19 @@ EXPORT_SYMBOL(kstrtobool_from_user); #endif /* !HAVE_KSTRTOBOOL_FROM_USER */ /* Block all signals except for the @sigs */ -sigset_t cfs_block_sigsinv(unsigned long sigs) +void cfs_block_sigsinv(unsigned long sigs, sigset_t *old) { - unsigned long flags; - sigset_t old; - - spin_lock_irqsave(¤t->sighand->siglock, flags); - old = current->blocked; - sigaddsetmask(¤t->blocked, ~sigs); - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - return old; + sigset_t new; + + siginitsetinv(&new, sigs); + sigorsets(&new, ¤t->blocked, &new); + sigprocmask(SIG_BLOCK, &new, old); } EXPORT_SYMBOL(cfs_block_sigsinv); void -cfs_restore_sigs(sigset_t old) +cfs_restore_sigs(sigset_t *old) { - unsigned long flags; - - spin_lock_irqsave(¤t->sighand->siglock, flags); - current->blocked = old; - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); + sigprocmask(SIG_SETMASK, old, NULL); } EXPORT_SYMBOL(cfs_restore_sigs); diff --git a/lustre/llite/llite_mmap.c b/lustre/llite/llite_mmap.c index 673ff2c..0a943d3 100644 --- a/lustre/llite/llite_mmap.c +++ b/lustre/llite/llite_mmap.c @@ -173,14 +173,14 @@ static int ll_page_mkwrite0(struct vm_area_struct *vma, struct page *vmpage, vio->u.fault.ft_vma = vma; vio->u.fault.ft_vmpage = vmpage; - set = cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM)); + cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM), &set); inode = vvp_object_inode(io->ci_obj); lli = ll_i2info(inode); result = cl_io_loop(env, io); - cfs_restore_sigs(set); + cfs_restore_sigs(&set); if (result == 0) { lock_page(vmpage); @@ -361,7 +361,7 @@ static vm_fault_t ll_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Only SIGKILL and SIGTERM is allowed for fault/nopage/mkwrite * so that it can be killed by admin but not cause segfault by * other signals. */ - set = cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM)); + cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM), &set); /* make sure offset is not a negative number */ if (vmf->pgoff > (MAX_LFS_FILESIZE >> PAGE_SHIFT)) @@ -390,7 +390,7 @@ restart: result |= VM_FAULT_LOCKED; } - cfs_restore_sigs(set); + cfs_restore_sigs(&set); out: if (vmf->page && result == VM_FAULT_LOCKED) { diff --git a/lustre/ptlrpc/client.c b/lustre/ptlrpc/client.c index 758d86e..5602b58 100644 --- a/lustre/ptlrpc/client.c +++ b/lustre/ptlrpc/client.c @@ -2477,9 +2477,10 @@ int ptlrpc_set_wait(const struct lu_env *env, struct ptlrpc_request_set *set) */ if (rc == -ETIMEDOUT && signal_pending(current)) { - sigset_t blocked_sigs = - cfs_block_sigsinv(LUSTRE_FATAL_SIGS); + sigset_t blocked_sigs; + cfs_block_sigsinv(LUSTRE_FATAL_SIGS, + &blocked_sigs); /* * In fact we only interrupt for the * "fatal" signals like SIGINT or @@ -2490,7 +2491,7 @@ int ptlrpc_set_wait(const struct lu_env *env, struct ptlrpc_request_set *set) */ if (signal_pending(current)) ptlrpc_interrupted_set(set); - cfs_restore_sigs(blocked_sigs); + cfs_restore_sigs(&blocked_sigs); } } -- 1.8.3.1