From: Miklos Szeredi Date: Thu, 11 Nov 2004 14:01:09 +0000 (+0000) Subject: fix X-Git-Tag: fuse_2_1_pre1~5 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=0e97c2ef2493df4ad109d75dc443a9f79357d050;p=qemu-gpiodev%2Flibfuse.git fix --- diff --git a/ChangeLog b/ChangeLog index c6a68e2..055c6f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,12 @@ -2004-11-10 Miklos Szeredi +2004-11-11 Miklos Szeredi * 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 * 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;