Commit 16aac5ad authored by Amir Goldstein's avatar Amir Goldstein
Browse files

ovl: support encoding non-decodable file handles



When all layers support file handles, we support encoding non-decodable
file handles (a.k.a. fid) even with nfs_export=off.

When file handles do not need to be decoded, we do not need to copy up
redirected lower directories on encode, and we encode also non-indexed
upper with lower file handle, so fid will not change on copy up.

This enables reporting fanotify events with file handles on overlayfs
with default config/mount options.

Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
parent 0c71faf5
Loading
Loading
Loading
Loading
+20 −6
Original line number Diff line number Diff line
@@ -174,28 +174,37 @@ static int ovl_connect_layer(struct dentry *dentry)
 * U = upper file handle
 * L = lower file handle
 *
 * (*) Connecting an overlay dir from real lower dentry is not always
 * (*) Decoding a connected overlay dir from real lower dentry is not always
 * possible when there are redirects in lower layers and non-indexed merge dirs.
 * To mitigate those case, we may copy up the lower dir ancestor before encode
 * a lower dir file handle.
 * of a decodable file handle for non-upper dir.
 *
 * Return 0 for upper file handle, > 0 for lower file handle or < 0 on error.
 */
static int ovl_check_encode_origin(struct dentry *dentry)
{
	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
	bool decodable = ofs->config.nfs_export;

	/* Lower file handle for non-upper non-decodable */
	if (!ovl_dentry_upper(dentry) && !decodable)
		return 0;

	/* Upper file handle for pure upper */
	if (!ovl_dentry_lower(dentry))
		return 0;

	/*
	 * Upper file handle for non-indexed upper.
	 *
	 * Root is never indexed, so if there's an upper layer, encode upper for
	 * root.
	 */
	if (ovl_dentry_upper(dentry) &&
	if (dentry == dentry->d_sb->s_root)
		return 0;

	/*
	 * Upper decodable file handle for non-indexed upper.
	 */
	if (ovl_dentry_upper(dentry) && decodable &&
	    !ovl_test_flag(OVL_INDEX, d_inode(dentry)))
		return 0;

@@ -205,7 +214,7 @@ static int ovl_check_encode_origin(struct dentry *dentry)
	 * ovl_connect_layer() will try to make origin's layer "connected" by
	 * copying up a "connectable" ancestor.
	 */
	if (d_is_dir(dentry) && ovl_upper_mnt(ofs))
	if (d_is_dir(dentry) && ovl_upper_mnt(ofs) && decodable)
		return ovl_connect_layer(dentry);

	/* Lower file handle for indexed and non-upper dir/non-dir */
@@ -876,3 +885,8 @@ const struct export_operations ovl_export_operations = {
	.get_name	= ovl_get_name,
	.get_parent	= ovl_get_parent,
};

/* encode_fh() encodes non-decodable file handles with nfs_export=off */
const struct export_operations ovl_export_fid_operations = {
	.encode_fh	= ovl_encode_fh,
};
+1 −1
Original line number Diff line number Diff line
@@ -1311,7 +1311,7 @@ static bool ovl_hash_bylower(struct super_block *sb, struct dentry *upper,
		return false;

	/* No, if non-indexed upper with NFS export */
	if (sb->s_export_op && upper)
	if (ofs->config.nfs_export && upper)
		return false;

	/* Otherwise, hash by lower inode for fsnotify */
+1 −0
Original line number Diff line number Diff line
@@ -799,6 +799,7 @@ int ovl_set_origin(struct ovl_fs *ofs, struct dentry *lower,

/* export.c */
extern const struct export_operations ovl_export_operations;
extern const struct export_operations ovl_export_fid_operations;

/* super.c */
int ovl_fill_super(struct super_block *sb, struct fs_context *fc);
+1 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ struct ovl_fs {
	const struct cred *creator_cred;
	bool tmpfile;
	bool noxattr;
	bool nofh;
	/* Did we take the inuse lock? */
	bool upperdir_locked;
	bool workdir_locked;
+9 −0
Original line number Diff line number Diff line
@@ -400,6 +400,7 @@ static int ovl_lower_dir(const char *name, struct path *path,
		pr_warn("fs on '%s' does not support file handles, falling back to index=off,nfs_export=off.\n",
			name);
	}
	ofs->nofh |= !fh_type;
	/*
	 * Decoding origin file handle is required for persistent st_ino.
	 * Without persistent st_ino, xino=auto falls back to xino=off.
@@ -818,6 +819,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
		ofs->config.index = false;
		pr_warn("upper fs does not support file handles, falling back to index=off.\n");
	}
	ofs->nofh |= !fh_type;

	/* Check if upper fs has 32bit inode numbers */
	if (fh_type != FILEID_INO32_GEN)
@@ -1452,8 +1454,15 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
		ofs->config.nfs_export = false;
	}

	/*
	 * Support encoding decodable file handles with nfs_export=on
	 * and encoding non-decodable file handles with nfs_export=off
	 * if all layers support file handles.
	 */
	if (ofs->config.nfs_export)
		sb->s_export_op = &ovl_export_operations;
	else if (!ofs->nofh)
		sb->s_export_op = &ovl_export_fid_operations;

	/* Never override disk quota limits or use reserved space */
	cap_lower(cred->cap_effective, CAP_SYS_RESOURCE);