From 8c193654168181686e3b8f40ddb70f9fa7519db0 Mon Sep 17 00:00:00 2001 From: Sergey Cheremencev Date: Fri, 18 Sep 2020 16:24:10 +0300 Subject: [PATCH] LU-13971 quota: report Pool Quotas for a user Patch adds ability to show quota limits and usage from all pools per user. Since this patch long option --pool without argument results in printing Pool Quotas for all known pools: lfs quota -u quota_usr --pool /mnt/testfs Pools from lustre: Quotas for pool: qpool1 Disk quotas for usr quota_usr (uid 60000): Filesystem kbytes quota limit grace files quota limit grace /mnt/lustre 0 0 10240 - 0 0 0 - Quotas for pool: qpool2 Disk quotas for usr quota_usr (uid 60000): Filesystem kbytes quota limit grace files quota limit grace /mnt/lustre 0 0 20480 - 0 0 0 - To get information for specific pool you still need to set pool name after --pool: lfs quota -u quota_usr --pool flash /mnt/testfs Patch also adds sanity-quota_74 to check new feature. Test-Parameters: trivial testlist=sanity-quota HPE-bug-id: LUS-8720 Change-Id: Ib918eef84c2352946ce13342471f36e2b500df32 Signed-off-by: Sergey Cheremencev Reviewed-on: https://review.whamcloud.com/39975 Reviewed-by: Petros Koutoupis Tested-by: jenkins Reviewed-by: Wang Shilong Tested-by: Maloo Reviewed-by: Oleg Drokin --- lustre/include/lustre/lustreapi.h | 2 ++ lustre/tests/sanity-quota.sh | 55 +++++++++++++++++++++++++++++++++++ lustre/utils/lfs.c | 60 +++++++++++++++++++++++++++++++++------ lustre/utils/liblustreapi.c | 40 +++++++++++++++++++++++--- 4 files changed, 145 insertions(+), 12 deletions(-) diff --git a/lustre/include/lustre/lustreapi.h b/lustre/include/lustre/lustreapi.h index abd42bd..0e00c23 100644 --- a/lustre/include/lustre/lustreapi.h +++ b/lustre/include/lustre/lustreapi.h @@ -166,6 +166,8 @@ int llapi_file_open_pool(const char *name, int flags, int mode, unsigned long long stripe_size, int stripe_offset, int stripe_count, int stripe_pattern, char *pool_name); int llapi_poollist(const char *name); +int llapi_get_poolbuf(const char *name, char **buf, + char ***poolist, int *poolcount); int llapi_get_poollist(const char *name, char **poollist, int list_size, char *buffer, int buffer_size); int llapi_get_poolmembers(const char *poolname, char **members, int list_size, diff --git a/lustre/tests/sanity-quota.sh b/lustre/tests/sanity-quota.sh index 89552fd..3d24f75 100755 --- a/lustre/tests/sanity-quota.sh +++ b/lustre/tests/sanity-quota.sh @@ -4862,6 +4862,61 @@ test_73() } run_test 73 "default limits at OST Pool Quotas" +test_74() +{ + local global_limit=200 # 200M + local limit=10 # 10M + local limit2=50 # 50M + local qpool="qpool1" + local qpool2="qpool2" + local tmp=0 + + mds_supports_qp + setup_quota_test || error "setup quota failed with $?" + stack_trap cleanup_quota_test EXIT + + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" + + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || + error "set user quota failed" + + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 1 || + error "pool_add_targets failed" + + $LFS setquota -u $TSTUSR -B ${limit}M --pool $qpool $DIR || + error "set user quota failed" + + pool_add $qpool2 || error "pool_add failed" + pool_add_targets $qpool2 1 1 || + error "pool_add_targets failed" + + $LFS setquota -u $TSTUSR -B ${limit2}M --pool $qpool2 $DIR || + error "set user quota failed" + + tmp=$(getquota -u $TSTUSR global bhardlimit) + [ $tmp -eq $((global_limit * 1024)) ] || + error "wrong global limit $global_limit" + + tmp=$(getquota -u $TSTUSR global bhardlimit $qpool) + [ $tmp -eq $((limit * 1024)) ] || error "wrong limit $tmp for $qpool" + + tmp=$(getquota -u $TSTUSR global bhardlimit $qpool2) + [ $tmp -eq $((limit2 * 1024)) ] || error "wrong limit $tmp for $qpool2" + + # check limits in pools + tmp=$($LFS quota -u $TSTUSR --pool $DIR | \ + grep -A4 $qpool | awk 'NR == 4{print $4}') + echo "pool limit for $qpool $tmp" + [ $tmp -eq $((limit * 1024)) ] || error "wrong limit:tmp for $qpool" + tmp=$($LFS quota -u $TSTUSR --pool $DIR | \ + grep -A4 $qpool2 | awk 'NR == 4{print $4}') + echo "pool limit for $qpool2 $tmp" + [ $tmp -eq $((limit2 * 1024)) ] || error "wrong limit:$tmp for $qpool2" +} +run_test 74 "check quota pools per user" + quota_fini() { do_nodes $(comma_list $(nodes_list)) \ diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index 3216a09..b32c6d1 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -8449,9 +8449,13 @@ static int lfs_quota(int argc, char **argv) bool human_readable = false; bool show_default = false; int qtype; + bool show_pools = false; struct option long_opts[] = { - { .val = LFS_POOL_OPT, .name = "pool", .has_arg = required_argument }, + { .val = LFS_POOL_OPT, .name = "pool", .has_arg = optional_argument }, { .name = NULL } }; + char **poollist = NULL; + char *buf = NULL; + int poolcount, i; qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1); if (!qctl) @@ -8527,14 +8531,26 @@ quota_type: human_readable = true; break; case LFS_POOL_OPT: - if (lfs_verify_poolarg(optarg)) { - rc = -1; - goto out; + if ((!optarg) && (argv[optind] != NULL) && + (argv[optind][0] != '-') && + (argv[optind][0] != '/')) { + optarg = argv[optind++]; + if (lfs_verify_poolarg(optarg)) { + rc = -EINVAL; + goto out; + } + strncpy(qctl->qc_poolname, optarg, + LOV_MAXPOOLNAME); + if (qctl->qc_cmd == LUSTRE_Q_GETINFO) + qctl->qc_cmd = LUSTRE_Q_GETINFOPOOL; + else + qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL; + break; } - strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME); - qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_GETINFO ? - LUSTRE_Q_GETINFOPOOL : - LUSTRE_Q_GETQUOTAPOOL; + + /* optarg is NULL */ + show_pools = true; + qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL; break; default: fprintf(stderr, "%s quota: unrecognized option '%s'\n", @@ -8626,9 +8642,37 @@ quota_type: } mnt = argv[optind]; + if (show_pools) { + char *p; + + i = 0; + rc = llapi_get_poolbuf(mnt, &buf, &poollist, &poolcount); + if (rc) + goto out; + + for (i = 0; i < poolcount; i++) { + p = memchr(poollist[i], '.', MAXNAMLEN); + if (!p) { + fprintf(stderr, "bad string format %.*s\n", + MAXNAMLEN, poollist[i]); + rc = -EINVAL; + goto out; + } + p++; + printf("Quotas for pool: %s\n", p); + strncpy(qctl->qc_poolname, p, LOV_MAXPOOLNAME); + rc = get_print_quota(mnt, name, qctl, verbose, quiet, + human_readable, show_default); + if (rc) + break; + } + goto out; + } + rc = get_print_quota(mnt, name, qctl, verbose, quiet, human_readable, show_default); out: + free(buf); free(qctl); return rc; } diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index 52a9b1c..80ca61e 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -1699,6 +1699,34 @@ free_path: /* wrapper for lfs.c and obd.c */ int llapi_poollist(const char *name) { + int poolcount, rc, i; + char *buf, **pools; + + rc = llapi_get_poolbuf(name, &buf, &pools, &poolcount); + if (rc) + return rc; + + for (i = 0; i < poolcount; i++) + llapi_printf(LLAPI_MSG_NORMAL, "%s\n", pools[i]); + free(buf); + + return 0; +} + +/** + * Get buffer that holds uuids and the list of pools in a filesystem. + * + * \param name filesystem name or path + * \param buf bufffer that has to be freed if function returns 0 + * \param pools pointer to the list of pools in buffer + * \param poolcount number of pools + * + * \return 0 when found at least 1 pool, i.e. poolcount > 0 + * \retval -error failure + */ +int llapi_get_poolbuf(const char *name, char **buf, + char ***pools, int *poolcount) +{ /* * list of pool names (assume that pool count is smaller * than OST count) @@ -1706,7 +1734,7 @@ int llapi_poollist(const char *name) char **list, *buffer = NULL, *fsname = (char *)name; char *poolname = NULL, *tmp = NULL, data[16]; enum param_filter type = FILTER_BY_PATH; - int obdcount, bufsize, rc, nb, i; + int obdcount, bufsize, rc, nb; if (name == NULL) return -EINVAL; @@ -1758,11 +1786,15 @@ retry_get_pools: goto retry_get_pools; } - for (i = 0; i < nb; i++) - llapi_printf(LLAPI_MSG_NORMAL, "%s\n", list[i]); rc = (nb < 0 ? nb : 0); + if (!rc) { + *buf = buffer; + *pools = list; + *poolcount = nb; + } err: - if (buffer) + /* Don't free buffer, it will be used later */ + if (rc && buffer) free(buffer); if (fsname != NULL && type == FILTER_BY_FS_NAME) free(fsname); -- 1.8.3.1