aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--README2
-rw-r--r--kernel/dev.c6
-rw-r--r--kernel/file.c11
4 files changed, 20 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 3b2f2d9..f3c3e89 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2006-02-16 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Fix rare race betweeen abort and release caused by failed iget()
+ in fuse_create_open().
+
2006-02-15 Miklos Szeredi <miklos@szeredi.hu>
* Work around FreeBSD runtime linker "feature" which binds an old
diff --git a/README b/README
index 4c5517a..6333943 100644
--- a/README
+++ b/README
@@ -44,7 +44,7 @@ be compiled. It is possible to override this with the
If './configure' cannot find the kernel source or it says the kernel
source should be prepared, you may either try
- ./configure--disable-kernel-module
+ ./configure --disable-kernel-module
or if your kernel does not already contain FUSE support, do the
following:
diff --git a/kernel/dev.c b/kernel/dev.c
index d8b5683..d35fc07 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -106,6 +106,12 @@ static void restore_sigs(sigset_t *oldset)
#endif
#endif
+/*
+ * Reset request, so that it can be reused
+ *
+ * The caller must be _very_ careful to make sure, that it is holding
+ * the only reference to req
+ */
void fuse_reset_request(struct fuse_req *req)
{
int preallocated = req->preallocated;
diff --git a/kernel/file.c b/kernel/file.c
index be9cc39..77c540e 100644
--- a/kernel/file.c
+++ b/kernel/file.c
@@ -130,9 +130,14 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
/* Special case for failed iget in CREATE */
static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
{
- u64 nodeid = req->in.h.nodeid;
- fuse_reset_request(req);
- fuse_send_forget(fc, req, nodeid, 1);
+ /* If called from end_io_requests(), req has more than one
+ reference and fuse_reset_request() cannot work */
+ if (fc->connected) {
+ u64 nodeid = req->in.h.nodeid;
+ fuse_reset_request(req);
+ fuse_send_forget(fc, req, nodeid, 1);
+ } else
+ fuse_put_request(fc, req);
}
void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff,