aboutsummaryrefslogtreecommitdiffstats
path: root/fs/overlayfs
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-07-29 06:05:23 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2016-07-29 06:05:23 -0400
commitd719e8f268fa4f9944b24b60814da9017dfb7787 (patch)
tree0840f4bffc0abe65fb60286732bdc2ac1846dc7b /fs/overlayfs
parentbb0d2b8ad29630b580ac903f989e704e23462357 (diff)
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>
Diffstat (limited to 'fs/overlayfs')
-rw-r--r--fs/overlayfs/dir.c1
-rw-r--r--fs/overlayfs/inode.c29
-rw-r--r--fs/overlayfs/overlayfs.h4
-rw-r--r--fs/overlayfs/super.c8
4 files changed, 37 insertions, 5 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 8beeed34dad6..b4eac8173f93 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -943,4 +943,5 @@ const struct inode_operations ovl_dir_inode_operations = {
943 .listxattr = ovl_listxattr, 943 .listxattr = ovl_listxattr,
944 .removexattr = ovl_removexattr, 944 .removexattr = ovl_removexattr,
945 .get_acl = ovl_get_acl, 945 .get_acl = ovl_get_acl,
946 .update_time = ovl_update_time,
946}; 947};
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 66f42f5cf705..041db9c6621c 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -185,8 +185,6 @@ static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
185 if (!realinode->i_op->readlink) 185 if (!realinode->i_op->readlink)
186 return -EINVAL; 186 return -EINVAL;
187 187
188 touch_atime(&realpath);
189
190 old_cred = ovl_override_creds(dentry->d_sb); 188 old_cred = ovl_override_creds(dentry->d_sb);
191 err = realinode->i_op->readlink(realpath.dentry, buf, bufsiz); 189 err = realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
192 revert_creds(old_cred); 190 revert_creds(old_cred);
@@ -367,6 +365,29 @@ int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags)
367 return err; 365 return err;
368} 366}
369 367
368int ovl_update_time(struct inode *inode, struct timespec *ts, int flags)
369{
370 struct dentry *alias;
371 struct path upperpath;
372
373 if (!(flags & S_ATIME))
374 return 0;
375
376 alias = d_find_any_alias(inode);
377 if (!alias)
378 return 0;
379
380 ovl_path_upper(alias, &upperpath);
381 if (upperpath.dentry) {
382 touch_atime(&upperpath);
383 inode->i_atime = d_inode(upperpath.dentry)->i_atime;
384 }
385
386 dput(alias);
387
388 return 0;
389}
390
370static const struct inode_operations ovl_file_inode_operations = { 391static const struct inode_operations ovl_file_inode_operations = {
371 .setattr = ovl_setattr, 392 .setattr = ovl_setattr,
372 .permission = ovl_permission, 393 .permission = ovl_permission,
@@ -376,6 +397,7 @@ static const struct inode_operations ovl_file_inode_operations = {
376 .listxattr = ovl_listxattr, 397 .listxattr = ovl_listxattr,
377 .removexattr = ovl_removexattr, 398 .removexattr = ovl_removexattr,
378 .get_acl = ovl_get_acl, 399 .get_acl = ovl_get_acl,
400 .update_time = ovl_update_time,
379}; 401};
380 402
381static const struct inode_operations ovl_symlink_inode_operations = { 403static const struct inode_operations ovl_symlink_inode_operations = {
@@ -387,6 +409,7 @@ static const struct inode_operations ovl_symlink_inode_operations = {
387 .getxattr = ovl_getxattr, 409 .getxattr = ovl_getxattr,
388 .listxattr = ovl_listxattr, 410 .listxattr = ovl_listxattr,
389 .removexattr = ovl_removexattr, 411 .removexattr = ovl_removexattr,
412 .update_time = ovl_update_time,
390}; 413};
391 414
392struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, 415struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
@@ -400,7 +423,7 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
400 423
401 inode->i_ino = get_next_ino(); 424 inode->i_ino = get_next_ino();
402 inode->i_mode = mode; 425 inode->i_mode = mode;
403 inode->i_flags |= S_NOATIME | S_NOCMTIME; 426 inode->i_flags |= S_NOCMTIME;
404 inode->i_private = oe; 427 inode->i_private = oe;
405 428
406 mode &= S_IFMT; 429 mode &= S_IFMT;
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index e8d50da384d5..fb73c09a84e7 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -181,6 +181,7 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
181int ovl_removexattr(struct dentry *dentry, const char *name); 181int ovl_removexattr(struct dentry *dentry, const char *name);
182struct posix_acl *ovl_get_acl(struct inode *inode, int type); 182struct posix_acl *ovl_get_acl(struct inode *inode, int type);
183int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags); 183int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags);
184int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
184 185
185struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, 186struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
186 struct ovl_entry *oe); 187 struct ovl_entry *oe);
@@ -189,6 +190,9 @@ static inline void ovl_copyattr(struct inode *from, struct inode *to)
189 to->i_uid = from->i_uid; 190 to->i_uid = from->i_uid;
190 to->i_gid = from->i_gid; 191 to->i_gid = from->i_gid;
191 to->i_mode = from->i_mode; 192 to->i_mode = from->i_mode;
193 to->i_atime = from->i_atime;
194 to->i_mtime = from->i_mtime;
195 to->i_ctime = from->i_ctime;
192} 196}
193 197
194/* dir.c */ 198/* dir.c */
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 80598912a5d9..058103c60f54 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -608,7 +608,7 @@ out:
608 608
609struct file *ovl_path_open(struct path *path, int flags) 609struct file *ovl_path_open(struct path *path, int flags)
610{ 610{
611 return dentry_open(path, flags, current_cred()); 611 return dentry_open(path, flags | O_NOATIME, current_cred());
612} 612}
613 613
614static void ovl_put_super(struct super_block *sb) 614static void ovl_put_super(struct super_block *sb)
@@ -1075,6 +1075,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
1075 pr_err("overlayfs: failed to clone upperpath\n"); 1075 pr_err("overlayfs: failed to clone upperpath\n");
1076 goto out_put_lowerpath; 1076 goto out_put_lowerpath;
1077 } 1077 }
1078 /* Don't inherit atime flags */
1079 ufs->upper_mnt->mnt_flags &= ~(MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME);
1080
1081 sb->s_time_gran = ufs->upper_mnt->mnt_sb->s_time_gran;
1078 1082
1079 ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); 1083 ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry);
1080 err = PTR_ERR(ufs->workdir); 1084 err = PTR_ERR(ufs->workdir);
@@ -1122,7 +1126,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
1122 * Make lower_mnt R/O. That way fchmod/fchown on lower file 1126 * Make lower_mnt R/O. That way fchmod/fchown on lower file
1123 * will fail instead of modifying lower fs. 1127 * will fail instead of modifying lower fs.
1124 */ 1128 */
1125 mnt->mnt_flags |= MNT_READONLY; 1129 mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME;
1126 1130
1127 ufs->lower_mnt[ufs->numlower] = mnt; 1131 ufs->lower_mnt[ufs->numlower] = mnt;
1128 ufs->numlower++; 1132 ufs->numlower++;