static const char si_units[] = "?kMGTPEZY";
-static int __bch2_strtoh(const char *cp, u64 *res,
- u64 t_max, bool t_signed)
+/* string_get_size units: */
+static const char *const units_2[] = {
+ "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"
+};
+static const char *const units_10[] = {
+ "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"
+};
+
+static int parse_u64(const char *cp, u64 *res)
{
- bool positive = *cp != '-';
- unsigned u;
+ const char *start = cp;
u64 v = 0;
- if (*cp == '+' || *cp == '-')
- cp++;
-
if (!isdigit(*cp))
return -EINVAL;
cp++;
} while (isdigit(*cp));
+ *res = v;
+ return cp - start;
+}
+
+static int bch2_pow(u64 n, u64 p, u64 *res)
+{
+ *res = 1;
+
+ while (p--) {
+ if (*res > div_u64(U64_MAX, n))
+ return -ERANGE;
+ *res *= n;
+ }
+ return 0;
+}
+
+static int parse_unit_suffix(const char *cp, u64 *res)
+{
+ const char *start = cp;
+ u64 base = 1024;
+ unsigned u;
+ int ret;
+
+ if (*cp == ' ')
+ cp++;
+
for (u = 1; u < strlen(si_units); u++)
if (*cp == si_units[u]) {
cp++;
goto got_unit;
}
- u = 0;
+
+ for (u = 0; u < ARRAY_SIZE(units_2); u++)
+ if (!strncmp(cp, units_2[u], strlen(units_2[u]))) {
+ cp += strlen(units_2[u]);
+ goto got_unit;
+ }
+
+ for (u = 0; u < ARRAY_SIZE(units_10); u++)
+ if (!strncmp(cp, units_10[u], strlen(units_10[u]))) {
+ cp += strlen(units_10[u]);
+ base = 1000;
+ goto got_unit;
+ }
+
+ *res = 1;
+ return 0;
got_unit:
- if (*cp == '\n')
+ ret = bch2_pow(base, u, res);
+ if (ret)
+ return ret;
+
+ return cp - start;
+}
+
+#define parse_or_ret(cp, _f) \
+do { \
+ int ret = _f; \
+ if (ret < 0) \
+ return ret; \
+ cp += ret; \
+} while (0)
+
+static int __bch2_strtou64_h(const char *cp, u64 *res)
+{
+ const char *start = cp;
+ u64 v = 0, b, f_n = 0, f_d = 1;
+ int ret;
+
+ parse_or_ret(cp, parse_u64(cp, &v));
+
+ if (*cp == '.') {
cp++;
- if (*cp)
- return -EINVAL;
+ ret = parse_u64(cp, &f_n);
+ if (ret < 0)
+ return ret;
+ cp += ret;
+
+ ret = bch2_pow(10, ret, &f_d);
+ if (ret)
+ return ret;
+ }
+
+ parse_or_ret(cp, parse_unit_suffix(cp, &b));
+
+ if (v > div_u64(U64_MAX, b))
+ return -ERANGE;
+ v *= b;
- if (fls64(v) + u * 10 > 64)
+ if (f_n > div_u64(U64_MAX, b))
return -ERANGE;
- v <<= u * 10;
+ f_n = div_u64(f_n * b, f_d);
+ if (v + f_n < v)
+ return -ERANGE;
+ v += f_n;
+
+ *res = v;
+ return cp - start;
+}
+
+static int __bch2_strtoh(const char *cp, u64 *res,
+ u64 t_max, bool t_signed)
+{
+ bool positive = *cp != '-';
+ u64 v = 0;
+
+ if (*cp == '+' || *cp == '-')
+ cp++;
+
+ parse_or_ret(cp, __bch2_strtou64_h(cp, &v));
+
+ if (*cp == '\n')
+ cp++;
+ if (*cp)
+ return -EINVAL;
if (positive) {
if (v > t_max)
#define STRTO_H(name, type) \
int bch2_ ## name ## _h(const char *cp, type *res) \
{ \
- u64 v; \
+ u64 v = 0; \
int ret = __bch2_strtoh(cp, &v, ANYSINT_MAX(type), \
ANYSINT_MAX(type) != ((type) ~0ULL)); \
*res = v; \
STRTO_H(strtoull, unsigned long long)
STRTO_H(strtou64, u64)
-void bch2_hprint(struct printbuf *buf, s64 v)
-{
- int u, t = 0;
-
- for (u = 0; v >= 1024 || v <= -1024; u++) {
- t = v & ~(~0U << 10);
- v >>= 10;
- }
-
- pr_buf(buf, "%lli", v);
-
- /*
- * 103 is magic: t is in the range [-1023, 1023] and we want
- * to turn it into [-9, 9]
- */
- if (u && v < 100 && v > -100)
- pr_buf(buf, ".%i", t / 103);
- if (u)
- pr_buf(buf, "%c", si_units[u]);
-}
-
-void bch2_string_opt_to_text(struct printbuf *out,
- const char * const list[],
- size_t selected)
-{
- size_t i;
-
- for (i = 0; list[i]; i++)
- pr_buf(out, i == selected ? "[%s] " : "%s ", list[i]);
-}
-
-void bch2_flags_to_text(struct printbuf *out,
- const char * const list[], u64 flags)
-{
- unsigned bit, nr = 0;
- bool first = true;
-
- if (out->pos != out->end)
- *out->pos = '\0';
-
- while (list[nr])
- nr++;
-
- while (flags && (bit = __ffs(flags)) < nr) {
- if (!first)
- pr_buf(out, ",");
- first = false;
- pr_buf(out, "%s", list[bit]);
- flags ^= 1 << bit;
- }
-}
-
u64 bch2_read_flag_list(char *opt, const char * const list[])
{
u64 ret = 0;
- char *p, *s, *d = kstrndup(opt, PAGE_SIZE - 1, GFP_KERNEL);
+ char *p, *s, *d = kstrdup(opt, GFP_KERNEL);
if (!d)
return -ENOMEM;
{
const struct time_unit *u = pick_time_units(ns);
- pr_buf(out, "%llu %s", div_u64(ns, u->nsecs), u->name);
+ prt_printf(out, "%llu %s", div_u64(ns, u->nsecs), u->name);
}
void bch2_time_stats_to_text(struct printbuf *out, struct time_stats *stats)
u64 q, last_q = 0;
int i;
- pr_buf(out, "count:\t\t%llu\n",
+ prt_printf(out, "count:\t\t%llu\n",
stats->count);
- pr_buf(out, "rate:\t\t%llu/sec\n",
+ prt_printf(out, "rate:\t\t%llu/sec\n",
freq ? div64_u64(NSEC_PER_SEC, freq) : 0);
- pr_buf(out, "frequency:\t");
+ prt_printf(out, "frequency:\t");
pr_time_units(out, freq);
- pr_buf(out, "\navg duration:\t");
+ prt_printf(out, "\navg duration:\t");
pr_time_units(out, stats->average_duration);
- pr_buf(out, "\nmax duration:\t");
+ prt_printf(out, "\nmax duration:\t");
pr_time_units(out, stats->max_duration);
i = eytzinger0_first(NR_QUANTILES);
u = pick_time_units(stats->quantiles.entries[i].m);
- pr_buf(out, "\nquantiles (%s):\t", u->name);
+ prt_printf(out, "\nquantiles (%s):\t", u->name);
eytzinger0_for_each(i, NR_QUANTILES) {
bool is_last = eytzinger0_next(i, NR_QUANTILES) == -1;
q = max(stats->quantiles.entries[i].m, last_q);
- pr_buf(out, "%llu%s",
+ prt_printf(out, "%llu%s",
div_u64(q, u->nsecs),
is_last ? "\n" : " ");
last_q = q;
pd->backpressure = 1;
}
-size_t bch2_pd_controller_print_debug(struct bch_pd_controller *pd, char *buf)
+void bch2_pd_controller_debug_to_text(struct printbuf *out, struct bch_pd_controller *pd)
{
- /* 2^64 - 1 is 20 digits, plus null byte */
- char rate[21];
- char actual[21];
- char target[21];
- char proportional[21];
- char derivative[21];
- char change[21];
- s64 next_io;
+ out->tabstops[0] = 20;
- bch2_hprint(&PBUF(rate), pd->rate.rate);
- bch2_hprint(&PBUF(actual), pd->last_actual);
- bch2_hprint(&PBUF(target), pd->last_target);
- bch2_hprint(&PBUF(proportional), pd->last_proportional);
- bch2_hprint(&PBUF(derivative), pd->last_derivative);
- bch2_hprint(&PBUF(change), pd->last_change);
+ prt_printf(out, "rate:");
+ prt_tab(out);
+ prt_human_readable_s64(out, pd->rate.rate);
+ prt_newline(out);
- next_io = div64_s64(pd->rate.next - local_clock(), NSEC_PER_MSEC);
+ prt_printf(out, "target:");
+ prt_tab(out);
+ prt_human_readable_u64(out, pd->last_target);
+ prt_newline(out);
- return sprintf(buf,
- "rate:\t\t%s/sec\n"
- "target:\t\t%s\n"
- "actual:\t\t%s\n"
- "proportional:\t%s\n"
- "derivative:\t%s\n"
- "change:\t\t%s/sec\n"
- "next io:\t%llims\n",
- rate, target, actual, proportional,
- derivative, change, next_io);
+ prt_printf(out, "actual:");
+ prt_tab(out);
+ prt_human_readable_u64(out, pd->last_actual);
+ prt_newline(out);
+
+ prt_printf(out, "proportional:");
+ prt_tab(out);
+ prt_human_readable_s64(out, pd->last_proportional);
+ prt_newline(out);
+
+ prt_printf(out, "derivative:");
+ prt_tab(out);
+ prt_human_readable_s64(out, pd->last_derivative);
+ prt_newline(out);
+
+ prt_printf(out, "change:");
+ prt_tab(out);
+ prt_human_readable_s64(out, pd->last_change);
+ prt_newline(out);
+
+ prt_printf(out, "next io:");
+ prt_tab(out);
+ prt_printf(out, "%llims", div64_s64(pd->rate.next - local_clock(), NSEC_PER_MSEC));
+ prt_newline(out);
}
/* misc: */
{
while (size) {
struct page *page = alloc_page(gfp_mask);
- unsigned len = min(PAGE_SIZE, size);
+ unsigned len = min_t(size_t, PAGE_SIZE, size);
if (!page)
return -ENOMEM;
- BUG_ON(!bio_add_page(bio, page, len, 0));
+ if (unlikely(!bio_add_page(bio, page, len, 0))) {
+ __free_page(page);
+ break;
+ }
+
size -= len;
}
}
}
-void bch_scnmemcpy(struct printbuf *out,
- const char *src, size_t len)
-{
- size_t n = printbuf_remaining(out);
-
- if (n) {
- n = min(n - 1, len);
- memcpy(out->pos, src, n);
- out->pos += n;
- *out->pos = '\0';
- }
-}
-
#include "eytzinger.h"
static int alignment_ok(const void *base, size_t align)
u64 *ret;
int cpu;
+ /* access to pcpu vars has to be blocked by other locking */
preempt_disable();
ret = this_cpu_ptr(p);
preempt_enable();