From: Miklos Szeredi Date: Mon, 21 Mar 2005 11:47:04 +0000 (+0000) Subject: Merge 2_2_bugfix up to 2_2_merge1 X-Git-Tag: fuse_2_3_pre1~4 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=d17da46055903a517274b7823d41fdd866f48d8d;p=qemu-gpiodev%2Flibfuse.git Merge 2_2_bugfix up to 2_2_merge1 --- diff --git a/ChangeLog b/ChangeLog index 4fb2bab..4aa92de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2005-03-19 Miklos Szeredi + + * kernel: add locking to background list (fixes previous fix) + +2005-03-18 Miklos Szeredi + + * kernel: fix bug which could cause leave busy inodes after + unmount, and Oops. + +2005-03-08 Miklos Szeredi + + * examples: add -lpthread to link flags to work around valgrind + quirk + + * lib: don't exit threads, so cancelation doesn't cause segfault + 2005-03-04 Miklos Szeredi * kernel: fix nasty bug which could cause an Oops under certain diff --git a/example/Makefile.am b/example/Makefile.am index 475cabf..e8c8a6d 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -6,4 +6,4 @@ fusexmp_SOURCES = fusexmp.c null_SOURCES = null.c hello_SOURCES = hello.c -LDADD = ../lib/libfuse.la +LDADD = ../lib/libfuse.la -lpthread diff --git a/kernel/configure.ac b/kernel/configure.ac index a27ceca..62c2b2f 100644 --- a/kernel/configure.ac +++ b/kernel/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(fuse-kernel, 2.2.1) +AC_INIT(fuse-kernel, 2.2) AC_CONFIG_HEADERS([config.h]) AC_PROG_INSTALL diff --git a/kernel/dev.c b/kernel/dev.c index f3de9de..5941035 100644 --- a/kernel/dev.c +++ b/kernel/dev.c @@ -178,6 +178,19 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) fuse_putback_request(fc, req); } +void fuse_release_background(struct fuse_req *req) +{ + if (req->inode) + iput(req->inode); + if (req->inode2) + iput(req->inode2); + if (req->file) + fput(req->file); + spin_lock(&fuse_lock); + list_del(&req->bg_entry); + spin_unlock(&fuse_lock); +} + /* Called with fuse_lock, unlocks it */ static void request_end(struct fuse_conn *fc, struct fuse_req *req) { @@ -186,12 +199,10 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) putback = atomic_dec_and_test(&req->count); spin_unlock(&fuse_lock); if (req->background) { - if (req->inode) - iput(req->inode); - if (req->inode2) - iput(req->inode2); - if (req->file) - fput(req->file); + down_read(&fc->sbput_sem); + if (fc->sb) + fuse_release_background(req); + up_read(&fc->sbput_sem); } wake_up(&req->waitq); if (req->in.h.opcode == FUSE_INIT) { @@ -207,11 +218,12 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) fuse_putback_request(fc, req); } -static void background_request(struct fuse_req *req) +static void background_request(struct fuse_conn *fc, struct fuse_req *req) { /* Need to get hold of the inode(s) and/or file used in the request, so FORGET and RELEASE are not sent too early */ req->background = 1; + list_add(&req->bg_entry, &fc->background); if (req->inode) req->inode = igrab(req->inode); if (req->inode2) @@ -231,7 +243,8 @@ static int request_wait_answer_nonint(struct fuse_req *req) } /* Called with fuse_lock held. Releases, and then reacquires it. */ -static void request_wait_answer(struct fuse_req *req, int interruptible) +static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req, + int interruptible) { int intr; @@ -271,7 +284,7 @@ static void request_wait_answer(struct fuse_req *req, int interruptible) list_del(&req->list); __fuse_put_request(req); } else if (!req->finished && req->sent) - background_request(req); + background_request(fc, req); } static unsigned len_args(unsigned numargs, struct fuse_arg *args) @@ -315,7 +328,7 @@ static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req, after request_end() */ __fuse_get_request(req); - request_wait_answer(req, interruptible); + request_wait_answer(fc, req, interruptible); } spin_unlock(&fuse_lock); } @@ -351,7 +364,9 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) void request_send_background(struct fuse_conn *fc, struct fuse_req *req) { req->isreply = 1; - background_request(req); + spin_lock(&fuse_lock); + background_request(fc, req); + spin_unlock(&fuse_lock); request_send_nowait(fc, req); } diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index 4aa643b..d877071 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -190,6 +190,9 @@ struct fuse_req { lists in fuse_conn */ struct list_head list; + /** Entry on the background list */ + struct list_head bg_entry; + /** refcount */ atomic_t count; @@ -284,6 +287,10 @@ struct fuse_conn { /** The list of requests being processed */ struct list_head processing; + /** Requests put in the background (RELEASE or any other + interrupted request) */ + struct list_head background; + /** Controls the maximum number of outstanding requests */ struct semaphore outstanding_sem; @@ -291,6 +298,9 @@ struct fuse_conn { outstanding_sem would go negative */ unsigned outstanding_debt; + /** RW semaphore for exclusion with fuse_put_super() */ + struct rw_semaphore sbput_sem; + /** The list of unused requests */ struct list_head unused_list; @@ -361,6 +371,7 @@ extern struct file_operations fuse_dev_operations; * - the private_data field of the device file * - the s_fs_info field of the super block * - unused_list, pending, processing lists in fuse_conn + * - background list in fuse_conn * - the unique request ID counter reqctr in fuse_conn * - the sb (super_block) field in fuse_conn * - the file (device file) field in fuse_conn @@ -488,6 +499,11 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); */ void request_send_background(struct fuse_conn *fc, struct fuse_req *req); +/** + * Release inodes and file assiciated with background request + */ +void fuse_release_background(struct fuse_req *req); + /** * Get the attributes of a file */ diff --git a/kernel/inode.c b/kernel/inode.c index d935d58..1feaba9 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -100,7 +100,7 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, static void fuse_clear_inode(struct inode *inode) { struct fuse_conn *fc = get_fuse_conn(inode); - if (fc) { + if (fc && (inode->i_sb->s_flags & MS_ACTIVE)) { struct fuse_inode *fi = get_fuse_inode(inode); fuse_send_forget(fc, fi->forget_req, fi->nodeid, inode->i_version); fi->forget_req = NULL; @@ -254,12 +254,18 @@ static void fuse_put_super(struct super_block *sb) { struct fuse_conn *fc = get_fuse_conn_super(sb); + down_write(&fc->sbput_sem); + while (!list_empty(&fc->background)) + fuse_release_background(list_entry(fc->background.next, + struct fuse_req, bg_entry)); + spin_lock(&fuse_lock); fc->sb = NULL; fc->user_id = 0; fc->flags = 0; /* Flush all readers on this fs */ wake_up_all(&fc->waitq); + up_write(&fc->sbput_sem); fuse_release_conn(fc); *get_fuse_conn_super_p(sb) = NULL; spin_unlock(&fuse_lock); @@ -467,7 +473,9 @@ static struct fuse_conn *new_conn(void) INIT_LIST_HEAD(&fc->pending); INIT_LIST_HEAD(&fc->processing); INIT_LIST_HEAD(&fc->unused_list); + INIT_LIST_HEAD(&fc->background); sema_init(&fc->outstanding_sem, 0); + init_rwsem(&fc->sbput_sem); for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { struct fuse_req *req = fuse_request_alloc(); if (!req) { diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c index 2e43671..819a2b9 100644 --- a/lib/fuse_mt.c +++ b/lib/fuse_mt.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ static void *do_work(void *data) struct fuse_worker *w = (struct fuse_worker *) data; struct fuse *f = w->f; struct fuse_context *ctx; + int is_mainthread = (f->numworker == 1); ctx = (struct fuse_context *) malloc(sizeof(struct fuse_context)); if (ctx == NULL) { @@ -83,6 +85,10 @@ static void *do_work(void *data) w->proc(w->f, cmd, w->data); } + /* Wait for cancellation */ + if (!is_mainthread) + pause(); + return NULL; }