Commit 33c5ac91 authored by Tejun Heo's avatar Tejun Heo

kernfs: implement custom exportfs ops and fid type

The current kernfs exportfs implementation uses the generic_fh_*()
helpers and FILEID_INO32_GEN[_PARENT] which limits ino to 32bits.
Let's implement custom exportfs operations and fid type to remove the
restriction.

* FILEID_KERNFS is a single u64 value whose content is
  kernfs_node->id.  This is the only native fid type.

* For backward compatibility with blk_log_action() path which exposes
  (ino,gen) pairs which userland assembles into FILEID_INO32_GEN keys,
  combine the generic keys into 64bit IDs in the same order.
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Namhyung Kim <namhyung@kernel.org>
parent fe0f726c
...@@ -53,40 +53,84 @@ const struct super_operations kernfs_sops = { ...@@ -53,40 +53,84 @@ const struct super_operations kernfs_sops = {
.show_path = kernfs_sop_show_path, .show_path = kernfs_sop_show_path,
}; };
static struct inode *kernfs_fh_get_inode(struct super_block *sb, static int kernfs_encode_fh(struct inode *inode, __u32 *fh, int *max_len,
u64 ino, u32 generation) struct inode *parent)
{
struct kernfs_node *kn = inode->i_private;
if (*max_len < 2) {
*max_len = 2;
return FILEID_INVALID;
}
*max_len = 2;
*(u64 *)fh = kn->id;
return FILEID_KERNFS;
}
static struct dentry *__kernfs_fh_to_dentry(struct super_block *sb,
struct fid *fid, int fh_len,
int fh_type, bool get_parent)
{ {
struct kernfs_super_info *info = kernfs_info(sb); struct kernfs_super_info *info = kernfs_info(sb);
struct inode *inode;
struct kernfs_node *kn; struct kernfs_node *kn;
struct inode *inode;
u64 id;
if (fh_len < 2)
return NULL;
if (ino == 0) switch (fh_type) {
case FILEID_KERNFS:
id = *(u64 *)fid;
break;
case FILEID_INO32_GEN:
case FILEID_INO32_GEN_PARENT:
/*
* blk_log_action() exposes (ino,gen) pair without type and
* userland can call us with generic fid constructed from
* them. Combine it back to ID. See blk_log_action().
*/
id = ((u64)fid->i32.gen << 32) | fid->i32.ino;
break;
default:
return NULL;
}
kn = kernfs_find_and_get_node_by_id(info->root, id);
if (!kn)
return ERR_PTR(-ESTALE); return ERR_PTR(-ESTALE);
kn = kernfs_find_and_get_node_by_id(info->root, if (get_parent) {
ino | ((u64)generation << 32)); struct kernfs_node *parent;
parent = kernfs_get_parent(kn);
kernfs_put(kn);
kn = parent;
if (!kn) if (!kn)
return ERR_PTR(-ESTALE); return ERR_PTR(-ESTALE);
}
inode = kernfs_get_inode(sb, kn); inode = kernfs_get_inode(sb, kn);
kernfs_put(kn); kernfs_put(kn);
if (!inode) if (!inode)
return ERR_PTR(-ESTALE); return ERR_PTR(-ESTALE);
return inode; return d_obtain_alias(inode);
} }
static struct dentry *kernfs_fh_to_dentry(struct super_block *sb, struct fid *fid, static struct dentry *kernfs_fh_to_dentry(struct super_block *sb,
int fh_len, int fh_type) struct fid *fid, int fh_len,
int fh_type)
{ {
return generic_fh_to_dentry(sb, fid, fh_len, fh_type, return __kernfs_fh_to_dentry(sb, fid, fh_len, fh_type, false);
kernfs_fh_get_inode);
} }
static struct dentry *kernfs_fh_to_parent(struct super_block *sb, struct fid *fid, static struct dentry *kernfs_fh_to_parent(struct super_block *sb,
int fh_len, int fh_type) struct fid *fid, int fh_len,
int fh_type)
{ {
return generic_fh_to_parent(sb, fid, fh_len, fh_type, return __kernfs_fh_to_dentry(sb, fid, fh_len, fh_type, true);
kernfs_fh_get_inode);
} }
static struct dentry *kernfs_get_parent_dentry(struct dentry *child) static struct dentry *kernfs_get_parent_dentry(struct dentry *child)
...@@ -97,6 +141,7 @@ static struct dentry *kernfs_get_parent_dentry(struct dentry *child) ...@@ -97,6 +141,7 @@ static struct dentry *kernfs_get_parent_dentry(struct dentry *child)
} }
static const struct export_operations kernfs_export_ops = { static const struct export_operations kernfs_export_ops = {
.encode_fh = kernfs_encode_fh,
.fh_to_dentry = kernfs_fh_to_dentry, .fh_to_dentry = kernfs_fh_to_dentry,
.fh_to_parent = kernfs_fh_to_parent, .fh_to_parent = kernfs_fh_to_parent,
.get_parent = kernfs_get_parent_dentry, .get_parent = kernfs_get_parent_dentry,
......
...@@ -104,6 +104,11 @@ enum fid_type { ...@@ -104,6 +104,11 @@ enum fid_type {
*/ */
FILEID_LUSTRE = 0x97, FILEID_LUSTRE = 0x97,
/*
* 64 bit unique kernfs id
*/
FILEID_KERNFS = 0xfe,
/* /*
* Filesystems must not use 0xff file ID. * Filesystems must not use 0xff file ID.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment