From 81e6b3685a1440a7662137f3abb8c86a42391189 Mon Sep 17 00:00:00 2001 From: Andres Beltran Date: Mon, 16 Jun 2025 23:39:25 +0000 Subject: [PATCH] quota-util: add methods to read and set project IDs --- src/shared/quota-util.c | 64 +++++++++++++++++++++++++++++++++++++++++ src/shared/quota-util.h | 3 ++ 2 files changed, 67 insertions(+) diff --git a/src/shared/quota-util.c b/src/shared/quota-util.c index a592b2fb001..06f27e85f25 100644 --- a/src/shared/quota-util.c +++ b/src/shared/quota-util.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "blockdev-util.h" +#include "chattr-util.h" #include "device-util.h" #include "errno-util.h" #include "missing_syscall.h" @@ -33,3 +34,66 @@ int quotactl_fd_with_fallback(int fd, int cmd, int id, void *addr) { return RET_NERRNO(quotactl(cmd, devnode, id, addr)); } + +int quota_query_proj_id(int fd, uint32_t proj_id, struct dqblk *ret_req) { + int r; + + assert(fd >= 0); + assert(ret_req); + + r = quotactl_fd_with_fallback(fd, QCMD_FIXED(Q_GETQUOTA, PRJQUOTA), proj_id, ret_req); + if (r == -ESRCH || ERRNO_IS_NEG_NOT_SUPPORTED(r) || ERRNO_IS_NEG_PRIVILEGE(r)) { + zero(ret_req); + return false; + } + if (r < 0) + return r; + + return true; +} + +int quota_proj_id_set_recursive(int fd, uint32_t proj_id, bool verify_exclusive) { + int r; + + assert(fd >= 0); + + /* Confirm only the current inode has the project id (in case of race conditions) */ + if (verify_exclusive) { + /* Set to top level first because of the case where directories already exist with multiple subdirectories, + * in which case, number of inodes will be > 1 if applied recursively only */ + r = set_proj_id(fd, proj_id); + if (r < 0) + return r; + + struct dqblk req; + r = quotactl_fd_with_fallback(fd, QCMD_FIXED(Q_GETQUOTA, PRJQUOTA), proj_id, &req); + if (r < 0) + return r; + + if (req.dqb_curinodes == 0) + return -ENOTRECOVERABLE; + + if (req.dqb_curinodes != 1) + return false; + } + + r = set_proj_id_recursive(fd, proj_id); + if (r < 0) + return r; + + return true; +} + +bool quota_dqblk_is_populated(const struct dqblk *req) { + assert(req); + + return FLAGS_SET(req->dqb_valid, QIF_BLIMITS|QIF_SPACE|QIF_ILIMITS|QIF_INODES|QIF_BTIME|QIF_ITIME) && + (req->dqb_bhardlimit > 0 || + req->dqb_bsoftlimit > 0 || + req->dqb_ihardlimit > 0 || + req->dqb_isoftlimit > 0 || + req->dqb_curspace > 0 || + req->dqb_curinodes > 0 || + req->dqb_btime > 0 || + req->dqb_itime > 0); +} diff --git a/src/shared/quota-util.h b/src/shared/quota-util.h index 5e878a5d398..ec4da0cbb89 100644 --- a/src/shared/quota-util.h +++ b/src/shared/quota-util.h @@ -16,3 +16,6 @@ static inline int QCMD_FIXED(uint32_t cmd, uint32_t type) { } int quotactl_fd_with_fallback(int fd, int cmd, int id, void *addr); +int quota_query_proj_id(int fd, uint32_t proj_id, struct dqblk *ret_req); +int quota_proj_id_set_recursive(int fd, uint32_t proj_id, bool verify_exclusive); +bool quota_dqblk_is_populated(const struct dqblk *dqblk); -- 2.47.3