|
@@ -18,6 +18,7 @@
|
|
|
#include <linux/statfs.h>
|
|
|
#include <linux/random.h>
|
|
|
#include <linux/sched.h>
|
|
|
+#include <linux/exportfs.h>
|
|
|
|
|
|
MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
|
|
|
MODULE_DESCRIPTION("Filesystem in Userspace");
|
|
@@ -552,6 +553,119 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
|
|
|
return fuse_iget(sb, 1, 0, &attr, 0, 0);
|
|
|
}
|
|
|
|
|
|
+struct fuse_inode_handle
|
|
|
+{
|
|
|
+ u64 nodeid;
|
|
|
+ u32 generation;
|
|
|
+};
|
|
|
+
|
|
|
+static struct dentry *fuse_get_dentry(struct super_block *sb,
|
|
|
+ struct fuse_inode_handle *handle)
|
|
|
+{
|
|
|
+ struct inode *inode;
|
|
|
+ struct dentry *entry;
|
|
|
+ int err = -ESTALE;
|
|
|
+
|
|
|
+ if (handle->nodeid == 0)
|
|
|
+ goto out_err;
|
|
|
+
|
|
|
+ inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid);
|
|
|
+ if (!inode)
|
|
|
+ goto out_err;
|
|
|
+ err = -ESTALE;
|
|
|
+ if (inode->i_generation != handle->generation)
|
|
|
+ goto out_iput;
|
|
|
+
|
|
|
+ entry = d_alloc_anon(inode);
|
|
|
+ err = -ENOMEM;
|
|
|
+ if (!entry)
|
|
|
+ goto out_iput;
|
|
|
+
|
|
|
+ if (get_node_id(inode) != FUSE_ROOT_ID) {
|
|
|
+ entry->d_op = &fuse_dentry_operations;
|
|
|
+ fuse_invalidate_entry_cache(entry);
|
|
|
+ }
|
|
|
+
|
|
|
+ return entry;
|
|
|
+
|
|
|
+ out_iput:
|
|
|
+ iput(inode);
|
|
|
+ out_err:
|
|
|
+ return ERR_PTR(err);
|
|
|
+}
|
|
|
+
|
|
|
+static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
|
|
|
+ int connectable)
|
|
|
+{
|
|
|
+ struct inode *inode = dentry->d_inode;
|
|
|
+ bool encode_parent = connectable && !S_ISDIR(inode->i_mode);
|
|
|
+ int len = encode_parent ? 6 : 3;
|
|
|
+ u64 nodeid;
|
|
|
+ u32 generation;
|
|
|
+
|
|
|
+ if (*max_len < len)
|
|
|
+ return 255;
|
|
|
+
|
|
|
+ nodeid = get_fuse_inode(inode)->nodeid;
|
|
|
+ generation = inode->i_generation;
|
|
|
+
|
|
|
+ fh[0] = (u32)(nodeid >> 32);
|
|
|
+ fh[1] = (u32)(nodeid & 0xffffffff);
|
|
|
+ fh[2] = generation;
|
|
|
+
|
|
|
+ if (encode_parent) {
|
|
|
+ struct inode *parent;
|
|
|
+
|
|
|
+ spin_lock(&dentry->d_lock);
|
|
|
+ parent = dentry->d_parent->d_inode;
|
|
|
+ nodeid = get_fuse_inode(parent)->nodeid;
|
|
|
+ generation = parent->i_generation;
|
|
|
+ spin_unlock(&dentry->d_lock);
|
|
|
+
|
|
|
+ fh[3] = (u32)(nodeid >> 32);
|
|
|
+ fh[4] = (u32)(nodeid & 0xffffffff);
|
|
|
+ fh[5] = generation;
|
|
|
+ }
|
|
|
+
|
|
|
+ *max_len = len;
|
|
|
+ return encode_parent ? 0x82 : 0x81;
|
|
|
+}
|
|
|
+
|
|
|
+static struct dentry *fuse_fh_to_dentry(struct super_block *sb,
|
|
|
+ struct fid *fid, int fh_len, int fh_type)
|
|
|
+{
|
|
|
+ struct fuse_inode_handle handle;
|
|
|
+
|
|
|
+ if ((fh_type != 0x81 && fh_type != 0x82) || fh_len < 3)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ handle.nodeid = (u64) fid->raw[0] << 32;
|
|
|
+ handle.nodeid |= (u64) fid->raw[1];
|
|
|
+ handle.generation = fid->raw[2];
|
|
|
+ return fuse_get_dentry(sb, &handle);
|
|
|
+}
|
|
|
+
|
|
|
+static struct dentry *fuse_fh_to_parent(struct super_block *sb,
|
|
|
+ struct fid *fid, int fh_len, int fh_type)
|
|
|
+{
|
|
|
+ struct fuse_inode_handle parent;
|
|
|
+
|
|
|
+ if (fh_type != 0x82 || fh_len < 6)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ parent.nodeid = (u64) fid->raw[3] << 32;
|
|
|
+ parent.nodeid |= (u64) fid->raw[4];
|
|
|
+ parent.generation = fid->raw[5];
|
|
|
+ return fuse_get_dentry(sb, &parent);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static const struct export_operations fuse_export_operations = {
|
|
|
+ .fh_to_dentry = fuse_fh_to_dentry,
|
|
|
+ .fh_to_parent = fuse_fh_to_parent,
|
|
|
+ .encode_fh = fuse_encode_fh,
|
|
|
+};
|
|
|
+
|
|
|
static const struct super_operations fuse_super_operations = {
|
|
|
.alloc_inode = fuse_alloc_inode,
|
|
|
.destroy_inode = fuse_destroy_inode,
|
|
@@ -652,6 +766,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
|
|
sb->s_magic = FUSE_SUPER_MAGIC;
|
|
|
sb->s_op = &fuse_super_operations;
|
|
|
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
|
|
+ sb->s_export_op = &fuse_export_operations;
|
|
|
|
|
|
file = fget(d.fd);
|
|
|
if (!file)
|