When non directory upper has overlay.fh xattr, lookup that file handle in lower layers to find the stable inode it refers to. Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> --- fs/overlayfs/namei.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index fcb7c15..42b6030 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -204,6 +204,9 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, if (d->fh) { kfree(d->fh); d->fh = NULL; + /* Follow once by file handle for non-dir */ + if (!d->is_dir) + d->by_fh = false; } if (!this->d_inode) @@ -219,15 +222,21 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, goto put_and_out; } if (!d_can_lookup(this)) { - d->stop = true; - if (d->is_dir) + if (d->is_dir) { + d->stop = true; goto put_and_out; - goto out; - } - d->is_dir = true; - if (!d->last && ovl_is_opaquedir(this)) { - d->stop = d->opaque = true; - goto out; + } + /* Lookup stable inode of non-dir by file handle */ + if (!d->by_fh) { + d->stop = true; + goto out; + } + } else { + d->is_dir = true; + if (!d->last && ovl_is_opaquedir(this)) { + d->stop = d->opaque = true; + goto out; + } } if (d->last) goto out; @@ -236,6 +245,11 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, if (err) goto out_err; } + /* No redirect fh for non-dir means pure upper */ + if (!d->is_dir) { + d->stop = !d->fh; + goto out; + } if (d->by_path) { err = ovl_check_redirect(this, d, prelen, post); if (err) -- 2.7.4