Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp3470992imm; Tue, 29 May 2018 07:49:33 -0700 (PDT) X-Google-Smtp-Source: AB8JxZr4lj9B3zkaBhS1bFytMDzb5Qf7yo8uk4iKIToB/y58YDQGvsWb6Z3VMwOQWg7JehT0R/oz X-Received: by 2002:a17:902:bb81:: with SMTP id m1-v6mr14387509pls.117.1527605372986; Tue, 29 May 2018 07:49:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527605372; cv=none; d=google.com; s=arc-20160816; b=0FhO+k2B26JGyLH1Ic+J7cWK4j74bgT3mkea4HbnO1LUxXK9PUAMKZkm47cjR1p+D/ tOHDCpm48NYYHzApm47nDMkNhkDO8JEeCXv5kN3DmtbpVh+YTQeX59GhNLkVVRzoKOH9 obhEHOn4v6OTnobDpzTSZiL6I9dpn7xJV5z5zZkHRj0yg7I/nIUBpA4euRiMDXbJIQnP wE3IafhIT/YK/GsZWuZFaq912/UI99ihyswdUrTA7dgSy7xeU+uF2F9eD5rlrc8As4vK XfQg5cv/PHTiJAFaqcngmpkdfmuZlXi+r2OogsWijnVniD/A0ltbqu+f0q0zRxF5NIqB d/1A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=nGRz8vYCLTy70vxps3g840DCu6g3pyPa/5D51Ssm/fE=; b=Z7wSnaa/ka41t84sAAVLqwpeXp09Z/BIKCCqeecu85LZL0Q4squKG7PZcb/R+WJXGV owxWxH2Pbbc3dnNp8lQW72kyzDDqBclYh2eVqDelgc2sogtkp8Nwp6G8SdA2sC1B3IBi 1WLxIhfUzqqmlVqEGALKjpc47r4geGeT7NQww5HdiJqtY1BDsv11ODErNJK9sroxgkRq I1GrVQ4yJVEK2scg4SS84Um4Hk2Im4UYhkyayP7aryf22oZAXGBB6zCJk4f8tlpMMKVt rz3x2Vo1eYW4Z8petzc+I6zE2B/QJBUdBgJGwNJOD0jEi2sVVs19JBov/atguJHTPe7N tpBw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r126-v6si33422822pfc.202.2018.05.29.07.49.19; Tue, 29 May 2018 07:49:32 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S936735AbeE2OrR (ORCPT + 99 others); Tue, 29 May 2018 10:47:17 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:50825 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S936564AbeE2Oqp (ORCPT ); Tue, 29 May 2018 10:46:45 -0400 Received: by mail-wm0-f68.google.com with SMTP id t11-v6so41425427wmt.0 for ; Tue, 29 May 2018 07:46:45 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=nGRz8vYCLTy70vxps3g840DCu6g3pyPa/5D51Ssm/fE=; b=Qjew3AKsMtok/f4klRVyYVXuCPg1duZWLxJmt1Nnp7eKP2DPadWuX9QYqJ1sbOfDOO 3mz29MGA7TLc/0NsXbKAHFIw89vGzLvmun2Sm0EPZE0bLJQyVgF0VdcOn8ub9/UoGFI1 J92Dob3Lo/lrxx9jw4sktxF7zEYnSPEogcMVnLBOL+m4a01sJMIg4NTn1RN7XNeOrp8b Mi+Du2bfCFtzCtowMuHaTEfAx8hMQWMXDC168F2l1wJiIwSsbF9tmzmuVBnGzk3kgaSl khmCkY+EXpNgKSd/8tdpQ501vEtJq61Y2CBQx+c/I3LkocQTuiQzqIsAnuvxVAZpv3H2 1EYQ== X-Gm-Message-State: ALKqPwflQWSBOKFc4lEWTBqkd6NmXs1k4x/IQxASgR4R9idGA/aX35II 1mY5nls68+ANmQDrW7u4/9Gu4Q== X-Received: by 2002:a1c:8ec1:: with SMTP id q184-v6mr1323549wmd.48.1527605204590; Tue, 29 May 2018 07:46:44 -0700 (PDT) Received: from veci.piliscsaba.redhat.com (catv-176-63-54-97.catv.broadband.hu. [176.63.54.97]) by smtp.gmail.com with ESMTPSA id n71-v6sm20942227wmi.14.2018.05.29.07.46.43 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 29 May 2018 07:46:44 -0700 (PDT) From: Miklos Szeredi To: linux-unionfs@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 24/28] ovl: Check redirect on index as well Date: Tue, 29 May 2018 16:46:08 +0200 Message-Id: <20180529144612.16675-25-mszeredi@redhat.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180529144612.16675-1-mszeredi@redhat.com> References: <20180529144612.16675-1-mszeredi@redhat.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Vivek Goyal Right now we seem to check redirect only if upperdentry is found. But it is possible that there is no upperdentry but later we found an index. We need to check redirect on index as well and set it in ovl_inode->redirect. Otherwise link code can assume that dentry does not have redirect and place a new one which breaks things. In my testing overlay/033 test started failing in xfstests. Following are the details. For example do following. $ mkdir lower upper work merged - Make lower dir with 4 links. $ echo "foo" > lower/l0.txt $ ln lower/l0.txt lower/l1.txt $ ln lower/l0.txt lower/l2.txt $ ln lower/l0.txt lower/l3.txt - Mount with index on and metacopy on. $ mount -t overlay -o lowerdir=lower,upperdir=upper,workdir=work,\ index=on,metacopy=on none merged - Link lower $ ln merged/l0.txt merged/l4.txt (This will metadata copy up of l0.txt and put an absolute redirect /l0.txt) $ echo 2 > /proc/sys/vm/drop/caches $ ls merged/l1.txt (Now l1.txt will be looked up. There is no upper dentry but there is lower dentry and index will be found. We don't check for redirect on index, hence ovl_inode->redirect will be NULL.) - Link Upper $ ln merged/l4.txt merged/l5.txt (Lookup of l4.txt will use inode from l1.txt lookup which is still in cache. It has ovl_inode->redirect NULL, hence link will put a new redirect and replace /l0.txt with /l4.txt - Drop caches. echo 2 > /proc/sys/vm/drop_caches - List l1.txt and it returns -ESTALE $ ls merged/l0.txt (It returns stale because, we found a metacopy of l0.txt in upper and it has redirect l4.txt but there is no file named l4.txt in lower layer. So lower data copy is not found and -ESTALE is returned.) So problem here is that we did not process redirect on index. Check redirect on index as well and then problem is fixed. Signed-off-by: Vivek Goyal Reviewed-by: Amir Goldstein Signed-off-by: Miklos Szeredi --- fs/overlayfs/namei.c | 50 +++++++++++++----------------------------------- fs/overlayfs/overlayfs.h | 1 + fs/overlayfs/util.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 37 deletions(-) diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index e38fa61e08df..2acd494ea9f0 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -31,32 +31,13 @@ static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d, size_t prelen, const char *post) { int res; - char *s, *next, *buf = NULL; + char *buf; - res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, NULL, 0); - if (res < 0) { - if (res == -ENODATA || res == -EOPNOTSUPP) - return 0; - goto fail; - } - buf = kzalloc(prelen + res + strlen(post) + 1, GFP_KERNEL); - if (!buf) - return -ENOMEM; + buf = ovl_get_redirect_xattr(dentry, prelen + strlen(post)); + if (IS_ERR_OR_NULL(buf)) + return PTR_ERR(buf); - if (res == 0) - goto invalid; - - res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, buf, res); - if (res < 0) - goto fail; - if (res == 0) - goto invalid; if (buf[0] == '/') { - for (s = buf; *s++ == '/'; s = next) { - next = strchrnul(s, '/'); - if (s == next) - goto invalid; - } /* * One of the ancestor path elements in an absolute path * lookup in ovl_lookup_layer() could have been opaque and @@ -67,9 +48,7 @@ static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d, */ d->stop = false; } else { - if (strchr(buf, '/') != NULL) - goto invalid; - + res = strlen(buf) + 1; memmove(buf + prelen, buf, res); memcpy(buf, d->name.name, prelen); } @@ -81,16 +60,6 @@ static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d, d->name.len = strlen(d->redirect); return 0; - -err_free: - kfree(buf); - return 0; -fail: - pr_warn_ratelimited("overlayfs: failed to get redirect (%i)\n", res); - goto err_free; -invalid: - pr_warn_ratelimited("overlayfs: invalid redirect (%s)\n", buf); - goto err_free; } static int ovl_acceptable(void *ctx, struct dentry *dentry) @@ -1071,8 +1040,15 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, if (upperdentry) ovl_dentry_set_upper_alias(dentry); - else if (index) + else if (index) { upperdentry = dget(index); + upperredirect = ovl_get_redirect_xattr(upperdentry, 0); + if (IS_ERR(upperredirect)) { + err = PTR_ERR(upperredirect); + upperredirect = NULL; + goto out_free_oe; + } + } if (upperdentry || ctr) { struct ovl_inode_params oip = { diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index bde352e414e7..24f1d0e8a178 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -276,6 +276,7 @@ void ovl_nlink_end(struct dentry *dentry, bool locked); int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir); int ovl_check_metacopy_xattr(struct dentry *dentry); bool ovl_is_metacopy_dentry(struct dentry *dentry); +char *ovl_get_redirect_xattr(struct dentry *dentry, int padding); static inline bool ovl_is_impuredir(struct dentry *dentry) { diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 1aa9e0c5a327..8cfb62cc8672 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -865,3 +865,53 @@ bool ovl_is_metacopy_dentry(struct dentry *dentry) return (oe->numlower > 1); } + +char *ovl_get_redirect_xattr(struct dentry *dentry, int padding) +{ + int res; + char *s, *next, *buf = NULL; + + res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, NULL, 0); + if (res < 0) { + if (res == -ENODATA || res == -EOPNOTSUPP) + return NULL; + goto fail; + } + + buf = kzalloc(res + padding + 1, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + if (res == 0) + goto invalid; + + res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, buf, res); + if (res < 0) + goto fail; + if (res == 0) + goto invalid; + + if (buf[0] == '/') { + for (s = buf; *s++ == '/'; s = next) { + next = strchrnul(s, '/'); + if (s == next) + goto invalid; + } + } else { + if (strchr(buf, '/') != NULL) + goto invalid; + } + + return buf; + +err_free: + kfree(buf); + return ERR_PTR(res); +fail: + pr_warn_ratelimited("overlayfs: failed to get redirect (%i)\n", res); + goto err_free; +invalid: + pr_warn_ratelimited("overlayfs: invalid redirect (%s)\n", buf); + res = -EINVAL; + goto err_free; +} -- 2.14.3