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

Konstantin Khorenko khorenko at virtuozzo.com
Mon Oct 17 08:01:26 PDT 2016


On 10/17/2016 03:01 PM, Stanislav Kinsburskiy wrote:
> 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

done, thank you.

>
> 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
>
> _______________________________________________
> Devel mailing list
> Devel at openvz.org
> https://lists.openvz.org/mailman/listinfo/devel
>


More information about the Devel mailing list