From 1dbf71d8faaaf0c933f47c5d81871fe3f3fdcf43 Mon Sep 17 00:00:00 2001 From: Emoly Liu Date: Fri, 25 Dec 2015 15:28:01 +0800 Subject: [PATCH] LU-7506 lfs: "lfs quota -h" should support petabytes output This patch adds human-readable petabytes output and allows to set fraction block limit, e.g. 1.5P. Also, it adds sanity-quota.sh test_27d to verify these new functions, and replaces some sprintf() with snprintf() to meet the code style requirement. Signed-off-by: Emoly Liu Change-Id: I1dced352687e8e53988f85d2781396e647b62865 Reviewed-on: http://review.whamcloud.com/17441 Tested-by: Jenkins Reviewed-by: Bobi Jam Tested-by: Maloo Reviewed-by: Andreas Dilger --- lustre/tests/sanity-quota.sh | 16 +++++++ lustre/utils/lfs.c | 37 +++++++++------ lustre/utils/liblustreapi.c | 106 ++++++++++++++++++++++++------------------- 3 files changed, 98 insertions(+), 61 deletions(-) diff --git a/lustre/tests/sanity-quota.sh b/lustre/tests/sanity-quota.sh index 6d7220d..9d5e75d 100644 --- a/lustre/tests/sanity-quota.sh +++ b/lustre/tests/sanity-quota.sh @@ -2042,6 +2042,22 @@ test_27c() { } run_test 27c "lfs quota should support human-readable output" +test_27d() { + local softlimit=1.5 + local hardlimit=2.3 + local limit + + $LFS setquota -u $TSTID -b ${softlimit}p -B ${hardlimit}P $DIR || + error "set fraction block limit failed" + limit=$($LFS quota -u $TSTID -h $DIR | grep $DIR | awk '{print $3}') + [ $limit == ${softlimit}P ] || error "get fraction softlimit failed" + limit=$($LFS quota -u $TSTID -h $DIR | grep $DIR | awk '{print $4}') + [ $limit == ${hardlimit}P ] || error "get fraction hardlimit failed" + + resetquota -u $TSTUSR +} +run_test 27d "lfs setquota should support fraction block limit" + test_30() { local LIMIT=4 # 4MB local TESTFILE="$DIR/$tdir/$tfile" diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index 71952b6..b08bbea 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -2917,22 +2917,29 @@ static void print_quota_title(char *name, struct if_quotactl *qctl, "files", "quota", "limit", "grace"); } -static void kbytes2str(__u64 num, char *buf, bool h) +static void kbytes2str(__u64 num, char *buf, int buflen, bool h) { if (!h) { - sprintf(buf, LPU64, num); + snprintf(buf, buflen, LPU64, num); } else { - if (num >> 30) - sprintf(buf, "%5.4gT", (double)num / (1 << 30)); + if (num >> 40) + snprintf(buf, buflen, "%5.4gP", + (double)num / ((__u64)1 << 40)); + else if (num >> 30) + snprintf(buf, buflen, "%5.4gT", + (double)num / (1 << 30)); else if (num >> 20) - sprintf(buf, "%5.4gG", (double)num / (1 << 20)); + snprintf(buf, buflen, "%5.4gG", + (double)num / (1 << 20)); else if (num >> 10) - sprintf(buf, "%5.4gM", (double)num / (1 << 10)); + snprintf(buf, buflen, "%5.4gM", + (double)num / (1 << 10)); else - sprintf(buf, LPU64"%s", num, "k"); + snprintf(buf, buflen, LPU64"%s", num, "k"); } } +#define STRBUF_LEN 32 static void print_quota(char *mnt, struct if_quotactl *qctl, int type, int rc, bool h) { @@ -2943,9 +2950,9 @@ static void print_quota(char *mnt, struct if_quotactl *qctl, int type, if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) { int bover = 0, iover = 0; struct obd_dqblk *dqb = &qctl->qc_dqblk; - char numbuf[3][32]; + char numbuf[3][STRBUF_LEN]; char timebuf[40]; - char strbuf[32]; + char strbuf[STRBUF_LEN]; if (dqb->dqb_bhardlimit && lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) { @@ -2978,21 +2985,22 @@ static void print_quota(char *mnt, struct if_quotactl *qctl, int type, if (bover) diff2str(dqb->dqb_btime, timebuf, now); - kbytes2str(lustre_stoqb(dqb->dqb_curspace), strbuf, h); + kbytes2str(lustre_stoqb(dqb->dqb_curspace), + strbuf, sizeof(strbuf), h); if (rc == -EREMOTEIO) sprintf(numbuf[0], "%s*", strbuf); else sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ? "%s" : "[%s]", strbuf); - kbytes2str(dqb->dqb_bsoftlimit, strbuf, h); + kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h); if (type == QC_GENERAL) sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ? "%s" : "[%s]", strbuf); else sprintf(numbuf[1], "%s", "-"); - kbytes2str(dqb->dqb_bhardlimit, strbuf, h); + kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h); sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ? "%s" : "[%s]", strbuf); @@ -3217,13 +3225,14 @@ ug_output: if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO && verbose) { - char strbuf[32]; + char strbuf[STRBUF_LEN]; rc2 = print_obd_quota(mnt, &qctl, 1, human_readable, &total_ialloc); rc3 = print_obd_quota(mnt, &qctl, 0, human_readable, &total_balloc); - kbytes2str(total_balloc, strbuf, human_readable); + kbytes2str(total_balloc, strbuf, sizeof(strbuf), + human_readable); printf("Total allocated inode limit: "LPU64", total " "allocated block limit: %s\n", total_ialloc, strbuf); } diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index fdf0529..094996a 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -187,55 +187,67 @@ llapi_log_callback_t llapi_info_callback_set(llapi_log_callback_t cb) int llapi_parse_size(const char *optarg, unsigned long long *size, unsigned long long *size_units, int bytes_spec) { - char *end; + char *end; + char *argbuf = (char *)optarg; + unsigned long long frac = 0, frac_d = 1; - if (strncmp(optarg, "-", 1) == 0) - return -1; + if (strncmp(optarg, "-", 1) == 0) + return -1; - if (*size_units == 0) - *size_units = 1; - - *size = strtoull(optarg, &end, 0); - - if (*end != '\0') { - if ((*end == 'b') && *(end + 1) == '\0' && - (*size & (~0ULL << (64 - 9))) == 0 && - !bytes_spec) { - *size_units = 1 << 9; - } else if ((*end == 'b') && - *(end + 1) == '\0' && - bytes_spec) { - *size_units = 1; - } else if ((*end == 'k' || *end == 'K') && - *(end + 1) == '\0' && - (*size & (~0ULL << (64 - 10))) == 0) { - *size_units = 1 << 10; - } else if ((*end == 'm' || *end == 'M') && - *(end + 1) == '\0' && - (*size & (~0ULL << (64 - 20))) == 0) { - *size_units = 1 << 20; - } else if ((*end == 'g' || *end == 'G') && - *(end + 1) == '\0' && - (*size & (~0ULL << (64 - 30))) == 0) { - *size_units = 1 << 30; - } else if ((*end == 't' || *end == 'T') && - *(end + 1) == '\0' && - (*size & (~0ULL << (64 - 40))) == 0) { - *size_units = 1ULL << 40; - } else if ((*end == 'p' || *end == 'P') && - *(end + 1) == '\0' && - (*size & (~0ULL << (64 - 50))) == 0) { - *size_units = 1ULL << 50; - } else if ((*end == 'e' || *end == 'E') && - *(end + 1) == '\0' && - (*size & (~0ULL << (64 - 60))) == 0) { - *size_units = 1ULL << 60; - } else { - return -1; - } - } - *size *= *size_units; - return 0; + if (*size_units == 0) + *size_units = 1; + + *size = strtoull(argbuf, &end, 0); + if (end != NULL && *end == '.') { + int i; + + argbuf = end + 1; + frac = strtoull(argbuf, &end, 10); + /* count decimal places */ + for (i = 0; i < (end - argbuf); i++) + frac_d *= 10; + } + + if (*end != '\0') { + if ((*end == 'b') && *(end + 1) == '\0' && + (*size & (~0ULL << (64 - 9))) == 0 && + !bytes_spec) { + *size_units = 1 << 9; + } else if ((*end == 'b') && + *(end + 1) == '\0' && + bytes_spec) { + *size_units = 1; + } else if ((*end == 'k' || *end == 'K') && + *(end + 1) == '\0' && + (*size & (~0ULL << (64 - 10))) == 0) { + *size_units = 1 << 10; + } else if ((*end == 'm' || *end == 'M') && + *(end + 1) == '\0' && + (*size & (~0ULL << (64 - 20))) == 0) { + *size_units = 1 << 20; + } else if ((*end == 'g' || *end == 'G') && + *(end + 1) == '\0' && + (*size & (~0ULL << (64 - 30))) == 0) { + *size_units = 1 << 30; + } else if ((*end == 't' || *end == 'T') && + *(end + 1) == '\0' && + (*size & (~0ULL << (64 - 40))) == 0) { + *size_units = 1ULL << 40; + } else if ((*end == 'p' || *end == 'P') && + *(end + 1) == '\0' && + (*size & (~0ULL << (64 - 50))) == 0) { + *size_units = 1ULL << 50; + } else if ((*end == 'e' || *end == 'E') && + *(end + 1) == '\0' && + (*size & (~0ULL << (64 - 60))) == 0) { + *size_units = 1ULL << 60; + } else { + return -1; + } + } + *size = *size * *size_units + frac * *size_units / frac_d; + + return 0; } /* XXX: llapi_xxx() functions return negative values upon failure */ -- 1.8.3.1