From f94e0100733292563be8699b502bebaa5c170dd6 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Thu, 12 May 2005 14:56:34 +0000 Subject: [PATCH] fix --- ChangeLog | 12 ++++++++ configure.in | 2 +- kernel/configure.ac | 2 +- kernel/dev.c | 73 ++++++++------------------------------------- kernel/dir.c | 36 +++++++++++----------- kernel/file.c | 35 ++++++++-------------- kernel/fuse_i.h | 12 +------- kernel/inode.c | 2 +- 8 files changed, 60 insertions(+), 114 deletions(-) diff --git a/ChangeLog b/ChangeLog index faf520a..5818732 100644 --- 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 diff --git a/configure.in b/configure.in index 014ddda..9349370 100644 --- a/configure.in +++ b/configure.in @@ -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) diff --git a/kernel/configure.ac b/kernel/configure.ac index 55c876f..f7f2a60 100644 --- a/kernel/configure.ac +++ b/kernel/configure.ac @@ -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 diff --git a/kernel/dev.c b/kernel/dev.c index d64423e..0bad236 100644 --- a/kernel/dev.c +++ b/kernel/dev.c @@ -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); diff --git a/kernel/dir.c b/kernel/dir.c index 078d517..99192c3 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -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); diff --git a/kernel/file.c b/kernel/file.c index 6fee83e..5ebf025 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -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; diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index 6ba851e..c579a69 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -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 */ diff --git a/kernel/inode.c b/kernel/inode.c index 4c36ad0..ed14602 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -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; -- 2.30.2