aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--Filesystems13
-rw-r--r--README.NFS11
-rw-r--r--kernel/dir.c125
-rw-r--r--kernel/inode.c50
5 files changed, 140 insertions, 63 deletions
diff --git a/ChangeLog b/ChangeLog
index 2c43391..846268a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2004-01-19 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Support for exporting filesystem over NFS (see README.NFS)
+
2004-01-14 Miklos Szeredi <mszeredi@inf.bme.hu>
* Support non-blocking writepage on 2.6. This makes FUSE behave
diff --git a/Filesystems b/Filesystems
index d366483..d61d305 100644
--- a/Filesystems
+++ b/Filesystems
@@ -90,3 +90,16 @@ Description:
the existence of anything else.
==============================================================================
+Name: KIO Fuse Gateway
+
+Author: Alexander Neundorf <neundorf at kde org>
+
+Homepage: http://kde.ground.cz/tiki-index.php?page=KIO+Fuse+Gateway
+
+Description:
+
+ This gateway makes it possible to mount ioslaves or a general
+ ioslave-gateway via fuse and make them this way available to all
+ linux apps.
+
+==============================================================================
diff --git a/README.NFS b/README.NFS
new file mode 100644
index 0000000..f3d0146
--- /dev/null
+++ b/README.NFS
@@ -0,0 +1,11 @@
+For the moment NFS exporting is supported on kernels versions >=
+2.6.0.
+
+You need to add an fsid=NNN option to /etc/exports to make exporting a
+FUSE directory work.
+
+You may get ESTALE (Stale NFS file handle) errors with this. This is
+because the current FUSE kernel API and the userspace library cannot
+handle a situation where the kernel forgets about a dentry which is
+still referenced by the remote NFS client. This problem will be
+addressed in a later version.
diff --git a/kernel/dir.c b/kernel/dir.c
index 00b1e98..7e91639 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -91,7 +91,7 @@ struct inode *fuse_iget(struct super_block *sb, ino_t ino,
if(inode) {
if(!inode->u.generic_ip)
fuse_init_inode(inode, attr);
-
+
change_attributes(inode, attr);
inode->i_version = version;
}
@@ -99,20 +99,6 @@ struct inode *fuse_iget(struct super_block *sb, ino_t ino,
return inode;
}
-/* If the inode belongs to an existing directory, then it cannot be
- assigned to new dentry */
-static int inode_ok(struct inode *inode)
-{
- struct dentry *alias;
- if(S_ISDIR(inode->i_mode) && (alias = d_find_alias(inode)) != NULL) {
- dput(alias);
- printk("fuse: cannot assign an existing directory\n");
- return 0;
-
- }
- return 1;
-}
-
static int fuse_do_lookup(struct inode *dir, struct dentry *entry,
struct fuse_lookup_out *outarg, int *version)
{
@@ -134,38 +120,26 @@ static int fuse_do_lookup(struct inode *dir, struct dentry *entry,
return out.h.error;
}
-static struct dentry *_fuse_lookup(struct inode *dir, struct dentry *entry)
+static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
+ struct inode **inodep)
{
- int ret;
+ int err;
struct fuse_lookup_out outarg;
int version;
- struct inode *inode;
+ struct inode *inode = NULL;
- ret = fuse_do_lookup(dir, entry, &outarg, &version);
- inode = NULL;
- if(!ret) {
- ret = -ENOMEM;
+ err = fuse_do_lookup(dir, entry, &outarg, &version);
+ if(!err) {
inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, version);
- if(!inode)
- goto err;
-
- ret = -EPROTO;
- if(!inode_ok(inode)) {
- iput(inode);
- goto err;
- }
- }
- else if(ret != -ENOENT)
- goto err;
+ if(!inode)
+ return -ENOMEM;
+ } else if(err != -ENOENT)
+ return err;
entry->d_time = jiffies;
entry->d_op = &fuse_dentry_opertations;
- d_add(entry, inode);
-
- return NULL;
-
- err:
- return ERR_PTR(ret);
+ *inodep = inode;
+ return 0;
}
/* create needs to return a positive entry, so this is actually an
@@ -210,11 +184,6 @@ static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
return -EPROTO;
}
- if(!inode_ok(inode)) {
- iput(inode);
- return -EPROTO;
- }
-
d_instantiate(entry, inode);
return 0;
}
@@ -224,6 +193,21 @@ 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)
{
struct fuse_conn *fc = INO_FC(dir);
@@ -242,8 +226,10 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
in.args[1].size = entry->d_name.len + 1;
in.args[1].value = entry->d_name.name;
request_send(fc, &in, &out);
+ if(out.h.error)
+ return out.h.error;
- return out.h.error;
+ return lookup_new_entry(dir, entry);
}
static int fuse_symlink(struct inode *dir, struct dentry *entry,
@@ -261,8 +247,10 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
in.args[1].size = strlen(link) + 1;
in.args[1].value = link;
request_send(fc, &in, &out);
+ if(out.h.error)
+ return out.h.error;
- return out.h.error;
+ return lookup_new_entry(dir, entry);
}
static int fuse_remove(struct inode *dir, struct dentry *entry,
@@ -337,11 +325,14 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
in.args[1].size = newent->d_name.len + 1;
in.args[1].value = newent->d_name.name;
request_send(fc, &in, &out);
+ if(out.h.error)
+ return out.h.error;
- return out.h.error;
+ /* Invalidate old entry, so attributes are refreshed */
+ d_invalidate(entry);
+ return lookup_new_entry(newdir, newent);
}
-
int fuse_do_getattr(struct inode *inode)
{
struct fuse_conn *fc = INO_FC(inode);
@@ -444,11 +435,14 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
struct file *cfile = file->private_data;
char *buf;
int ret;
-
+
+ if(!cfile)
+ return -EISDIR;
+
buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
if(!buf)
return -ENOMEM;
-
+
ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE);
if(ret < 0)
printk("fuse_readdir: failed to read container file\n");
@@ -522,9 +516,6 @@ static int fuse_dir_open(struct inode *inode, struct file *file)
struct fuse_out out = FUSE_OUT_INIT;
struct fuse_getdir_out outarg;
- if(!(file->f_flags & O_DIRECTORY))
- return 0;
-
in.h.opcode = FUSE_GETDIR;
in.h.ino = inode->i_ino;
out.numargs = 1;
@@ -667,7 +658,11 @@ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
struct nameidata *nd)
{
- return _fuse_lookup(dir, entry);
+ struct inode *inode;
+ int err = fuse_lookup_iget(dir, entry, &inode);
+ if (err)
+ return ERR_PTR(err);
+ return d_splice_alias(inode, entry);
}
static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
@@ -688,10 +683,30 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
}
#else /* KERNEL_2_6 */
-#define fuse_lookup _fuse_lookup
#define fuse_create _fuse_create
#define fuse_permission _fuse_permission
+static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
+{
+ struct inode *inode;
+ struct dentry *alias;
+
+ int err = fuse_lookup_iget(dir, entry, &inode);
+ if(err)
+ return ERR_PTR(err);
+
+ if(inode && S_ISDIR(inode->i_mode) &&
+ (alias = d_find_alias(inode)) != NULL) {
+ dput(alias);
+ iput(inode);
+ printk("fuse: cannot assign an existing directory\n");
+ return -EPROTO;
+ }
+
+ d_add(entry, inode);
+ return NULL;
+}
+
static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
int rdev)
{
diff --git a/kernel/inode.c b/kernel/inode.c
index a868edb..4a16051 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -105,14 +105,6 @@ static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
return out.h.error;
}
-static struct super_operations fuse_super_operations = {
- .read_inode = fuse_read_inode,
- .clear_inode = fuse_clear_inode,
- .put_super = fuse_put_super,
- .statfs = fuse_statfs,
-};
-
-
static struct fuse_conn *get_conn(struct fuse_mount_data *d)
{
struct fuse_conn *fc = NULL;
@@ -156,6 +148,45 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
return fuse_iget(sb, 1, &attr, 0);
}
+
+#ifdef KERNEL_2_6
+
+static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
+{
+ __u32 *objp = vobjp;
+ unsigned long ino = objp[0];
+ /* __u32 generation = objp[1]; */
+ struct inode *inode;
+ struct dentry *entry;
+
+ if(ino == 0)
+ return ERR_PTR(-ESTALE);
+
+ inode = ilookup(sb, ino);
+ if(!inode)
+ return ERR_PTR(-ESTALE);
+
+ entry = d_alloc_anon(inode);
+ if(!entry) {
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return entry;
+}
+
+static struct export_operations fuse_export_operations = {
+ .get_dentry = fuse_get_dentry,
+};
+#endif
+
+static struct super_operations fuse_super_operations = {
+ .read_inode = fuse_read_inode,
+ .clear_inode = fuse_clear_inode,
+ .put_super = fuse_put_super,
+ .statfs = fuse_statfs,
+};
+
static int fuse_read_super(struct super_block *sb, void *data, int silent)
{
struct fuse_conn *fc;
@@ -166,6 +197,9 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent)
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = FUSE_SUPER_MAGIC;
sb->s_op = &fuse_super_operations;
+#ifdef KERNEL_2_6
+ sb->s_export_op = &fuse_export_operations;
+#endif
root = get_root_inode(sb, d->rootmode);
if(root == NULL) {