diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2006-04-26 10:49:16 +0200 |
---|---|---|
committer | Miklos Szeredi <miklos@szeredi.hu> | 2006-04-26 10:49:16 +0200 |
commit | 8aa09a50b5d9dbdf627f79e19d72d82994348089 (patch) | |
tree | 5b50a1b62c8b95223023053595c452b0641f5767 /fs/fuse | |
parent | [fuse] fix deadlock between fuse_put_super() and request_end(), try #2 (diff) | |
download | linux-8aa09a50b5d9dbdf627f79e19d72d82994348089.tar.xz linux-8aa09a50b5d9dbdf627f79e19d72d82994348089.zip |
[fuse] fix race between checking and setting file->private_data
BKL does not protect against races if the task may sleep between
checking and setting a value. So move checking of file->private_data
near to setting it in fuse_fill_super().
Found by Al Viro.
Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/inode.c | 13 |
1 files changed, 8 insertions, 5 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index fd34037b0588..7627022446b2 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -500,11 +500,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) if (file->f_op != &fuse_dev_operations) return -EINVAL; - /* Setting file->private_data can't race with other mount() - instances, since BKL is held for ->get_sb() */ - if (file->private_data) - return -EINVAL; - fc = new_conn(); if (!fc) return -ENOMEM; @@ -540,6 +535,12 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) if (err) goto err_free_req; + /* Setting file->private_data can't race with other mount() + instances, since BKL is held for ->get_sb() */ + err = -EINVAL; + if (file->private_data) + goto err_kobject_del; + sb->s_root = root_dentry; fc->mounted = 1; fc->connected = 1; @@ -556,6 +557,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) return 0; + err_kobject_del: + kobject_del(&fc->kobj); err_free_req: fuse_request_free(init_req); err_put_root: |