Skip to content

Commit

Permalink
ovl: update atime on upper
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Miklos Szeredi committed Jul 29, 2016
1 parent bb0d2b8 commit d719e8f
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 5 deletions.
1 change: 1 addition & 0 deletions fs/overlayfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -943,4 +943,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,
};
29 changes: 26 additions & 3 deletions fs/overlayfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,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);
Expand Down Expand Up @@ -367,6 +365,29 @@ int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags)
return err;
}

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,
Expand All @@ -376,6 +397,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 = {
Expand All @@ -387,6 +409,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,
Expand All @@ -400,7 +423,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;
Expand Down
4 changes: 4 additions & 0 deletions fs/overlayfs/overlayfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
int ovl_removexattr(struct dentry *dentry, const char *name);
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);
Expand All @@ -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 */
Expand Down
8 changes: 6 additions & 2 deletions fs/overlayfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,

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)
Expand Down Expand Up @@ -1075,6 +1075,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);
Expand Down Expand Up @@ -1122,7 +1126,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++;
Expand Down

0 comments on commit d719e8f

Please sign in to comment.