quota: auto-select linux or nwquota backend
All checks were successful
Source release / source-package (push) Successful in 1m3s
All checks were successful
Source release / source-package (push) Successful in 1m3s
This commit is contained in:
@@ -241,9 +241,19 @@ typedef struct zNW_trustee_name_s {
|
||||
#define NWFS_METADATA_FIXED_SIZE offsetof(zNW_metadata_s, nwm_trustee)
|
||||
#define NWFS_USERQUOTA_FIXED_SIZE offsetof(zNW_user_quota_s, nwuq_user)
|
||||
#define NWFS_QUOTA_BACKEND_ENV "NWFS_QUOTA_BACKEND"
|
||||
#define NWFS_QUOTA_BACKEND_AUTO "AUTO"
|
||||
#define NWFS_QUOTA_BACKEND_LINUXQUOTA "LINUXQUOTA"
|
||||
#define NWFS_QUOTA_BACKEND_METADATAONLY "METADATAONLY"
|
||||
#define NWFS_QUOTA_BACKEND_NSS "NSS"
|
||||
#define NWFS_QUOTA_BACKEND_NWQUOTA "NWQUOTA"
|
||||
|
||||
typedef enum nwfs_quota_backend_id_e {
|
||||
NWFS_QUOTA_BACKEND_ID_AUTO = 0,
|
||||
NWFS_QUOTA_BACKEND_ID_LINUXQUOTA = 1,
|
||||
NWFS_QUOTA_BACKEND_ID_METADATAONLY = 2,
|
||||
NWFS_QUOTA_BACKEND_ID_NSS = 3,
|
||||
NWFS_QUOTA_BACKEND_ID_NWQUOTA = 4
|
||||
} nwfs_quota_backend_id_e;
|
||||
|
||||
typedef enum nwfs_status_e {
|
||||
NWFS_OK = 0,
|
||||
|
||||
@@ -309,12 +309,6 @@ int nwfs_metadata_get_quota_limit(const zNW_metadata_s *metadata, SQUAD *quota_l
|
||||
return NWFS_OK;
|
||||
}
|
||||
|
||||
enum {
|
||||
NWFS_QUOTA_BACKEND_ID_LINUXQUOTA = 0,
|
||||
NWFS_QUOTA_BACKEND_ID_METADATAONLY = 1,
|
||||
NWFS_QUOTA_BACKEND_ID_NSS = 2
|
||||
};
|
||||
|
||||
static int nwfs_ascii_casecmp(const char *left, const char *right)
|
||||
{
|
||||
unsigned char lc;
|
||||
@@ -343,7 +337,10 @@ static int nwfs_ascii_casecmp(const char *left, const char *right)
|
||||
int nwfs_quota_backend_from_string(const char *name)
|
||||
{
|
||||
if (name == NULL || *name == '\0' ||
|
||||
nwfs_ascii_casecmp(name, NWFS_QUOTA_BACKEND_LINUXQUOTA) == 0) {
|
||||
nwfs_ascii_casecmp(name, NWFS_QUOTA_BACKEND_AUTO) == 0) {
|
||||
return NWFS_QUOTA_BACKEND_ID_AUTO;
|
||||
}
|
||||
if (nwfs_ascii_casecmp(name, NWFS_QUOTA_BACKEND_LINUXQUOTA) == 0) {
|
||||
return NWFS_QUOTA_BACKEND_ID_LINUXQUOTA;
|
||||
}
|
||||
if (nwfs_ascii_casecmp(name, NWFS_QUOTA_BACKEND_METADATAONLY) == 0) {
|
||||
@@ -352,18 +349,25 @@ int nwfs_quota_backend_from_string(const char *name)
|
||||
if (nwfs_ascii_casecmp(name, NWFS_QUOTA_BACKEND_NSS) == 0) {
|
||||
return NWFS_QUOTA_BACKEND_ID_NSS;
|
||||
}
|
||||
if (nwfs_ascii_casecmp(name, NWFS_QUOTA_BACKEND_NWQUOTA) == 0) {
|
||||
return NWFS_QUOTA_BACKEND_ID_NWQUOTA;
|
||||
}
|
||||
return NWFS_ERR_INVAL;
|
||||
}
|
||||
|
||||
const char *nwfs_quota_backend_name(int backend)
|
||||
{
|
||||
switch (backend) {
|
||||
case NWFS_QUOTA_BACKEND_ID_AUTO:
|
||||
return NWFS_QUOTA_BACKEND_AUTO;
|
||||
case NWFS_QUOTA_BACKEND_ID_LINUXQUOTA:
|
||||
return NWFS_QUOTA_BACKEND_LINUXQUOTA;
|
||||
case NWFS_QUOTA_BACKEND_ID_METADATAONLY:
|
||||
return NWFS_QUOTA_BACKEND_METADATAONLY;
|
||||
case NWFS_QUOTA_BACKEND_ID_NSS:
|
||||
return NWFS_QUOTA_BACKEND_NSS;
|
||||
case NWFS_QUOTA_BACKEND_ID_NWQUOTA:
|
||||
return NWFS_QUOTA_BACKEND_NWQUOTA;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1095,38 +1095,35 @@ int nw_set_vol_restrictions(uint8 volnr, int uid, uint32 quota)
|
||||
const char *device;
|
||||
struct dqblk dqblk;
|
||||
int res;
|
||||
int backend = nwfs_quota_backend_current();
|
||||
uint32 quota4k = quota;
|
||||
|
||||
XDPRINTF((2,0, "nw_set_vol_restrictions vol=%d uid=%d quota=%d blocks",
|
||||
volnr, uid, quota));
|
||||
XDPRINTF((2,0, "nw_set_vol_restrictions vol=%d uid=%d quota=%d blocks backend=%s",
|
||||
volnr, uid, quota, nwfs_quota_backend_name(backend)));
|
||||
|
||||
if (nwfs_quota_backend_current() == 1)
|
||||
return(nw_set_vol_restrictions_metadata(volnr, uid, quota));
|
||||
|
||||
/* Convert from blocks to K */
|
||||
quota *= 4;
|
||||
if (backend == NWFS_QUOTA_BACKEND_ID_METADATAONLY ||
|
||||
backend == NWFS_QUOTA_BACKEND_ID_NWQUOTA)
|
||||
return(nw_set_vol_restrictions_metadata(volnr, uid, quota4k));
|
||||
|
||||
if (volnr >= used_nw_volumes || nw_volumes == (NW_VOL *) NULL)
|
||||
return(-0x98);
|
||||
|
||||
/* AUTO means: use Linux quota when the backing filesystem proves it can,
|
||||
* otherwise store the NetWare restriction in netware.userquota for the
|
||||
* internal nwquota simulation path. Keep explicit LINUXQUOTA strict enough
|
||||
* for administrators who want to notice missing kernel quotas.
|
||||
*/
|
||||
device=find_device_file(nw_volumes[volnr].unixname);
|
||||
if (device == (char *) NULL) {
|
||||
XDPRINTF((2,0, "nw_set_vol_restrictions: no device for volume=%d path=%s, using metadata fallback",
|
||||
volnr, nw_volumes[volnr].unixname));
|
||||
|
||||
/* Classic mars-nwe volumes such as SYS are often directories below a
|
||||
* non-quota filesystem or pseudo/home volumes without a quotactl-capable
|
||||
* backing device. SYSCON still uses User Volume/Disk Restrictions for
|
||||
* NetWare 3.x/4.x style administration. Preserve the working Linux quota
|
||||
* path when a device exists, but store restrictions in the NSS-compatible
|
||||
* netware.userquota xattr when no kernel quota device can be found.
|
||||
*/
|
||||
quota /= 4; /* metadata stores NetWare 4K blocks, not Linux K blocks */
|
||||
return(nw_set_vol_restrictions_metadata(volnr, uid, quota));
|
||||
XDPRINTF((2,0,
|
||||
"nw_set_vol_restrictions: no quota device for volume=%d path=%s, using nwquota metadata backend",
|
||||
volnr, nw_volumes[volnr].unixname));
|
||||
return(nw_set_vol_restrictions_metadata(volnr, uid, quota4k));
|
||||
}
|
||||
|
||||
/* If this call fails then it it probable that quotas are not enabled
|
||||
* on the specified device. Someone needs to set the error number
|
||||
* to whatever will make most sense to netware.
|
||||
*/
|
||||
/* Convert from NetWare 4K blocks to Linux 1K quota blocks. */
|
||||
quota *= 4;
|
||||
|
||||
res=su_quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device, uid, (caddr_t) &dqblk);
|
||||
|
||||
if (res != 0) {
|
||||
@@ -1138,10 +1135,15 @@ int nw_set_vol_restrictions(uint8 volnr, int uid, uint32 quota)
|
||||
XDPRINTF((2,0, "No quota record yet device=%s uid=%d, creating one",
|
||||
device, uid));
|
||||
memset(&dqblk, 0, sizeof(dqblk));
|
||||
} else if (backend == NWFS_QUOTA_BACKEND_ID_AUTO) {
|
||||
XDPRINTF((2,0,
|
||||
"Linux quota probe failed device=%s uid=%d errno=%d; using nwquota metadata backend",
|
||||
device, uid, err));
|
||||
return(nw_set_vol_restrictions_metadata(volnr, uid, quota4k));
|
||||
} else {
|
||||
XDPRINTF((2,0, "Get quota before set failed device=%s uid=%d errno=%d",
|
||||
device, uid, err));
|
||||
return(0); /* Quotas are probably not enabled. Keep old compatibility. */
|
||||
return(0); /* Explicit LINUXQUOTA old compatibility path. */
|
||||
}
|
||||
}
|
||||
dqblk.dqb_bhardlimit = quota;
|
||||
@@ -1156,14 +1158,20 @@ int nw_set_vol_restrictions(uint8 volnr, int uid, uint32 quota)
|
||||
#endif
|
||||
}
|
||||
XDPRINTF((2,0, "Set quota device=%s uid=%d %d(%d)K %d(%d) files",
|
||||
device, uid,
|
||||
dqblk.dqb_bhardlimit,
|
||||
(uint32)(dqblk.dqb_curspace / 1024),
|
||||
dqblk.dqb_ihardlimit,
|
||||
dqblk.dqb_curinodes));
|
||||
device, uid,
|
||||
dqblk.dqb_bhardlimit,
|
||||
(uint32)(dqblk.dqb_curspace / 1024),
|
||||
dqblk.dqb_ihardlimit,
|
||||
dqblk.dqb_curinodes));
|
||||
|
||||
res=su_quotactl(QCMD(MARS_Q_SETQUOTA, USRQUOTA), device, uid, (caddr_t) &dqblk);
|
||||
if (res != 0) {
|
||||
if (backend == NWFS_QUOTA_BACKEND_ID_AUTO) {
|
||||
XDPRINTF((2,0,
|
||||
"Set Linux quota failed device=%s uid=%d quota=%dK errno=%d; using nwquota metadata backend",
|
||||
device, uid, quota, errno));
|
||||
return(nw_set_vol_restrictions_metadata(volnr, uid, quota4k));
|
||||
}
|
||||
XDPRINTF((2,0, "Set quota failed device=%s uid=%d quota=%dK errno=%d",
|
||||
device, uid, quota, errno));
|
||||
return(-0xfb);
|
||||
@@ -1177,24 +1185,27 @@ int nw_get_vol_restrictions(uint8 volnr, int uid, uint32 *quota, uint32 *inuse)
|
||||
const char *device;
|
||||
struct dqblk dqblk;
|
||||
int res;
|
||||
int backend = nwfs_quota_backend_current();
|
||||
|
||||
*quota = 0x40000000;
|
||||
*inuse = 0;
|
||||
if (volnr >= used_nw_volumes || nw_volumes == (NW_VOL *) NULL)
|
||||
return(-0x98);
|
||||
|
||||
if (nwfs_quota_backend_current() == 1)
|
||||
if (backend == NWFS_QUOTA_BACKEND_ID_METADATAONLY ||
|
||||
backend == NWFS_QUOTA_BACKEND_ID_NWQUOTA)
|
||||
return(nw_get_vol_restrictions_metadata(volnr, uid, quota, inuse));
|
||||
|
||||
device=find_device_file(nw_volumes[volnr].unixname);
|
||||
if (device == (char *) NULL) {
|
||||
XDPRINTF((2,0,
|
||||
"nw_get_vol_restrictions: no quota device for volume=%d path=%s, using metadata fallback",
|
||||
"nw_get_vol_restrictions: no quota device for volume=%d path=%s, using nwquota metadata backend",
|
||||
volnr, nw_volumes[volnr].unixname));
|
||||
return(nw_get_vol_restrictions_metadata(volnr, uid, quota, inuse));
|
||||
}
|
||||
|
||||
XDPRINTF((2,0, "Get quota for uid %d on device %s",
|
||||
uid, device));
|
||||
uid, device));
|
||||
|
||||
res=su_quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device, uid, (caddr_t) &dqblk);
|
||||
|
||||
@@ -1208,9 +1219,15 @@ int nw_get_vol_restrictions(uint8 volnr, int uid, uint32 *quota, uint32 *inuse)
|
||||
*inuse = 0;
|
||||
return(0);
|
||||
}
|
||||
if (backend == NWFS_QUOTA_BACKEND_ID_AUTO) {
|
||||
XDPRINTF((2,0,
|
||||
"Linux quota probe failed device=%s uid=%d errno=%d; using nwquota metadata backend",
|
||||
device, uid, err));
|
||||
return(nw_get_vol_restrictions_metadata(volnr, uid, quota, inuse));
|
||||
}
|
||||
XDPRINTF((2,0, "Get quota failed device=%s uid=%d errno=%d",
|
||||
device, uid, err));
|
||||
return(0); /* Quotas are probably not enabled */
|
||||
return(0); /* Explicit LINUXQUOTA old compatibility path. */
|
||||
}
|
||||
if (dqblk.dqb_bhardlimit == 0) {
|
||||
*quota = 0x40000000;
|
||||
|
||||
@@ -93,11 +93,13 @@ int main(void)
|
||||
CHECK(nwfs_xattr_name_visible(zNW_METADATA, 1));
|
||||
CHECK(nwfs_xattr_name_visible(zNW_QUOTA, 0));
|
||||
|
||||
CHECK(nwfs_quota_backend_from_string(NULL) == 0);
|
||||
CHECK(nwfs_quota_backend_from_string(NWFS_QUOTA_BACKEND_LINUXQUOTA) == 0);
|
||||
CHECK(nwfs_quota_backend_from_string(NWFS_QUOTA_BACKEND_METADATAONLY) == 1);
|
||||
CHECK(nwfs_quota_backend_from_string(NWFS_QUOTA_BACKEND_NSS) == 2);
|
||||
CHECK(nwfs_quota_backend_name(1) != NULL);
|
||||
CHECK(nwfs_quota_backend_from_string(NULL) == NWFS_QUOTA_BACKEND_ID_AUTO);
|
||||
CHECK(nwfs_quota_backend_from_string(NWFS_QUOTA_BACKEND_AUTO) == NWFS_QUOTA_BACKEND_ID_AUTO);
|
||||
CHECK(nwfs_quota_backend_from_string(NWFS_QUOTA_BACKEND_LINUXQUOTA) == NWFS_QUOTA_BACKEND_ID_LINUXQUOTA);
|
||||
CHECK(nwfs_quota_backend_from_string(NWFS_QUOTA_BACKEND_METADATAONLY) == NWFS_QUOTA_BACKEND_ID_METADATAONLY);
|
||||
CHECK(nwfs_quota_backend_from_string(NWFS_QUOTA_BACKEND_NSS) == NWFS_QUOTA_BACKEND_ID_NSS);
|
||||
CHECK(nwfs_quota_backend_from_string(NWFS_QUOTA_BACKEND_NWQUOTA) == NWFS_QUOTA_BACKEND_ID_NWQUOTA);
|
||||
CHECK(nwfs_quota_backend_name(NWFS_QUOTA_BACKEND_ID_NWQUOTA) != NULL);
|
||||
CHECK(nwfs_quota_backend_from_string("bogus") == NWFS_ERR_INVAL);
|
||||
|
||||
nwfs_quota_init("a);
|
||||
|
||||
Reference in New Issue
Block a user