public inbox for linux-unionfs@vger.kernel.org
 help / color / mirror / Atom feed
From: Amir Goldstein <amir73il@gmail.com>
To: Miklos Szeredi <miklos@szeredi.hu>
Cc: Vivek Goyal <vgoyal@redhat.com>, cgxu519 <cgxu519@gmx.com>,
	linux-unionfs@vger.kernel.org
Subject: [RFC][PATCH v2 3/5] ovl: lazy copy up of data on first data access
Date: Tue, 22 Jan 2019 14:34:55 +0200	[thread overview]
Message-ID: <20190122123457.10600-4-amir73il@gmail.com> (raw)
In-Reply-To: <20190122123457.10600-1-amir73il@gmail.com>

When metacopy feature is enabled and filemap operations supported,
copy up only metadata when opening a file O_RDWR and defer copy up
of data until the first data access file operation.

Copy up on first page fault will be handled by a followup patch.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/overlayfs/copy_up.c   |  5 +---
 fs/overlayfs/file.c      | 63 +++++++++++++++++++++++++++++++++++-----
 fs/overlayfs/overlayfs.h | 10 ++++++-
 fs/overlayfs/util.c      |  4 +--
 4 files changed, 68 insertions(+), 14 deletions(-)

diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 05f853c7db0d..92a27ba65c78 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -731,10 +731,7 @@ static bool ovl_need_meta_copy_up(struct dentry *dentry, umode_t mode,
 	if (!S_ISREG(mode))
 		return false;
 
-	if (flags && ((OPEN_FMODE(flags) & FMODE_WRITE) || (flags & O_TRUNC)))
-		return false;
-
-	return true;
+	return !ovl_open_flags_need_data_copy_up(flags);
 }
 
 /* Copy up data of an inode which was copied up metadata only in the past. */
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
index 5f648979adbf..e02b61af9488 100644
--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -90,10 +90,24 @@ static int ovl_real_fdget_meta(const struct file *file, struct fd *real,
 {
 	struct inode *inode = file_inode(file);
 	struct inode *realinode;
+	int err;
 
 	real->flags = 0;
 	real->file = file->private_data;
 
+	/*
+	 * Lazy copy up caches the meta copy upper file on open O_RDWR.
+	 * We need to promote upper inode to full data copy up before
+	 * we allow access to real file data on a writable file, otherwise
+	 * we may try to open a lower file O_RDWR or perform data operations
+	 * (e.g. fallocate) on the metacopy inode.
+	 */
+	if (!allow_meta) {
+		err = ovl_maybe_copy_up(file_dentry(file), file->f_flags);
+		if (err)
+			return err;
+	}
+
 	if (allow_meta)
 		realinode = ovl_inode_real(inode);
 	else
@@ -127,11 +141,34 @@ static bool ovl_filemap_support(struct file *file)
 	return ofs->upper_mnt && ovl_aops.writepage;
 }
 
-static bool ovl_should_use_filemap(struct file *file)
+static bool ovl_should_use_filemap_meta(struct file *file, bool meta_only)
 {
+	int err;
+
 	if (!ovl_filemap_support(file))
 		return false;
 
+	/*
+	 * If file was opened O_RDWR with lazy copy up of data, the first
+	 * data access file operation will trigger data copy up. If file was
+	 * opened O_RDWR and @meta_only is true, we use overlay inode filemap
+	 * operations, but defer data copy up further.
+	 *
+	 * For example, mmap() and fsync() are metadata only operations that
+	 * do not trigger lazy copy up of data, but read() (on a file open for
+	 * write) is a data access operation that does trigger data copy up.
+	 */
+	if (!meta_only) {
+		err = ovl_maybe_copy_up(file_dentry(file), file->f_flags);
+		if (err) {
+			pr_warn_ratelimited("overlayfs: failed lazy copy up data (%pd2, err=%i)\n",
+					    file_dentry(file), err);
+			return false;
+		}
+	} else if (file->f_mode & FMODE_WRITE) {
+		return true;
+	}
+
 	/*
 	 * Use overlay inode page cache for all inodes that could be dirty,
 	 * including pure upper inodes, so ovl_sync_fs() can sync all dirty
@@ -140,9 +177,14 @@ static bool ovl_should_use_filemap(struct file *file)
 	return ovl_has_upperdata(file_inode(file));
 }
 
+static bool ovl_should_use_filemap(struct file *file)
+{
+	return ovl_should_use_filemap_meta(file, false);
+}
+
 static int ovl_flush_filemap(struct file *file, loff_t offset, loff_t len)
 {
-	if (!ovl_should_use_filemap(file))
+	if (!ovl_should_use_filemap_meta(file, true))
 		return 0;
 
 	return filemap_write_and_wait_range(file_inode(file)->i_mapping,
@@ -152,16 +194,23 @@ static int ovl_flush_filemap(struct file *file, loff_t offset, loff_t len)
 static int ovl_open(struct inode *inode, struct file *file)
 {
 	struct file *realfile;
+	int metacopy = 0;
 	int err;
 
-	err = ovl_maybe_copy_up(file_dentry(file), file->f_flags);
+	/* (O_RDWR | O_WRONLY) signals that we want meta copy up */
+	if (ovl_filemap_support(file) && (file->f_flags & O_ACCMODE) == O_RDWR)
+		metacopy = (O_RDWR | O_WRONLY);
+
+	/* Allow to copy up meta and defer copy up data to first data access */
+	err = ovl_maybe_copy_up(file_dentry(file), file->f_flags | metacopy);
 	if (err)
 		return err;
 
 	/* No longer need these flags, so don't pass them on to underlying fs */
 	file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 
-	realfile = ovl_open_realfile(file, ovl_inode_realdata(inode));
+	realfile = ovl_open_realfile(file, metacopy ? ovl_inode_real(inode) :
+				     ovl_inode_realdata(inode));
 	if (IS_ERR(realfile))
 		return PTR_ERR(realfile);
 
@@ -337,7 +386,7 @@ static int ovl_real_fsync(struct file *file, loff_t start, loff_t end,
 
 static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
-	if (ovl_should_use_filemap(file))
+	if (ovl_should_use_filemap_meta(file, true))
 		return __generic_file_fsync(file, start, end, datasync);
 
 	return ovl_real_fsync(file, start, end, datasync);
@@ -381,7 +430,7 @@ static int ovl_real_mmap(struct file *file, struct vm_area_struct *vma)
 
 static int ovl_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	if (ovl_should_use_filemap(file))
+	if (ovl_should_use_filemap_meta(file, true))
 		generic_file_mmap(file, vma);
 
 	return ovl_real_mmap(file, vma);
@@ -441,7 +490,7 @@ extern int generic_fadvise(struct file *file, loff_t offset, loff_t len,
 
 static int ovl_fadvise(struct file *file, loff_t offset, loff_t len, int advice)
 {
-	if (ovl_should_use_filemap(file))
+	if (ovl_should_use_filemap_meta(file, true))
 		return generic_fadvise(file, offset, len, advice);
 
 	/* XXX: Should we allow messing with lower shared page cache? */
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index ab61c07e8583..6baa3460c173 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -195,14 +195,22 @@ static inline struct dentry *ovl_do_tmpfile(struct dentry *dentry, umode_t mode)
 	return ret;
 }
 
-static inline bool ovl_open_flags_need_copy_up(int flags)
+static inline bool ovl_open_flags_need_data_copy_up(int flags)
 {
 	if (!flags)
 		return false;
 
+	/* Either O_RDWR or O_WRONLY will trigger data copy up */
 	return ((OPEN_FMODE(flags) & FMODE_WRITE) || (flags & O_TRUNC));
 }
 
+static inline bool ovl_open_flags_need_copy_up(int flags)
+{
+	/* O_RDWR|O_WRONLY together will trigger meta copy up */
+	return (flags & O_ACCMODE) == (O_RDWR | O_WRONLY) ||
+		ovl_open_flags_need_data_copy_up(flags);
+}
+
 /* util.c */
 int ovl_want_write(struct dentry *dentry);
 void ovl_drop_write(struct dentry *dentry);
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 7c01327b1852..df6d13185f40 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -367,7 +367,7 @@ void ovl_set_upperdata(struct inode *inode)
 /* Caller should hold ovl_inode->lock */
 bool ovl_dentry_needs_data_copy_up_locked(struct dentry *dentry, int flags)
 {
-	if (!ovl_open_flags_need_copy_up(flags))
+	if (!ovl_open_flags_need_data_copy_up(flags))
 		return false;
 
 	return !ovl_test_flag(OVL_UPPERDATA, d_inode(dentry));
@@ -375,7 +375,7 @@ bool ovl_dentry_needs_data_copy_up_locked(struct dentry *dentry, int flags)
 
 bool ovl_dentry_needs_data_copy_up(struct dentry *dentry, int flags)
 {
-	if (!ovl_open_flags_need_copy_up(flags))
+	if (!ovl_open_flags_need_data_copy_up(flags))
 		return false;
 
 	return !ovl_has_upperdata(d_inode(dentry));
-- 
2.17.1

  parent reply	other threads:[~2019-01-22 12:34 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-22 12:34 [RFC][PATCH v2 0/5] Experiments with overlayfs filemap Amir Goldstein
2019-01-22 12:34 ` [RFC][PATCH v2 1/5] ovl: reorder tests in ovl_open_need_copy_up() Amir Goldstein
2019-01-22 12:34 ` [RFC][PATCH v2 2/5] ovl: prepare for generic filemap file operations Amir Goldstein
2019-01-22 12:34 ` Amir Goldstein [this message]
2019-01-22 12:34 ` [RFC][PATCH v2 4/5] ovl: lazy copy up data on page fault Amir Goldstein
2019-01-22 12:34 ` [RFC][PATCH v2 5/5] ovl: noop aops to test filemap operations and lazy copy up Amir Goldstein
2019-01-24 17:18 ` [RFC][PATCH v2 0/5] Experiments with overlayfs filemap Amir Goldstein
2019-01-24 22:35   ` Amir Goldstein
2019-01-25  9:54     ` Miklos Szeredi
2019-01-25 11:24       ` Amir Goldstein
2019-01-25 12:21         ` Miklos Szeredi
2019-01-25 13:04           ` Amir Goldstein
2019-01-25 13:31             ` Miklos Szeredi
2019-01-25 15:56               ` Miklos Szeredi
2019-01-25 21:18                 ` Amir Goldstein
2019-01-27 18:22                   ` Amir Goldstein
2019-01-28 19:22                     ` Vivek Goyal
2019-01-28 20:57                       ` Amir Goldstein
2019-01-28 21:17                         ` Miklos Szeredi
2019-01-28 21:22                           ` Miklos Szeredi
2019-01-28 22:14                             ` Amir Goldstein
2019-01-29  7:17                               ` Miklos Szeredi
2019-01-29  8:54                                 ` Amir Goldstein
2019-01-29  8:58                                   ` Miklos Szeredi
2019-01-29  9:12                                     ` Amir Goldstein
2019-01-29 12:44                                       ` Miklos Szeredi
2019-01-29 16:47                                         ` Amir Goldstein
2019-01-31 16:23                                           ` Miklos Szeredi
2019-01-31 21:54                                             ` Amir Goldstein
2019-02-01  9:14                                               ` Miklos Szeredi
2019-02-01 13:22                                                 ` Amir Goldstein
2019-02-01 16:29                                                   ` Vivek Goyal
2019-02-01 13:25                                                 ` Amir Goldstein
2019-02-01 16:24                                                   ` Miklos Szeredi
2019-02-01 16:47                                                     ` Vivek Goyal
2019-02-02 16:51                                                     ` Amir Goldstein
2019-02-05  7:42                                                       ` Amir Goldstein
2019-02-05  7:50                                                         ` Miklos Szeredi
2019-02-05 13:03                                                         ` Amir Goldstein
2019-02-06 15:36                                                           ` Miklos Szeredi
2019-02-12  7:43                                                             ` Amir Goldstein
2019-02-12  8:11                                                               ` Miklos Szeredi

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=20190122123457.10600-4-amir73il@gmail.com \
    --to=amir73il@gmail.com \
    --cc=cgxu519@gmx.com \
    --cc=linux-unionfs@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    --cc=vgoyal@redhat.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