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

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
Loading
Loading
Loading
Loading
+61 −16
Original line number Diff line number Diff line
@@ -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 (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);

	kn = kernfs_find_and_get_node_by_id(info->root,
					    ino | ((u64)generation << 32));
	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,
+5 −0
Original line number Diff line number Diff line
@@ -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.
	 */