From d223e8ef00bd9ffb0f034c212ec589ebb81e5e09 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Thu, 11 Jun 2026 12:22:50 +0000 Subject: [PATCH] quota: split generic quota and nwquota files --- AI.md | 16 ++- REDESIGN.md | 8 +- TODO.md | 15 ++- include/nwfs/{nwfsQuota.h => nwquota.h} | 13 +-- include/nwfs/quota.h | 16 +++ src/nwfs/CMakeLists.txt | 6 +- src/nwfs/quota/{nwfsQuota.c => nwquota.c} | 116 ++++++++++------------ src/nwfs/quota/quota.c | 32 ++++++ src/nwvolume.c | 3 +- 9 files changed, 143 insertions(+), 82 deletions(-) rename include/nwfs/{nwfsQuota.h => nwquota.h} (69%) create mode 100644 include/nwfs/quota.h rename src/nwfs/quota/{nwfsQuota.c => nwquota.c} (64%) create mode 100644 src/nwfs/quota/quota.c diff --git a/AI.md b/AI.md index 4c14e15..484d803 100644 --- a/AI.md +++ b/AI.md @@ -2074,12 +2074,24 @@ and all submodules, then rebuild a clean tree before producing new patches. Next patch number should be `0271`. +### 0343 quota file/name split handoff note + +0343 keeps the quota backends deliberately distinguishable. The generic quota +frontend helpers live in `include/nwfs/quota.h` and `src/nwfs/quota/quota.c` +with `nwfs_quota_*` names only. The NetWare metadata backend lives in +`include/nwfs/nwquota.h` and `src/nwfs/quota/nwquota.c` with +`nwfs_nwquota_*` public names and `nwfs_nwquota_*` private helpers. + +Do not merge Linux quota and NWQUOTA back into one source file. Future Linux +`quotactl()` relocation should get a separate backend implementation while +keeping the generic `quota.c` file backend-neutral. + ### 0342 quota relocation handoff note 0342 starts the planned quota move into `libnwfs`. It moves the metadata/NWQUOTA backend helpers from `src/nwvolume.c` into -`src/nwfs/quota/nwfsQuota.c` with public declarations in -`include/nwfs/nwfsQuota.h`. `src/nwvolume.c` remains the mars-nwe volume/NCP +`src/nwfs/quota/quota.c` and `src/nwfs/quota/nwquota.c` with public declarations in +`include/nwfs/quota.h` and `include/nwfs/nwquota.h`. `src/nwvolume.c` remains the mars-nwe volume/NCP entry point and still handles Linux `quotactl()` probing, but now calls libnwfs for NWQUOTA restriction, usage, and adjust operations. diff --git a/REDESIGN.md b/REDESIGN.md index c53e136..d9957f7 100644 --- a/REDESIGN.md +++ b/REDESIGN.md @@ -3207,13 +3207,13 @@ work where project-level headers are added. Third-party imports remain under their own upstream licenses inside the relevant `third_party/` subtree and must be documented separately. -### Quota backend placement after 0342 +### Quota backend placement after 0343 -The first quota relocation step moves the metadata/NWQUOTA implementation into +The quota relocation keeps the two quota systems deliberately separated inside `libnwfs`: -- public API: `include/nwfs/nwfsQuota.h` -- implementation: `src/nwfs/quota/nwfsQuota.c` +- generic quota frontend/API: `include/nwfs/quota.h`, `src/nwfs/quota/quota.c`, `nwfs_quota_*` +- NetWare metadata backend/API: `include/nwfs/nwquota.h`, `src/nwfs/quota/nwquota.c`, `nwfs_nwquota_*` - volume-layer callers: `src/nwvolume.c` `src/nwvolume.c` remains the NCP/volume entry point and still owns Linux diff --git a/TODO.md b/TODO.md index 9031f73..a2dceac 100644 --- a/TODO.md +++ b/TODO.md @@ -2323,12 +2323,17 @@ Follow-up: system-collision risk. If yes, give the library, headers, CMake package, and imported tools an `nw` namespace from the first patch. -### Quota relocation follow-ups after 0342 +### Quota relocation follow-ups after 0343 -- Re-run `tests/nwfs/nwfs_ncpfs_userquota_dual_smoke.sh` after the 0342 - structural move. Expected result stays the same as 0340: Linuxquota and - metadata/NWQUOTA both deny the next 4K write before data. +- Re-run `tests/nwfs/nwfs_ncpfs_userquota_dual_smoke.sh` after the 0343 + file/function split. Expected result stays the same as 0340/0342: + Linuxquota and metadata/NWQUOTA both deny the next 4K write before data. +- Keep generic quota helpers in `src/nwfs/quota/quota.c` / + `include/nwfs/quota.h` with `nwfs_quota_*` names only. +- Keep NetWare metadata quota in `src/nwfs/quota/nwquota.c` / + `include/nwfs/nwquota.h` with `nwfs_nwquota_*` names. - Move the remaining Linux `quotactl()` backend out of `src/nwvolume.c` into - `src/nwfs/quota/` once 0342 is confirmed green. + its own `src/nwfs/quota/` backend file once 0343 is confirmed green; do not + merge it into `nwquota.c`. - Keep `src/nwvolume.c` as the stable NCP volume API shim until namespace and quota are both sufficiently represented in `libnwfs`. diff --git a/include/nwfs/nwfsQuota.h b/include/nwfs/nwquota.h similarity index 69% rename from include/nwfs/nwfsQuota.h rename to include/nwfs/nwquota.h index bf2b76a..3422f8f 100644 --- a/include/nwfs/nwfsQuota.h +++ b/include/nwfs/nwquota.h @@ -1,13 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -#ifndef _NWFS_QUOTA_H_ -#define _NWFS_QUOTA_H_ 1 +#ifndef _NWFS_NWQUOTA_H_ +#define _NWFS_NWQUOTA_H_ 1 #include -#include - -uint32_t nwfs_quota_blocks_for_size(off_t size); -int nwfs_quota_backend_current(void); +/* + * NetWare metadata quota backend. This owns the volume-root + * netware.userquota xattr and keeps restriction/usage accounting separate + * from Linux kernel quotactl quota. + */ int nwfs_nwquota_set_restriction(const char *volume_root, int uid, uint32_t quota4k); int nwfs_nwquota_get_restriction(const char *volume_root, int uid, diff --git a/include/nwfs/quota.h b/include/nwfs/quota.h new file mode 100644 index 0000000..67c0f43 --- /dev/null +++ b/include/nwfs/quota.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _NWFS_QUOTA_FRONTEND_H_ +#define _NWFS_QUOTA_FRONTEND_H_ 1 + +#include +#include + +/* + * Generic quota helpers shared by quota backends and the mars_nwe volume + * layer. Backend-specific APIs live in separate headers such as nwquota.h; + * do not add NWQUOTA or Linux quotactl entry points here. + */ +uint32_t nwfs_quota_blocks_for_size(off_t size); +int nwfs_quota_backend_current(void); + +#endif diff --git a/src/nwfs/CMakeLists.txt b/src/nwfs/CMakeLists.txt index f851b13..ec45075 100644 --- a/src/nwfs/CMakeLists.txt +++ b/src/nwfs/CMakeLists.txt @@ -8,7 +8,8 @@ add_library(nwfs SHARED unixNSpace.c longNSpace.c dataStreamNSpace.c - quota/nwfsQuota.c) + quota/quota.c + quota/nwquota.c) add_library(mars_nwe::nwfs ALIAS nwfs) set_target_properties(nwfs PROPERTIES @@ -34,7 +35,8 @@ install(TARGETS nwfs install(FILES "${CMAKE_SOURCE_DIR}/include/nwfs/zXattr.h" - "${CMAKE_SOURCE_DIR}/include/nwfs/nwfsQuota.h" + "${CMAKE_SOURCE_DIR}/include/nwfs/quota.h" + "${CMAKE_SOURCE_DIR}/include/nwfs/nwquota.h" "${CMAKE_SOURCE_DIR}/include/nwfs/zasAuthModel.h" "${CMAKE_SOURCE_DIR}/include/nwfs/nameSpaceModel.h" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/nwfs") diff --git a/src/nwfs/quota/nwfsQuota.c b/src/nwfs/quota/nwquota.c similarity index 64% rename from src/nwfs/quota/nwfsQuota.c rename to src/nwfs/quota/nwquota.c index 851f68d..1a00cf1 100644 --- a/src/nwfs/quota/nwfsQuota.c +++ b/src/nwfs/quota/nwquota.c @@ -1,12 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif /* - * NetWare-compatible quota helpers for mars_nwe/libnwfs. + * NetWare metadata quota backend for libnwfs. * - * This file contains the NWQUOTA metadata backend that stores per-user - * restrictions and live usage in the volume-root netware.userquota xattr. - * Linux kernel quota probing is still driven by the mars_nwe volume layer; - * this file owns the NetWare metadata backend so other nwfs namespace code can - * eventually share it as the filesystem compatibility layer grows. + * This file owns NWQUOTA accounting: per-user restrictions and live usage are + * stored in the volume-root netware.userquota xattr. Keep this backend + * separate from the generic quota frontend (quota.c) and from the future Linux + * kernel quotactl backend. */ #if defined(__has_include) # if __has_include("config.h") @@ -32,34 +34,23 @@ #endif #include -#include +#include +#include -uint32_t nwfs_quota_blocks_for_size(off_t size) -{ - if (size <= 0) - return(0); - return((uint32_t)(((unsigned long long)size + 4095ULL) / 4096ULL)); -} - -int nwfs_quota_backend_current(void) -{ - return(nwfs_quota_backend_from_string(getenv(NWFS_QUOTA_BACKEND_ENV))); -} - -static void nwfs_mars_uid_to_guid(int uid, GUID_t *guid) +static void nwfs_nwquota_mars_uid_to_guid(int uid, GUID_t *guid) { memset(guid, 0, sizeof(*guid)); guid->timeLow = (LONG)uid; } -static int nwfs_guid_to_mars_uid(const GUID_t *guid) +static int nwfs_nwquota_guid_to_mars_uid(const GUID_t *guid) { return((int)guid->timeLow); } #if XATTR_SUPPORT -static const char *nwfs_xattr_name(const char *name, char *buffer, - size_t buffer_len) +static const char *nwfs_nwquota_xattr_name(const char *name, char *buffer, + size_t buffer_len) { if (!name || !*name) return(name); @@ -85,12 +76,12 @@ static const char *nwfs_xattr_name(const char *name, char *buffer, } #endif -static ssize_t nwfs_quota_getxattr(const char *path, const char *name, - void *value, size_t size) +static ssize_t nwfs_nwquota_getxattr(const char *path, const char *name, + void *value, size_t size) { #if XATTR_SUPPORT char xname[256 + 5]; - return(getxattr(path, nwfs_xattr_name(name, xname, sizeof(xname)), + return(getxattr(path, nwfs_nwquota_xattr_name(name, xname, sizeof(xname)), value, size)); #else (void)path; @@ -102,12 +93,12 @@ static ssize_t nwfs_quota_getxattr(const char *path, const char *name, #endif } -static int nwfs_quota_setxattr(const char *path, const char *name, - const void *value, size_t size, int flags) +static int nwfs_nwquota_setxattr(const char *path, const char *name, + const void *value, size_t size, int flags) { #if XATTR_SUPPORT char xname[256 + 5]; - return(setxattr(path, nwfs_xattr_name(name, xname, sizeof(xname)), + return(setxattr(path, nwfs_nwquota_xattr_name(name, xname, sizeof(xname)), value, size, flags)); #else (void)path; @@ -120,8 +111,8 @@ static int nwfs_quota_setxattr(const char *path, const char *name, #endif } -static int read_userquota_from_volume(const char *volume_root, - zNW_user_quota_s *userquota) +static int nwfs_nwquota_read_userquota_from_volume(const char *volume_root, + zNW_user_quota_s *userquota) { ssize_t len; int euid; @@ -142,8 +133,8 @@ static int read_userquota_from_volume(const char *volume_root, return(-1); memset(userquota, 0, sizeof(*userquota)); - len = nwfs_quota_getxattr(volume_root, zNW_USERQUOTA, userquota, - sizeof(*userquota)); + len = nwfs_nwquota_getxattr(volume_root, zNW_USERQUOTA, userquota, + sizeof(*userquota)); if (len < 0) { rc = -1; } else if (nwfs_userquota_validate(userquota, (size_t)len) != NWFS_OK) { @@ -155,8 +146,8 @@ static int read_userquota_from_volume(const char *volume_root, return(rc); } -static int write_userquota_to_volume(const char *volume_root, - zNW_user_quota_s *userquota) +static int nwfs_nwquota_write_userquota_to_volume(const char *volume_root, + zNW_user_quota_s *userquota) { size_t size; int euid; @@ -173,20 +164,20 @@ static int write_userquota_to_volume(const char *volume_root, if (euid != 0 && seteuid(0)) return(-1); - rc = nwfs_quota_setxattr(volume_root, zNW_USERQUOTA, userquota, size, 0); + rc = nwfs_nwquota_setxattr(volume_root, zNW_USERQUOTA, userquota, size, 0); if (euid != 0 && seteuid(euid)) abort(); return(rc); } -static int nwfs_volume_file_owned_by_quota_user(const struct stat *st, int uid) +static int nwfs_nwquota_file_owned_by_quota_user(const struct stat *st, int uid) { return(st && st->st_uid == (uid_t)uid); } -static uint32_t nwfs_volume_user_usage_4k_scan(const char *path, int uid, - dev_t root_dev) +static uint32_t nwfs_nwquota_user_usage_4k_scan(const char *path, int uid, + dev_t root_dev) { DIR *dir; struct dirent *de; @@ -197,7 +188,7 @@ static uint32_t nwfs_volume_user_usage_4k_scan(const char *path, int uid, return(0); if (st.st_dev != root_dev) return(0); - if (S_ISREG(st.st_mode) && nwfs_volume_file_owned_by_quota_user(&st, uid)) + if (S_ISREG(st.st_mode) && nwfs_nwquota_file_owned_by_quota_user(&st, uid)) return(nwfs_quota_blocks_for_size(st.st_size)); if (!S_ISDIR(st.st_mode)) return(0); @@ -222,13 +213,13 @@ static uint32_t nwfs_volume_user_usage_4k_scan(const char *path, int uid, child[len] = '\0'; } strcpy(child + len, de->d_name); - blocks += nwfs_volume_user_usage_4k_scan(child, uid, root_dev); + blocks += nwfs_nwquota_user_usage_4k_scan(child, uid, root_dev); } closedir(dir); return(blocks); } -static uint32_t nwfs_volume_user_usage_4k(const char *volume_root, int uid) +static uint32_t nwfs_nwquota_user_usage_4k(const char *volume_root, int uid) { struct stat st; @@ -236,11 +227,11 @@ static uint32_t nwfs_volume_user_usage_4k(const char *volume_root, int uid) return(0); if (stat(volume_root, &st) != 0) return(0); - return(nwfs_volume_user_usage_4k_scan(volume_root, uid, st.st_dev)); + return(nwfs_nwquota_user_usage_4k_scan(volume_root, uid, st.st_dev)); } -static uint32_t nwfs_userquota_used_4k(zNW_user_restriction_s *entry, - uint32_t scanned) +static uint32_t nwfs_nwquota_used_4k(zNW_user_restriction_s *entry, + uint32_t scanned) { uint32_t stored; @@ -267,13 +258,13 @@ int nwfs_nwquota_set_restriction(const char *volume_root, int uid, uint32_t inuse; int i; - if (read_userquota_from_volume(volume_root, &userquota)) + if (nwfs_nwquota_read_userquota_from_volume(volume_root, &userquota)) nwfs_userquota_init(&userquota); - inuse = nwfs_volume_user_usage_4k(volume_root, uid); + inuse = nwfs_nwquota_user_usage_4k(volume_root, uid); for (i = 0; i < userquota.nwuq_num_users; i++) { - if (nwfs_guid_to_mars_uid(&userquota.nwuq_user[i].nwur_user) == uid) { + if (nwfs_nwquota_guid_to_mars_uid(&userquota.nwuq_user[i].nwur_user) == uid) { if (quota4k == 0) { if (i + 1 < userquota.nwuq_num_users) { memmove(&userquota.nwuq_user[i], &userquota.nwuq_user[i + 1], @@ -285,7 +276,7 @@ int nwfs_nwquota_set_restriction(const char *volume_root, int uid, userquota.nwuq_user[i].nwur_restriction = (SQUAD)quota4k; userquota.nwuq_user[i].nwur_reserved_2 = (QUAD)inuse; } - return(write_userquota_to_volume(volume_root, &userquota)); + return(nwfs_nwquota_write_userquota_to_volume(volume_root, &userquota)); } } @@ -294,11 +285,12 @@ int nwfs_nwquota_set_restriction(const char *volume_root, int uid, if (userquota.nwuq_num_users >= zMAX_XATTR_USERS) return(-1); - nwfs_mars_uid_to_guid(uid, &userquota.nwuq_user[userquota.nwuq_num_users].nwur_user); + nwfs_nwquota_mars_uid_to_guid( + uid, &userquota.nwuq_user[userquota.nwuq_num_users].nwur_user); userquota.nwuq_user[userquota.nwuq_num_users].nwur_restriction = (SQUAD)quota4k; userquota.nwuq_user[userquota.nwuq_num_users].nwur_reserved_2 = (QUAD)inuse; userquota.nwuq_num_users++; - return(write_userquota_to_volume(volume_root, &userquota)); + return(nwfs_nwquota_write_userquota_to_volume(volume_root, &userquota)); } int nwfs_nwquota_get_restriction(const char *volume_root, int uid, @@ -312,17 +304,17 @@ int nwfs_nwquota_get_restriction(const char *volume_root, int uid, *quota4k = 0x40000000; *inuse4k = 0; - if (read_userquota_from_volume(volume_root, &userquota)) + if (nwfs_nwquota_read_userquota_from_volume(volume_root, &userquota)) return(0); for (i = 0; i < userquota.nwuq_num_users; i++) { - if (nwfs_guid_to_mars_uid(&userquota.nwuq_user[i].nwur_user) == uid) { - uint32_t scanned = nwfs_volume_user_usage_4k(volume_root, uid); + if (nwfs_nwquota_guid_to_mars_uid(&userquota.nwuq_user[i].nwur_user) == uid) { + uint32_t scanned = nwfs_nwquota_user_usage_4k(volume_root, uid); if (userquota.nwuq_user[i].nwur_restriction <= 0) *quota4k = 0x40000000; else *quota4k = (uint32_t)userquota.nwuq_user[i].nwur_restriction; - *inuse4k = nwfs_userquota_used_4k(&userquota.nwuq_user[i], scanned); + *inuse4k = nwfs_nwquota_used_4k(&userquota.nwuq_user[i], scanned); return(0); } } @@ -334,11 +326,11 @@ int nwfs_nwquota_has_restriction(const char *volume_root, int uid) zNW_user_quota_s userquota; int i; - if (read_userquota_from_volume(volume_root, &userquota)) + if (nwfs_nwquota_read_userquota_from_volume(volume_root, &userquota)) return(0); for (i = 0; i < userquota.nwuq_num_users; i++) { - if (nwfs_guid_to_mars_uid(&userquota.nwuq_user[i].nwur_user) == uid) + if (nwfs_nwquota_guid_to_mars_uid(&userquota.nwuq_user[i].nwur_user) == uid) return(1); } return(0); @@ -354,13 +346,13 @@ int nwfs_nwquota_adjust_usage(const char *volume_root, int uid, *used4k = 0; if (delta4k == 0) return(0); - if (read_userquota_from_volume(volume_root, &userquota)) + if (nwfs_nwquota_read_userquota_from_volume(volume_root, &userquota)) return(0); for (i = 0; i < userquota.nwuq_num_users; i++) { - if (nwfs_guid_to_mars_uid(&userquota.nwuq_user[i].nwur_user) == uid) { - uint32_t scanned = nwfs_volume_user_usage_4k(volume_root, uid); - uint32_t used = nwfs_userquota_used_4k(&userquota.nwuq_user[i], scanned); + if (nwfs_nwquota_guid_to_mars_uid(&userquota.nwuq_user[i].nwur_user) == uid) { + uint32_t scanned = nwfs_nwquota_user_usage_4k(volume_root, uid); + uint32_t used = nwfs_nwquota_used_4k(&userquota.nwuq_user[i], scanned); if (delta4k < 0) { uint32_t dec = (uint32_t)(-delta4k); @@ -373,7 +365,7 @@ int nwfs_nwquota_adjust_usage(const char *volume_root, int uid, userquota.nwuq_user[i].nwur_reserved_2 = (QUAD)used; if (used4k) *used4k = used; - return(write_userquota_to_volume(volume_root, &userquota)); + return(nwfs_nwquota_write_userquota_to_volume(volume_root, &userquota)); } } return(0); diff --git a/src/nwfs/quota/quota.c b/src/nwfs/quota/quota.c new file mode 100644 index 0000000..c064c41 --- /dev/null +++ b/src/nwfs/quota/quota.c @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Generic quota helpers for libnwfs. + * + * Keep this file backend-neutral. NetWare metadata quota lives in nwquota.c; + * Linux kernel quotactl quota should get its own backend file when it moves + * from the mars_nwe volume layer. + */ +#if defined(__has_include) +# if __has_include("config.h") +# include "config.h" +# endif +#endif + +#include +#include +#include + +#include +#include + +uint32_t nwfs_quota_blocks_for_size(off_t size) +{ + if (size <= 0) + return(0); + return((uint32_t)(((unsigned long long)size + 4095ULL) / 4096ULL)); +} + +int nwfs_quota_backend_current(void) +{ + return(nwfs_quota_backend_from_string(getenv(NWFS_QUOTA_BACKEND_ENV))); +} diff --git a/src/nwvolume.c b/src/nwvolume.c index fe993ab..9803d6f 100644 --- a/src/nwvolume.c +++ b/src/nwvolume.c @@ -55,7 +55,8 @@ #include "unxfile.h" #include "nwxattr.h" #include -#include +#include +#include #define VOLOPTIONS_DEFAULT VOL_OPTION_ATTRIBUTES