fuse: no abort on interrupt
Don't set 'aborted' flag on a request if it's interrupted. We have to wait for the answer anyway, and this would only a very little time while copying the reply. This means, that write() on the fuse device will not return -ENOENT during normal operation, only if the filesystem is aborted by a forced umount or through the fusectl interface. This could simplify userspace code somewhat when backward compatibility with earlier kernel versions is not required. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
819c4b3b40
commit
a131de0a48
@@ -273,28 +273,41 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
|
|||||||
queue_interrupt(fc, req);
|
queue_interrupt(fc, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req->force) {
|
if (!req->force) {
|
||||||
spin_unlock(&fc->lock);
|
|
||||||
wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
|
|
||||||
spin_lock(&fc->lock);
|
|
||||||
} else {
|
|
||||||
sigset_t oldset;
|
sigset_t oldset;
|
||||||
|
|
||||||
/* Only fatal signals may interrupt this */
|
/* Only fatal signals may interrupt this */
|
||||||
block_sigs(&oldset);
|
block_sigs(&oldset);
|
||||||
wait_answer_interruptible(fc, req);
|
wait_answer_interruptible(fc, req);
|
||||||
restore_sigs(&oldset);
|
restore_sigs(&oldset);
|
||||||
|
|
||||||
|
if (req->aborted)
|
||||||
|
goto aborted;
|
||||||
|
if (req->state == FUSE_REQ_FINISHED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Request is not yet in userspace, bail out */
|
||||||
|
if (req->state == FUSE_REQ_PENDING) {
|
||||||
|
list_del(&req->list);
|
||||||
|
__fuse_put_request(req);
|
||||||
|
req->out.h.error = -EINTR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req->aborted)
|
/*
|
||||||
goto aborted;
|
* Either request is already in userspace, or it was forced.
|
||||||
if (req->state == FUSE_REQ_FINISHED)
|
* Wait it out.
|
||||||
return;
|
*/
|
||||||
|
spin_unlock(&fc->lock);
|
||||||
|
wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
|
||||||
|
spin_lock(&fc->lock);
|
||||||
|
|
||||||
req->out.h.error = -EINTR;
|
if (!req->aborted)
|
||||||
req->aborted = 1;
|
return;
|
||||||
|
|
||||||
aborted:
|
aborted:
|
||||||
|
BUG_ON(req->state != FUSE_REQ_FINISHED);
|
||||||
if (req->locked) {
|
if (req->locked) {
|
||||||
/* This is uninterruptible sleep, because data is
|
/* This is uninterruptible sleep, because data is
|
||||||
being copied to/from the buffers of req. During
|
being copied to/from the buffers of req. During
|
||||||
@@ -305,14 +318,6 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
|
|||||||
wait_event(req->waitq, !req->locked);
|
wait_event(req->waitq, !req->locked);
|
||||||
spin_lock(&fc->lock);
|
spin_lock(&fc->lock);
|
||||||
}
|
}
|
||||||
if (req->state == FUSE_REQ_PENDING) {
|
|
||||||
list_del(&req->list);
|
|
||||||
__fuse_put_request(req);
|
|
||||||
} else if (req->state == FUSE_REQ_SENT) {
|
|
||||||
spin_unlock(&fc->lock);
|
|
||||||
wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
|
|
||||||
spin_lock(&fc->lock);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned len_args(unsigned numargs, struct fuse_arg *args)
|
static unsigned len_args(unsigned numargs, struct fuse_arg *args)
|
||||||
|
Reference in New Issue
Block a user