forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement export_operations, to allow fuse filesystems to be exported to NFS. This feature has been in the out-of-tree fuse module, and is widely used and tested. It has not been originally merged into mainline, because doing the NFS export in userspace was thought to be a cleaner and more efficient way of doing it, than through the kernel. While that is true, it would also have involved a lot of duplicated effort at reimplementing NFS exporting (all the different versions of the protocol). This effort was unfortunately not undertaken by anyone, so we are left with doing it the easy but less efficient way. If this feature goes in, the out-of-tree fuse module can go away, which would have several advantages: - not having to maintain two versions - less confusion for users - no bugs due to kernel API changes Comment from hch: - Use the same fh_type values as XFS, since we use the same fh encoding. Signed-off-by: Miklos Szeredi <[email protected]> Cc: Christoph Hellwig <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
- Loading branch information
Showing
3 changed files
with
121 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
#include <linux/statfs.h> | ||
#include <linux/random.h> | ||
#include <linux/sched.h> | ||
#include <linux/exportfs.h> | ||
|
||
MODULE_AUTHOR("Miklos Szeredi <[email protected]>"); | ||
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) | ||
|