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
This commit is contained in:
Norman Feske 2025-03-20 16:02:58 +01:00
parent 5cfe44ab72
commit 05d69a0bb3
13 changed files with 51 additions and 48 deletions

View File

@ -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;

View File

@ -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 &current_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;
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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,

View File

@ -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;
}

View File

@ -126,7 +126,7 @@ class Vfs_ram::Node : private Genode::Avl_node<Node>
return ++inode_count;
}
Vfs::Timestamp _modification_time { Vfs::Timestamp::INVALID };
Vfs::Timestamp _modification_time { };
bool _marked_as_unlinked = false;

View File

@ -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;

View File

@ -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)
};
}

View File

@ -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)
};
}

View File

@ -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_ */

View File

@ -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 }
};
});

View File

@ -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);