fix
authorMiklos Szeredi <miklos@szeredi.hu>
Thu, 12 May 2005 14:56:34 +0000 (14:56 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Thu, 12 May 2005 14:56:34 +0000 (14:56 +0000)
ChangeLog
configure.in
kernel/configure.ac
kernel/dev.c
kernel/dir.c
kernel/file.c
kernel/fuse_i.h
kernel/inode.c

index faf520a5431696f9c4b8a3b28ba57b4d67d4bb6b..5818732e88f99681087c81bf7cc1286b7557b74d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2005-05-12  Miklos Szeredi <miklos@szeredi.hu>
+
+       * File save in krusader and other editors doesn't work with sshfs,
+       because open() is interrupted by a periodic signal, and open()
+       restarts forever, without any progress.  This could just be fixed
+       in open(), but the problem is more generic: if signals are
+       received more often than the filesystem can get the request to
+       userspace, it will never finish.  This is probably only a
+       theoretical problem, nevertheless I'm removing the possibility to
+       interrupt requests with anything other than SIGKILL, even before
+       being sent to userspace.  Bugreport by Eduard Czimbalmos.
+
 2005-05-09  Miklos Szeredi <miklos@szeredi.hu>
 
        * libfuse: add "tree_lock" rwlock, that is locked for write in
index 014ddda9e8f6cd56ebc30ce440b2a3dcf2a18c0a..93493702dbbc20f209fef36a2c2e4d573cb115a6 100644 (file)
@@ -1,4 +1,4 @@
-AC_INIT(fuse, 2.3-pre7)
+AC_INIT(fuse, 2.3-pre8)
 AM_INIT_AUTOMAKE
 AM_CONFIG_HEADER(include/config.h)
 
index 55c876f1400a6b5acd81a540a2d88aae446a50f0..f7f2a60b52c32db62b31b4c90fdee2fabcd14377 100644 (file)
@@ -1,4 +1,4 @@
-AC_INIT(fuse-kernel, 2.3-pre7)
+AC_INIT(fuse-kernel, 2.3-pre8)
 AC_CONFIG_HEADERS([config.h])
 
 AC_PROG_INSTALL
index d64423e1e44667019c266cd12796a2c03e7364fd..0bad23638a0c567d9e484f0f6d93a216489e8da1 100644 (file)
@@ -139,19 +139,8 @@ static struct fuse_req *do_get_request(struct fuse_conn *fc)
        return req;
 }
 
+/* This can return NULL, but only in case it's interrupted by a SIGKILL */
 struct fuse_req *fuse_get_request(struct fuse_conn *fc)
-{
-       if (down_interruptible(&fc->outstanding_sem))
-               return NULL;
-       return do_get_request(fc);
-}
-
-/*
- * Non-interruptible version of the above function is for operations
- * which can't legally return -ERESTART{SYS,NOINTR}.  This can still
- * return NULL, but only in case the signal is SIGKILL.
- */
-struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc)
 {
        int intr;
        sigset_t oldset;
@@ -277,43 +266,20 @@ static void background_request(struct fuse_conn *fc, struct fuse_req *req)
                get_file(req->file);
 }
 
-static int request_wait_answer_nonint(struct fuse_req *req)
-{
-       int err;
-       sigset_t oldset;
-       block_sigs(&oldset);
-       err = wait_event_interruptible(req->waitq, req->finished);
-       restore_sigs(&oldset);
-       return err;
-}
-
 /* Called with fuse_lock held.  Releases, and then reacquires it. */
-static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req,
-                               int interruptible)
+static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
 {
-       int intr;
+       sigset_t oldset;
 
        spin_unlock(&fuse_lock);
-       if (interruptible)
-               intr = wait_event_interruptible(req->waitq, req->finished);
-       else
-               intr = request_wait_answer_nonint(req);
+       block_sigs(&oldset);
+       wait_event_interruptible(req->waitq, req->finished);
+       restore_sigs(&oldset);
        spin_lock(&fuse_lock);
-       if (intr && interruptible && req->sent) {
-               /* If request is already in userspace, only allow KILL
-                  signal to interrupt */
-               spin_unlock(&fuse_lock);
-               intr = request_wait_answer_nonint(req);
-               spin_lock(&fuse_lock);
-       }
-       if (!intr)
+       if (req->finished)
                return;
 
-       if (!interruptible || req->sent)
-               req->out.h.error = -EINTR;
-       else
-               req->out.h.error = -ERESTARTNOINTR;
-
+       req->out.h.error = -EINTR;
        req->interrupted = 1;
        if (req->locked) {
                /* This is uninterruptible sleep, because data is
@@ -366,8 +332,10 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
        wake_up(&fc->waitq);
 }
 
-static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req,
-                             int interruptible)
+/*
+ * This can only be interrupted by a SIGKILL
+ */
+void request_send(struct fuse_conn *fc, struct fuse_req *req)
 {
        req->isreply = 1;
        spin_lock(&fuse_lock);
@@ -381,26 +349,11 @@ static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req,
                   after request_end() */
                __fuse_get_request(req);
 
-               request_wait_answer(fc, req, interruptible);
+               request_wait_answer(fc, req);
        }
        spin_unlock(&fuse_lock);
 }
 
-void request_send(struct fuse_conn *fc, struct fuse_req *req)
-{
-       request_send_wait(fc, req, 1);
-}
-
-/*
- * Non-interruptible version of the above function is for operations
- * which can't legally return -ERESTART{SYS,NOINTR}.  This can still
- * be interrupted but only with SIGKILL.
- */
-void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req)
-{
-       request_send_wait(fc, req, 0);
-}
-
 static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
 {
        spin_lock(&fuse_lock);
index 078d517c0f6b8d946044ce5f6600670c46c325c1..99192c30665709fb69be2aa7616c1e6ede72a904 100644 (file)
@@ -52,12 +52,12 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
                struct inode *inode = entry->d_inode;
                struct fuse_inode *fi = get_fuse_inode(inode);
                struct fuse_conn *fc = get_fuse_conn(inode);
-               struct fuse_req *req = fuse_get_request_nonint(fc);
+               struct fuse_req *req = fuse_get_request(fc);
                if (!req)
                        return 0;
 
                fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
-               request_send_nonint(fc, req);
+               request_send(fc, req);
                err = req->out.h.error;
                if (!err) {
                        if (outarg.nodeid != get_node_id(inode)) {
@@ -107,7 +107,7 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
 
        req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        fuse_lookup_init(req, dir, entry, &outarg);
        request_send(fc, req);
@@ -201,7 +201,7 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
        struct fuse_conn *fc = get_fuse_conn(dir);
        struct fuse_req *req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.mode = mode;
@@ -227,7 +227,7 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
        struct fuse_conn *fc = get_fuse_conn(dir);
        struct fuse_req *req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.mode = mode;
@@ -252,7 +252,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
 
        req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        req->in.h.opcode = FUSE_SYMLINK;
        req->in.numargs = 2;
@@ -269,7 +269,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
        struct fuse_conn *fc = get_fuse_conn(dir);
        struct fuse_req *req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        req->in.h.opcode = FUSE_UNLINK;
        req->in.h.nodeid = get_node_id(dir);
@@ -300,7 +300,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
        struct fuse_conn *fc = get_fuse_conn(dir);
        struct fuse_req *req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        req->in.h.opcode = FUSE_RMDIR;
        req->in.h.nodeid = get_node_id(dir);
@@ -327,7 +327,7 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
        struct fuse_conn *fc = get_fuse_conn(olddir);
        struct fuse_req *req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.newdir = get_node_id(newdir);
@@ -372,7 +372,7 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
        struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_req *req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.oldnodeid = get_node_id(inode);
@@ -402,7 +402,7 @@ int fuse_do_getattr(struct inode *inode)
        struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_req *req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        req->in.h.opcode = FUSE_GETATTR;
        req->in.h.nodeid = get_node_id(inode);
@@ -562,7 +562,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
        struct page *page;
        struct inode *inode = file->f_dentry->d_inode;
        struct fuse_conn *fc = get_fuse_conn(inode);
-       struct fuse_req *req = fuse_get_request_nonint(fc);
+       struct fuse_req *req = fuse_get_request(fc);
        if (!req)
                return -EINTR;
 
@@ -592,7 +592,7 @@ static char *read_link(struct dentry *dentry)
        char *link;
 
        if (!req)
-               return ERR_PTR(-ERESTARTNOINTR);
+               return ERR_PTR(-EINTR);
 
        link = (char *) __get_free_page(GFP_KERNEL);
        if (!link) {
@@ -738,7 +738,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
 
        req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.valid = iattr_to_fattr(attr, &inarg.attr);
@@ -871,7 +871,7 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
 
        req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.size = size;
@@ -911,7 +911,7 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
 
        req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.size = size;
@@ -961,7 +961,7 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
 
        req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.size = size;
@@ -1007,7 +1007,7 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
 
        req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTNOINTR;
+               return -EINTR;
 
        req->in.h.opcode = FUSE_REMOVEXATTR;
        req->in.h.nodeid = get_node_id(inode);
index 6fee83eb5233e0ecada255a8d029bedbd0b9dcca..5ebf025c8f51cc992e1c3dad7cbfc3261577091a 100644 (file)
@@ -24,9 +24,6 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
        struct fuse_open_out outarg;
        struct fuse_file *ff;
        int err;
-       /* Restarting the syscall is not allowed if O_CREAT and O_EXCL
-          are both set, because creation will fail on the restart */
-       int excl = (file->f_flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL);
 
        err = generic_file_open(inode, file);
        if (err)
@@ -40,12 +37,9 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
                        return err;
        }
 
-       if (excl)
-               req = fuse_get_request_nonint(fc);
-       else
-               req = fuse_get_request(fc);
+       req = fuse_get_request(fc);
        if (!req)
-               return excl ? -EINTR : -ERESTARTSYS;
+               return -EINTR;
 
        err = -ENOMEM;
        ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
@@ -69,10 +63,7 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
        req->out.numargs = 1;
        req->out.args[0].size = sizeof(outarg);
        req->out.args[0].value = &outarg;
-       if (excl)
-               request_send_nonint(fc, req);
-       else
-               request_send(fc, req);
+       request_send(fc, req);
        err = req->out.h.error;
        if (!err && !(fc->flags & FUSE_KERNEL_CACHE))
 #ifdef KERNEL_2_6
@@ -137,7 +128,7 @@ static int fuse_flush(struct file *file)
        if (fc->no_flush)
                return 0;
 
-       req = fuse_get_request_nonint(fc);
+       req = fuse_get_request(fc);
        if (!req)
                return -EINTR;
 
@@ -150,7 +141,7 @@ static int fuse_flush(struct file *file)
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
-       request_send_nonint(fc, req);
+       request_send(fc, req);
        err = req->out.h.error;
        fuse_put_request(fc, req);
        if (err == -ENOSYS) {
@@ -175,7 +166,7 @@ int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
 
        req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTSYS;
+               return -EINTR;
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.fh = ff->fh;
@@ -228,7 +219,7 @@ size_t fuse_send_read_common(struct fuse_req *req, struct file *file,
        req->out.argvar = 1;
        req->out.numargs = 1;
        req->out.args[0].size = count;
-       request_send_nonint(fc, req);
+       request_send(fc, req);
        return req->out.args[0].size;
 }
 
@@ -244,7 +235,7 @@ static int fuse_readpage(struct file *file, struct page *page)
        struct inode *inode = page->mapping->host;
        struct fuse_conn *fc = get_fuse_conn(inode);
        loff_t pos = (loff_t) page->index << PAGE_CACHE_SHIFT;
-       struct fuse_req *req = fuse_get_request_nonint(fc);
+       struct fuse_req *req = fuse_get_request(fc);
        int err = -EINTR;
        if (!req)
                goto out;
@@ -318,7 +309,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping,
        int err;
        data.file = file;
        data.inode = inode;
-       data.req = fuse_get_request_nonint(fc);
+       data.req = fuse_get_request(fc);
        if (!data.req)
                return -EINTR;
 
@@ -411,7 +402,7 @@ static int fuse_file_bigread(struct file *file, struct inode *inode,
 
        req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTSYS;
+               return -EINTR;
 
        for (; starti < endi; starti = nexti) {
                nexti = starti + (FUSE_BLOCK_SIZE >> PAGE_CACHE_SHIFT);
@@ -452,7 +443,7 @@ static size_t fuse_send_write(struct fuse_req *req, struct file *file,
        req->out.numargs = 1;
        req->out.args[0].size = sizeof(struct fuse_write_out);
        req->out.args[0].value = &outarg;
-       request_send_nonint(fc, req);
+       request_send(fc, req);
        return outarg.size;
 }
 
@@ -472,7 +463,7 @@ static int fuse_commit_write(struct file *file, struct page *page,
        struct inode *inode = page->mapping->host;
        struct fuse_conn *fc = get_fuse_conn(inode);
        loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset;
-       struct fuse_req *req = fuse_get_request_nonint(fc);
+       struct fuse_req *req = fuse_get_request(fc);
        if (!req)
                return -EINTR;
 
@@ -546,7 +537,7 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
        ssize_t res = 0;
        struct fuse_req *req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTSYS;
+               return -EINTR;
 
        while (count) {
                size_t tmp;
index 6ba851e3f3405cb25d0820bca66dd6f982797302..c579a696acdf09da3360dcbb8f9b9ef759313280 100644 (file)
@@ -485,11 +485,6 @@ void fuse_reset_request(struct fuse_req *req);
  */
 struct fuse_req *fuse_get_request(struct fuse_conn *fc);
 
-/**
- * Reserve a preallocated request, only interruptible by SIGKILL
- */
-struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc);
-
 /**
  * Decrement reference count of a request.  If count goes to zero put
  * on unused list (preallocated) or free reqest (not preallocated).
@@ -497,15 +492,10 @@ struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc);
 void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req);
 
 /**
- * Send a request (synchronous, interruptible)
+ * Send a request (synchronous)
  */
 void request_send(struct fuse_conn *fc, struct fuse_req *req);
 
-/**
- * Send a request (synchronous, non-interruptible except by SIGKILL)
- */
-void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req);
-
 /**
  * Send a request with no reply
  */
index 4c36ad04f1ae83a45addd0c74a82fac3ebf406b5..ed14602cc1e2d4e2cf20788c83885f5547ad27bd 100644 (file)
@@ -299,7 +299,7 @@ static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
 
         req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTSYS;
+               return -EINTR;
 
        req->in.numargs = 0;
        req->in.h.opcode = FUSE_STATFS;