On Tue, Apr 25, 2023 at 4:22 PM Amir Goldstein <amir73il@xxxxxxxxx> wrote: > > When all layers support file handles, we support encoding non-decodeable > 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@xxxxxxxxx> > --- FYI, the exportfs support for non-decodable file handles has been merged. This follow up series which adds support for non-decodable file handles to overlayfs has been pushed to: https://github.com/amir73il/linux/commits/ovl_encode_fid and to overlayfs-next (pending review by Miklos). fanotify (over ovl) tests are available at: https://github.com/amir73il/ltp/commits/ovl_encode_fid Thanks, Amir. > fs/overlayfs/export.c | 26 ++++++++++++++++++++------ > fs/overlayfs/inode.c | 2 +- > fs/overlayfs/overlayfs.h | 1 + > fs/overlayfs/ovl_entry.h | 1 + > fs/overlayfs/super.c | 9 +++++++++ > 5 files changed, 32 insertions(+), 7 deletions(-) > > diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c > index defd4e231ad2..dfd05ad2b722 100644 > --- a/fs/overlayfs/export.c > +++ b/fs/overlayfs/export.c > @@ -173,28 +173,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 decodeable 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 decodeable = ofs->config.nfs_export; > + > + /* Lower file handle for non-upper non-decodeable */ > + if (!ovl_dentry_upper(dentry) && !decodeable) > + 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 decodeable file handle for non-indexed upper. > + */ > + if (ovl_dentry_upper(dentry) && decodeable && > !ovl_test_flag(OVL_INDEX, d_inode(dentry))) > return 0; > > @@ -204,7 +213,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) && decodeable) > return ovl_connect_layer(dentry); > > /* Lower file handle for indexed and non-upper dir/non-dir */ > @@ -875,3 +884,8 @@ const struct export_operations ovl_export_operations = { > .get_name = ovl_get_name, > .get_parent = ovl_get_parent, > }; > + > +/* encode_fh() encodes non-decodeable file handles with nfs_export=off */ > +const struct export_operations ovl_export_fid_operations = { > + .encode_fh = ovl_encode_fh, > +}; > diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c > index 541cf3717fc2..b6bec4064390 100644 > --- a/fs/overlayfs/inode.c > +++ b/fs/overlayfs/inode.c > @@ -1304,7 +1304,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 */ > diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h > index 4d0b278f5630..87d44b889129 100644 > --- a/fs/overlayfs/overlayfs.h > +++ b/fs/overlayfs/overlayfs.h > @@ -734,3 +734,4 @@ 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; > diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h > index fd11fe6d6d45..5cc0b6e65488 100644 > --- a/fs/overlayfs/ovl_entry.h > +++ b/fs/overlayfs/ovl_entry.h > @@ -67,6 +67,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; > diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c > index f1d9f75f8786..5ed8c2650293 100644 > --- a/fs/overlayfs/super.c > +++ b/fs/overlayfs/super.c > @@ -954,6 +954,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. > @@ -1391,6 +1392,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) > @@ -2049,8 +2051,15 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) > ofs->config.nfs_export = false; > } > > + /* > + * Support encoding decodeable file handles with nfs_export=on > + * and encoding non-decodeable 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); > -- > 2.34.1 >