FreeBSD: Implement relatime property

While FreeBSD does not support relatime natively, it seems trivial
to implement it just as dataset property for consistency.  To not
change the status quo, change its default to off on FreeBSD.  Now,
if explicitly enabled, it should actually work.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Alexander Motin <alexander.motin@TrueNAS.com>
Closes #18385
This commit is contained in:
Alexander Motin
2026-04-01 16:48:50 -04:00
committed by GitHub
parent 0f86f244ce
commit 16858492e6
7 changed files with 65 additions and 9 deletions
@@ -71,6 +71,7 @@ struct zfsvfs {
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 */
zfs_teardown_lock_t z_teardown_lock;
zfs_teardown_inactive_lock_t z_teardown_inactive_lock;
+3 -1
View File
@@ -170,11 +170,13 @@ zfs_exit(zfsvfs_t *zfsvfs, const char *tag)
(tp)->tv_nsec = (long)(stmp)[1]; \
}
#define ZFS_ACCESSTIME_STAMP(zfsvfs, zp) \
if ((zfsvfs)->z_atime && !((zfsvfs)->z_vfs->vfs_flag & VFS_RDONLY)) \
if ((zfsvfs)->z_atime && !((zfsvfs)->z_vfs->vfs_flag & VFS_RDONLY) && \
(!(zfsvfs)->z_relatime || zfs_relatime_need_update(zp))) \
zfs_tstamp_update_setup_ext(zp, ACCESSED, NULL, NULL, B_FALSE);
extern void zfs_tstamp_update_setup_ext(struct znode *,
uint_t, uint64_t [2], uint64_t [2], boolean_t have_tx);
extern boolean_t zfs_relatime_need_update(const struct znode *);
extern void zfs_znode_free(struct znode *);
extern zil_replay_func_t *const zfs_replay_vector[TX_MAX_TYPE];
+8
View File
@@ -494,6 +494,12 @@ atime_changed_cb(void *arg, uint64_t newval)
}
}
static void
relatime_changed_cb(void *arg, uint64_t newval)
{
((zfsvfs_t *)arg)->z_relatime = (newval != 0);
}
static void
xattr_changed_cb(void *arg, uint64_t newval)
{
@@ -752,6 +758,8 @@ zfs_register_callbacks(vfs_t *vfsp)
*/
error = dsl_prop_register(ds,
zfs_prop_to_name(ZFS_PROP_ATIME), atime_changed_cb, zfsvfs);
error = error ? error : dsl_prop_register(ds,
zfs_prop_to_name(ZFS_PROP_RELATIME), relatime_changed_cb, zfsvfs);
error = error ? error : dsl_prop_register(ds,
zfs_prop_to_name(ZFS_PROP_XATTR), xattr_changed_cb, zfsvfs);
error = error ? error : dsl_prop_register(ds,
+43
View File
@@ -1325,6 +1325,49 @@ zfs_znode_free(znode_t *zp)
zfs_znode_free_kmem(zp);
}
/*
* 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.
*/
boolean_t
zfs_relatime_need_update(const znode_t *zp)
{
uint64_t mtime[2], ctime[2];
sa_bulk_attr_t bulk[2];
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
struct timespec now, tmp_atime, tmp_ts;
int count = 0;
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs), NULL, mtime, 16);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, ctime, 16);
if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count) != 0)
return (B_TRUE);
ZFS_TIME_DECODE(&tmp_atime, zp->z_atime);
/*
* 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.
*/
ZFS_TIME_DECODE(&tmp_ts, mtime);
/* CSTYLED */
if (timespeccmp(&tmp_ts, &tmp_atime, >=))
return (B_TRUE);
ZFS_TIME_DECODE(&tmp_ts, ctime);
/* CSTYLED */
if (timespeccmp(&tmp_ts, &tmp_atime, >=))
return (B_TRUE);
vfs_timestamp(&now);
if ((hrtime_t)now.tv_sec - (hrtime_t)tmp_atime.tv_sec >= 24*60*60)
return (B_TRUE);
return (B_FALSE);
}
void
zfs_tstamp_update_setup_ext(znode_t *zp, uint_t flag, uint64_t mtime[2],
uint64_t ctime[2], boolean_t have_tx)
+8 -3
View File
@@ -497,9 +497,14 @@ 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, sfeatures);
zprop_register_index(ZFS_PROP_RELATIME, "relatime", 1, PROP_INHERIT,
ZFS_TYPE_FILESYSTEM, "on | off", "RELATIME", boolean_table,
sfeatures);
zprop_register_index(ZFS_PROP_RELATIME, "relatime",
#ifdef __FreeBSD__
0, /* FreeBSD does not natively support relatime. */
#else
1,
#endif
PROP_INHERIT, ZFS_TYPE_FILESYSTEM, "on | off", "RELATIME",
boolean_table, sfeatures);
zprop_register_index(ZFS_PROP_DEVICES, "devices", 1, PROP_INHERIT,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "DEVICES",
boolean_table, sfeatures);
+2 -1
View File
@@ -50,7 +50,8 @@ tests = ['dbufstats_001_pos', 'dbufstats_002_pos', 'dbufstats_003_pos',
tags = ['functional', 'arc']
[tests/functional/atime]
tests = ['atime_001_pos', 'atime_002_neg', 'root_atime_off', 'root_atime_on']
tests = ['atime_001_pos', 'atime_002_neg', 'atime_003_pos', 'root_atime_off',
'root_atime_on', 'root_relatime_on']
tags = ['functional', 'atime']
[tests/functional/bclone]
-4
View File
@@ -30,10 +30,6 @@ tags = ['functional', 'acl', 'posix']
tests = ['posix_001_pos', 'posix_002_pos', 'posix_003_pos', 'posix_004_pos']
tags = ['functional', 'acl', 'posix-sa']
[tests/functional/atime:Linux]
tests = ['atime_003_pos', 'root_relatime_on']
tags = ['functional', 'atime']
[tests/functional/block_cloning:Linux]
tests = ['block_cloning_ficlone', 'block_cloning_ficlonerange',
'block_cloning_ficlonerange_partial', 'block_cloning_disabled_ficlone',