"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

Stefan Sperling <stsp@stsp.name>
rename(2) and stat(2) of parent dir
Tue, 19 Mar 2024 14:45:39 +0100

Download raw body.

  • Stefan Sperling:

    rename(2) and stat(2) of parent dir

Just FYI, in case anyone knows what the expected behaviour of
stat(2) on a directory should be after files have been renamed
inside of this directory:

I had to make the following tweak to avoid a race in new code
I am writing for gotd. See the log message below for details.

The problematic sequence is basically:

   stat dir/ -> mtime == X
   rename dir/foo dir/bar
   stat dir/ -> mtime == Y, or sometimes mtime == X then keep
     trying stat dir/ and eventually mtime == Y

Whereas this always works as expected:

   rename dir/foo dir/bar
   readdir dir/ -> bar shows up

commit 30a624fb1ef8d2d9706a604cbf65dcdacf072e72 (main, origin/main)
from: Stefan Sperling <stsp@stsp.name>
date: Tue Mar 19 13:36:57 2024 UTC
 avoid a rename/stat race when gotd installs a new pack and then uses it
 Reset the cached repository's pack directory mtime after installing a new
 pack and pack index file. I have observed the mtime of the pack directory
 as reported by stat(2) remaining unchanged, until some time has passed
 beyond the rename(2) calls used to install the pack file and its index.
 If gotd immediately tries to read objects installed in a new pack file then
 the mtime reported by stat(2) might appear as unchanged. gotd will then fail
 to update its cached list of pack index files and not find the newly
 installed objects.
 Clearing the cached timestamp forces a readdir(3) call which does expose
 the newly installed pack index file as expected.
 Not sure whether stat(2) is supposed to immediately expose mtime changes
 after a rename(2). If so then this might warrant digging into the kernel.
 Seen while running regression tests for upcoming gotd notification support.
diff 10477b5aacb13088676c3bfd7e0fcc477ba2724e 30a624fb1ef8d2d9706a604cbf65dcdacf072e72
commit - 10477b5aacb13088676c3bfd7e0fcc477ba2724e
commit + 30a624fb1ef8d2d9706a604cbf65dcdacf072e72
blob - ed6de8db29817b25f285cd13c8395a03bfa2e2aa
blob + 6c4441cc4454a3e740e917e1c8cf70fb2764235c
--- gotd/repo_write.c
+++ gotd/repo_write.c
@@ -1715,6 +1715,12 @@ repo_write_dispatch_session(int fd, short event, void 
+				/*
+				 * Ensure we re-read the pack index list
+				 * upon next access.
+				 */
+				repo_write.repo->pack_path_mtime.tv_sec = 0;
+				repo_write.repo->pack_path_mtime.tv_nsec = 0;
 			err = update_refs(iev);
 			if (err) {
blob - b0b449ab2c4db803b92e006427b500772b2d2e55
blob + d67328a67243a5beff513f9e3feeb89708060657
--- gotd/session.c
+++ gotd/session.c
@@ -367,6 +367,10 @@ install_pack(struct gotd_session_client *client, const
 		goto done;
+	/* Ensure we re-read the pack index list upon next access. */
+	gotd_session.repo->pack_path_mtime.tv_sec = 0;
+	gotd_session.repo->pack_path_mtime.tv_nsec = 0;
 	client->packidx_path = NULL;