* kernel: Don't set 'aborted' flag on a request if it's
authorMiklos Szeredi <miklos@szeredi.hu>
Wed, 27 May 2009 10:24:15 +0000 (10:24 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Wed, 27 May 2009 10:24:15 +0000 (10:24 +0000)
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

ChangeLog
kernel/dev.c
lib/fuse.c

index aa93730e24cc95b7adea2f11fdc67ef01388d9a0..1575f2ce3576ba9a227b5933202c987b88afc743 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2009-05-27  Miklos Szeredi <miklos@szeredi.hu>
+
+       * 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 <miklos@szeredi.hu>
 
        * Released 2.7.4
index f8b7f3a9d84d5365c861aa6f6312bab237b7a1f5..568f91beed09f59462de0d637fe7285a100abc37 100644 (file)
@@ -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)
index fc4d9673b69e2d15e08a4d06ceec4e2545942c11..ce988fb2988c9e3023309ed3d55885660babf87e 100644 (file)
@@ -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);
 }