Fix two bugs the Fedora move exposed

Neither is Fedora-specific. A different host and a freshly built
userland simply drove code that Windows never reached.

tools/mkfs.c did not compile at all. The DT_UNKNOWN/DT_DIR/DT_REG
fallbacks sat above <dirent.h>, so on glibc -- which spells them as
enumerators -- the #ifndef asked before the header was read, always
answered "missing", and then the header's own enum expanded to
`enum { 0 = 0, ... }`. Move the fallbacks below the include. The
include cannot move up instead: it has to follow the #undef that ends
the `#define dirent schfs_dirent` block.

getstackpcs() page-faulted. It dereferenced rbp[1] without validating
rbp, and the guard rejected 0xffffffff -- dead code on x86-64, already
caught by the KERNBASE test -- while the value that actually turns up
is all-ones, which is above KERNBASE. rbp[1] then wrapped to 0x7 and
took trap 14. `cp` panicked the kernel every time. Bound rbp from
above and require 8-byte alignment.

That second one masks other bugs: getcallerpcs() runs on every lock
acquisition and again from the trap handler, so a walker that can
fault replaces a real diagnosis with a bogus one.

Baseline on the Fedora laptop is now green: make ports, make,
make schfs-check including the round-trip that had never run, and
bootcheck at 27/27 plus 108 [ok] across the extended suites.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Nexoniarz 2026-08-09 19:29:21 +02:00
commit 15331d4399
5 changed files with 112 additions and 23 deletions

View file

@ -41,21 +41,6 @@
#define bzero(p, n) memset((p), 0, (n))
#define bcopy(src, dst, n) memmove((dst), (src), (n))
// struct dirent's d_type is a BSD/glibc extension; mingw-w64 has no such
// field. The loops below already handle DT_UNKNOWN by probing with opendir(),
// which is the portable answer and was written for filesystems that decline to
// report a type -- so on Windows every entry simply takes that path.
#ifndef DT_UNKNOWN
#define DT_UNKNOWN 0
#define DT_DIR 4
#define DT_REG 8
#endif
#ifdef _WIN32
#define DIRENT_TYPE(dp) DT_UNKNOWN
#else
#define DIRENT_TYPE(dp) ((dp)->d_type)
#endif
#define stat xv6_stat
#define sigset_t xv6_sigset_t
#define dirent schfs_dirent
@ -69,6 +54,29 @@
// After the #undef above, so this gets the host's struct stat and not xv6's.
#include <sys/stat.h>
// struct dirent's d_type is a BSD/glibc extension; mingw-w64 has no such
// field. The loops below already handle DT_UNKNOWN by probing with opendir(),
// which is the portable answer and was written for filesystems that decline to
// report a type -- so on Windows every entry simply takes that path.
//
// This block must stay *below* <dirent.h>, not up with the other compatibility
// shims. glibc spells these as enumerators with matching macros, so asking
// #ifndef before the header is read always says "missing" -- and then the
// header's own `enum { DT_UNKNOWN = 0, ... }` expands to `enum { 0 = 0, ... }`
// and the build dies on a syntax error a long way from the cause. The header
// cannot move up either: it has to follow the `#undef dirent` above, or it
// would define the xv6 struct dirent instead of the host's.
#ifndef DT_UNKNOWN
#define DT_UNKNOWN 0
#define DT_DIR 4
#define DT_REG 8
#endif
#ifdef _WIN32
#define DIRENT_TYPE(dp) DT_UNKNOWN
#else
#define DIRENT_TYPE(dp) ((dp)->d_type)
#endif
#ifndef static_assert
#define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0)
#endif