[Devel,vz7,RHEL7.3,beta] ovl: update atime on upper

Submitted by Maxim Patlasov on Nov. 4, 2016, 11:49 p.m.

Details

Message ID 147830330634.12963.7171165628299438126.stgit@maxim-thinkpad
State New
Series "ovl: update atime on upper"
Headers show

Commit Message

Maxim Patlasov Nov. 4, 2016, 11:49 p.m.
Backport d719e8f268 from mainline:

     ovl: update atime on upper

     Fix atime update logic in overlayfs.

     This patch adds an i_op->update_time() handler to overlayfs inodes.  This
     forwards atime updates to the upper layer only.  No atime updates are done
     on lower layers.

     Remove implicit atime updates to underlying files and directories with
     O_NOATIME.  Remove explicit atime update in ovl_readlink().

     Clear atime related mnt flags from cloned upper mount.  This means atime
     updates are controlled purely by overlayfs mount options.

     Reported-by: Konstantin Khlebnikov <koct9i@gmail.com>
     Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>

 https://jira.sw.ru/browse/PSBM-54821

 Signed-off-by: Maxim Patlasov <mpatlasov@virtuozzo.com>
---
 fs/overlayfs/dir.c       |    1 +
 fs/overlayfs/inode.c     |   29 ++++++++++++++++++++++++++---
 fs/overlayfs/overlayfs.h |    4 ++++
 fs/overlayfs/super.c     |    8 ++++++--
 4 files changed, 37 insertions(+), 5 deletions(-)

Patch hide | download patch | download mbox

diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 1de7ac7..b348d0d 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -924,6 +924,7 @@  const struct inode_operations_wrapper ovl_dir_inode_operations = {
 	.getxattr	= ovl_getxattr,
 	.listxattr	= ovl_listxattr,
 	.removexattr	= ovl_removexattr,
+	.update_time	= ovl_update_time,
 	},
 	.rename2	= ovl_rename2,
 };
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 72cab85..bc8c363 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -257,8 +257,6 @@  static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
 	if (!realinode->i_op->readlink)
 		return -EINVAL;
 
-	touch_atime(&realpath);
-
 	return realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
 }
 
@@ -415,6 +413,29 @@  struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags)
 	return realpath.dentry->d_inode;
 }
 
+int ovl_update_time(struct inode *inode, struct timespec *ts, int flags)
+{
+	struct dentry *alias;
+	struct path upperpath;
+
+	if (!(flags & S_ATIME))
+		return 0;
+
+	alias = d_find_any_alias(inode);
+	if (!alias)
+		return 0;
+
+	ovl_path_upper(alias, &upperpath);
+	if (upperpath.dentry) {
+		touch_atime(&upperpath);
+		inode->i_atime = d_inode(upperpath.dentry)->i_atime;
+	}
+
+	dput(alias);
+
+	return 0;
+}
+
 static const struct inode_operations_wrapper ovl_file_inode_operations = {
 	.ops = {
 	.setattr	= ovl_setattr,
@@ -424,6 +445,7 @@  static const struct inode_operations_wrapper ovl_file_inode_operations = {
 	.getxattr	= ovl_getxattr,
 	.listxattr	= ovl_listxattr,
 	.removexattr	= ovl_removexattr,
+	.update_time	= ovl_update_time,
 	},
 };
 
@@ -437,6 +459,7 @@  static const struct inode_operations ovl_symlink_inode_operations = {
 	.getxattr	= ovl_getxattr,
 	.listxattr	= ovl_listxattr,
 	.removexattr	= ovl_removexattr,
+	.update_time	= ovl_update_time,
 };
 
 struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
@@ -450,7 +473,7 @@  struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
 
 	inode->i_ino = get_next_ino();
 	inode->i_mode = mode;
-	inode->i_flags |= S_NOATIME | S_NOCMTIME;
+	inode->i_flags |= S_NOCMTIME;
 
 	mode &= S_IFMT;
 	switch (mode) {
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index cbf7585..7be7fd4 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -179,6 +179,7 @@  ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
 int ovl_removexattr(struct dentry *dentry, const char *name);
 struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags);
+int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
 
 struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
 			    struct ovl_entry *oe);
@@ -187,6 +188,9 @@  static inline void ovl_copyattr(struct inode *from, struct inode *to)
 	to->i_uid = from->i_uid;
 	to->i_gid = from->i_gid;
 	to->i_mode = from->i_mode;
+	to->i_atime = from->i_atime;
+	to->i_mtime = from->i_mtime;
+	to->i_ctime = from->i_ctime;
 }
 
 /* dir.c */
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index ace8313..cc986ca 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -568,7 +568,7 @@  out:
 
 struct file *ovl_path_open(struct path *path, int flags)
 {
-	return dentry_open(path, flags, current_cred());
+	return dentry_open(path, flags | O_NOATIME, current_cred());
 }
 
 static void ovl_put_super(struct super_block *sb)
@@ -1059,6 +1059,10 @@  static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 			pr_err("overlayfs: failed to clone upperpath\n");
 			goto out_put_lowerpath;
 		}
+		/* Don't inherit atime flags */
+		ufs->upper_mnt->mnt_flags &= ~(MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME);
+
+		sb->s_time_gran = ufs->upper_mnt->mnt_sb->s_time_gran;
 
 		ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry);
 		err = PTR_ERR(ufs->workdir);
@@ -1107,7 +1111,7 @@  static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 		 * Make lower_mnt R/O.  That way fchmod/fchown on lower file
 		 * will fail instead of modifying lower fs.
 		 */
-		mnt->mnt_flags |= MNT_READONLY;
+		mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME;
 
 		ufs->lower_mnt[ufs->numlower] = mnt;
 		ufs->numlower++;

Comments

Konstantin Khorenko Nov. 7, 2016, 7:49 a.m.
Skipping this: it already presents in branch-rh7-3.10.0-493.vz7.25.x-ovz branch,
rebased from previous branch.

commit b0fd74bd9daa30be587f8b16a40130abbc101ab7
Author: Maxim Patlasov <mpatlasov@virtuozzo.com>
Date:   Fri Sep 16 18:34:33 2016 +0400

     ms/ovl: update atime on upperovl: update atime on upper

--
Best regards,

Konstantin Khorenko,
Virtuozzo Linux Kernel Team

On 11/05/2016 02:49 AM, Maxim Patlasov wrote:
>  Backport d719e8f268 from mainline:
>
>      ovl: update atime on upper
>
>      Fix atime update logic in overlayfs.
>
>      This patch adds an i_op->update_time() handler to overlayfs inodes.  This
>      forwards atime updates to the upper layer only.  No atime updates are done
>      on lower layers.
>
>      Remove implicit atime updates to underlying files and directories with
>      O_NOATIME.  Remove explicit atime update in ovl_readlink().
>
>      Clear atime related mnt flags from cloned upper mount.  This means atime
>      updates are controlled purely by overlayfs mount options.
>
>      Reported-by: Konstantin Khlebnikov <koct9i@gmail.com>
>      Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
>
>  https://jira.sw.ru/browse/PSBM-54821
>
>  Signed-off-by: Maxim Patlasov <mpatlasov@virtuozzo.com>
> ---
>  fs/overlayfs/dir.c       |    1 +
>  fs/overlayfs/inode.c     |   29 ++++++++++++++++++++++++++---
>  fs/overlayfs/overlayfs.h |    4 ++++
>  fs/overlayfs/super.c     |    8 ++++++--
>  4 files changed, 37 insertions(+), 5 deletions(-)
>
> diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
> index 1de7ac7..b348d0d 100644
> --- a/fs/overlayfs/dir.c
> +++ b/fs/overlayfs/dir.c
> @@ -924,6 +924,7 @@ const struct inode_operations_wrapper ovl_dir_inode_operations = {
>  	.getxattr	= ovl_getxattr,
>  	.listxattr	= ovl_listxattr,
>  	.removexattr	= ovl_removexattr,
> +	.update_time	= ovl_update_time,
>  	},
>  	.rename2	= ovl_rename2,
>  };
> diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
> index 72cab85..bc8c363 100644
> --- a/fs/overlayfs/inode.c
> +++ b/fs/overlayfs/inode.c
> @@ -257,8 +257,6 @@ static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
>  	if (!realinode->i_op->readlink)
>  		return -EINVAL;
>
> -	touch_atime(&realpath);
> -
>  	return realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
>  }
>
> @@ -415,6 +413,29 @@ struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags)
>  	return realpath.dentry->d_inode;
>  }
>
> +int ovl_update_time(struct inode *inode, struct timespec *ts, int flags)
> +{
> +	struct dentry *alias;
> +	struct path upperpath;
> +
> +	if (!(flags & S_ATIME))
> +		return 0;
> +
> +	alias = d_find_any_alias(inode);
> +	if (!alias)
> +		return 0;
> +
> +	ovl_path_upper(alias, &upperpath);
> +	if (upperpath.dentry) {
> +		touch_atime(&upperpath);
> +		inode->i_atime = d_inode(upperpath.dentry)->i_atime;
> +	}
> +
> +	dput(alias);
> +
> +	return 0;
> +}
> +
>  static const struct inode_operations_wrapper ovl_file_inode_operations = {
>  	.ops = {
>  	.setattr	= ovl_setattr,
> @@ -424,6 +445,7 @@ static const struct inode_operations_wrapper ovl_file_inode_operations = {
>  	.getxattr	= ovl_getxattr,
>  	.listxattr	= ovl_listxattr,
>  	.removexattr	= ovl_removexattr,
> +	.update_time	= ovl_update_time,
>  	},
>  };
>
> @@ -437,6 +459,7 @@ static const struct inode_operations ovl_symlink_inode_operations = {
>  	.getxattr	= ovl_getxattr,
>  	.listxattr	= ovl_listxattr,
>  	.removexattr	= ovl_removexattr,
> +	.update_time	= ovl_update_time,
>  };
>
>  struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
> @@ -450,7 +473,7 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
>
>  	inode->i_ino = get_next_ino();
>  	inode->i_mode = mode;
> -	inode->i_flags |= S_NOATIME | S_NOCMTIME;
> +	inode->i_flags |= S_NOCMTIME;
>
>  	mode &= S_IFMT;
>  	switch (mode) {
> diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
> index cbf7585..7be7fd4 100644
> --- a/fs/overlayfs/overlayfs.h
> +++ b/fs/overlayfs/overlayfs.h
> @@ -179,6 +179,7 @@ ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
>  ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
>  int ovl_removexattr(struct dentry *dentry, const char *name);
>  struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags);
> +int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
>
>  struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
>  			    struct ovl_entry *oe);
> @@ -187,6 +188,9 @@ static inline void ovl_copyattr(struct inode *from, struct inode *to)
>  	to->i_uid = from->i_uid;
>  	to->i_gid = from->i_gid;
>  	to->i_mode = from->i_mode;
> +	to->i_atime = from->i_atime;
> +	to->i_mtime = from->i_mtime;
> +	to->i_ctime = from->i_ctime;
>  }
>
>  /* dir.c */
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index ace8313..cc986ca 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -568,7 +568,7 @@ out:
>
>  struct file *ovl_path_open(struct path *path, int flags)
>  {
> -	return dentry_open(path, flags, current_cred());
> +	return dentry_open(path, flags | O_NOATIME, current_cred());
>  }
>
>  static void ovl_put_super(struct super_block *sb)
> @@ -1059,6 +1059,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
>  			pr_err("overlayfs: failed to clone upperpath\n");
>  			goto out_put_lowerpath;
>  		}
> +		/* Don't inherit atime flags */
> +		ufs->upper_mnt->mnt_flags &= ~(MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME);
> +
> +		sb->s_time_gran = ufs->upper_mnt->mnt_sb->s_time_gran;
>
>  		ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry);
>  		err = PTR_ERR(ufs->workdir);
> @@ -1107,7 +1111,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
>  		 * Make lower_mnt R/O.  That way fchmod/fchown on lower file
>  		 * will fail instead of modifying lower fs.
>  		 */
> -		mnt->mnt_flags |= MNT_READONLY;
> +		mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME;
>
>  		ufs->lower_mnt[ufs->numlower] = mnt;
>  		ufs->numlower++;
>
> .
>