From: Miklos Szeredi Date: Mon, 19 Jan 2004 18:20:49 +0000 (+0000) Subject: NFS export for 2.6 X-Git-Tag: fuse_1_1_pre2~5 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=e815c03771bfe19a12f9ff76639b28567942903c;p=qemu-gpiodev%2Flibfuse.git NFS export for 2.6 --- diff --git a/ChangeLog b/ChangeLog index 2c43391..846268a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2004-01-19 Miklos Szeredi + + * Support for exporting filesystem over NFS (see README.NFS) + 2004-01-14 Miklos Szeredi * 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 + +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) {