[Devel] [PATCH] fs/fuse: move FUSE_S_FAIL_IMMEDIATELY check before kio req send
Pavel Butsykin
pbutsykin at virtuozzo.com
Wed Jan 23 20:22:33 MSK 2019
23.01.2019 16:55, Kirill Tkhai пишет:
> On 23.01.2019 14:49, Pavel Butsykin wrote:
>> Fuse file with FUSE_S_FAIL_IMMEDIATELY state should not allow to execute new
>> requests. But in case of kio requests it doesn't work because the status check
>> is located behind kio.op->req_send(). To fix this let's move the status check
>> before kio.op->req_send().
>>
>> Note: We can drop hunk with req->end(fc, req) in __fuse_request_send() because
>> it was only needed to clenup kio setattr request after pcs_kio_setattr_handle().
>>
>> Signed-off-by: Pavel Butsykin <pbutsykin at virtuozzo.com>
> Why is this safe?
>
> After you move the check out of fc->lock, it becomes racy, and fuse_invalidate_files()
> may become work not as expected.
test_bit is atomic operation. Which type of race do you mean?
>> ---
>> fs/fuse/dev.c | 40 +++++++++++++++++++++++-----------------
>> 1 file changed, 23 insertions(+), 17 deletions(-)
>>
>> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
>> index dc21886ee55d..dcbed5d4932c 100644
>> --- a/fs/fuse/dev.c
>> +++ b/fs/fuse/dev.c
>> @@ -538,6 +538,11 @@ static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req,
>>
>> BUG_ON(test_bit(FR_BACKGROUND, &req->flags));
>>
>> + if (ff && test_bit(FUSE_S_FAIL_IMMEDIATELY, &ff->ff_state)) {
>> + req->out.h.error = -EIO;
>> + return;
>> + }
>> +
>> if (fc->kio.op && !fc->kio.op->req_send(fc, req, false, false))
>> return;
>>
>> @@ -547,11 +552,6 @@ static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req,
>> req->out.h.error = -ENOTCONN;
>> if (req->end)
>> req->end(fc, req);
>> - } else if (ff && test_bit(FUSE_S_FAIL_IMMEDIATELY, &ff->ff_state)) {
>> - spin_unlock(&fiq->waitq.lock);
>> - req->out.h.error = -EIO;
>> - if (req->end)
>> - req->end(fc, req);
>> } else {
>> req->in.h.unique = fuse_get_unique(fiq);
>> queue_request(fiq, req);
>> @@ -627,20 +627,26 @@ void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req)
>> {
>> BUG_ON(!req->end);
>>
>> - if (fc->kio.op && !fc->kio.op->req_send(fc, req, true, false))
>> - return;
>> -
>> - spin_lock(&fc->lock);
>> if (req->page_cache && req->ff &&
>> test_bit(FUSE_S_FAIL_IMMEDIATELY, &req->ff->ff_state)) {
>> - BUG_ON(req->in.h.opcode != FUSE_READ);
>> - req->out.h.error = -EIO;
>> - __clear_bit(FR_BACKGROUND, &req->flags);
>> - __clear_bit(FR_PENDING, &req->flags);
>> - list_del_init(&req->list);
>> - spin_unlock(&fc->lock);
>> - request_end(fc, req);
>> - } else if (fc->connected) {
>> + BUG_ON(req->in.h.opcode != FUSE_READ);
>> + req->out.h.error = -EIO;
>> + __clear_bit(FR_BACKGROUND, &req->flags);
>> + __clear_bit(FR_PENDING, &req->flags);
>> +
>> + spin_lock(&fc->lock);
>> + list_del_init(&req->list);
>> + spin_unlock(&fc->lock);
>> +
>> + request_end(fc, req);
>> + return;
>> + }
>> +
>> + if (fc->kio.op && !fc->kio.op->req_send(fc, req, true, false))
>> + return;
>> +
>> + spin_lock(&fc->lock);
>> + if (fc->connected) {
>> fuse_request_send_background_locked(fc, req);
>> spin_unlock(&fc->lock);
>> } else {
>>
More information about the Devel
mailing list