aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/dir.c91
-rw-r--r--kernel/fuse_i.h2
-rw-r--r--kernel/inode.c6
3 files changed, 56 insertions, 43 deletions
diff --git a/kernel/dir.c b/kernel/dir.c
index 5fec669..b9c26e6 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -74,23 +74,29 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
else if(S_ISLNK(inode->i_mode)) {
inode->i_op = &fuse_symlink_inode_operations;
}
- else {
+ else if(S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
+ S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)){
inode->i_op = &fuse_file_inode_operations;
init_special_inode(inode, inode->i_mode,
new_decode_dev(attr->rdev));
- }
+ } else
+ printk("fuse_init_inode: bad file type: %o\n", inode->i_mode);
+
inode->u.generic_ip = inode;
}
-struct inode *fuse_iget(struct super_block *sb, ino_t ino,
+struct inode *fuse_iget(struct super_block *sb, ino_t ino, int generation,
struct fuse_attr *attr, int version)
{
struct inode *inode;
inode = iget(sb, ino);
if(inode) {
- if(!inode->u.generic_ip)
+ if(!inode->u.generic_ip) {
+ inode->i_generation = generation;
fuse_init_inode(inode, attr);
+ } else if(inode->i_generation != generation)
+ printk("fuse_iget: bad generation for ino %lu\n", ino);
change_attributes(inode, attr);
inode->i_version = version;
@@ -130,7 +136,8 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
err = fuse_do_lookup(dir, entry, &outarg, &version);
if(!err) {
- inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, version);
+ inode = fuse_iget(dir->i_sb, outarg.ino, outarg.generation,
+ &outarg.attr, version);
if(!inode)
return -ENOMEM;
} else if(err != -ENOENT)
@@ -142,8 +149,28 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
return 0;
}
-/* create needs to return a positive entry, so this is actually an
- mknod+lookup */
+static int lookup_new_entry(struct inode *dir, struct dentry *entry,
+ struct fuse_lookup_out *outarg, int version,
+ int mode)
+{
+ struct inode *inode;
+ inode = fuse_iget(dir->i_sb, outarg->ino, outarg->generation,
+ &outarg->attr, version);
+ if(!inode)
+ return -ENOMEM;
+
+ /* Don't allow userspace to do really stupid things... */
+ if((inode->i_mode ^ mode) & S_IFMT) {
+ iput(inode);
+ printk("fuse_mknod: inode has wrong type\n");
+ return -EINVAL;
+ }
+
+ d_instantiate(entry, inode);
+ return 0;
+}
+
+
static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
dev_t rdev)
{
@@ -151,8 +178,7 @@ static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
struct fuse_in in = FUSE_IN_INIT;
struct fuse_out out = FUSE_OUT_INIT;
struct fuse_mknod_in inarg;
- struct fuse_mknod_out outarg;
- struct inode *inode;
+ struct fuse_lookup_out outarg;
memset(&inarg, 0, sizeof(inarg));
inarg.mode = mode;
@@ -173,19 +199,7 @@ static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
if(out.h.error)
return out.h.error;
- inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, out.h.unique);
- if(!inode)
- return -ENOMEM;
-
- /* Don't allow userspace to do really stupid things... */
- if((inode->i_mode ^ mode) & S_IFMT) {
- iput(inode);
- printk("fuse_mknod: inode has wrong type\n");
- return -EPROTO;
- }
-
- d_instantiate(entry, inode);
- return 0;
+ return lookup_new_entry(dir, entry, &outarg, out.h.unique, mode);
}
static int _fuse_create(struct inode *dir, struct dentry *entry, int mode)
@@ -193,20 +207,6 @@ static int _fuse_create(struct inode *dir, struct dentry *entry, int mode)
return _fuse_mknod(dir, entry, mode, 0);
}
-/* knfsd needs the new entry instantiated in mkdir/symlink/link. this
- should rather be done like mknod: attributes returned in out arg to
- save a call to userspace */
-static int lookup_new_entry(struct inode *dir, struct dentry *entry)
-{
- struct inode *inode;
- int err = fuse_lookup_iget(dir, entry, &inode);
- if(err || !inode) {
- printk("fuse_mkdir: failed to look up new entry\n");
- return err ? err : -ENOENT;
- }
- d_instantiate(entry, inode);
- return 0;
-}
static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
{
@@ -214,6 +214,7 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
struct fuse_in in = FUSE_IN_INIT;
struct fuse_out out = FUSE_OUT_INIT;
struct fuse_mkdir_in inarg;
+ struct fuse_lookup_out outarg;
memset(&inarg, 0, sizeof(inarg));
inarg.mode = mode;
@@ -225,11 +226,14 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
in.args[0].value = &inarg;
in.args[1].size = entry->d_name.len + 1;
in.args[1].value = entry->d_name.name;
+ out.numargs = 1;
+ out.args[0].size = sizeof(outarg);
+ out.args[0].value = &outarg;
request_send(fc, &in, &out);
if(out.h.error)
return out.h.error;
- return lookup_new_entry(dir, entry);
+ return lookup_new_entry(dir, entry, &outarg, out.h.unique, S_IFDIR);
}
static int fuse_symlink(struct inode *dir, struct dentry *entry,
@@ -238,6 +242,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
struct fuse_conn *fc = INO_FC(dir);
struct fuse_in in = FUSE_IN_INIT;
struct fuse_out out = FUSE_OUT_INIT;
+ struct fuse_lookup_out outarg;
in.h.opcode = FUSE_SYMLINK;
in.h.ino = dir->i_ino;
@@ -246,11 +251,14 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
in.args[0].value = entry->d_name.name;
in.args[1].size = strlen(link) + 1;
in.args[1].value = link;
+ out.numargs = 1;
+ out.args[0].size = sizeof(outarg);
+ out.args[0].value = &outarg;
request_send(fc, &in, &out);
if(out.h.error)
return out.h.error;
- return lookup_new_entry(dir, entry);
+ return lookup_new_entry(dir, entry, &outarg, out.h.unique, S_IFLNK);
}
static int fuse_remove(struct inode *dir, struct dentry *entry,
@@ -325,6 +333,7 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
struct fuse_in in = FUSE_IN_INIT;
struct fuse_out out = FUSE_OUT_INIT;
struct fuse_link_in inarg;
+ struct fuse_lookup_out outarg;
memset(&inarg, 0, sizeof(inarg));
inarg.newdir = newdir->i_ino;
@@ -336,13 +345,17 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
in.args[0].value = &inarg;
in.args[1].size = newent->d_name.len + 1;
in.args[1].value = newent->d_name.name;
+ out.numargs = 1;
+ out.args[0].size = sizeof(outarg);
+ out.args[0].value = &outarg;
request_send(fc, &in, &out);
if(out.h.error)
return out.h.error;
/* Invalidate old entry, so attributes are refreshed */
d_invalidate(entry);
- return lookup_new_entry(newdir, newent);
+ return lookup_new_entry(newdir, newent, &outarg, out.h.unique,
+ inode->i_mode);
}
int fuse_do_getattr(struct inode *inode)
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index d4a677e..48e52c9 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -174,7 +174,7 @@ extern spinlock_t fuse_lock;
/**
* Get a filled in inode
*/
-struct inode *fuse_iget(struct super_block *sb, ino_t ino,
+struct inode *fuse_iget(struct super_block *sb, ino_t ino, int generation,
struct fuse_attr *attr, int version);
diff --git a/kernel/inode.c b/kernel/inode.c
index 9ab0dc3..08bf3c9 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -148,7 +148,7 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
memset(&attr, 0, sizeof(attr));
attr.mode = mode;
- return fuse_iget(sb, 1, &attr, 0);
+ return fuse_iget(sb, 1, 0, &attr, 0);
}
@@ -158,7 +158,7 @@ static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
{
__u32 *objp = vobjp;
unsigned long ino = objp[0];
- /* __u32 generation = objp[1]; */
+ __u32 generation = objp[1];
struct inode *inode;
struct dentry *entry;
@@ -166,7 +166,7 @@ static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
return ERR_PTR(-ESTALE);
inode = ilookup(sb, ino);
- if(!inode)
+ if(!inode || inode->i_generation != generation)
return ERR_PTR(-ESTALE);
entry = d_alloc_anon(inode);