Skip to content

Commit 8a22efa

Browse files
amir73ilMiklos Szeredi
authored andcommitted
ovl: do not try to reconnect a disconnected origin dentry
On lookup of non directory, we try to decode the origin file handle stored in upper inode. The origin file handle is supposed to be decoded to a disconnected non-dir dentry, which is fine, because we only need the lower inode of a copy up origin. However, if the origin file handle somehow turns out to be a directory we pay the expensive cost of reconnecting the directory dentry, only to get a mismatch file type and drop the dentry. Optimize this case by explicitly opting out of reconnecting the dentry. Opting-out of reconnect is done by passing a NULL acceptable callback to exportfs_decode_fh(). While the case described above is a strange corner case that does not really need to be optimized, the API added for this optimization will be used by a following patch to optimize a more common case of decoding an overlayfs file handle. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
1 parent 5b2cccd commit 8a22efa

File tree

4 files changed

+23
-11
lines changed

4 files changed

+23
-11
lines changed

fs/exportfs/expfs.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,15 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
435435
if (IS_ERR_OR_NULL(result))
436436
return ERR_PTR(-ESTALE);
437437

438+
/*
439+
* If no acceptance criteria was specified by caller, a disconnected
440+
* dentry is also accepatable. Callers may use this mode to query if
441+
* file handle is stale or to get a reference to an inode without
442+
* risking the high overhead caused by directory reconnect.
443+
*/
444+
if (!acceptable)
445+
return result;
446+
438447
if (d_is_dir(result)) {
439448
/*
440449
* This request is for a directory.

fs/overlayfs/export.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,7 @@ static struct dentry *ovl_upper_fh_to_d(struct super_block *sb,
685685
if (!ofs->upper_mnt)
686686
return ERR_PTR(-EACCES);
687687

688-
upper = ovl_decode_real_fh(fh, ofs->upper_mnt);
688+
upper = ovl_decode_real_fh(fh, ofs->upper_mnt, true);
689689
if (IS_ERR_OR_NULL(upper))
690690
return upper;
691691

@@ -735,7 +735,7 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb,
735735
}
736736

737737
/* Then lookup origin by fh */
738-
err = ovl_check_origin_fh(ofs, fh, NULL, &stack);
738+
err = ovl_check_origin_fh(ofs, fh, true, NULL, &stack);
739739
if (err) {
740740
goto out_err;
741741
} else if (index) {

fs/overlayfs/namei.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ static struct ovl_fh *ovl_get_fh(struct dentry *dentry, const char *name)
180180
goto out;
181181
}
182182

183-
struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt)
183+
struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt,
184+
bool connected)
184185
{
185186
struct dentry *real;
186187
int bytes;
@@ -195,7 +196,7 @@ struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt)
195196
bytes = (fh->len - offsetof(struct ovl_fh, fid));
196197
real = exportfs_decode_fh(mnt, (struct fid *)fh->fid,
197198
bytes >> 2, (int)fh->type,
198-
ovl_acceptable, mnt);
199+
connected ? ovl_acceptable : NULL, mnt);
199200
if (IS_ERR(real)) {
200201
/*
201202
* Treat stale file handle to lower file as "origin unknown".
@@ -319,14 +320,15 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
319320
}
320321

321322

322-
int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh,
323+
int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected,
323324
struct dentry *upperdentry, struct ovl_path **stackp)
324325
{
325326
struct dentry *origin = NULL;
326327
int i;
327328

328329
for (i = 0; i < ofs->numlower; i++) {
329-
origin = ovl_decode_real_fh(fh, ofs->lower_layers[i].mnt);
330+
origin = ovl_decode_real_fh(fh, ofs->lower_layers[i].mnt,
331+
connected);
330332
if (origin)
331333
break;
332334
}
@@ -370,7 +372,7 @@ static int ovl_check_origin(struct ovl_fs *ofs, struct dentry *upperdentry,
370372
if (IS_ERR_OR_NULL(fh))
371373
return PTR_ERR(fh);
372374

373-
err = ovl_check_origin_fh(ofs, fh, upperdentry, stackp);
375+
err = ovl_check_origin_fh(ofs, fh, false, upperdentry, stackp);
374376
kfree(fh);
375377

376378
if (err) {
@@ -460,7 +462,7 @@ struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index)
460462
if (IS_ERR_OR_NULL(fh))
461463
return ERR_CAST(fh);
462464

463-
upper = ovl_decode_real_fh(fh, ofs->upper_mnt);
465+
upper = ovl_decode_real_fh(fh, ofs->upper_mnt, true);
464466
kfree(fh);
465467

466468
if (IS_ERR_OR_NULL(upper))
@@ -567,7 +569,7 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index)
567569

568570
/* Check if non-dir index is orphan and don't warn before cleaning it */
569571
if (!d_is_dir(index) && d_inode(index)->i_nlink == 1) {
570-
err = ovl_check_origin_fh(ofs, fh, index, &stack);
572+
err = ovl_check_origin_fh(ofs, fh, false, index, &stack);
571573
if (err)
572574
goto fail;
573575

fs/overlayfs/overlayfs.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,9 @@ static inline bool ovl_is_impuredir(struct dentry *dentry)
266266

267267
/* namei.c */
268268
int ovl_check_fh_len(struct ovl_fh *fh, int fh_len);
269-
struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt);
270-
int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh,
269+
struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt,
270+
bool connected);
271+
int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected,
271272
struct dentry *upperdentry, struct ovl_path **stackp);
272273
int ovl_verify_set_fh(struct dentry *dentry, const char *name,
273274
struct dentry *real, bool is_upper, bool set);

0 commit comments

Comments
 (0)