aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--example/Makefile.am2
-rw-r--r--kernel/configure.ac2
-rw-r--r--kernel/dev.c37
-rw-r--r--kernel/fuse_i.h16
-rw-r--r--kernel/inode.c10
-rw-r--r--lib/fuse_mt.c6
7 files changed, 75 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index 4fb2bab..4aa92de 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2005-03-19 Miklos Szeredi <miklos@szeredi.hu>
+
+ * kernel: add locking to background list (fixes previous fix)
+
+2005-03-18 Miklos Szeredi <miklos@szeredi.hu>
+
+ * kernel: fix bug which could cause leave busy inodes after
+ unmount, and Oops.
+
+2005-03-08 Miklos Szeredi <miklos@szeredi.hu>
+
+ * 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 <miklos@szeredi.hu>
* 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
@@ -489,6 +500,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
*/
int fuse_do_getattr(struct inode *inode);
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 <stdlib.h>
#include <string.h>
#include <pthread.h>
+#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/time.h>
@@ -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;
}