[Devel] [PATCH 2/2] fuse: handle only fatal signals while waiting request answer

Stanislav Kinsburskiy skinsbursky at virtuozzo.com
Mon Oct 17 05:01:47 PDT 2016


Kostya, please, modify patch comment with the following substitution:


s/
it doesn't drop pending signal flag/
it doesn't drop pending signal flag, if processes is traced/
g

Thanks.

13.10.2016 12:03, Stanislav Kinsburskiy пишет:
> This patch is backport of 7d3a07fcb8a0d5c06718de14fb91fdf1ef20a0e2 commit.
> Although this commit loks more like cleanup, it's not.
> It fixes the issue with signals, which can lead to abort of page read in fuse,
> called from page fault, immediatly leading to SIGBUS sent to the caller.
> The issue is in block_sigs implementation: it doesn't drop pending signal
> flag, which interrupts wait_event_interruptible in request_wait_answer, while
> it's supposed to be interrupted by SIGKILL only.
> IOW, any signal, arrived to the process, which does page fault handling on
> fuse file, _before_ request_wait_answer is called, will lead to request
> interruption, producing SIGBUS error in page fault handler (filemap_fault).
>
> https://jira.sw.ru/browse/PSBM-53581
>
> Signed-off-by: Stanislav Kinsburskiy <skinsbursky at virtuozzo.com>
> ---
>   fs/fuse/dev.c |   42 ++++++++++++++++--------------------------
>   1 file changed, 16 insertions(+), 26 deletions(-)
>
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index a0d0b1a..0b6d000 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -99,19 +99,6 @@ void fuse_request_free(struct fuse_req *req)
>   	kmem_cache_free(fuse_req_cachep, req);
>   }
>   
> -static void block_sigs(sigset_t *oldset)
> -{
> -	sigset_t mask;
> -
> -	siginitsetinv(&mask, sigmask(SIGKILL));
> -	sigprocmask(SIG_BLOCK, &mask, oldset);
> -}
> -
> -static void restore_sigs(sigset_t *oldset)
> -{
> -	sigprocmask(SIG_SETMASK, oldset, NULL);
> -}
> -
>   void __fuse_get_request(struct fuse_req *req)
>   {
>   	atomic_inc(&req->count);
> @@ -144,15 +131,9 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
>   	atomic_inc(&fc->num_waiting);
>   
>   	if (fuse_block_alloc(fc, for_background)) {
> -		sigset_t oldset;
> -		int intr;
> -
> -		block_sigs(&oldset);
> -		intr = wait_event_interruptible_exclusive(fc->blocked_waitq,
> -				!fuse_block_alloc(fc, for_background));
> -		restore_sigs(&oldset);
>   		err = -EINTR;
> -		if (intr)
> +		if (wait_event_killable_exclusive(fc->blocked_waitq,
> +				!fuse_block_alloc(fc, for_background)))
>   			goto out;
>   	}
>   
> @@ -412,6 +393,19 @@ __acquires(fc->lock)
>   	spin_lock(&fc->lock);
>   }
>   
> +static void wait_answer_killable(struct fuse_conn *fc,
> +				 struct fuse_req *req)
> +__releases(fc->lock)
> +__acquires(fc->lock)
> +{
> +	if (fatal_signal_pending(current))
> +		return;
> +
> +	spin_unlock(&fc->lock);
> +	wait_event_killable(req->waitq, req->state == FUSE_REQ_FINISHED);
> +	spin_lock(&fc->lock);
> +}
> +
>   static void queue_interrupt(struct fuse_conn *fc, struct fuse_req *req)
>   {
>   	list_add_tail(&req->intr_entry, &fc->interrupts);
> @@ -438,12 +432,8 @@ __acquires(fc->lock)
>   	}
>   
>   	if (!req->force) {
> -		sigset_t oldset;
> -
>   		/* Only fatal signals may interrupt this */
> -		block_sigs(&oldset);
> -		wait_answer_interruptible(fc, req);
> -		restore_sigs(&oldset);
> +		wait_answer_killable(fc, req);
>   
>   		if (req->aborted)
>   			goto aborted;
>
> _______________________________________________
> Devel mailing list
> Devel at openvz.org
> https://lists.openvz.org/mailman/listinfo/devel



More information about the Devel mailing list