From: Amir Goldstein <amir73il@gmail.com>
To: Miklos Szeredi <miklos@szeredi.hu>
Cc: zhangyi <yi.zhang@huawei.com>, linux-unionfs@vger.kernel.org
Subject: [PATCH 2/3] ovl: set origin xattr for merge dir on lookup
Date: Tue, 7 Nov 2017 23:38:59 +0200 [thread overview]
Message-ID: <1510090740-7216-3-git-send-email-amir73il@gmail.com> (raw)
In-Reply-To: <1510090740-7216-1-git-send-email-amir73il@gmail.com>
For old existing merge dirs whose "origin" xattr was not set at copy up
time, we amend the situation on lookup.
If no origin fh is stored in upper of a merge dir, store fh of upper most
lower dir or 'null' fh if lower does not support file handles. We do this
so we can filter out whiteouts in case lower dir is removed offline and
then upper dir becomes a pure upper in a future mount.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/overlayfs/namei.c | 61 ++++++++++++++++++++++++++++++++++++++++--------
fs/overlayfs/overlayfs.h | 2 +-
fs/overlayfs/super.c | 4 ++--
3 files changed, 54 insertions(+), 13 deletions(-)
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 322c6214114f..65606a0a124c 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -87,6 +87,8 @@ static int ovl_acceptable(void *ctx, struct dentry *dentry)
return 1;
}
+static struct ovl_fh ovl_null_fh;
+
static struct ovl_fh *ovl_get_origin_fh(struct dentry *dentry)
{
int res;
@@ -100,7 +102,7 @@ static struct ovl_fh *ovl_get_origin_fh(struct dentry *dentry)
}
/* Zero size value means "copied up but origin unknown" */
if (res == 0)
- return NULL;
+ goto null_fh;
fh = kzalloc(res, GFP_KERNEL);
if (!fh)
@@ -118,12 +120,12 @@ static struct ovl_fh *ovl_get_origin_fh(struct dentry *dentry)
/* Treat larger version and unknown flags as "origin unknown" */
if (fh->version > OVL_FH_VERSION || fh->flags & ~OVL_FH_FLAG_ALL)
- goto out;
+ goto null_fh;
/* Treat endianness mismatch as "origin unknown" */
if (!(fh->flags & OVL_FH_FLAG_ANY_ENDIAN) &&
(fh->flags & OVL_FH_FLAG_BIG_ENDIAN) != OVL_FH_FLAG_CPU_ENDIAN)
- goto out;
+ goto null_fh;
return fh;
@@ -131,6 +133,10 @@ static struct ovl_fh *ovl_get_origin_fh(struct dentry *dentry)
kfree(fh);
return NULL;
+null_fh:
+ kfree(fh);
+ return &ovl_null_fh;
+
fail:
pr_warn_ratelimited("overlayfs: failed to get origin (%i)\n", res);
goto out;
@@ -149,6 +155,9 @@ static struct dentry *ovl_get_origin(struct dentry *dentry,
if (IS_ERR_OR_NULL(fh))
return (struct dentry *)fh;
+ if (fh == &ovl_null_fh)
+ return NULL;
+
/*
* Make sure that the stored uuid matches the uuid of the lower
* layer where file handle will be decoded.
@@ -333,6 +342,10 @@ static int ovl_verify_origin_fh(struct dentry *dentry, const struct ovl_fh *fh)
if (IS_ERR(ofh))
return PTR_ERR(ofh);
+ /* NULL fh (no lower fh support) and stored 'null' fh is a match */
+ if (ofh == &ovl_null_fh)
+ return fh ? -ESTALE : 0;
+
if (fh->len != ofh->len || memcmp(fh, ofh, fh->len))
err = -ESTALE;
@@ -345,24 +358,40 @@ static int ovl_verify_origin_fh(struct dentry *dentry, const struct ovl_fh *fh)
*
* If @set is true and there is no stored file handle, encode and store origin
* file handle in OVL_XATTR_ORIGIN.
+ * If @strict is true, then the stored file handle must be non 'null'.
+ * If @strict is false, then a stored 'null' file handle and lower with no file
+ * handle support is considered a match.
*
* Return 0 on match, -ESTALE on mismatch, < 0 on error.
*/
int ovl_verify_origin(struct dentry *dentry, struct dentry *origin,
- bool is_upper, bool set)
+ bool is_upper, bool set, bool strict)
{
struct inode *inode;
- struct ovl_fh *fh;
+ const struct ovl_fh *fh = NULL;
int err;
- fh = ovl_encode_fh(origin, is_upper);
- err = PTR_ERR(fh);
- if (IS_ERR(fh))
+ /*
+ * When lower layer doesn't support export operations store a 'null' fh,
+ * so we can use the overlay.origin xattr to distignuish between a copy
+ * up and a pure upper inode.
+ */
+ err = -EOPNOTSUPP;
+ if (ovl_can_decode_fh(origin->d_sb)) {
+ fh = ovl_encode_fh(origin, is_upper);
+ err = PTR_ERR(fh);
+ if (IS_ERR(fh))
+ goto fail;
+ } else if (strict) {
goto fail;
+ }
err = ovl_verify_origin_fh(dentry, fh);
- if (set && err == -ENODATA)
- err = ovl_do_setxattr(dentry, OVL_XATTR_ORIGIN, fh, fh->len, 0);
+ if (set && err == -ENODATA) {
+ err = ovl_do_setxattr(dentry, OVL_XATTR_ORIGIN, fh,
+ fh ? fh->len : 0, 0);
+ }
+
if (err)
goto fail;
@@ -662,6 +691,18 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
if (!this)
continue;
+ /*
+ * If no origin fh is stored in upper of a merge dir, store fh
+ * of upper most lower dir or 'null' fh if lower does not
+ * support file handles. We do this so we can filter out
+ * whiteouts in case lower dir is removed offline and this upper
+ * becomes a pure upper in a future mount.
+ */
+ if (this && upperdentry && !ctr) {
+ (void)ovl_verify_origin(upperdentry, this,
+ false, true, false);
+ }
+
stack[ctr].dentry = this;
stack[ctr].layer = lower.layer;
ctr++;
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index bee51296db38..df925188394f 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -252,7 +252,7 @@ static inline bool ovl_is_impuredir(struct dentry *dentry)
/* namei.c */
int ovl_verify_origin(struct dentry *dentry, struct dentry *origin,
- bool is_upper, bool set);
+ bool is_upper, bool set, bool strict);
int ovl_verify_index(struct dentry *index, struct ovl_path *lower,
unsigned int numlower);
int ovl_get_index_name(struct dentry *origin, struct qstr *name);
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index af4d3e876398..f8bba4f8b940 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1120,7 +1120,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
/* Verify lower root is upper root origin */
err = ovl_verify_origin(upperpath.dentry,
oe->lowerstack[0].dentry,
- false, true);
+ false, true, true);
if (err) {
pr_err("overlayfs: failed to verify upper root origin\n");
goto out_free_oe;
@@ -1131,7 +1131,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
if (ufs->indexdir) {
/* Verify upper root is index dir origin */
err = ovl_verify_origin(ufs->indexdir, upperpath.dentry,
- true, true);
+ true, true, true);
if (err)
pr_err("overlayfs: failed to verify index dir origin\n");
--
2.7.4
next prev parent reply other threads:[~2017-11-07 21:38 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-11-07 21:38 [PATCH 0/3] Overlayfs restoring of origin fh Amir Goldstein
2017-11-07 21:38 ` [PATCH 1/3] ovl: remove unneeded arg from ovl_verify_origin() Amir Goldstein
2017-11-07 21:38 ` Amir Goldstein [this message]
2017-11-08 6:59 ` [PATCH 2/3] ovl: set origin xattr for merge dir on lookup zhangyi (F)
2017-11-08 8:27 ` Amir Goldstein
2017-11-08 13:30 ` Amir Goldstein
2017-11-09 4:20 ` zhangyi (F)
2017-11-07 21:39 ` [PATCH 3/3] ovl: recover from whiteouts in impure dir iteration Amir Goldstein
2017-11-09 10:07 ` [PATCH 0/3] Overlayfs restoring of origin fh Miklos Szeredi
2017-11-09 11:33 ` Amir Goldstein
2017-11-09 11:46 ` zhangyi (F)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1510090740-7216-3-git-send-email-amir73il@gmail.com \
--to=amir73il@gmail.com \
--cc=linux-unionfs@vger.kernel.org \
--cc=miklos@szeredi.hu \
--cc=yi.zhang@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).