aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2004-06-20 08:57:39 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2004-06-20 08:57:39 +0000
commited62d86dc82e1c729aa8cc95d6d1e5a743e4a2a7 (patch)
tree5ea67e569cdb519c9e1eeddce9545ddda57ecdda
parent7eafccef7f5788e54efa5318d9f5af13a0cbd291 (diff)
downloadlibfuse-ed62d86dc82e1c729aa8cc95d6d1e5a743e4a2a7.tar.gz
fixes and cleanups
-rw-r--r--ChangeLog4
-rw-r--r--kernel/inode.c57
2 files changed, 35 insertions, 26 deletions
diff --git a/ChangeLog b/ChangeLog
index 4126df2..6a595fb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2004-06-20 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Fix some races and cleanups in fuse_read_super()
+
2004-06-19 Miklos Szeredi <mszeredi@inf.bme.hu>
* Requests are allocated at open time
diff --git a/kernel/inode.c b/kernel/inode.c
index 89b6da6..d04d636 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -204,28 +204,23 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
return 0;
}
-static struct fuse_conn *get_conn(int fd)
+static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
{
- struct fuse_conn *fc = NULL;
- struct file *file;
+ struct fuse_conn *fc;
struct inode *ino;
- file = fget(fd);
- ino = NULL;
- if (file)
- ino = file->f_dentry->d_inode;
-
+ ino = file->f_dentry->d_inode;
if (!ino || !proc_fuse_dev || proc_fuse_dev->low_ino != ino->i_ino) {
- printk("FUSE: bad communication file descriptor: %i\n", fd);
- goto out;
+ printk("FUSE: bad communication file descriptor\n");
+ return NULL;
}
-
fc = file->private_data;
-
- out:
- fput(file);
+ if (fc->sb != NULL) {
+ printk("fuse_read_super: connection already mounted\n");
+ return NULL;
+ }
+ fc->sb = sb;
return fc;
-
}
static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
@@ -282,6 +277,7 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent)
struct fuse_conn *fc;
struct inode *root;
struct fuse_mount_data d;
+ struct file *file;
if (!parse_fuse_opt((char *) data, &d))
return -EINVAL;
@@ -298,20 +294,19 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent)
sb->s_export_op = &fuse_export_operations;
#endif
- fc = get_conn(d.fd);
- if (fc == NULL)
+ file = fget(d.fd);
+ if (!file)
return -EINVAL;
spin_lock(&fuse_lock);
- if (fc->sb != NULL) {
- printk("fuse_read_super: connection already mounted\n");
- spin_unlock(&fuse_lock);
+ fc = get_conn(file, sb);
+ spin_unlock(&fuse_lock);
+ fput(file);
+ if (fc == NULL)
return -EINVAL;
- }
- fc->sb = sb;
+
fc->flags = d.flags;
fc->uid = d.uid;
- spin_unlock(&fuse_lock);
/* fc is needed in fuse_init_file_inode which could be called
from get_root_inode */
@@ -320,14 +315,24 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent)
root = get_root_inode(sb, d.rootmode);
if (root == NULL) {
printk("fuse_read_super: failed to get root inode\n");
- return -EINVAL;
+ goto err;
}
sb->s_root = d_alloc_root(root);
- if (!sb->s_root)
- return -EINVAL;
+ if (!sb->s_root) {
+ iput(root);
+ goto err;
+ }
return 0;
+
+ err:
+ spin_lock(&fuse_lock);
+ fc->sb = NULL;
+ fuse_release_conn(fc);
+ spin_unlock(&fuse_lock);
+ SB_FC(sb) = NULL;
+ return -EINVAL;
}
#ifdef KERNEL_2_6