NFS export for 2.6
authorMiklos Szeredi <miklos@szeredi.hu>
Mon, 19 Jan 2004 18:20:49 +0000 (18:20 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Mon, 19 Jan 2004 18:20:49 +0000 (18:20 +0000)
ChangeLog
Filesystems
README.NFS [new file with mode: 0644]
kernel/dir.c
kernel/inode.c

index 2c43391c959e51bfcea9ee61e24bf3344e8c201c..846268a2d93336cf1cb258eaf38459aa73ec315e 100644 (file)
--- 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
index d366483f33bff826222d056ce40e71b0f470662b..d61d30589e20beec891998ab589a7748f38b1461 100644 (file)
@@ -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 (file)
index 0000000..f3d0146
--- /dev/null
@@ -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.
index 00b1e983adc9e10ea74921fdde35c279648b1e79..7e91639c3f0f0b4d6e208062e918f504b845cb19 100644 (file)
@@ -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)
 {
index a868edb8eb1d72cf2e51b4b45b845890e972759c..4a160512c4f574d1d7da31d6e69fbf4efd40bf85 100644 (file)
@@ -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) {