quota: avoid nwquota fallback on linux set failures

This commit is contained in:
OpenAI
2026-06-12 08:07:56 +00:00
committed by Mario Fetka
parent 13810839fc
commit ccc7d63be9
5 changed files with 57 additions and 23 deletions

10
AI.md
View File

@@ -2313,3 +2313,13 @@ logs/archives are usually copied or uploaded later by a normal desktop user.
later live smokes, `nw.log` slice, tar.gz and zip from being emitted.
- Keep the archive outside the output directory (`/tmp/<timestamp>-quota-all-smoke.*`)
so tar/zip do not recursively include their own output file.
### 0384 Linuxquota clear/log cleanup note
- Linuxquota set/clear must not echo a broad `dqb_valid` mask from `Q_GETQUOTA`
back into `Q_SETQUOTA`. Set only block-limit fields for NetWare user-volume
restrictions; usage and inode fields remain kernel-owned.
- AUTO fallback to NWQUOTA is for genuinely unavailable Linux quota devices
(`no-device`, `unsupported`, `probe-failed`). A real Linuxquota `set-failed`
on a QUOTA-style volume is an error to fix, not a reason to create a parallel
metadata-authoritative state.

View File

@@ -3469,3 +3469,24 @@ logs/archives are usually copied or uploaded later by a normal desktop user.
later live smokes, `nw.log` slice, tar.gz and zip from being emitted.
- Keep the archive outside the output directory (`/tmp/<timestamp>-quota-all-smoke.*`)
so tar/zip do not recursively include their own output file.
### 0384 Linuxquota clear/log cleanup
The all-quota smoke after 0383 showed the quota functionality green, but the
server log still contained an ugly QUOTA-side message during userquota remove:
`Linux quota set unavailable ... result=set-failed; using nwquota metadata backend`.
That is contrary to the backend ownership rule. On Linuxquota volumes the
kernel quota backend is authoritative; NWQUOTA metadata is only a mirror and a
restore source, not an alternate authority after a kernel `set-failed`.
0384 tightens this in two ways:
- `lnxquota.c` no longer reuses the broad `dqb_valid` mask returned by
`Q_GETQUOTA` when calling `Q_SETQUOTA`; it marks only block limits valid.
This matches the project-quota fix made earlier and avoids kernels rejecting
attempts to set usage/grace/inode fields when mars-nwe only means to update a
NetWare user-volume block restriction.
- `nw_set_vol_restrictions()` falls back to NWQUOTA only when Linux quota is
unavailable (`no-device`, `unsupported`, `probe-failed`). A real `set-failed`
remains a Linuxquota error instead of silently switching QUOTA to a parallel
metadata-authoritative path.

View File

@@ -2572,3 +2572,12 @@ logs/archives are usually copied or uploaded later by a normal desktop user.
later live smokes, `nw.log` slice, tar.gz and zip from being emitted.
- Keep the archive outside the output directory (`/tmp/<timestamp>-quota-all-smoke.*`)
so tar/zip do not recursively include their own output file.
### 0384 quota cleanup follow-up
- DONE in 0384: remove the misleading AUTO fallback on Linuxquota `set-failed`;
fallback to NWQUOTA only when Linux quota is unavailable/probe-failed.
- DONE in 0384: Linux userquota `Q_SETQUOTA` sets only block-limit fields so
clear/remove restrictions should not log `set-failed; using nwquota metadata backend`.
- After applying 0384, rerun `nwfs_ncpfs_all_quota_smoke.sh` and verify the
`nw.log` slice has no QUOTA-side `set-failed; using nwquota metadata backend`.

View File

@@ -170,16 +170,16 @@ int nwfs_lnxquota_set_restriction(const char *volume_root, int uid,
dqblk.dqb_bhardlimit = quota1k;
dqblk.dqb_bsoftlimit = quota1k;
/* Q_GETQUOTA can return a broad dqb_valid mask. Do not echo it back to
* Q_SETQUOTA, because some kernels reject attempts to set usage/grace-time
* fields together with the block limits. NetWare user-volume restrictions
* map only to block limits here; inode limits and usage stay kernel-owned.
*/
# ifdef QIF_BLIMITS
dqblk.dqb_valid |= QIF_BLIMITS;
dqblk.dqb_valid = QIF_BLIMITS;
# else
dqblk.dqb_valid = 0;
# endif
if (quota1k == 0) {
dqblk.dqb_ihardlimit = 0;
dqblk.dqb_isoftlimit = 0;
# ifdef QIF_ILIMITS
dqblk.dqb_valid |= QIF_ILIMITS;
# endif
}
res = nwfs_lnxquota_quotactl(QCMD(NWFS_LNXQUOTA_SET_CMD, USRQUOTA),
device, uid, (caddr_t)&dqblk);

View File

@@ -972,9 +972,10 @@ int nw_set_vol_restrictions(uint8 volnr, int uid, uint32 quota)
return(0);
}
if (backend == NWFS_QUOTA_BACKEND_ID_AUTO ||
lnxres == NWFS_LNXQUOTA_NO_DEVICE ||
lnxres == NWFS_LNXQUOTA_UNSUPPORTED) {
if (backend == NWFS_QUOTA_BACKEND_ID_AUTO &&
(lnxres == NWFS_LNXQUOTA_NO_DEVICE ||
lnxres == NWFS_LNXQUOTA_UNSUPPORTED ||
lnxres == NWFS_LNXQUOTA_PROBE_FAILED)) {
XDPRINTF((2,0,
"Linux quota set unavailable volume=%d path=%s uid=%d result=%s; using nwquota metadata backend",
volnr, nw_volumes[volnr].unixname, uid,
@@ -982,14 +983,6 @@ int nw_set_vol_restrictions(uint8 volnr, int uid, uint32 quota)
return(nwfs_nwquota_set_restriction((const char*)nw_volumes[volnr].unixname, uid, quota) ? -0xfb : 0);
}
if (lnxres == NWFS_LNXQUOTA_PROBE_FAILED) {
XDPRINTF((2,0,
"Linux quota probe failed volume=%d path=%s uid=%d result=%s",
volnr, nw_volumes[volnr].unixname, uid,
nwfs_lnxquota_result_name(lnxres)));
return(0); /* Explicit LINUXQUOTA old compatibility path. */
}
XDPRINTF((2,0,
"Linux quota set failed volume=%d path=%s uid=%d result=%s",
volnr, nw_volumes[volnr].unixname, uid,
@@ -1024,10 +1017,11 @@ int nw_get_vol_restrictions(uint8 volnr, int uid, uint32 *quota, uint32 *inuse)
nw_restore_lnxquota_from_nwquota(volnr, uid, quota, inuse))
return(0);
if (backend == NWFS_QUOTA_BACKEND_ID_AUTO ||
lnxres == NWFS_LNXQUOTA_NO_DEVICE ||
lnxres == NWFS_LNXQUOTA_UNSUPPORTED ||
lnxres == NWFS_LNXQUOTA_NO_ENTRY) {
if (backend == NWFS_QUOTA_BACKEND_ID_AUTO &&
(lnxres == NWFS_LNXQUOTA_NO_DEVICE ||
lnxres == NWFS_LNXQUOTA_UNSUPPORTED ||
lnxres == NWFS_LNXQUOTA_PROBE_FAILED ||
lnxres == NWFS_LNXQUOTA_NO_ENTRY)) {
XDPRINTF((2,0,
"Linux quota get unavailable volume=%d path=%s uid=%d result=%s; using nwquota metadata backend",
volnr, nw_volumes[volnr].unixname, uid,