summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2004-11-11 14:01:09 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2004-11-11 14:01:09 +0000
commit0e97c2ef2493df4ad109d75dc443a9f79357d050 (patch)
tree773405cd4c9ab7ff152c85dadf55b0024f5f849b
parentd1a835e7a5624c7ce265f8e523599b2285c70c85 (diff)
downloadfuse-0e97c2ef2493df4ad109d75dc443a9f79357d050.tar.gz
fix
-rw-r--r--ChangeLog6
-rw-r--r--kernel/dev.c7
-rw-r--r--kernel/fuse_i.h3
-rw-r--r--kernel/inode.c7
4 files changed, 20 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index c6a68e2..055c6f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,12 @@
-2004-11-10 Miklos Szeredi <miklos@szeredi.hu>
+2004-11-11 Miklos Szeredi <miklos@szeredi.hu>
* Check kernel interface version in fusermount to prevent
strangeness in case of mismatch.
+ * Fix potential race between umount and fuse_invalidate
+
+ * Check superblock of proc file in addition to inode number
+
2004-11-10 Miklos Szeredi <miklos@szeredi.hu>
* Released 2.1-pre0
diff --git a/kernel/dev.c b/kernel/dev.c
index c87d6c4..fca6c20 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -479,7 +479,11 @@ static int fuse_user_request(struct fuse_conn *fc, const char *buf,
switch (uh.opcode) {
case FUSE_INVALIDATE:
- err = fuse_invalidate(fc, &uh);
+ down(&fc->sb_sem);
+ err = -ENODEV;
+ if (fc->sb)
+ err = fuse_invalidate(fc, &uh);
+ up(&fc->sb_sem);
break;
default:
@@ -602,6 +606,7 @@ static struct fuse_conn *new_conn(void)
INIT_LIST_HEAD(&fc->processing);
INIT_LIST_HEAD(&fc->unused_list);
sema_init(&fc->unused_sem, MAX_OUTSTANDING);
+ sema_init(&fc->sb_sem, 1);
for (i = 0; i < MAX_OUTSTANDING; i++) {
struct fuse_req *req = fuse_request_alloc();
if (!req) {
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index c74238b..c256bb2 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -224,6 +224,9 @@ struct fuse_conn {
/** Controls the maximum number of outstanding requests */
struct semaphore unused_sem;
+ /** Semaphore protecting the super block from going away */
+ struct semaphore sb_sem;
+
/** The list of unused requests */
struct list_head unused_list;
diff --git a/kernel/inode.c b/kernel/inode.c
index 8de566c..b11a8c2 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -123,8 +123,10 @@ static void fuse_put_super(struct super_block *sb)
{
struct fuse_conn *fc = SB_FC(sb);
+ down(&fc->sb_sem);
spin_lock(&fuse_lock);
fc->sb = NULL;
+ up(&fc->sb_sem);
fc->uid = 0;
fc->flags = 0;
/* Flush all readers on this fs */
@@ -311,7 +313,8 @@ static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
struct inode *ino;
ino = file->f_dentry->d_inode;
- if (!ino || !proc_fuse_dev || proc_fuse_dev->low_ino != ino->i_ino) {
+ if (!ino || !proc_fuse_dev || proc_mnt->mnt_sb != ino->i_sb ||
+ proc_fuse_dev->low_ino != ino->i_ino) {
printk("FUSE: bad communication file descriptor\n");
return NULL;
}
@@ -432,8 +435,10 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent)
return 0;
err:
+ down(&fc->sb_sem);
spin_lock(&fuse_lock);
fc->sb = NULL;
+ up(&fc->sb_sem);
fuse_release_conn(fc);
spin_unlock(&fuse_lock);
SB_FC(sb) = NULL;