Implement relatime.
Add the "relatime" property. When set to "on", a file's atime will only be updated if the existing atime at least a day old or if the existing ctime or mtime has been updated since the last access. This behavior is compatible with the Linux "relatime" mount option. Signed-off-by: Tim Chase <tim@chase2k.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #2064 Closes #1917
This commit is contained in:
parent
2278381ce2
commit
6d111134c0
|
@ -147,6 +147,7 @@ typedef enum {
|
|||
ZFS_PROP_SELINUX_FSCONTEXT,
|
||||
ZFS_PROP_SELINUX_DEFCONTEXT,
|
||||
ZFS_PROP_SELINUX_ROOTCONTEXT,
|
||||
ZFS_PROP_RELATIME,
|
||||
ZFS_NUM_PROPS
|
||||
} zfs_prop_t;
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ typedef struct zfs_sb {
|
|||
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 */
|
||||
rrwlock_t z_teardown_lock;
|
||||
krwlock_t z_teardown_inactive_lock;
|
||||
|
|
|
@ -1421,6 +1421,7 @@ zfs_is_namespace_prop(zfs_prop_t prop)
|
|||
switch (prop) {
|
||||
|
||||
case ZFS_PROP_ATIME:
|
||||
case ZFS_PROP_RELATIME:
|
||||
case ZFS_PROP_DEVICES:
|
||||
case ZFS_PROP_EXEC:
|
||||
case ZFS_PROP_SETUID:
|
||||
|
@ -1756,6 +1757,11 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
|
|||
mntopt_off = MNTOPT_NOATIME;
|
||||
break;
|
||||
|
||||
case ZFS_PROP_RELATIME:
|
||||
mntopt_on = MNTOPT_RELATIME;
|
||||
mntopt_off = MNTOPT_NORELATIME;
|
||||
break;
|
||||
|
||||
case ZFS_PROP_DEVICES:
|
||||
mntopt_on = MNTOPT_DEVICES;
|
||||
mntopt_off = MNTOPT_NODEVICES;
|
||||
|
@ -1816,6 +1822,7 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
|
|||
|
||||
switch (prop) {
|
||||
case ZFS_PROP_ATIME:
|
||||
case ZFS_PROP_RELATIME:
|
||||
case ZFS_PROP_DEVICES:
|
||||
case ZFS_PROP_EXEC:
|
||||
case ZFS_PROP_READONLY:
|
||||
|
|
|
@ -738,7 +738,7 @@ the \fBxattr=sa\fR property. See the \fBxattr\fR property for more details.
|
|||
.ad
|
||||
.sp .6
|
||||
.RS 4n
|
||||
Controls whether the access time for files is updated when they are read. Turning this property off avoids producing write traffic when reading files and can result in significant performance gains, though it might confuse mailers and other similar utilities. The default value is \fBon\fR.
|
||||
Controls whether the access time for files is updated when they are read. Turning this property off avoids producing write traffic when reading files and can result in significant performance gains, though it might confuse mailers and other similar utilities. The default value is \fBon\fR. See also \fBrelatime\fR below.
|
||||
.RE
|
||||
|
||||
.sp
|
||||
|
@ -1021,6 +1021,17 @@ If \fBrefreservation\fR is set, a snapshot is only allowed if there is enough fr
|
|||
This property can also be referred to by its shortened column name, \fBrefreserv\fR.
|
||||
.RE
|
||||
|
||||
.sp
|
||||
.ne 2
|
||||
.mk
|
||||
.na
|
||||
\fB\fBrelatime\fR=\fBon\fR | \fBoff\fR\fR
|
||||
.ad
|
||||
.sp .6
|
||||
.RS 4n
|
||||
Controls the manner in which the access time is updated when \fBatime=on\fR is set. Turning this property \fBon\fR causes the access time to be updated relative to the modify or change time. Access time is only updated if the previous access time was earlier than the current modify or change time or if the existing access time hasn't been updated within the past 24 hours. The default value is \fBoff\fR.
|
||||
.RE
|
||||
|
||||
.sp
|
||||
.ne 2
|
||||
.mk
|
||||
|
@ -3184,6 +3195,7 @@ pool/home/bob usedbyrefreservation 0 -
|
|||
pool/home/bob logbias latency default
|
||||
pool/home/bob dedup off default
|
||||
pool/home/bob mlslabel none default
|
||||
pool/home/bob relatime off default
|
||||
.fi
|
||||
.in -2
|
||||
.sp
|
||||
|
|
|
@ -263,6 +263,8 @@ zfs_prop_init(void)
|
|||
/* inherit index (boolean) properties */
|
||||
zprop_register_index(ZFS_PROP_ATIME, "atime", 1, PROP_INHERIT,
|
||||
ZFS_TYPE_FILESYSTEM, "on | off", "ATIME", boolean_table);
|
||||
zprop_register_index(ZFS_PROP_RELATIME, "relatime", 0, PROP_INHERIT,
|
||||
ZFS_TYPE_FILESYSTEM, "on | off", "RELATIME", boolean_table);
|
||||
zprop_register_index(ZFS_PROP_DEVICES, "devices", 1, PROP_INHERIT,
|
||||
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "DEVICES",
|
||||
boolean_table);
|
||||
|
|
|
@ -137,6 +137,12 @@ atime_changed_cb(void *arg, uint64_t newval)
|
|||
((zfs_sb_t *)arg)->z_atime = newval;
|
||||
}
|
||||
|
||||
static void
|
||||
relatime_changed_cb(void *arg, uint64_t newval)
|
||||
{
|
||||
((zfs_sb_t *)arg)->z_relatime = newval;
|
||||
}
|
||||
|
||||
static void
|
||||
xattr_changed_cb(void *arg, uint64_t newval)
|
||||
{
|
||||
|
@ -275,6 +281,8 @@ zfs_register_callbacks(zfs_sb_t *zsb)
|
|||
dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
|
||||
error = dsl_prop_register(ds,
|
||||
zfs_prop_to_name(ZFS_PROP_ATIME), atime_changed_cb, zsb);
|
||||
error = dsl_prop_register(ds,
|
||||
zfs_prop_to_name(ZFS_PROP_RELATIME), relatime_changed_cb, zsb);
|
||||
error = error ? error : dsl_prop_register(ds,
|
||||
zfs_prop_to_name(ZFS_PROP_XATTR), xattr_changed_cb, zsb);
|
||||
error = error ? error : dsl_prop_register(ds,
|
||||
|
@ -314,6 +322,8 @@ unregister:
|
|||
*/
|
||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ATIME),
|
||||
atime_changed_cb, zsb);
|
||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_RELATIME),
|
||||
relatime_changed_cb, zsb);
|
||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_XATTR),
|
||||
xattr_changed_cb, zsb);
|
||||
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_RECORDSIZE),
|
||||
|
@ -914,6 +924,9 @@ zfs_unregister_callbacks(zfs_sb_t *zsb)
|
|||
VERIFY(dsl_prop_unregister(ds, "atime", atime_changed_cb,
|
||||
zsb) == 0);
|
||||
|
||||
VERIFY(dsl_prop_unregister(ds, "relatime", relatime_changed_cb,
|
||||
zsb) == 0);
|
||||
|
||||
VERIFY(dsl_prop_unregister(ds, "xattr", xattr_changed_cb,
|
||||
zsb) == 0);
|
||||
|
||||
|
|
|
@ -1109,25 +1109,89 @@ zfs_zinactive(znode_t *zp)
|
|||
ZFS_OBJ_HOLD_EXIT(zsb, z_id);
|
||||
}
|
||||
|
||||
static inline int
|
||||
zfs_compare_timespec(struct timespec *t1, struct timespec *t2)
|
||||
{
|
||||
if (t1->tv_sec < t2->tv_sec)
|
||||
return (-1);
|
||||
|
||||
if (t1->tv_sec > t2->tv_sec)
|
||||
return (1);
|
||||
|
||||
return (t1->tv_nsec - t2->tv_nsec);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether the znode's atime must be updated. The logic mostly
|
||||
* duplicates the Linux kernel's relatime_need_update() functionality.
|
||||
* This function is only called if the underlying filesystem actually has
|
||||
* atime updates enabled.
|
||||
*/
|
||||
static inline boolean_t
|
||||
zfs_atime_need_update(znode_t *zp, timestruc_t *now)
|
||||
{
|
||||
if (!ZTOZSB(zp)->z_relatime)
|
||||
return (B_TRUE);
|
||||
|
||||
/*
|
||||
* In relatime mode, only update the atime if the previous atime
|
||||
* is earlier than either the ctime or mtime or if at least a day
|
||||
* has passed since the last update of atime.
|
||||
*/
|
||||
if (zfs_compare_timespec(&ZTOI(zp)->i_mtime, &ZTOI(zp)->i_atime) >= 0)
|
||||
return (B_TRUE);
|
||||
|
||||
if (zfs_compare_timespec(&ZTOI(zp)->i_ctime, &ZTOI(zp)->i_atime) >= 0)
|
||||
return (B_TRUE);
|
||||
|
||||
if ((long)now->tv_sec - ZTOI(zp)->i_atime.tv_sec >= 24*60*60)
|
||||
return (B_TRUE);
|
||||
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare to update znode time stamps.
|
||||
*
|
||||
* IN: zp - znode requiring timestamp update
|
||||
* flag - ATTR_MTIME, ATTR_CTIME, ATTR_ATIME flags
|
||||
* have_tx - true of caller is creating a new txg
|
||||
*
|
||||
* OUT: zp - new atime (via underlying inode's i_atime)
|
||||
* mtime - new mtime
|
||||
* ctime - new ctime
|
||||
*
|
||||
* NOTE: The arguments are somewhat redundant. The following condition
|
||||
* is always true:
|
||||
*
|
||||
* have_tx == !(flag & ATTR_ATIME)
|
||||
*/
|
||||
void
|
||||
zfs_tstamp_update_setup(znode_t *zp, uint_t flag, uint64_t mtime[2],
|
||||
uint64_t ctime[2], boolean_t have_tx)
|
||||
{
|
||||
timestruc_t now;
|
||||
|
||||
ASSERT(have_tx == !(flag & ATTR_ATIME));
|
||||
gethrestime(&now);
|
||||
|
||||
if (have_tx) { /* will sa_bulk_update happen really soon? */
|
||||
/*
|
||||
* NOTE: The following test intentionally does not update z_atime_dirty
|
||||
* in the case where an ATIME update has been requested but for which
|
||||
* the update is omitted due to relatime logic. The rationale being
|
||||
* that if the flag was set somewhere else, we should leave it alone
|
||||
* here.
|
||||
*/
|
||||
if (flag & ATTR_ATIME) {
|
||||
if (zfs_atime_need_update(zp, &now)) {
|
||||
ZFS_TIME_ENCODE(&now, zp->z_atime);
|
||||
ZTOI(zp)->i_atime.tv_sec = zp->z_atime[0];
|
||||
ZTOI(zp)->i_atime.tv_nsec = zp->z_atime[1];
|
||||
zp->z_atime_dirty = 1;
|
||||
}
|
||||
} else {
|
||||
zp->z_atime_dirty = 0;
|
||||
zp->z_seq++;
|
||||
} else {
|
||||
zp->z_atime_dirty = 1;
|
||||
}
|
||||
|
||||
if (flag & ATTR_ATIME) {
|
||||
ZFS_TIME_ENCODE(&now, zp->z_atime);
|
||||
ZTOI(zp)->i_atime.tv_sec = zp->z_atime[0];
|
||||
ZTOI(zp)->i_atime.tv_nsec = zp->z_atime[1];
|
||||
}
|
||||
|
||||
if (flag & ATTR_MTIME) {
|
||||
|
|
Loading…
Reference in New Issue