From: Amir Goldstein <amir73il@gmail.com>
To: Miklos Szeredi <miklos@szeredi.hu>
Cc: Al Viro <viro@zeniv.linux.org.uk>,
linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org
Subject: [PATCH v2 23/23] ovl: copy up on read operations on indexed lower
Date: Thu, 8 Jun 2017 18:00:49 +0300 [thread overview]
Message-ID: <1496934049-11216-3-git-send-email-amir73il@gmail.com> (raw)
In-Reply-To: <1496934049-11216-1-git-send-email-amir73il@gmail.com>
With inodes index feature, all lower and upper hardlinks point to
the same overlay inode. However, when a lower hardlink is accessed
for read operation, the real inode operated on is not the same inode
as the real inode for read operation on an upper hardlink.
When accessing a lower hardlink for read, which is already indexed by
an earlier upper hardlink copy up, call ovl_copy_up() to link the
indexed upper on top of the lower hardlink and then operate on the
upper real inode to avoid this inconsistency.
The following test demonstrates the upper/lower hardlinks inconsistency:
$ echo -n a > /lower/foo
$ ln /lower/foo /lower/bar
$ cd /mnt
$ tail foo bar # both aliases are ro lower
==> foo <==
a
==> bar <==
a
$ echo -n b >> foo
$ tail foo bar # foo is rw upper, bar is ro lower
==> foo <==
ab
==> bar <==
a
$ echo -n c >> bar
$ tail foo bar # both aliases are rw upper
==> foo <==
abc
==> bar <==
abc
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/overlayfs/copy_up.c | 28 ++++++++++++++++++++++++++++
fs/overlayfs/overlayfs.h | 1 +
fs/overlayfs/super.c | 4 +++-
fs/overlayfs/util.c | 12 +++++++++++-
4 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 8a297cfc33fb..27aabed25680 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -1023,3 +1023,31 @@ int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags)
return err;
}
+
+/* Copy up on read ops of non-dir indexed lower */
+int ovl_maybe_ro_copy_up(struct dentry *dentry)
+{
+ enum ovl_path_type type = ovl_path_type(dentry);
+ int err;
+
+ if (WARN_ON(!d_inode(dentry)) || d_is_dir(dentry) ||
+ OVL_TYPE_UPPER(type) || !OVL_TYPE_INDEX(type))
+ return 0;
+
+ err = ovl_want_write(dentry);
+ if (err)
+ goto fail;
+
+ err = ovl_copy_up(dentry);
+ ovl_drop_write(dentry);
+
+ if (err)
+ goto fail;
+
+ return 0;
+
+fail:
+ pr_warn_ratelimited("overlayfs: failed copy up on read (%pd2, err=%i)\n",
+ dentry, err);
+ return err;
+}
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 434870f5bb4b..10df85d41546 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -305,6 +305,7 @@ void ovl_cleanup(struct inode *dir, struct dentry *dentry);
/* copy_up.c */
int ovl_copy_up(struct dentry *dentry);
int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags);
+int ovl_maybe_ro_copy_up(struct dentry *dentry);
int ovl_copy_xattr(struct dentry *old, struct dentry *new);
int ovl_set_attr(struct dentry *upper, struct kstat *stat);
struct ovl_fh *ovl_encode_fh(struct dentry *lower, bool is_upper);
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 4cf18850b4de..5ef9ce7489be 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -76,6 +76,8 @@ static struct dentry *ovl_d_real(struct dentry *dentry,
unsigned int open_flags)
{
struct dentry *real;
+ /* Copy up on open for read of indexed lower */
+ bool rocopyup = !inode && ovl_indexdir(dentry->d_sb);
int err;
if (!d_is_reg(dentry)) {
@@ -87,7 +89,7 @@ static struct dentry *ovl_d_real(struct dentry *dentry,
if (d_is_negative(dentry))
return dentry;
- if (open_flags) {
+ if (open_flags || rocopyup) {
err = ovl_open_maybe_copy_up(dentry, open_flags);
if (err)
return ERR_PTR(err);
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index fa6c2ae4a747..bad3df557cc6 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -14,6 +14,7 @@
#include <linux/xattr.h>
#include <linux/exportfs.h>
#include <linux/uuid.h>
+#include <linux/ratelimit.h>
#include "overlayfs.h"
#include "ovl_entry.h"
@@ -131,10 +132,15 @@ void ovl_path_lower(struct dentry *dentry, struct path *path)
*path = oe->numlower ? oe->lowerstack[0] : (struct path) { };
}
+/* Caller must not hold ovl_want_write(dentry) */
enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path)
{
- enum ovl_path_type type = ovl_path_type(dentry);
+ enum ovl_path_type type;
+ /* best effort copy up indexed lower */
+ ovl_maybe_ro_copy_up(dentry);
+
+ type = ovl_path_type(dentry);
if (!OVL_TYPE_UPPER(type))
ovl_path_lower(dentry, path);
else
@@ -169,11 +175,15 @@ struct dentry *ovl_dentry_index(struct dentry *dentry)
return oe->indexdentry;
}
+/* Caller must not hold ovl_want_write(dentry) */
struct dentry *ovl_dentry_real(struct dentry *dentry)
{
struct ovl_entry *oe = dentry->d_fsdata;
struct dentry *realdentry;
+ /* Best effort copy up of indexed lower */
+ ovl_maybe_ro_copy_up(dentry);
+
realdentry = ovl_upperdentry_dereference(oe);
if (!realdentry)
realdentry = __ovl_dentry_lower(oe);
--
2.7.4
next prev parent reply other threads:[~2017-06-08 15:00 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-06-07 7:51 [PATCH v2 00/20] Overlayfs inodes index Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 01/20] vfs: introduce inode 'inuse' lock Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 02/20] ovl: get exclusive ownership on upper/work dirs Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 03/20] ovl: relax same fs constrain for ovl_check_origin() Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 04/20] ovl: generalize ovl_create_workdir() Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 05/20] ovl: introduce the inodes index dir feature Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 06/20] ovl: verify upper root dir matches lower root dir Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 07/20] ovl: verify index dir matches upper dir Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 08/20] ovl: lookup index entry for non-dir Amir Goldstein
2017-06-08 12:11 ` Miklos Szeredi
2017-06-08 14:48 ` Amir Goldstein
2017-06-08 15:17 ` Miklos Szeredi
2017-06-08 16:09 ` Amir Goldstein
2017-06-09 8:43 ` Miklos Szeredi
2017-06-09 9:38 ` Amir Goldstein
2017-06-09 11:49 ` Miklos Szeredi
2017-06-09 13:14 ` Miklos Szeredi
2017-06-09 13:24 ` Amir Goldstein
2017-06-09 13:29 ` Miklos Szeredi
2017-06-09 22:56 ` Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 09/20] ovl: move inode helpers to inode.c Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 10/20] ovl: use ovl_inode_init() for initializing new inode Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 11/20] ovl: hash overlay non-dir inodes by copy up origin inode Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 12/20] ovl: fix nlink leak in ovl_rename() Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 13/20] ovl: adjust overlay inode nlink for indexed inodes Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 14/20] ovl: defer upper dir lock to tempfile link Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 15/20] ovl: factor out ovl_copy_up_inode() helper Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 16/20] ovl: generalize ovl_copy_up_locked() using actors Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 17/20] ovl: generalize ovl_copy_up_one() " Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 18/20] ovl: implement index dir copy up method Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 19/20] ovl: handle race of concurrent lower hardlinks copy up Amir Goldstein
2017-06-07 7:51 ` [PATCH v2 20/20] ovl: constant inode number for hardlinks Amir Goldstein
2017-06-07 7:54 ` [PATCH v2 00/20] Overlayfs inodes index Miklos Szeredi
2017-06-07 7:58 ` Amir Goldstein
2017-06-07 14:58 ` Amir Goldstein
2017-06-08 15:00 ` [PATCH v2 21/23] ovl: use inodes index on readonly mount Amir Goldstein
2017-06-08 15:00 ` [PATCH v2 22/23] ovl: move copy up helpers to copy_up.c Amir Goldstein
2017-06-08 15:00 ` Amir Goldstein [this message]
2017-06-07 17:17 ` [PATCH v2 00/20] Overlayfs inodes index J. Bruce Fields
2017-06-07 18:36 ` Amir Goldstein
2017-06-07 18:59 ` J. Bruce Fields
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=1496934049-11216-3-git-send-email-amir73il@gmail.com \
--to=amir73il@gmail.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-unionfs@vger.kernel.org \
--cc=miklos@szeredi.hu \
--cc=viro@zeniv.linux.org.uk \
/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).