.B lfs setquota [-u|-g] <name> <block-softlimit> <block-hardlimit>
\fB<inode-softlimit> <inode-hardlimit> <filesystem>\fR
.br
+.B lfs setquota -t [-u|-g] <block-grace> <inode-grace> <filesystem>
+.br
.B lfs quota [-o obd_uuid] [-u|-g] <name> <filesystem>
.br
+.B lfs quota -t [-u|-g] <filesystem>
+.br
.B lfs check <mds| osts| servers>
.br
.B lfs df [-i] [-h] [path]
.B setquota [-u|-g] <name> <block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit> <filesystem>
To set filesystem quotas for users or groups. Limits are specific as blocks and inodes, see EXAMPLES
.TP
+.B setquota -t [-u|-g] <block-grace> <inode-grace> <filesystem>
+To set filesystem quota grace times for users or groups. Grace time is specified in "XXwXXdXXhXXmXXs" format or as an integer seconds value, see EXAMPLES
+.TP
.B quota [-o obd_uuid] [-u|-g] <name> <filesystem>
To display disk usage and limits, either for the full filesystem, or for objects on a specific obd. A user or group name must be specified.
.TP
+.B quota -t [-u|-g] <filesystem>
+To display block and inode grace times for user (-u) or group (-g) quotas
+.TP
.B check
Display the status of MDS or OSTs (as specified in the command) or all the servers (MDS and OSTs)
.TP
.B $ lfs setquota -u bob 0 1000000 0 10000 /mnt/lustre
Set quotas of user `bob': 1GB block quota and 10,000 file quota
.TP
+.B $ lfs setquota -t -u 1000 1w4d /mnt/lustre
+Set grace times for user quotas: 1000 seconds for block quotas, 1 week and 4 days for inode quotas
+.TP
.B $ lfs quota -u bob /mnt/lustre
List quotas of user `bob'
.TP
+.B $ lfs quota -t -u /mnt/lustre
+Show grace times for user quotas on /mnt/lustre
+.TP
.B $ lfs check servers
Check the status of all servers (MDT, OST)
.TP
test_file_soft $TESTFILE $LIMIT $GRACE
$LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
-
+
# cleanup
$LFS setquota -t -u $MAX_DQ_TIME $MAX_IQ_TIME $MOUNT
$LFS setquota -t -g $MAX_DQ_TIME $MAX_IQ_TIME $MOUNT
}
run_test 4 "File soft limit (start timer, timer goes off, stop timer) ==="
+test_4a() {
+ GR_STR1="1w3d"
+ GR_STR2="1000s"
+ GR_STR3="5s"
+ GR_STR4="1w2d3h4m5s"
+ GR_STR5="5c"
+ GR_STR6="1111111111111111"
+
+ # test of valid grace strings handling
+ echo " Valid grace strings test"
+ $LFS setquota -t -u $GR_STR1 $GR_STR2 $MOUNT
+ $LFS quota -u -t $MOUNT | grep "Block grace time: $GR_STR1"
+ $LFS setquota -t -g $GR_STR3 $GR_STR4 $MOUNT
+ $LFS quota -g -t $MOUNT | grep "Inode grace time: $GR_STR4"
+
+ # test of invalid grace strings handling
+ echo " Invalid grace strings test"
+ ! $LFS setquota -t -u $GR_STR4 $GR_STR5 $MOUNT
+ ! $LFS setquota -t -g $GR_STR4 $GR_STR6 $MOUNT
+
+ # cleanup
+ $LFS setquota -t -u $MAX_DQ_TIME $MAX_IQ_TIME $MOUNT
+ $LFS setquota -t -g $MAX_DQ_TIME $MAX_IQ_TIME $MOUNT
+}
+run_test 4a "Grace time strings handling ==="
+
# chown & chgrp (chown & chgrp successfully even out of block/file quota)
test_5() {
BLIMIT=$(( $BUNIT_SZ * $((OSTCOUNT + 1)) * 10)) # 10 bunits on each server
dd if=/dev/zero of=$TSTDIR/quota_tst50_1 bs=$BLK_SZ count=$((BLIMIT+1)) || error "write failure, expect success"
echo " Chown files to $TSTUSR.$TSTUSR ..."
- for i in `seq 0 ILIMIT`; do
+ for i in `seq 0 $ILIMIT`; do
chown $TSTUSR.$TSTUSR $TSTDIR/quota_tst50_$i || \
error "chown failure, but expect success"
done
} \
} while (0)
+#define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
+
+/* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
+ * returns the value or ULONG_MAX on integer overflow or incorrect format
+ * Notes:
+ * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
+ * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
+ * 3. empty integer value is interpreted as 0
+ */
+
+static unsigned long str2sec(const char* timestr) {
+ const char spec[] = "smhdw";
+ const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
+ unsigned long val = 0;
+ char *tail;
+
+ if (strpbrk(timestr, spec) == NULL) {
+ /* no specifiers inside the time string,
+ should treat it as an integer value */
+ val = strtoul(timestr, &tail, 10);
+ return *tail ? ULONG_MAX : val;
+ }
+
+ /* format string is XXwXXdXXhXXmXXs */
+ while (*timestr) {
+ unsigned long v;
+ int ind;
+ char* ptr;
+
+ v = strtoul(timestr, &tail, 10);
+ if (v == ULONG_MAX || *tail == '\0')
+ /* value too large (ULONG_MAX or more)
+ or missing specifier */
+ goto error;
+
+ ptr = strchr(spec, *tail);
+ if (ptr == NULL)
+ /* unknown specifier */
+ goto error;
+
+ ind = ptr - spec;
+
+ /* check if product will overflow the type */
+ if (!(v < ULONG_MAX / mult[ind]))
+ goto error;
+
+ ADD_OVERFLOW(val, mult[ind] * v);
+ if (val == ULONG_MAX)
+ goto error;
+
+ timestr = tail + 1;
+ }
+
+ return val;
+
+error:
+ return ULONG_MAX;
+}
+
int lfs_setquota(int argc, char **argv)
{
int c;
if (optind + 3 != argc)
return CMD_HELP;
- ARG2INT(dqi->dqi_bgrace, argv[optind++], "block-grace");
- ARG2INT(dqi->dqi_igrace, argv[optind++], "inode-grace");
+ if ((dqi->dqi_bgrace = str2sec(argv[optind++])) == ULONG_MAX) {
+ fprintf(stderr, "error: bad %s: %s\n", "block-grace", argv[optind - 1]);
+ return CMD_HELP;
+ }
+ if ((dqi->dqi_igrace = str2sec(argv[optind++])) == ULONG_MAX) {
+ fprintf(stderr, "error: bad %s: %s\n", "inode-grace", argv[optind - 1]);
+ return CMD_HELP;
+ }
}
mnt = argv[optind];
}
-static void grace2str(time_t seconds,char *buf)
+/* Converts seconds value into format string
+ * result is returned in buf
+ * Notes:
+ * 1. result is in descenting order: 1w2d3h4m5s
+ * 2. zero fields are not filled (except for p. 3): 5d1s
+ * 3. zero seconds value is presented as "0s"
+ */
+static void sec2str(time_t seconds, char *buf)
{
- uint minutes, hours, days;
-
- minutes = (seconds + 30) / 60;
- hours = minutes / 60;
- minutes %= 60;
- days = hours / 24;
- hours %= 24;
- if (days >= 2)
- snprintf(buf, 40, "%ddays", days);
- else
- snprintf(buf, 40, "%02d:%02d", hours + days * 24, minutes);
+ const char spec[] = "smhdw";
+ const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
+ unsigned long c;
+ char* tail = buf;
+ int i;
+
+ for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
+ c = seconds / mult[i];
+
+ if (c > 0 || (i == 0 && buf == tail))
+ tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
+
+ seconds %= mult[i];
+ }
}
strcpy(buf, "none");
return;
}
- grace2str(seconds - now, buf);
+ sec2str(seconds - now, buf);
}
static void print_quota_title(char *name, struct if_quotactl *qctl)
char bgtimebuf[40];
char igtimebuf[40];
- grace2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf);
- grace2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf);
+ sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf);
+ sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf);
printf("Block grace time: %s; Inode grace time: %s\n",
bgtimebuf, igtimebuf);
}