From ffbf806d5ccd6af99ef14ac970b5dc973c50432b Mon Sep 17 00:00:00 2001
From: Kent Overstreet <kent.overstreet@gmail.com>
Date: Sat, 11 Jun 2022 18:13:40 -0400
Subject: [PATCH] Update bcachefs sources to 3704d0779c bcachefs: Improved
 human readable integer parsing

---
 .bcachefs_revision             |   2 +-
 include/linux/printbuf.h       |   2 +
 libbcachefs/alloc_background.c |  19 ++++-
 libbcachefs/util.c             | 132 +++++++++++++++++++++++++++++----
 libbcachefs/util.h             |   2 +-
 5 files changed, 137 insertions(+), 20 deletions(-)

diff --git a/.bcachefs_revision b/.bcachefs_revision
index 5b9e7323..8e176a6f 100644
--- a/.bcachefs_revision
+++ b/.bcachefs_revision
@@ -1 +1 @@
-24f7e08cd8a8b62fc467f1b359bd934ad943f0b7
+3704d0779c7885dd74ab345aa7017a4430231e1a
diff --git a/include/linux/printbuf.h b/include/linux/printbuf.h
index c898faac..fa8e73d5 100644
--- a/include/linux/printbuf.h
+++ b/include/linux/printbuf.h
@@ -225,6 +225,8 @@ static inline void printbuf_reset(struct printbuf *buf)
 {
 	buf->pos		= 0;
 	buf->allocation_failure	= 0;
+	buf->indent		= 0;
+	buf->tabstop		= 0;
 }
 
 /**
diff --git a/libbcachefs/alloc_background.c b/libbcachefs/alloc_background.c
index d114ba09..86df10e6 100644
--- a/libbcachefs/alloc_background.c
+++ b/libbcachefs/alloc_background.c
@@ -1190,12 +1190,26 @@ void bch2_do_invalidates(struct bch_fs *c)
 		queue_work(system_long_wq, &c->invalidate_work);
 }
 
+static int bucket_freespace_init(struct btree_trans *trans, struct btree_iter *iter)
+{
+	struct bch_alloc_v4 a;
+	struct bkey_s_c k;
+	int ret;
+
+	k = bch2_btree_iter_peek_slot(iter);
+	ret = bkey_err(k);
+	if (ret)
+		return ret;
+
+	bch2_alloc_to_v4(k, &a);
+	return bch2_bucket_do_index(trans, k, &a, true);
+}
+
 static int bch2_dev_freespace_init(struct bch_fs *c, struct bch_dev *ca)
 {
 	struct btree_trans trans;
 	struct btree_iter iter;
 	struct bkey_s_c k;
-	struct bch_alloc_v4 a;
 	struct bch_member *m;
 	int ret;
 
@@ -1208,10 +1222,9 @@ static int bch2_dev_freespace_init(struct bch_fs *c, struct bch_dev *ca)
 		if (iter.pos.offset >= ca->mi.nbuckets)
 			break;
 
-		bch2_alloc_to_v4(k, &a);
 		ret = __bch2_trans_do(&trans, NULL, NULL,
 				      BTREE_INSERT_LAZY_RW,
-				 bch2_bucket_do_index(&trans, k, &a, true));
+				 bucket_freespace_init(&trans, &iter));
 		if (ret)
 			break;
 	}
diff --git a/libbcachefs/util.c b/libbcachefs/util.c
index 37ef7094..85b8f3df 100644
--- a/libbcachefs/util.c
+++ b/libbcachefs/util.c
@@ -27,15 +27,18 @@
 
 static const char si_units[] = "?kMGTPEZY";
 
-static int __bch2_strtoh(const char *cp, u64 *res,
-			 u64 t_max, bool t_signed)
-{
-	bool positive = *cp != '-';
-	unsigned u;
-	u64 v = 0;
+/* 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"
+};
 
-	if (*cp == '+' || *cp == '-')
-		cp++;
+static int parse_u64(const char *cp, u64 *res)
+{
+	const char *start = cp;
+	u64 v = 0;
 
 	if (!isdigit(*cp))
 		return -EINVAL;
@@ -50,23 +53,122 @@ static int __bch2_strtoh(const char *cp, u64 *res,
 		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:
+	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++;
+		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 (f_n > div_u64(U64_MAX, b))
+		return -ERANGE;
+
+	if (v + (f_n * b) / f_d < v)
+		return -ERANGE;
+	v += (f_n * b) / f_d;
+
+	*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 (fls64(v) + u * 10 > 64)
-		return -ERANGE;
-
-	v <<= u * 10;
-
 	if (positive) {
 		if (v > t_max)
 			return -ERANGE;
@@ -86,7 +188,7 @@ got_unit:
 #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;						\
diff --git a/libbcachefs/util.h b/libbcachefs/util.h
index bbef4745..1fe66fd9 100644
--- a/libbcachefs/util.h
+++ b/libbcachefs/util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 u*/
+/* SPDX-License-Identifier: GPL-2.0 */
 #ifndef _BCACHEFS_UTIL_H
 #define _BCACHEFS_UTIL_H