diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2004-11-11 14:01:09 +0000 |
---|---|---|
committer | Miklos Szeredi <miklos@szeredi.hu> | 2004-11-11 14:01:09 +0000 |
commit | 0e97c2ef2493df4ad109d75dc443a9f79357d050 (patch) | |
tree | 773405cd4c9ab7ff152c85dadf55b0024f5f849b | |
parent | d1a835e7a5624c7ce265f8e523599b2285c70c85 (diff) | |
download | fuse-0e97c2ef2493df4ad109d75dc443a9f79357d050.tar.gz |
fix
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | kernel/dev.c | 7 | ||||
-rw-r--r-- | kernel/fuse_i.h | 3 | ||||
-rw-r--r-- | kernel/inode.c | 7 |
4 files changed, 20 insertions, 3 deletions
@@ -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; |