From 05d69a0bb3f2bc40fa224e6cc81ce5f24c0a0759 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Thu, 20 Mar 2025 16:02:58 +0100 Subject: [PATCH] os: increase mtime resolution to milliseconds This patch changes the 'Timestamp' type of the VFS and file-system session to an unsigned 64-bit value holding the number of milliseconds since the UNIX epoch (beginning of 1970). The special case of an invalid timestamp has been removed as it was never consistently handled anyway. In contrast to the POSIX timespec, which represents tv_sec and tv_nsec both as signed values, this patch uses an unsigned value because the interpretation of negative tv_sec and tv_nsec values is muddy. Hypothetical modification times older that 1970 are capped at 1970. Fixes #3511 --- repos/dde_rump/src/lib/vfs/rump/vfs_rump.cc | 13 +++++++++--- repos/libports/src/lib/libc/vfs_plugin.cc | 13 ++++++++---- .../file_system_session/file_system_session.h | 20 +------------------ repos/os/include/vfs/dir_file_system.h | 2 +- repos/os/include/vfs/types.h | 6 +----- repos/os/src/lib/vfs/fs_file_system.h | 6 ++++-- repos/os/src/lib/vfs/ram_file_system.h | 2 +- repos/os/src/lib/vfs/tar_file_system.h | 7 ++++++- repos/os/src/server/lx_fs/directory.h | 7 ++----- repos/os/src/server/lx_fs/file.h | 7 ++----- repos/os/src/server/lx_fs/lx_util.h | 11 ++++++++++ repos/os/src/server/vfs/main.cc | 3 ++- repos/os/src/server/vfs/node.h | 2 +- 13 files changed, 51 insertions(+), 48 deletions(-) diff --git a/repos/dde_rump/src/lib/vfs/rump/vfs_rump.cc b/repos/dde_rump/src/lib/vfs/rump/vfs_rump.cc index f45e8d54c1..3df9e29dfc 100644 --- a/repos/dde_rump/src/lib/vfs/rump/vfs_rump.cc +++ b/repos/dde_rump/src/lib/vfs/rump/vfs_rump.cc @@ -171,8 +171,13 @@ class Vfs::Rump_file_system : public File_system void update_modification_timestamp(Vfs::Timestamp time) override { struct timespec ts[2] = { - { .tv_sec = 0, .tv_nsec = 0 }, - { .tv_sec = time.value, .tv_nsec = 0 } + { + .tv_sec = 0, + .tv_nsec = 0 + }, { + .tv_sec = time_t( time.ms_since_1970 / 1000), + .tv_nsec = time_t((time.ms_since_1970 % 1000)*1000*1000) + } }; /* silently igore error */ @@ -726,7 +731,9 @@ class Vfs::Rump_file_system : public File_system .inode = sb.st_ino, .device = sb.st_dev, - .modification_time = { sb.st_mtim.tv_sec } + .modification_time = { + .ms_since_1970 = uint64_t(sb.st_mtim.tv_sec*1000 + + sb.st_mtim.tv_nsec/1000000) } }; return STAT_OK; diff --git a/repos/libports/src/lib/libc/vfs_plugin.cc b/repos/libports/src/lib/libc/vfs_plugin.cc index d51db16ec4..bb33c597be 100644 --- a/repos/libports/src/lib/libc/vfs_plugin.cc +++ b/repos/libports/src/lib/libc/vfs_plugin.cc @@ -118,6 +118,10 @@ static void vfs_stat_to_libc_stat_struct(Vfs::Directory_service::Stat const &src *dst = { }; + timespec const mtime { + .tv_sec = time_t( src.modification_time.ms_since_1970 / 1000), + .tv_nsec = time_t((src.modification_time.ms_since_1970 % 1000)*1000*1000) }; + dst->st_uid = 0; dst->st_gid = 0; dst->st_mode = (src.rwx.readable ? readable_bits : 0) @@ -129,8 +133,7 @@ static void vfs_stat_to_libc_stat_struct(Vfs::Directory_service::Stat const &src dst->st_blocks = (dst->st_size + FS_BLOCK_SIZE - 1) / FS_BLOCK_SIZE; dst->st_ino = src.inode; dst->st_dev = src.device; - long long mtime = src.modification_time.value; - dst->st_mtime = mtime != Vfs::Timestamp::INVALID ? mtime : 0; + dst->st_mtim = mtime; dst->st_nlink = 1; } @@ -546,7 +549,7 @@ struct Sync enum { INITIAL, TIMESTAMP_UPDATED, QUEUED, COMPLETE } state { INITIAL }; Vfs::Vfs_handle &vfs_handle; - Vfs::Timestamp mtime { Vfs::Timestamp::INVALID }; + Vfs::Timestamp mtime { }; Sync(Vfs::Vfs_handle &vfs_handle, Libc::Vfs_plugin::Update_mtime update_mtime, Libc::Current_real_time ¤t_real_time) @@ -561,7 +564,9 @@ struct Sync } else { timespec const ts = current_real_time.current_real_time(); - mtime = { .value = (long long)ts.tv_sec }; + mtime.ms_since_1970 = ts.tv_sec >= 0 + ? ts.tv_sec*1000ull + ts.tv_nsec/1000000ull + : 0; } } diff --git a/repos/os/include/file_system_session/file_system_session.h b/repos/os/include/file_system_session/file_system_session.h index 29a8d1a8aa..285f771aab 100644 --- a/repos/os/include/file_system_session/file_system_session.h +++ b/repos/os/include/file_system_session/file_system_session.h @@ -86,25 +86,7 @@ namespace File_system { using seek_off_t = Genode::uint64_t; using file_size_t = Genode::uint64_t; - struct Timestamp - { - /* - * The INVALID value is used whenever the underlying file system - * session does not support modification timestamps. The value is - * chosen such that it is unlikely to occur, instead of simply '0', - * which would correspond to plausible time (see comment below). - * This allows for handling this case explicitly. In any case, an - * invalid timestamp should not be used for doing any calculations. - */ - static constexpr Genode::int64_t INVALID = 0x7fffffffffffffffLL; - - /* - * The 'value' member contains the modification timestamp in seconds. - * Value '0' is defined as 1970-01-01T00:00:00Z, where a positive value - * covers all seconds after this date and a negative one all before. - */ - Genode::int64_t value; - }; + struct Timestamp { Genode::uint64_t ms_since_1970; }; using Out_of_ram = Genode::Out_of_ram; using Out_of_caps = Genode::Out_of_caps; diff --git a/repos/os/include/vfs/dir_file_system.h b/repos/os/include/vfs/dir_file_system.h index f4ce033265..107a490926 100644 --- a/repos/os/include/vfs/dir_file_system.h +++ b/repos/os/include/vfs/dir_file_system.h @@ -451,7 +451,7 @@ class Vfs::Dir_file_system : public File_system .rwx = Node_rwx::rwx(), .inode = 1, .device = (Genode::addr_t)this, - .modification_time = { Vfs::Timestamp::INVALID }, + .modification_time = { }, }; return STAT_OK; } diff --git a/repos/os/include/vfs/types.h b/repos/os/include/vfs/types.h index fa4b90158e..130a792a57 100644 --- a/repos/os/include/vfs/types.h +++ b/repos/os/include/vfs/types.h @@ -50,11 +50,7 @@ namespace Vfs { using Genode::Byte_range_ptr; using Genode::Const_byte_range_ptr; - struct Timestamp - { - static constexpr Genode::int64_t INVALID = 0x7fffffffffffffffLL; - Genode::int64_t value; - }; + struct Timestamp { Genode::uint64_t ms_since_1970; }; enum class Node_type { DIRECTORY, diff --git a/repos/os/src/lib/vfs/fs_file_system.h b/repos/os/src/lib/vfs/fs_file_system.h index 2d25cf153a..7e14f57905 100644 --- a/repos/os/src/lib/vfs/fs_file_system.h +++ b/repos/os/src/lib/vfs/fs_file_system.h @@ -300,7 +300,8 @@ class Vfs::Fs_file_system : public File_system, private Remote_io Packet_descriptor p(source.alloc_packet(0), file_handle(), Packet_descriptor::WRITE_TIMESTAMP, - ::File_system::Timestamp { .value = time.value }); + ::File_system::Timestamp { + .ms_since_1970 = time.ms_since_1970 }); _vfs_fs._submit_packet(p); } catch (::File_system::Session::Tx::Source::Packet_alloc_failed) { @@ -617,7 +618,8 @@ class Vfs::Fs_file_system : public File_system, private Remote_io out.rwx = _node_rwx(status.rwx); out.inode = status.inode; out.device = (Genode::addr_t)this; - out.modification_time.value = status.modification_time.value; + out.modification_time = { + .ms_since_1970 = status.modification_time.ms_since_1970 }; return STAT_OK; } diff --git a/repos/os/src/lib/vfs/ram_file_system.h b/repos/os/src/lib/vfs/ram_file_system.h index a1719ce09a..2a1a811c99 100644 --- a/repos/os/src/lib/vfs/ram_file_system.h +++ b/repos/os/src/lib/vfs/ram_file_system.h @@ -126,7 +126,7 @@ class Vfs_ram::Node : private Genode::Avl_node return ++inode_count; } - Vfs::Timestamp _modification_time { Vfs::Timestamp::INVALID }; + Vfs::Timestamp _modification_time { }; bool _marked_as_unlinked = false; diff --git a/repos/os/src/lib/vfs/tar_file_system.h b/repos/os/src/lib/vfs/tar_file_system.h index ebc1d3cc54..a2beefcf23 100644 --- a/repos/os/src/lib/vfs/tar_file_system.h +++ b/repos/os/src/lib/vfs/tar_file_system.h @@ -626,6 +626,11 @@ class Vfs::Tar_file_system : public File_system return Node_type::DIRECTORY; }; + auto timestamp_from_mtime = [] (auto mtime) -> Timestamp + { + return { .ms_since_1970 = mtime >= 0 ? Genode::uint64_t(mtime*1000) : 0 }; + }; + out = { .size = record.size(), .type = node_type(), @@ -634,7 +639,7 @@ class Vfs::Tar_file_system : public File_system .executable = record.rwx().executable }, .inode = (Genode::addr_t)node_ptr, .device = (Genode::addr_t)this, - .modification_time = { record.mtime() } + .modification_time = timestamp_from_mtime(record.mtime()) }; return STAT_OK; diff --git a/repos/os/src/server/lx_fs/directory.h b/repos/os/src/server/lx_fs/directory.h index d6f793afbe..bfad95d111 100644 --- a/repos/os/src/server/lx_fs/directory.h +++ b/repos/os/src/server/lx_fs/directory.h @@ -116,10 +116,7 @@ class Lx_fs::Directory : public Node void update_modification_time(Timestamp const time) override { - struct timespec ts[2] = { - { .tv_sec = (time_t)0, .tv_nsec = 0 }, - { .tv_sec = (time_t)time.value, .tv_nsec = 0 } - }; + struct timespec ts[2] = { { }, timespec_from_timestamp(time) }; /* silently ignore errors */ futimens(dirfd(_fd), (const timespec*)&ts); @@ -258,7 +255,7 @@ class Lx_fs::Directory : public Node .writeable = (st.st_mode & S_IWUSR) != 0, .executable = (st.st_mode & S_IXUSR) != 0}, .inode = (unsigned long)inode(), - .modification_time = { st.st_mtime } + .modification_time = timestamp_from_timespec(st.st_mtim) }; } diff --git a/repos/os/src/server/lx_fs/file.h b/repos/os/src/server/lx_fs/file.h index dfacbc1801..0c8edecbc1 100644 --- a/repos/os/src/server/lx_fs/file.h +++ b/repos/os/src/server/lx_fs/file.h @@ -114,10 +114,7 @@ class Lx_fs::File : public Node void update_modification_time(Timestamp const time) override { - struct timespec ts[2] = { - { .tv_sec = (time_t)0, .tv_nsec = 0 }, - { .tv_sec = (time_t)time.value, .tv_nsec = 0 } - }; + struct timespec ts[2] = { { }, timespec_from_timestamp(time) }; /* silently ignore errors */ futimens(_fd, (const timespec*)&ts); @@ -167,7 +164,7 @@ class Lx_fs::File : public Node .writeable = (st.st_mode & S_IWUSR) != 0, .executable = (st.st_mode & S_IXUSR) != 0}, .inode = (unsigned long)inode(), - .modification_time = { st.st_mtime } + .modification_time = timestamp_from_timespec(st.st_mtim) }; } diff --git a/repos/os/src/server/lx_fs/lx_util.h b/repos/os/src/server/lx_fs/lx_util.h index 6a9276356a..b4f9a61a82 100644 --- a/repos/os/src/server/lx_fs/lx_util.h +++ b/repos/os/src/server/lx_fs/lx_util.h @@ -61,6 +61,17 @@ namespace Lx_fs { * */ Path_string absolute_root_dir(char const *root_path); + + static inline timespec timespec_from_timestamp(File_system::Timestamp t) + { + return { .tv_sec = time_t (t.ms_since_1970 * 1000), + .tv_nsec = time_t((t.ms_since_1970 % 1000)*1000*1000) }; + } + + static inline File_system::Timestamp timestamp_from_timespec(timespec ts) + { + return { .ms_since_1970 = Genode::uint64_t(ts.tv_sec*1000 + ts.tv_nsec/1000000) }; + } } #endif /* _LX_UTIL_H_ */ diff --git a/repos/os/src/server/vfs/main.cc b/repos/os/src/server/vfs/main.cc index edc0b898f2..8175faf747 100644 --- a/repos/os/src/server/vfs/main.cc +++ b/repos/os/src/server/vfs/main.cc @@ -684,7 +684,8 @@ class Vfs_server::Session_component : private Session_resources, .executable = vfs_stat.rwx.executable }, .inode = vfs_stat.inode, - .modification_time = { vfs_stat.modification_time.value } + .modification_time = { + .ms_since_1970 = vfs_stat.modification_time.ms_since_1970 } }; }); diff --git a/repos/os/src/server/vfs/node.h b/repos/os/src/server/vfs/node.h index 29bdad41ec..128ba16d49 100644 --- a/repos/os/src/server/vfs/node.h +++ b/repos/os/src/server/vfs/node.h @@ -447,7 +447,7 @@ class Vfs_server::Io_node : public Vfs_server::Node, void _execute_write_timestamp() { _packet.with_timestamp([&] (::File_system::Timestamp const time) { - Vfs::Timestamp ts { .value = time.value }; + Vfs::Timestamp ts { .ms_since_1970 = time.ms_since_1970 }; _handle.fs().update_modification_timestamp(&_handle, ts); }); _acknowledge_as_success(0);