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: Tejun Heo <tj@kernel.org>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
Tejun Heo 2019-11-04 15:54:30 -08:00
parent fe0f726c9f
commit 33c5ac9175
2 changed files with 66 additions and 16 deletions

View File

@ -53,40 +53,84 @@ const struct super_operations kernfs_sops = {
.show_path = kernfs_sop_show_path,
};
static struct inode *kernfs_fh_get_inode(struct super_block *sb,
u64 ino, u32 generation)
static int kernfs_encode_fh(struct inode *inode, __u32 *fh, int *max_len,
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 inode *inode;
struct kernfs_node *kn;
struct inode *inode;
u64 id;
if (ino == 0)
return ERR_PTR(-ESTALE);
if (fh_len < 2)
return NULL;
kn = kernfs_find_and_get_node_by_id(info->root,
ino | ((u64)generation << 32));
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);
if (get_parent) {
struct kernfs_node *parent;
parent = kernfs_get_parent(kn);
kernfs_put(kn);
kn = parent;
if (!kn)
return ERR_PTR(-ESTALE);
}
inode = kernfs_get_inode(sb, kn);
kernfs_put(kn);
if (!inode)
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,
int fh_len, int fh_type)
static struct dentry *kernfs_fh_to_dentry(struct super_block *sb,
struct fid *fid, int fh_len,
int fh_type)
{
return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
kernfs_fh_get_inode);
return __kernfs_fh_to_dentry(sb, fid, fh_len, fh_type, false);
}
static struct dentry *kernfs_fh_to_parent(struct super_block *sb, struct fid *fid,
int fh_len, int fh_type)
static struct dentry *kernfs_fh_to_parent(struct super_block *sb,
struct fid *fid, int fh_len,
int fh_type)
{
return generic_fh_to_parent(sb, fid, fh_len, fh_type,
kernfs_fh_get_inode);
return __kernfs_fh_to_dentry(sb, fid, fh_len, fh_type, true);
}
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 = {
.encode_fh = kernfs_encode_fh,
.fh_to_dentry = kernfs_fh_to_dentry,
.fh_to_parent = kernfs_fh_to_parent,
.get_parent = kernfs_get_parent_dentry,

View File

@ -104,6 +104,11 @@ enum fid_type {
*/
FILEID_LUSTRE = 0x97,
/*
* 64 bit unique kernfs id
*/
FILEID_KERNFS = 0xfe,
/*
* Filesystems must not use 0xff file ID.
*/