From ea327aa4c86bacdba40edd0064498716abd85cfd Mon Sep 17 00:00:00 2001 From: ChatGPT Date: Thu, 18 Jun 2026 09:08:42 +0000 Subject: [PATCH] nwnss: preserve source-compat lock boundaries --- include/nwnss/internal/nwnssSourceCompat.h | 120 ++++++++++++++++++--- nwnss-audit.md | 2 +- 2 files changed, 108 insertions(+), 14 deletions(-) diff --git a/include/nwnss/internal/nwnssSourceCompat.h b/include/nwnss/internal/nwnssSourceCompat.h index ea6a328..d01b45d 100644 --- a/include/nwnss/internal/nwnssSourceCompat.h +++ b/include/nwnss/internal/nwnssSourceCompat.h @@ -71,15 +71,48 @@ typedef LONG UINT32; #ifndef ZOS_zWrite #define ZOS_zWrite(_status, _key, _flags, _offset, _len, _data, _retLen) \ do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ (_status) = zWrite((_key), (_flags), (_offset), (_len), (_data), (_retLen)); \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ } while (0) #endif #include +/* + * Original ZOS macros release the global NSS MPK lock around calls that may + * enter the OS, event layer, module-symbol loader or file backend. The + * userspace compat header is force-included into imported sources that do not + * see the full kernel nssOSAPIs.h macro set, so keep the same lock boundary + * locally without assuming every caller currently owns the lock. + */ +#define MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_owned) \ + do { \ + (_owned) = MPKNSS_I_OWN_SPINLOCK(); \ + if (_owned) \ + { \ + MPKNSS_UNLOCK(); \ + } \ + } while (0) +#define MARS_NWE_NWNSS_MPK_BOUNDARY_END(_owned) \ + do { \ + if (_owned) \ + { \ + MPKNSS_LOCK(); \ + } \ + } while (0) + + #ifndef ZOS_StartThread #define ZOS_StartThread(_thread, _name, _func, _stack, _prio, _arg) \ - do { (void)(_name); (void)(_func); (void)(_stack); (void)(_prio); (void)(_arg); (_thread) = 0; } while (0) + do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ + (void)(_name); (void)(_func); (void)(_stack); (void)(_prio); (void)(_arg); \ + (_thread) = 0; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ + } while (0) #endif #ifndef ZOS_StartThreadWithModuleHandle @@ -89,22 +122,42 @@ typedef LONG UINT32; #ifndef ZOS_RegisterConsumer #define ZOS_RegisterConsumer(_reg) \ - do { (void)RegisterConsumer((_reg)); } while (0) + do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ + (void)RegisterConsumer((_reg)); \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ + } while (0) #endif #ifndef ZOS_UnRegisterConsumer #define ZOS_UnRegisterConsumer(_consumer, _event) \ - do { (void)UnRegisterConsumer((_consumer), (_event)); } while (0) + do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ + (void)UnRegisterConsumer((_consumer), (_event)); \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ + } while (0) #endif #ifndef ZOS_ImportPublicSymbol #define ZOS_ImportPublicSymbol(_target, _module, _name) \ - do { (void)(_module); (void)(_name); (_target) = NULL; } while (0) + do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ + (void)(_module); (void)(_name); (_target) = NULL; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ + } while (0) #endif #ifndef ZOS_UnImportPublicSymbol #define ZOS_UnImportPublicSymbol(_module, _name) \ - do { (void)(_module); (void)(_name); } while (0) + do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ + (void)(_module); (void)(_name); \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ + } while (0) #endif #ifndef EXPORT_SYMBOL @@ -123,35 +176,76 @@ typedef LONG UINT32; #ifndef ZOS_zClose #define ZOS_zClose(_status, _key) \ - do { (_status) = zClose((_key)); } while (0) + do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ + (_status) = zClose((_key)); \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ + } while (0) #endif #ifndef ZOS_zOpen #define ZOS_zOpen(_status, _rootKey, _task, _flags, _path, _rights, _outKey) \ - do { (_status) = zOpen((_rootKey), (_task), (_flags), (_path), (_rights), (_outKey)); } while (0) + do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ + (_status) = zOpen((_rootKey), (_task), (_flags), (_path), (_rights), (_outKey)); \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ + } while (0) #endif #ifndef ZOS_zDelete #define ZOS_zDelete(_status, _rootKey, _task, _flags, _path, _rights, _cb) \ - do { (void)(_cb); (_status) = zDelete((_rootKey), (_task), (_flags), (_path), (_rights), NULL); } while (0) + do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ + (void)(_cb); \ + (_status) = zDelete((_rootKey), (_task), (_flags), (_path), (_rights), NULL); \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ + } while (0) #endif #ifndef ZOS_zCreate #define ZOS_zCreate(_status, _rootKey, _task, _flags, _nameSpace, _path, _fileType, _attr, _createFlags, _rights, _outKey) \ - do { (_status) = zCreate((_rootKey), (_task), (_flags), (_nameSpace), (_path), (_fileType), (_attr), (_createFlags), (_rights), (_outKey)); } while (0) + do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ + (_status) = zCreate((_rootKey), (_task), (_flags), (_nameSpace), (_path), (_fileType), (_attr), (_createFlags), (_rights), (_outKey)); \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ + } while (0) #endif #ifndef ZOS_zDIORead #define ZOS_zDIORead(_status, _key, _offset, _count, _flags, _cb, _buf) \ - do { (_status) = zDIORead((_key), (_offset), (_count), (_flags), (_cb), (_buf)); } while (0) + do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ + (_status) = zDIORead((_key), (_offset), (_count), (_flags), (_cb), (_buf)); \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ + } while (0) #endif #ifndef ZOS_zDIOWrite #define ZOS_zDIOWrite(_status, _key, _offset, _count, _flags, _cb, _buf) \ - do { (_status) = zDIOWrite((_key), (_offset), (_count), (_flags), (_cb), (_buf)); } while (0) + do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ + (_status) = zDIOWrite((_key), (_offset), (_count), (_flags), (_cb), (_buf)); \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ + } while (0) #endif #ifndef ZOS_zRootKey #define ZOS_zRootKey(_status, _flags, _outKey) \ - do { (_status) = zRootKey((_flags), (_outKey)); } while (0) + do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ + (_status) = zRootKey((_flags), (_outKey)); \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ + } while (0) #endif #ifndef ZOS_zSetEOF #define ZOS_zSetEOF(_status, _key, _offset, _size, _flags) \ - do { (_status) = zSetEOF((_key), (_offset), (_size), (_flags)); } while (0) + do { \ + BOOL _mars_nwe_mpk_owned; \ + MARS_NWE_NWNSS_MPK_BOUNDARY_BEGIN(_mars_nwe_mpk_owned); \ + (_status) = zSetEOF((_key), (_offset), (_size), (_flags)); \ + MARS_NWE_NWNSS_MPK_BOUNDARY_END(_mars_nwe_mpk_owned); \ + } while (0) #endif #ifndef errPrintf diff --git a/nwnss-audit.md b/nwnss-audit.md index bc504a8..7fda55b 100644 --- a/nwnss-audit.md +++ b/nwnss-audit.md @@ -402,7 +402,7 @@ even if it already compiles or has indirect test coverage. |---|---:|---|---|---| | TODO | ORIG+FIX? | not yet classified | `src/nwnss/CMakeLists.txt` | Must be compared against original source and classified. | | TEMP | TEMP | link smoke | `src/nwnss/nssStartupNameGlobals.c` | Transition globals from nssStartup.c; should disappear later. | -| PARTIAL | PORT | build + nwnss.neb/schedule | `include/nwnss/internal/nwnssSourceCompat.h` | Only ZOS/NEB/scheduler related parts checked so far. | +| AUDITED | PORT | build + nwnss.neb/schedule | `include/nwnss/internal/nwnssSourceCompat.h` | Private force-include compatibility layer for imported NSS sources that do not see the full kernel `nssOSAPIs.h` macro environment. Rechecked after the scheduler/NEB audit: NSS libc aliases, printk/kfree/module-export no-ops, symbol-import fallbacks and z* file-backend fallbacks are deliberate userspace boundaries. ZOS calls that may enter the OS/event/module/file backend now preserve the original MPKNSS release/reacquire boundary when the caller owns the lock; they do not invent cross-process NEB/module semantics or enable real block I/O. | | AUDITED | PORT | nwnss.utc | `src/nwnss/utcUserland.c` | Userspace boundary for imported UTC helpers: exports the same timezone/daylight globals expected by `utc.h` plus `GetUTCTime()`, backed by libc `time(3)` and explicit UTC/default timezone state until the broader NSS clock configuration layer is imported. Original UTC conversion files are otherwise present under `public_core/library/utc`; no UTC sharedsrc implementation was found. Tests cover UTC round trips plus manual timezone-offset conversion. | ### Sources: COMN root