diff options
author | Tomohiro Kusumi <[email protected]> | 2019-05-08 02:06:30 +0900 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2019-05-07 10:06:30 -0700 |
commit | 9c53e51616c99592973ebf94b4fd54a5f8c8756d (patch) | |
tree | 7e1b9d39cebc8fdb7a4b4fc9f3853b79b122c196 /include | |
parent | 75346937de39f059722eedd29468ac9b86bea67c (diff) |
Fix `zfs set atime|relatime=off|on` behavior on inherited datasets
`zfs set atime|relatime=off|on` doesn't disable or enable the property
on read for datasets whose property was inherited from parent, until
a dataset is once unmounted and mounted again.
(The properties start to work properly if a dataset is once unmounted
and mounted again. The difference comes from regular mount process,
e.g. via zpool import, uses mount options based on properties read
from ondisk layout for each dataset, whereas
`zfs set atime|relatime=off|on` just remounts a specified dataset.)
--
# zpool create p1 <device>
# zfs create p1/f1
# zfs set atime=off p1
# echo test > /p1/f1/test
# sync
# zfs list
NAME USED AVAIL REFER MOUNTPOINT
p1 176K 18.9G 25.5K /p1
p1/f1 26K 18.9G 26K /p1/f1
# zfs get atime
NAME PROPERTY VALUE SOURCE
p1 atime off local
p1/f1 atime off inherited from p1
# stat /p1/f1/test | grep Access | tail -1
Access: 2019-04-26 23:32:33.741205192 +0900
# cat /p1/f1/test
test
# stat /p1/f1/test | grep Access | tail -1
Access: 2019-04-26 23:32:50.173231861 +0900
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ changed by read(2)
--
The problem is that zfsvfs::z_atime which was probably intended to keep
incore atime state just gets updated by a callback function of "atime"
property change, atime_changed_cb(), and never used for anything else.
Since now that all file read and atime update use a common function
zpl_iter_read_common() -> file_accessed(), and whether to update atime
via ->dirty_inode() is determined by atime_needs_update(),
atime_needs_update() needs to return false once atime is turned off.
It currently continues to return true on `zfs set atime=off`.
Fix atime_changed_cb() by setting or dropping SB_NOATIME in VFS super
block depending on a new atime value, so that atime_needs_update() works
as expected after property change.
The same problem applies to "relatime" except that a self contained
relatime test is needed. This is because relatime_need_update() is based
on a mount option flag MNT_RELATIME, which doesn't exist in datasets
with inherited "relatime" property via `zfs set relatime=...`, hence it
needs its own relatime test zfs_relatime_need_update().
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Tomohiro Kusumi <[email protected]>
Closes #8674
Closes #8675
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/vfs_compat.h | 4 | ||||
-rw-r--r-- | include/sys/zfs_vfsops.h | 1 | ||||
-rw-r--r-- | include/sys/zfs_znode.h | 1 |
3 files changed, 5 insertions, 1 deletions
diff --git a/include/linux/vfs_compat.h b/include/linux/vfs_compat.h index c01f58508..04a2c2b87 100644 --- a/include/linux/vfs_compat.h +++ b/include/linux/vfs_compat.h @@ -207,6 +207,10 @@ zpl_bdi_destroy(struct super_block *sb) #define SB_MANDLOCK MS_MANDLOCK #endif +#ifndef SB_NOATIME +#define SB_NOATIME MS_NOATIME +#endif + /* * 2.6.38 API change, * LOOKUP_RCU flag introduced to distinguish rcu-walk from ref-walk cases. diff --git a/include/sys/zfs_vfsops.h b/include/sys/zfs_vfsops.h index cad0aaece..42f534f5d 100644 --- a/include/sys/zfs_vfsops.h +++ b/include/sys/zfs_vfsops.h @@ -98,7 +98,6 @@ struct zfsvfs { zfs_case_t z_case; /* case-sense */ boolean_t z_utf8; /* utf8-only */ int z_norm; /* normalization flags */ - boolean_t z_atime; /* enable atimes mount option */ boolean_t z_relatime; /* enable relatime mount option */ boolean_t z_unmounted; /* unmounted */ rrmlock_t z_teardown_lock; diff --git a/include/sys/zfs_znode.h b/include/sys/zfs_znode.h index 2dfcf453a..d4a3ea769 100644 --- a/include/sys/zfs_znode.h +++ b/include/sys/zfs_znode.h @@ -363,6 +363,7 @@ extern int zfs_inode_alloc(struct super_block *, struct inode **ip); extern void zfs_inode_destroy(struct inode *); extern void zfs_inode_update(znode_t *); extern void zfs_mark_inode_dirty(struct inode *); +extern boolean_t zfs_relatime_need_update(const struct inode *); extern void zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype, znode_t *dzp, znode_t *zp, char *name, vsecattr_t *, zfs_fuid_info_t *, |