test: add more cases for vfsFifoTest

This commit is contained in:
dualfroz committed 2026-09-12 18:31:48 +02:00
1 parent 3b72ea3aee
commit 6005863c35
1 file changed
+84
+84
View File
@@ -319,3 +319,87 @@ KTEST(sfsBackedFifoReopenAfterCompletedRoundTripGetsFreshWorkingSession)
int rfd2 = vfsOpen("/mnt/fifoRoundTrip", oReadOnly);
KT_GE(t, rfd2, 0);
/* A genuinely fresh pipe reports "try again" here, exactly like a
first-ever open -- a stale, no-longer-attached handle would instead
report -1 forever for an entirely different reason (pipeAt finding
nothing "used" at that slot), which the write assertion below is
what actually tells apart from this one. */
char probe[4];
KT_EQ(t, vfsRead(rfd2, probe, sizeof(probe)), -1);
int wfd2 = vfsOpen("/mnt/fifoRoundTrip", oWriteOnly);
KT_GE(t, wfd2, 0);
KT_EQ(t, vfsWrite(wfd2, "two", 3), 3);
char second[4];
memset(second, 0, sizeof(second));
KT_EQ(t, vfsRead(rfd2, second, sizeof(second)), 3);
KT_TRUE(t, memcmp(second, "two", 3) == 0);
vfsClose(rfd2);
vfsClose(wfd2);
KT_EQ(t, vfsUnlink("/mnt/fifoRoundTrip"), 0);
}
KTEST(sfsBackedFifoBindingSurvivesReformatOfAnUnrelatedInode)
{
/* sfsTest.c's tests each start with their own sfsFormat(), reusing
inode numbers dozens of times a boot. A fifo binding left open
ACROSS such a reformat (contrived here, but exactly the shape
reclaimOpenFds/sched.c would leave behind for a thread that died
without closing its fd -- see sched.c) must never let the fresh
filesystem's completely unrelated reuse of the same inode number
inherit the old, orphaned session. */
KT_TRUE(t, sfsFormat());
KT_EQ(t, vfsMkfifo("/mnt/fifoGenA"), 0);
int32 firstInode = sfsLookup("/fifoGenA");
KT_GE(t, firstInode, 0);
/* Left deliberately open across the reformat below -- an orphaned
session, on purpose, is exactly what must NOT leak into the new one. */
int staleRfd = vfsOpen("/mnt/fifoGenA", oReadOnly);
KT_GE(t, staleRfd, 0);
/* A full reformat: every old inode number, including firstInode, now
means whatever the fresh, empty filesystem below reassigns it to. */
KT_TRUE(t, sfsFormat());
KT_EQ(t, vfsMkfifo("/mnt/fifoGenA"), 0);
int32 secondInode = sfsLookup("/fifoGenA");
KT_GE(t, secondInode, 0);
/* Deterministic on a freshly formatted, otherwise-empty filesystem:
both are the very first entry created after root, so the numbers
collide -- exactly the scenario that makes the generation check
necessary rather than merely defensive. */
KT_EQ(t, secondInode, firstInode);
int rfd = vfsOpen("/mnt/fifoGenA", oReadOnly);
int wfd = vfsOpen("/mnt/fifoGenA", oWriteOnly);
KT_GE(t, rfd, 0);
KT_GE(t, wfd, 0);
KT_EQ(t, vfsWrite(wfd, "new", 3), 3);
/* The discriminating check: if the binding table wrongly inherited the
pre-reformat session (generation check not actually doing its job),
staleRfd would be a SECOND reader attached to the very same
underlying pipe wfd just wrote into, and -- read before rfd below --
would steal the payload meant for the new session's own reader.
Correct isolation means staleRfd's pipe never had any writer at all
(it only ever attached as a reader), so it must still report "try
again", never the new session's bytes. */
char stalePeek[4];
KT_EQ(t, vfsRead(staleRfd, stalePeek, sizeof(stalePeek)), -1);
char buffer[4];
memset(buffer, 0, sizeof(buffer));
KT_EQ(t, vfsRead(rfd, buffer, sizeof(buffer)), 3);
KT_TRUE(t, memcmp(buffer, "new", 3) == 0);
vfsClose(rfd);
vfsClose(wfd);
/* The orphaned pre-reformat fd is cleaned up here rather than left to
leak a pipe.c slot for the rest of the boot -- vfsClose only ever
touches pipe.c state (pipeCloseRead), never re-derefs the long-gone
inode, so this is safe regardless of what the fresh filesystem did
with the number. */
vfsClose(staleRfd);
vfsUnlink("/mnt/fifoGenA");
}