From: Miklos Szeredi Date: Wed, 27 May 2009 10:24:15 +0000 (+0000) Subject: * kernel: Don't set 'aborted' flag on a request if it's X-Git-Tag: fuse_2_7_5~4 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=2f8f3e78c8f9eb29b112fab12d97cff6fd487063;p=qemu-gpiodev%2Flibfuse.git * kernel: Don't set 'aborted' flag on a request if it's interrupted (commit a131de0a). Reported and tested by John Haxby * Don't call forget_node() if the lookup was negative and write() for the reply returned ENOENT. Reported by John Haxby --- diff --git a/ChangeLog b/ChangeLog index aa93730..1575f2c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2009-05-27 Miklos Szeredi + + * kernel: Don't set 'aborted' flag on a request if it's + interrupted (commit a131de0a). Reported and tested by John Haxby + + * Don't call forget_node() if the lookup was negative and write() + for the reply returned ENOENT. Reported by John Haxby + 2008-07-25 Miklos Szeredi * Released 2.7.4 diff --git a/kernel/dev.c b/kernel/dev.c index f8b7f3a..568f91b 100644 --- a/kernel/dev.c +++ b/kernel/dev.c @@ -274,28 +274,41 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) queue_interrupt(fc, req); } - if (req->force) { - spin_unlock(&fc->lock); - wait_event(req->waitq, req->state == FUSE_REQ_FINISHED); - spin_lock(&fc->lock); - } else { + if (!req->force) { sigset_t oldset; /* Only fatal signals may interrupt this */ block_sigs(&oldset); wait_answer_interruptible(fc, req); 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; - if (req->state == FUSE_REQ_FINISHED) - return; + /* + * Either request is already in userspace, or it was forced. + * Wait it out. + */ + spin_unlock(&fc->lock); + wait_event(req->waitq, req->state == FUSE_REQ_FINISHED); + spin_lock(&fc->lock); - req->out.h.error = -EINTR; - req->aborted = 1; + if (!req->aborted) + return; aborted: + BUG_ON(req->state != FUSE_REQ_FINISHED); if (req->locked) { /* This is uninterruptible sleep, because data is being copied to/from the buffers of req. During @@ -306,14 +319,6 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) wait_event(req->waitq, !req->locked); 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) diff --git a/lib/fuse.c b/lib/fuse.c index fc4d967..ce988fb 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -1317,8 +1317,11 @@ static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e, { if (!err) { struct fuse *f = req_fuse(req); - if (fuse_reply_entry(req, e) == -ENOENT) - forget_node(f, e->ino, 1); + if (fuse_reply_entry(req, e) == -ENOENT) { + /* Skip forget for negative result */ + if (e->ino != 0) + forget_node(f, e->ino, 1); + } } else reply_err(req, err); }