test: extend coverage of vfsFifoTest
This commit is contained in:
1 parent
4b41308da9
commit
3b72ea3aee
1 file changed
+159
@@ -160,3 +160,162 @@ KTEST(vfsUnlinkOnNeverOpenedFifoReclaimsPipeSlot)
|
||||
vfsUnlink(paths[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Coverage for PERSISTENT named pipes: vfsMkfifo under "/mnt" now creates a
|
||||
* real, on-disk sfs.h entry (sfsTypeFifo) instead of being rejected, so the
|
||||
* special file itself -- unlike everything above, which lives only in this
|
||||
* process's kmalloc heap -- survives sfsUnmount()+sfsMount(). The live
|
||||
* pipe.h byte stream two openers exchange data through is still purely
|
||||
* in-memory (vfs.c's sfsFifoHandleFor), created lazily on first open, since
|
||||
* buffered bytes never persist across a real mkfifo(2)'s reboot either --
|
||||
* only the rendezvous point's name and type do. Every test below starts
|
||||
* with its own sfsFormat() (same discipline sfsTest.c uses) so results
|
||||
* never depend on whatever an earlier test (here or in sfsTest.c, same
|
||||
* boot, same disk) left behind.
|
||||
*/
|
||||
|
||||
KTEST(sfsBackedMkfifoCreatesPersistentFifoVisibleViaStat)
|
||||
{
|
||||
KT_TRUE(t, sfsFormat());
|
||||
KT_EQ(t, vfsMkfifo("/mnt/fifoBasic"), 0);
|
||||
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/mnt/fifoBasic", &st), 0);
|
||||
KT_EQ(t, st.type, fsTypeFifo);
|
||||
KT_EQU(t, st.size, 0u);
|
||||
|
||||
/* Same path again must fail, exactly like the tmpfs case above. */
|
||||
KT_EQ(t, vfsMkfifo("/mnt/fifoBasic"), -1);
|
||||
|
||||
KT_EQ(t, vfsUnlink("/mnt/fifoBasic"), 0);
|
||||
KT_EQ(t, vfsStat("/mnt/fifoBasic", &st), -1);
|
||||
}
|
||||
|
||||
KTEST(sfsBackedFifoRendezvousByPathAloneNoSharedHandle)
|
||||
{
|
||||
KT_TRUE(t, sfsFormat());
|
||||
KT_EQ(t, vfsMkfifo("/mnt/fifoRendezvous"), 0);
|
||||
|
||||
int rfd = vfsOpen("/mnt/fifoRendezvous", oReadOnly);
|
||||
KT_GE(t, rfd, 0);
|
||||
|
||||
/* Nobody has opened the write end yet: "try again" (-1), never spurious
|
||||
end-of-file, exactly like the tmpfs fifo and a freshly
|
||||
pipeCreateDetached handle both already guarantee. */
|
||||
char probe[4];
|
||||
KT_EQ(t, vfsRead(rfd, probe, sizeof(probe)), -1);
|
||||
KT_NOTNULL(t, vfsBlockingChannel(rfd, false));
|
||||
|
||||
int wfd = vfsOpen("/mnt/fifoRendezvous", oWriteOnly);
|
||||
KT_GE(t, wfd, 0);
|
||||
KT_NE(t, rfd, wfd);
|
||||
|
||||
KT_EQ(t, vfsWrite(wfd, "hi", 2), 2);
|
||||
char buffer[4];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
KT_EQ(t, vfsRead(rfd, buffer, sizeof(buffer)), 2);
|
||||
KT_TRUE(t, memcmp(buffer, "hi", 2) == 0);
|
||||
|
||||
vfsClose(rfd);
|
||||
vfsClose(wfd);
|
||||
KT_EQ(t, vfsUnlink("/mnt/fifoRendezvous"), 0);
|
||||
}
|
||||
|
||||
KTEST(sfsBackedFifoUnlinkWhileOpenLeavesLiveFdsWorking)
|
||||
{
|
||||
KT_TRUE(t, sfsFormat());
|
||||
KT_EQ(t, vfsMkfifo("/mnt/fifoUnlinkLive"), 0);
|
||||
|
||||
int rfd = vfsOpen("/mnt/fifoUnlinkLive", oReadOnly);
|
||||
int wfd = vfsOpen("/mnt/fifoUnlinkLive", oWriteOnly);
|
||||
KT_GE(t, rfd, 0);
|
||||
KT_GE(t, wfd, 0);
|
||||
|
||||
/* Real unlink-while-open semantics, same guarantee as the tmpfs fifo:
|
||||
removing the directory entry must not disturb fds opened before the
|
||||
unlink -- they keep working off their own copy of the raw pipe
|
||||
handle number. */
|
||||
KT_EQ(t, vfsUnlink("/mnt/fifoUnlinkLive"), 0);
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/mnt/fifoUnlinkLive", &st), -1);
|
||||
|
||||
KT_EQ(t, vfsWrite(wfd, "ok", 2), 2);
|
||||
char buffer[4];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
KT_EQ(t, vfsRead(rfd, buffer, sizeof(buffer)), 2);
|
||||
KT_TRUE(t, memcmp(buffer, "ok", 2) == 0);
|
||||
|
||||
vfsClose(rfd);
|
||||
vfsClose(wfd);
|
||||
}
|
||||
|
||||
KTEST(sfsBackedFifoEntryPersistsAcrossUnmountRemount)
|
||||
{
|
||||
KT_TRUE(t, sfsFormat());
|
||||
KT_EQ(t, vfsMkfifo("/mnt/fifoPersist"), 0);
|
||||
|
||||
/* The real point of this test (mirrors sfsTest.c's own
|
||||
sfsMountReloadsExistingFilesystem-style coverage): drop EVERY
|
||||
in-memory sfs.c structure (bitmaps, superblock) and reconstruct them
|
||||
purely from what sfsFormat/sfsCreateFifo actually wrote to disk --
|
||||
proving the fifo is a genuine on-disk entry, not a kmalloc node that
|
||||
would evaporate the instant this process's heap did (like the tmpfs
|
||||
fifo above, which vfsMkfifo("/mnt/...") deliberately never was). */
|
||||
sfsUnmount();
|
||||
KT_TRUE(t, sfsMount());
|
||||
|
||||
FbStat st;
|
||||
KT_EQ(t, vfsStat("/mnt/fifoPersist", &st), 0);
|
||||
KT_EQ(t, st.type, fsTypeFifo);
|
||||
|
||||
/* Still fully functional after the remount, not just present in a
|
||||
directory listing: a fresh open/write/read round trip works exactly
|
||||
as it would have before the remount. */
|
||||
int rfd = vfsOpen("/mnt/fifoPersist", oReadOnly);
|
||||
int wfd = vfsOpen("/mnt/fifoPersist", oWriteOnly);
|
||||
KT_GE(t, rfd, 0);
|
||||
KT_GE(t, wfd, 0);
|
||||
KT_EQ(t, vfsWrite(wfd, "yo", 2), 2);
|
||||
char buffer[4];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
KT_EQ(t, vfsRead(rfd, buffer, sizeof(buffer)), 2);
|
||||
KT_TRUE(t, memcmp(buffer, "yo", 2) == 0);
|
||||
|
||||
vfsClose(rfd);
|
||||
vfsClose(wfd);
|
||||
KT_EQ(t, vfsUnlink("/mnt/fifoPersist"), 0);
|
||||
}
|
||||
|
||||
KTEST(sfsBackedFifoReopenAfterCompletedRoundTripGetsFreshWorkingSession)
|
||||
{
|
||||
/* Ordinary fifo usage, not a corner case: open both ends, exchange
|
||||
data, close both, then reopen the SAME persistent path later for a
|
||||
second, unrelated conversation -- exactly what a real named pipe is
|
||||
for. The first round trip fully releases pipe.h's underlying slot
|
||||
back to its general pool (pipeReleaseIfUnused, once both readers and
|
||||
writers hit 0), so the second round's vfs.c-level binding
|
||||
(sfsFifoHandleFor) MUST detect that its remembered handle number no
|
||||
longer refers to the same pipe (pipeIncarnation, pipe.h) and mint a
|
||||
genuinely fresh one -- otherwise this second write would silently
|
||||
target a slot nobody has attached to (or, worse, one some unrelated
|
||||
pipe elsewhere in the kernel grabbed in between), and would report
|
||||
-1 forever instead of actually delivering the byte. */
|
||||
KT_TRUE(t, sfsFormat());
|
||||
KT_EQ(t, vfsMkfifo("/mnt/fifoRoundTrip"), 0);
|
||||
|
||||
int rfd1 = vfsOpen("/mnt/fifoRoundTrip", oReadOnly);
|
||||
int wfd1 = vfsOpen("/mnt/fifoRoundTrip", oWriteOnly);
|
||||
KT_GE(t, rfd1, 0);
|
||||
KT_GE(t, wfd1, 0);
|
||||
KT_EQ(t, vfsWrite(wfd1, "one", 3), 3);
|
||||
char first[4];
|
||||
memset(first, 0, sizeof(first));
|
||||
KT_EQ(t, vfsRead(rfd1, first, sizeof(first)), 3);
|
||||
KT_TRUE(t, memcmp(first, "one", 3) == 0);
|
||||
vfsClose(rfd1);
|
||||
vfsClose(wfd1);
|
||||
|
||||
/* Second, independent session on the same path. */
|
||||
int rfd2 = vfsOpen("/mnt/fifoRoundTrip", oReadOnly);
|
||||
KT_GE(t, rfd2, 0);
|
||||
|
||||
Reference in new issue
Block a user