Skip to content

Commit 16aac5a

Browse files
committed
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>
1 parent 0c71faf commit 16aac5a

File tree

5 files changed

+32
-7
lines changed

5 files changed

+32
-7
lines changed

fs/overlayfs/export.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,28 +174,37 @@ static int ovl_connect_layer(struct dentry *dentry)
174174
* U = upper file handle
175175
* L = lower file handle
176176
*
177-
* (*) Connecting an overlay dir from real lower dentry is not always
177+
* (*) Decoding a connected overlay dir from real lower dentry is not always
178178
* possible when there are redirects in lower layers and non-indexed merge dirs.
179179
* To mitigate those case, we may copy up the lower dir ancestor before encode
180-
* a lower dir file handle.
180+
* of a decodable file handle for non-upper dir.
181181
*
182182
* Return 0 for upper file handle, > 0 for lower file handle or < 0 on error.
183183
*/
184184
static int ovl_check_encode_origin(struct dentry *dentry)
185185
{
186186
struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
187+
bool decodable = ofs->config.nfs_export;
188+
189+
/* Lower file handle for non-upper non-decodable */
190+
if (!ovl_dentry_upper(dentry) && !decodable)
191+
return 0;
187192

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

192197
/*
193-
* Upper file handle for non-indexed upper.
194-
*
195198
* Root is never indexed, so if there's an upper layer, encode upper for
196199
* root.
197200
*/
198-
if (ovl_dentry_upper(dentry) &&
201+
if (dentry == dentry->d_sb->s_root)
202+
return 0;
203+
204+
/*
205+
* Upper decodable file handle for non-indexed upper.
206+
*/
207+
if (ovl_dentry_upper(dentry) && decodable &&
199208
!ovl_test_flag(OVL_INDEX, d_inode(dentry)))
200209
return 0;
201210

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

211220
/* Lower file handle for indexed and non-upper dir/non-dir */
@@ -876,3 +885,8 @@ const struct export_operations ovl_export_operations = {
876885
.get_name = ovl_get_name,
877886
.get_parent = ovl_get_parent,
878887
};
888+
889+
/* encode_fh() encodes non-decodable file handles with nfs_export=off */
890+
const struct export_operations ovl_export_fid_operations = {
891+
.encode_fh = ovl_encode_fh,
892+
};

fs/overlayfs/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1311,7 +1311,7 @@ static bool ovl_hash_bylower(struct super_block *sb, struct dentry *upper,
13111311
return false;
13121312

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

13171317
/* Otherwise, hash by lower inode for fsnotify */

fs/overlayfs/overlayfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,7 @@ int ovl_set_origin(struct ovl_fs *ofs, struct dentry *lower,
799799

800800
/* export.c */
801801
extern const struct export_operations ovl_export_operations;
802+
extern const struct export_operations ovl_export_fid_operations;
802803

803804
/* super.c */
804805
int ovl_fill_super(struct super_block *sb, struct fs_context *fc);

fs/overlayfs/ovl_entry.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ struct ovl_fs {
8282
const struct cred *creator_cred;
8383
bool tmpfile;
8484
bool noxattr;
85+
bool nofh;
8586
/* Did we take the inuse lock? */
8687
bool upperdir_locked;
8788
bool workdir_locked;

fs/overlayfs/super.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ static int ovl_lower_dir(const char *name, struct path *path,
400400
pr_warn("fs on '%s' does not support file handles, falling back to index=off,nfs_export=off.\n",
401401
name);
402402
}
403+
ofs->nofh |= !fh_type;
403404
/*
404405
* Decoding origin file handle is required for persistent st_ino.
405406
* 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,
818819
ofs->config.index = false;
819820
pr_warn("upper fs does not support file handles, falling back to index=off.\n");
820821
}
822+
ofs->nofh |= !fh_type;
821823

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

1457+
/*
1458+
* Support encoding decodable file handles with nfs_export=on
1459+
* and encoding non-decodable file handles with nfs_export=off
1460+
* if all layers support file handles.
1461+
*/
14551462
if (ofs->config.nfs_export)
14561463
sb->s_export_op = &ovl_export_operations;
1464+
else if (!ofs->nofh)
1465+
sb->s_export_op = &ovl_export_fid_operations;
14571466

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

0 commit comments

Comments
 (0)