mirror of
https://github.com/torvalds/linux
synced 2024-07-21 10:41:44 +00:00
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: Amir Goldstein <amir73il@gmail.com>
This commit is contained in:
parent
0c71faf5a6
commit
16aac5ad1f
|
@ -174,28 +174,37 @@ static int ovl_connect_layer(struct dentry *dentry)
|
||||||
* U = upper file handle
|
* U = upper file handle
|
||||||
* L = lower 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.
|
* 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
|
* 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.
|
* Return 0 for upper file handle, > 0 for lower file handle or < 0 on error.
|
||||||
*/
|
*/
|
||||||
static int ovl_check_encode_origin(struct dentry *dentry)
|
static int ovl_check_encode_origin(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
|
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 */
|
/* Upper file handle for pure upper */
|
||||||
if (!ovl_dentry_lower(dentry))
|
if (!ovl_dentry_lower(dentry))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Upper file handle for non-indexed upper.
|
|
||||||
*
|
|
||||||
* Root is never indexed, so if there's an upper layer, encode upper for
|
* Root is never indexed, so if there's an upper layer, encode upper for
|
||||||
* root.
|
* 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)))
|
!ovl_test_flag(OVL_INDEX, d_inode(dentry)))
|
||||||
return 0;
|
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
|
* ovl_connect_layer() will try to make origin's layer "connected" by
|
||||||
* copying up a "connectable" ancestor.
|
* 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);
|
return ovl_connect_layer(dentry);
|
||||||
|
|
||||||
/* Lower file handle for indexed and non-upper dir/non-dir */
|
/* 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_name = ovl_get_name,
|
||||||
.get_parent = ovl_get_parent,
|
.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,
|
||||||
|
};
|
||||||
|
|
|
@ -1311,7 +1311,7 @@ static bool ovl_hash_bylower(struct super_block *sb, struct dentry *upper,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* No, if non-indexed upper with NFS export */
|
/* No, if non-indexed upper with NFS export */
|
||||||
if (sb->s_export_op && upper)
|
if (ofs->config.nfs_export && upper)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Otherwise, hash by lower inode for fsnotify */
|
/* Otherwise, hash by lower inode for fsnotify */
|
||||||
|
|
|
@ -799,6 +799,7 @@ int ovl_set_origin(struct ovl_fs *ofs, struct dentry *lower,
|
||||||
|
|
||||||
/* export.c */
|
/* export.c */
|
||||||
extern const struct export_operations ovl_export_operations;
|
extern const struct export_operations ovl_export_operations;
|
||||||
|
extern const struct export_operations ovl_export_fid_operations;
|
||||||
|
|
||||||
/* super.c */
|
/* super.c */
|
||||||
int ovl_fill_super(struct super_block *sb, struct fs_context *fc);
|
int ovl_fill_super(struct super_block *sb, struct fs_context *fc);
|
||||||
|
|
|
@ -82,6 +82,7 @@ struct ovl_fs {
|
||||||
const struct cred *creator_cred;
|
const struct cred *creator_cred;
|
||||||
bool tmpfile;
|
bool tmpfile;
|
||||||
bool noxattr;
|
bool noxattr;
|
||||||
|
bool nofh;
|
||||||
/* Did we take the inuse lock? */
|
/* Did we take the inuse lock? */
|
||||||
bool upperdir_locked;
|
bool upperdir_locked;
|
||||||
bool workdir_locked;
|
bool workdir_locked;
|
||||||
|
|
|
@ -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",
|
pr_warn("fs on '%s' does not support file handles, falling back to index=off,nfs_export=off.\n",
|
||||||
name);
|
name);
|
||||||
}
|
}
|
||||||
|
ofs->nofh |= !fh_type;
|
||||||
/*
|
/*
|
||||||
* Decoding origin file handle is required for persistent st_ino.
|
* Decoding origin file handle is required for persistent st_ino.
|
||||||
* Without persistent st_ino, xino=auto falls back to xino=off.
|
* 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;
|
ofs->config.index = false;
|
||||||
pr_warn("upper fs does not support file handles, falling back to index=off.\n");
|
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 */
|
/* Check if upper fs has 32bit inode numbers */
|
||||||
if (fh_type != FILEID_INO32_GEN)
|
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;
|
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)
|
if (ofs->config.nfs_export)
|
||||||
sb->s_export_op = &ovl_export_operations;
|
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 */
|
/* Never override disk quota limits or use reserved space */
|
||||||
cap_lower(cred->cap_effective, CAP_SYS_RESOURCE);
|
cap_lower(cred->cap_effective, CAP_SYS_RESOURCE);
|
||||||
|
|
Loading…
Reference in a new issue