From da5b44eaf131c748caeedf59b3dc9e42b94c82f0 Mon Sep 17 00:00:00 2001 From: Ryan Jeffrey Date: Wed, 30 Sep 2020 21:19:52 +0200 Subject: libdiskfs: Add relatime support * doc/hurd.texi (diskfs_set_node_atime): Document relatime behavior. * libdiskfs/diskfs.h (diskfs_set_node_atime): Likewise. * libdiskfs/init-init.c (_diskfs_relatime): Add variable. * libdiskfs/file-statfs.c (ST_RELATIME): Define if not defined already. (diskfs_S_file_statfs): Report ST_RELATIME when _diskfs_relatime is set. * libdiskfs/node-times.c (atime_should_update): New function. (diskfs_set_node_atime): Document relatime behavior. Call atime_should_update instead of reading _diskfs_noatime. * libdiskfs/opts-common.c (diskfs_common_options): Add --strictatime and -R/--relatime options. * libdiskfs/opts-std-runtime.c (struct parse_hook): Add relatime field. (set_opts): Set _diskfs_relatime from relatime field. (parse_opt): Parse -R option. * libdiskfs/opts-std-startup.c (parse_startup_opt): Parse -R option. * libdiskfs/priv.h (_diskfs_relatime): Declare variable. (atime_should_update): Declare function. * libdiskfs/opts-append-std.c (diskfs_append_std_options): Add reporting --relatime option. * libdiskfs/conch-fetch.c (iohelp_fetch_shared_data): Call atime_should_update instead of reading _diskfs_noatime. * libdiskfs/rdwr-internal.c (_diskfs_rdwr_internal): Likewise. --- doc/hurd.texi | 4 +++- libdiskfs/conch-fetch.c | 2 +- libdiskfs/diskfs.h | 4 +++- libdiskfs/file-statfs.c | 6 ++++++ libdiskfs/init-init.c | 1 + libdiskfs/node-times.c | 37 +++++++++++++++++++++++++++++++++++-- libdiskfs/opts-append-std.c | 2 ++ libdiskfs/opts-common.c | 4 ++++ libdiskfs/opts-std-runtime.c | 16 ++++++++++++---- libdiskfs/opts-std-startup.c | 14 +++++++++++++- libdiskfs/priv.h | 11 +++++++++++ libdiskfs/rdwr-internal.c | 4 ++-- 12 files changed, 93 insertions(+), 12 deletions(-) diff --git a/doc/hurd.texi b/doc/hurd.texi index 038d80b6..c3442c8c 100644 --- a/doc/hurd.texi +++ b/doc/hurd.texi @@ -3973,7 +3973,9 @@ disk allocation strategies. @deftypefun void diskfs_set_node_atime (@w{struct node *@var{np}}) If disk is not readonly and the noatime option is not enabled, set -@code{@var{np}->dn_set_atime}. +@code{@var{np}->dn_set_atime}. If relatime is enabled, only set +@code{@var{np}->dn_set_atime} if the atime has not been updated today, +or if ctime or mtime are more recent than atime. @end deftypefun @deftypefun void diskfs_set_node_times (@w{struct node *@var{np}}) diff --git a/libdiskfs/conch-fetch.c b/libdiskfs/conch-fetch.c index 43a0e870..2a9a5c8f 100644 --- a/libdiskfs/conch-fetch.c +++ b/libdiskfs/conch-fetch.c @@ -58,7 +58,7 @@ iohelp_fetch_shared_data (void *arg) cred->po->np->dn_set_mtime = 1; mod = 1; } - if (cred->mapped->accessed && ! _diskfs_noatime) + if (cred->mapped->accessed && atime_should_update (cred->po->np)) { cred->po->np->dn_set_atime = 1; mod = 1; diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h index dfccf880..2390c64d 100644 --- a/libdiskfs/diskfs.h +++ b/libdiskfs/diskfs.h @@ -1046,7 +1046,9 @@ error_t diskfs_init_dir (struct node *dp, struct node *pdp, struct protid *cred); /* If disk is not readonly and the noatime option is not enabled, set - NP->dn_set_atime. */ + NP->dn_set_atime. If relatime is enabled, only set NP->dn_set_atime + if the atime has not been updated today, or if ctime or mtime are + more recent than atime */ void diskfs_set_node_atime (struct node *np); /* If NP->dn_set_ctime is set, then modify NP->dn_stat.st_ctim diff --git a/libdiskfs/file-statfs.c b/libdiskfs/file-statfs.c index c9fd6f1b..3cc60b4f 100644 --- a/libdiskfs/file-statfs.c +++ b/libdiskfs/file-statfs.c @@ -21,6 +21,10 @@ #include "priv.h" #include "fs_S.h" +#ifndef ST_RELATIME +# define ST_RELATIME 64 +#endif /* ST_RELATIME */ + /* Implement file_getcontrol as described in . */ kern_return_t diskfs_S_file_statfs (struct protid *file, @@ -43,6 +47,8 @@ diskfs_S_file_statfs (struct protid *file, statbuf->f_flag |= ST_SYNCHRONOUS; if (_diskfs_noatime) statbuf->f_flag |= ST_NOATIME; + else if (_diskfs_relatime) + statbuf->f_flag |= ST_RELATIME; diskfs_set_statfs (statbuf); diff --git a/libdiskfs/init-init.c b/libdiskfs/init-init.c index b9a714fe..1c432401 100644 --- a/libdiskfs/init-init.c +++ b/libdiskfs/init-init.c @@ -38,6 +38,7 @@ mach_port_t diskfs_fsys_identity; int _diskfs_nosuid, _diskfs_noexec; int _diskfs_noatime; +int _diskfs_relatime; struct hurd_port _diskfs_exec_portcell; diff --git a/libdiskfs/node-times.c b/libdiskfs/node-times.c index 9a6c8dd9..05f558be 100644 --- a/libdiskfs/node-times.c +++ b/libdiskfs/node-times.c @@ -24,12 +24,45 @@ #include "priv.h" #include +/* If the disk is not readonly and noatime is not set, then check relatime + conditions: if either `np->dn_stat.st_mtim.tv_sec' or + `np->dn_stat.st_ctim.tv_sec' is greater than `np->dn_stat.st_atim.tv_sec', + or if the atime is greater than 24 hours old, return true. + */ +int +atime_should_update (struct node *np) +{ + struct timeval t; + + if (_diskfs_noatime) + return 0; + + if (_diskfs_relatime) + { + /* Update atime if mtime is younger than atime. */ + if (np->dn_stat.st_mtim.tv_sec > np->dn_stat.st_atim.tv_sec) + return 1; + /* Update atime if ctime is younger than atime. */ + if (np->dn_stat.st_ctim.tv_sec > np->dn_stat.st_atim.tv_sec) + return 1; + /* Update atime if current atime is more than 24 hours old. */ + maptime_read (diskfs_mtime, &t); + if ((long)(t.tv_sec - np->dn_stat.st_atim.tv_sec) >= 24 * 60 * 60) + return 1; + return 0; + } + + return 1; /* strictatime */ +} + /* If disk is not readonly and the noatime option is not enabled, set - NP->dn_set_atime. */ + NP->dn_set_atime. If relatime is enabled, only set NP->dn_set_atime + if the atime has not been updated today, or if ctime or mtime are + more recent than atime */ void diskfs_set_node_atime (struct node *np) { - if (!_diskfs_noatime && !diskfs_check_readonly ()) + if (!diskfs_check_readonly () && atime_should_update (np)) np->dn_set_atime = 1; } diff --git a/libdiskfs/opts-append-std.c b/libdiskfs/opts-append-std.c index b951bf93..98e89dd0 100644 --- a/libdiskfs/opts-append-std.c +++ b/libdiskfs/opts-append-std.c @@ -42,6 +42,8 @@ diskfs_append_std_options (char **argz, size_t *argz_len) err = argz_add (argz, argz_len, "--no-exec"); if (!err && _diskfs_noatime) err = argz_add (argz, argz_len, "--no-atime"); + else if (!err && _diskfs_relatime) + err = argz_add (argz, argz_len, "--relatime"); if (!err && _diskfs_no_inherit_dir_group) err = argz_add (argz, argz_len, "--no-inherit-dir-group"); diff --git a/libdiskfs/opts-common.c b/libdiskfs/opts-common.c index d37c2868..841f13c3 100644 --- a/libdiskfs/opts-common.c +++ b/libdiskfs/opts-common.c @@ -47,6 +47,7 @@ const struct argp_option diskfs_common_options[] = "Do not update file access times on disk for reads"}, {"noatime", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, {"atime", OPT_ATIME, 0, 0, "Do update file access times for reads normally"}, + {"strictatime", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, {"no-inherit-dir-group", OPT_NO_INHERIT_DIR_GROUP, 0, 0, "Create new nodes with gid of the process"}, {"nogrpid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, @@ -55,5 +56,8 @@ const struct argp_option diskfs_common_options[] = "Create new nodes with gid of parent dir (default)"}, {"grpid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, {"bsdgroups", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, + {"relatime", 'R', 0, 0, + "Only update access times once daily or if older than change time " + "or modification time."}, {0, 0} }; diff --git a/libdiskfs/opts-std-runtime.c b/libdiskfs/opts-std-runtime.c index 177dfaf6..48acbaaf 100644 --- a/libdiskfs/opts-std-runtime.c +++ b/libdiskfs/opts-std-runtime.c @@ -33,7 +33,7 @@ std_runtime_options[] = struct parse_hook { int readonly, sync, sync_interval, remount, nosuid, noexec, noatime, - noinheritdirgroup; + noinheritdirgroup, relatime; }; /* Implement the options in H, and free H. */ @@ -80,6 +80,8 @@ set_opts (struct parse_hook *h) _diskfs_noexec = h->noexec; if (h->noatime != -1) _diskfs_noatime = h->noatime; + else if (h->relatime != -1) + _diskfs_relatime = h->relatime; if (h->noinheritdirgroup != -1) _diskfs_no_inherit_dir_group = h->noinheritdirgroup; @@ -100,10 +102,16 @@ parse_opt (int opt, char *arg, struct argp_state *state) case 'u': h->remount = 1; break; case 'S': h->nosuid = 1; break; case 'E': h->noexec = 1; break; - case 'A': h->noatime = 1; break; + case 'A': + { + h->relatime = -1; + h->noatime = 1; + break; + } + case 'R': h->relatime = 1; break; case OPT_SUID_OK: h->nosuid = 0; break; case OPT_EXEC_OK: h->noexec = 0; break; - case OPT_ATIME: h->noatime = 0; break; + case OPT_ATIME: h->noatime = h->relatime = 0; break; case OPT_NO_INHERIT_DIR_GROUP: h->noinheritdirgroup = 1; break; case OPT_INHERIT_DIR_GROUP: h->noinheritdirgroup = 0; break; case 'n': h->sync_interval = 0; h->sync = 0; break; @@ -129,7 +137,7 @@ parse_opt (int opt, char *arg, struct argp_state *state) h->sync = diskfs_synchronous; h->sync_interval = -1; h->remount = 0; - h->nosuid = h->noexec = h->noatime = h->noinheritdirgroup = -1; + h->nosuid = h->noexec = h->noatime = h->noinheritdirgroup = h->relatime = -1; /* We know that we have one child, with which we share our hook. */ state->child_inputs[0] = h; diff --git a/libdiskfs/opts-std-startup.c b/libdiskfs/opts-std-startup.c index a38db99a..e5531a46 100644 --- a/libdiskfs/opts-std-startup.c +++ b/libdiskfs/opts-std-startup.c @@ -86,10 +86,22 @@ parse_startup_opt (int opt, char *arg, struct argp_state *state) TOGGLE (diskfs_readonly, 'r', 'w'); TOGGLE (_diskfs_nosuid, 'S', OPT_SUID_OK); TOGGLE (_diskfs_noexec, 'E', OPT_EXEC_OK); - TOGGLE (_diskfs_noatime, 'A', OPT_ATIME); TOGGLE (_diskfs_no_inherit_dir_group, OPT_NO_INHERIT_DIR_GROUP, OPT_INHERIT_DIR_GROUP); #undef TOGGLE + /* The next three cases must be done manually to avoid duplicates */ + case 'A': + _diskfs_noatime = 1; + break; + + case 'R': + _diskfs_relatime = 1; + break; + + case OPT_ATIME: /* strictatime. */ + _diskfs_noatime = 0; + _diskfs_relatime = 0; + break; case 's': if (arg == NULL) diff --git a/libdiskfs/priv.h b/libdiskfs/priv.h index 5be7c2b5..420323dd 100644 --- a/libdiskfs/priv.h +++ b/libdiskfs/priv.h @@ -38,6 +38,10 @@ extern int _diskfs_nosuid, _diskfs_noexec; /* This relaxes the requirement to set `st_atim'. */ extern int _diskfs_noatime; +/* Will set `st_atim' if it has not been updated in 24 hours or + if `st_ctim' or `st_mtim' are younger than `st_atim'. */ +extern int _diskfs_relatime; + /* This enables SysV style group behaviour. New nodes inherit the GID of the user creating them unless the SGID bit is set of the parent directory. */ @@ -98,6 +102,13 @@ void _diskfs_control_clean (void *); links, then request soft references to be dropped. */ void _diskfs_lastref (struct node *np); +/* If the disk is not readonly and noatime is not set, then check relatime + conditions: if either `np->dn_stat.st_mtim.tv_sec' or + `np->dn_stat.st_ctim.tv_sec' is greater than `np->dn_stat.st_atim.tv_sec', + or if the atime is greater than 24 hours old, return true. + */ +int atime_should_update (struct node *np); + /* Number of outstanding PT_CTL ports. */ extern int _diskfs_ncontrol_ports; diff --git a/libdiskfs/rdwr-internal.c b/libdiskfs/rdwr-internal.c index eec0d6a0..8b2e1319 100644 --- a/libdiskfs/rdwr-internal.c +++ b/libdiskfs/rdwr-internal.c @@ -49,7 +49,7 @@ _diskfs_rdwr_internal (struct node *np, { if (dir) np->dn_set_mtime = 1; - else if (! _diskfs_noatime) + else if (atime_should_update (np)) np->dn_set_atime = 1; } @@ -70,7 +70,7 @@ _diskfs_rdwr_internal (struct node *np, { if (dir) np->dn_set_mtime = 1; - else if (!_diskfs_noatime) + else if (atime_should_update (np)) np->dn_set_atime = 1; } -- cgit v1.2.3