]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
ovl: update atime on upper
authorMiklos Szeredi <mszeredi@redhat.com>
Fri, 29 Jul 2016 10:05:23 +0000 (12:05 +0200)
committerShan Hai <shan.hai@oracle.com>
Fri, 4 Aug 2017 05:50:23 +0000 (13:50 +0800)
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>
Orabug: 26401569

(backport upstream commit d719e8f268fa4f9944b24b60814da9017dfb7787)

Signed-off-by: Shan Hai <shan.hai@oracle.com>
Reviewed-by: Somasundaram Krishnasamy <somasundaram.krishnasamy@oracle.com>
fs/overlayfs/dir.c
fs/overlayfs/inode.c
fs/overlayfs/overlayfs.h
fs/overlayfs/super.c

index 71b35bd725081500ef7dca357ccbc282b95e83bc..4a2995489af6140f9f9ea01b11f62f70ed7e8110 100644 (file)
@@ -951,4 +951,5 @@ const struct inode_operations ovl_dir_inode_operations = {
        .listxattr      = ovl_listxattr,
        .removexattr    = ovl_removexattr,
        .get_acl        = ovl_get_acl,
+       .update_time    = ovl_update_time,
 };
index ec55dff57f824940fa147836480e6c3d7e139c75..84d87186ac676833f48d9b4d351da404abaafc94 100644 (file)
@@ -205,8 +205,6 @@ static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
        if (!realinode->i_op->readlink)
                return -EINVAL;
 
-       touch_atime(&realpath);
-
        old_cred = ovl_override_creds(dentry->d_sb);
        err = realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
        revert_creds(old_cred);
@@ -413,6 +411,29 @@ struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags)
        return d_backing_inode(realpath.dentry);
 }
 
+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 ovl_file_inode_operations = {
        .setattr        = ovl_setattr,
        .permission     = ovl_permission,
@@ -422,6 +443,7 @@ static const struct inode_operations ovl_file_inode_operations = {
        .listxattr      = ovl_listxattr,
        .removexattr    = ovl_removexattr,
        .get_acl        = ovl_get_acl,
+       .update_time    = ovl_update_time,
 };
 
 static const struct inode_operations ovl_symlink_inode_operations = {
@@ -434,6 +456,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,
@@ -447,7 +470,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;
        inode->i_private = oe;
 
        mode &= S_IFMT;
index 68e5910f9a0be5c331cf3d6c58195973b9d2a92c..cd7c9ad6b824c01dcc1e7daa18abb2cf88ae5ac3 100644 (file)
@@ -181,6 +181,7 @@ int ovl_removexattr(struct dentry *dentry, const char *name);
 struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags);
 struct posix_acl *ovl_get_acl(struct inode *inode, int type);
 int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int 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);
@@ -189,6 +190,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 */
index 74ceaa2cc4dfdaec08f61615a4abe5ca9cc8b9e2..6368adbc0c2d2c666dbd684d4445073857b8cd97 100644 (file)
@@ -495,7 +495,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)
@@ -967,6 +967,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);
@@ -1012,7 +1016,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++;