Richard W.M. Jones
2023-Sep-03 15:23 UTC
[Libguestfs] [PATCH libnbd 0/5] copy: Allow human sizes for --queue-size, etc
See companion patch: Subject: [PATCH nbdkit] server: Move size parsing code (nbdkit_parse_size) to common/include This is the second part of the patch. It adds the new human_size_parse function to libnbd and then uses it for parsing --queue-size, --request-size and --sparse. The main complication here is that there was already a common/utils/human-size.h header which ends up (eventually) being combined with the new header, but the process to get there and ensure that git bisection works is lengthy. Eventually we can copy the new, combined "human-size.h" back to nbdkit, but I didn't add that yet. Rich.
Richard W.M. Jones
2023-Sep-03 15:23 UTC
[Libguestfs] [PATCH libnbd 1/5] copy, info: Include common/utils/human-size.h
The next commit will add a new "human-size.h" header copied in from nbdkit. This breaks existing code that uses common/utils/human-size.h (which we will combine later). As a temporary hack to maintain bisection, make sure we are using the deprecated "human-size.h" header. This hack will be removed later. --- copy/main.c | 2 +- info/show.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/copy/main.c b/copy/main.c index 6928a4acde..d2f415dc47 100644 --- a/copy/main.c +++ b/copy/main.c @@ -39,7 +39,7 @@ #include <libnbd.h> #include "ispowerof2.h" -#include "human-size.h" +#include "../utils/human-size.h" #include "minmax.h" #include "version.h" #include "nbdcopy.h" diff --git a/info/show.c b/info/show.c index 920bbb0a27..99b7b5b60a 100644 --- a/info/show.c +++ b/info/show.c @@ -29,7 +29,7 @@ #include <libnbd.h> #include "ansi-colours.h" -#include "human-size.h" +#include "../utils/human-size.h" #include "string-vector.h" #include "nbdinfo.h" -- 2.41.0
Richard W.M. Jones
2023-Sep-03 15:23 UTC
[Libguestfs] [PATCH libnbd 2/5] common/include: Import the human_size_parse (nbdkit_parse_size) function
This function is copied from nbdkit commit XXX [fill in after nbdkit change is upstream] XXX --- .gitignore | 1 + common/include/Makefile.am | 6 ++ common/include/human-size.h | 137 +++++++++++++++++++++++++++++++ common/include/test-human-size.c | 133 ++++++++++++++++++++++++++++++ 4 files changed, 277 insertions(+) diff --git a/.gitignore b/.gitignore index 866d745a46..bbe52c94dc 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ Makefile.in /common/include/test-ascii-ctype /common/include/test-byte-swapping /common/include/test-checked-overflow +/common/include/test-human-size /common/include/test-isaligned /common/include/test-ispowerof2 /common/include/test-iszero diff --git a/common/include/Makefile.am b/common/include/Makefile.am index 1acc9fa413..f32cdcf85a 100644 --- a/common/include/Makefile.am +++ b/common/include/Makefile.am @@ -24,6 +24,7 @@ EXTRA_DIST = \ byte-swapping.h \ checked-overflow.h \ compiler-macros.h \ + human-size.h \ isaligned.h \ ispowerof2.h \ iszero.h \ @@ -40,6 +41,7 @@ TESTS = \ test-ascii-ctype \ test-byte-swapping \ test-checked-overflow \ + test-human-size \ test-isaligned \ test-ispowerof2 \ test-iszero \ @@ -63,6 +65,10 @@ test_checked_overflow_SOURCES = test-checked-overflow.c checked-overflow.h test_checked_overflow_CPPFLAGS = -I$(srcdir) test_checked_overflow_CFLAGS = $(WARNINGS_CFLAGS) +test_human_size_SOURCES = test-human-size.c human-size.h +test_human_size_CPPFLAGS = -I$(srcdir) +test_human_size_CFLAGS = $(WARNINGS_CFLAGS) + test_isaligned_SOURCES = test-isaligned.c isaligned.h test_isaligned_CPPFLAGS = -I$(srcdir) test_isaligned_CFLAGS = $(WARNINGS_CFLAGS) diff --git a/common/include/human-size.h b/common/include/human-size.h new file mode 100644 index 0000000000..788dbd7ba5 --- /dev/null +++ b/common/include/human-size.h @@ -0,0 +1,137 @@ +/* nbdkit + * Copyright Red Hat + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Red Hat nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef NBDKIT_HUMAN_SIZE_H +#define NBDKIT_HUMAN_SIZE_H + +#include <stdint.h> +#include <inttypes.h> +#include <errno.h> + +/* Attempt to parse a string with a possible scaling suffix, such as + * "2M". Disk sizes cannot usefully exceed off_t (which is signed) + * and cannot be negative. + * + * On error, returns -1 and sets *error and *pstr. You can form a + * final error message by appending "<error>: <pstr>". + */ +static inline int64_t +human_size_parse (const char *str, + const char **error, const char **pstr) +{ + int64_t size; + char *end; + uint64_t scale = 1; + + /* XXX Should we also parse things like '1.5M'? */ + /* XXX Should we allow hex? If so, hex cannot use scaling suffixes, + * because some of them are valid hex digits. + */ + errno = 0; + size = strtoimax (str, &end, 10); + if (str == end) { + *error = "could not parse size string"; + *pstr = str; + return -1; + } + if (size < 0) { + *error = "size cannot be negative"; + *pstr = str; + return -1; + } + if (errno) { + *error = "size exceeds maximum value"; + *pstr = str; + return -1; + } + + switch (*end) { + /* No suffix */ + case '\0': + end--; /* Safe, since we already filtered out empty string */ + break; + + /* Powers of 1024 */ + case 'e': case 'E': + scale *= 1024; + /* fallthru */ + case 'p': case 'P': + scale *= 1024; + /* fallthru */ + case 't': case 'T': + scale *= 1024; + /* fallthru */ + case 'g': case 'G': + scale *= 1024; + /* fallthru */ + case 'm': case 'M': + scale *= 1024; + /* fallthru */ + case 'k': case 'K': + scale *= 1024; + /* fallthru */ + case 'b': case 'B': + break; + + /* "sectors", ie. units of 512 bytes, even if that's not the real + * sector size + */ + case 's': case 'S': + scale = 512; + break; + + default: + *error = "could not parse size: unknown suffix"; + *pstr = end; + return -1; + } + + /* XXX Maybe we should support 'MiB' as a synonym for 'M'; and 'MB' + * for powers of 1000, for similarity to GNU tools. But for now, + * anything beyond 'M' is dropped. + */ + if (end[1]) { + *error = "could not parse size: unknown suffix"; + *pstr = end; + return -1; + } + + if (INT64_MAX / scale < size) { + *error = "could not parse size: size * scale overflows"; + *pstr = str; + return -1; + } + + return size * scale; +} + +#endif /* NBDKIT_HUMAN_SIZE_H */ diff --git a/common/include/test-human-size.c b/common/include/test-human-size.c new file mode 100644 index 0000000000..e8cbe7f413 --- /dev/null +++ b/common/include/test-human-size.c @@ -0,0 +1,133 @@ +/* nbdkit + * Copyright Red Hat + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Red Hat nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdint.h> + +#include "array-size.h" +#include "human-size.h" + +int +main (void) +{ + size_t i; + bool pass = true; + struct pair { + const char *str; + int64_t res; + } pairs[] = { + /* Bogus strings */ + { "", -1 }, + { "0x0", -1 }, + { "garbage", -1 }, + { "0garbage", -1 }, + { "8E", -1 }, + { "8192P", -1 }, + + /* Strings leading to overflow */ + { "9223372036854775808", -1 }, /* INT_MAX + 1 */ + { "18446744073709551614", -1 }, /* UINT64_MAX - 1 */ + { "18446744073709551615", -1 }, /* UINT64_MAX */ + { "18446744073709551616", -1 }, /* UINT64_MAX + 1 */ + { "999999999999999999999999", -1 }, + + /* Strings representing negative values */ + { "-1", -1 }, + { "-2", -1 }, + { "-9223372036854775809", -1 }, /* INT64_MIN - 1 */ + { "-9223372036854775808", -1 }, /* INT64_MIN */ + { "-9223372036854775807", -1 }, /* INT64_MIN + 1 */ + { "-18446744073709551616", -1 }, /* -UINT64_MAX - 1 */ + { "-18446744073709551615", -1 }, /* -UINT64_MAX */ + { "-18446744073709551614", -1 }, /* -UINT64_MAX + 1 */ + + /* Strings we may want to support in the future */ + { "M", -1 }, + { "1MB", -1 }, + { "1MiB", -1 }, + { "1.5M", -1 }, + + /* Valid strings */ + { "-0", 0 }, + { "0", 0 }, + { "+0", 0 }, + { " 08", 8 }, + { "1", 1 }, + { "+1", 1 }, + { "1234567890", 1234567890 }, + { "+1234567890", 1234567890 }, + { "9223372036854775807", INT64_MAX }, + { "1s", 512 }, + { "2S", 1024 }, + { "1b", 1 }, + { "1B", 1 }, + { "1k", 1024 }, + { "1K", 1024 }, + { "1m", 1024 * 1024 }, + { "1M", 1024 * 1024 }, + { "+1M", 1024 * 1024 }, + { "1g", 1024 * 1024 * 1024 }, + { "1G", 1024 * 1024 * 1024 }, + { "1t", 1024LL * 1024 * 1024 * 1024 }, + { "1T", 1024LL * 1024 * 1024 * 1024 }, + { "1p", 1024LL * 1024 * 1024 * 1024 * 1024 }, + { "1P", 1024LL * 1024 * 1024 * 1024 * 1024 }, + { "8191p", 1024LL * 1024 * 1024 * 1024 * 1024 * 8191 }, + { "1e", 1024LL * 1024 * 1024 * 1024 * 1024 * 1024 }, + { "1E", 1024LL * 1024 * 1024 * 1024 * 1024 * 1024 }, + }; + + for (i = 0; i < ARRAY_SIZE (pairs); i++) { + const char *error = NULL, *pstr = NULL; + int64_t r; + + r = human_size_parse (pairs[i].str, &error, &pstr); + if (r != pairs[i].res) { + fprintf (stderr, + "Wrong parse for %s, got %" PRId64 ", expected %" PRId64 "\n", + pairs[i].str, r, pairs[i].res); + pass = false; + } + if (r == -1) { + if (error == NULL || pstr == NULL) { + fprintf (stderr, "Wrong error message handling for %s\n", pairs[i].str); + pass = false; + } + } + } + + exit (pass ? EXIT_SUCCESS : EXIT_FAILURE); +} -- 2.41.0
Richard W.M. Jones
2023-Sep-03 15:23 UTC
[Libguestfs] [PATCH libnbd 3/5] common: Combine human-size.h headers into one
Copy the human_size() function from common/utils/ into the new human-size.h header in common/include/. Remove human-size.c and combine the tests into one. --- common/include/human-size.h | 51 ++++++++++++++++++ common/include/test-human-size.c | 79 +++++++++++++++++++++++++--- common/utils/Makefile.am | 10 +--- common/utils/human-size.c | 56 -------------------- common/utils/human-size.h | 49 ------------------ common/utils/test-human-size.c | 89 -------------------------------- 6 files changed, 126 insertions(+), 208 deletions(-) diff --git a/common/include/human-size.h b/common/include/human-size.h index 788dbd7ba5..47729c3c58 100644 --- a/common/include/human-size.h +++ b/common/include/human-size.h @@ -134,4 +134,55 @@ human_size_parse (const char *str, return size * scale; } +/* If you allocate a buffer of at least this length in bytes and pass + * it as the first parameter to human_size, then it will not overrun. + */ +#define HUMAN_SIZE_LONGEST 64 + +/* Convert bytes to a human-readable string. + * + * This is roughly the opposite of nbdkit_parse_size. It will convert + * multiples of powers of 1024 to the appropriate human size with the + * right extension like 'M' or 'G'. Anything that cannot be converted + * is returned as bytes. The *human flag is set to true if the output + * was abbreviated to a human-readable size, or false if it is just + * bytes. + * + * If buf == NULL, a buffer is allocated and returned. In this case + * the returned buffer must be freed. + * + * buf may also be allocated by the caller, in which case it must be + * at least HUMAN_SIZE_LONGEST bytes. + * + * On error the function returns an error and sets errno. + */ +static inline char * +human_size (char *buf, uint64_t bytes, bool *human) +{ + static const char ext[][2] = { "E", "P", "T", "G", "M", "K", "" }; + size_t i; + + if (buf == NULL) { + buf = malloc (HUMAN_SIZE_LONGEST); + if (buf == NULL) + return NULL; + } + + /* Work out which extension to use, if any. */ + i = 6; + if (bytes != 0) { + while ((bytes & 1023) == 0) { + bytes >>= 10; + i--; + } + } + + /* Set the flag to true if we're going to add a human-readable extension. */ + if (human) + *human = ext[i][0] != '\0'; + + snprintf (buf, HUMAN_SIZE_LONGEST, "%" PRIu64 "%s", bytes, ext[i]); + return buf; +} + #endif /* NBDKIT_HUMAN_SIZE_H */ diff --git a/common/include/test-human-size.c b/common/include/test-human-size.c index e8cbe7f413..d56186b9da 100644 --- a/common/include/test-human-size.c +++ b/common/include/test-human-size.c @@ -36,15 +36,18 @@ #include <stdlib.h> #include <stdbool.h> #include <stdint.h> +#include <string.h> #include "array-size.h" #include "human-size.h" -int -main (void) +static unsigned errors = 0; + +/* Test the human_size_parse function. */ +static void +test1 (void) { size_t i; - bool pass = true; struct pair { const char *str; int64_t res; @@ -119,15 +122,79 @@ main (void) fprintf (stderr, "Wrong parse for %s, got %" PRId64 ", expected %" PRId64 "\n", pairs[i].str, r, pairs[i].res); - pass = false; + errors++; } if (r == -1) { if (error == NULL || pstr == NULL) { fprintf (stderr, "Wrong error message handling for %s\n", pairs[i].str); - pass = false; + errors++; } } } +} + +/* Test the human_size function. */ +static void +test2_run (uint64_t bytes, const char *expected, bool expected_human_flag) +{ + char actual[HUMAN_SIZE_LONGEST]; + bool actual_human_flag; + + human_size (actual, bytes, &actual_human_flag); + + if (strcmp (actual, expected) == 0 && + actual_human_flag == expected_human_flag) { + printf ("test-human-size: %" PRIu64 " -> \"%s\" (%s) OK\n", + bytes, actual, actual_human_flag ? "true" : "false"); + fflush (stdout); + } + else { + fprintf (stderr, + "test-human-size: error: test case %" PRIu64 " " + "expected \"%s\" (%s) " + "but returned \"%s\" (%s)\n", + bytes, + expected, expected_human_flag ? "true" : "false", + actual, actual_human_flag ? "true" : "false"); + errors++; + } +} + +static void +test2 (void) +{ + test2_run (0, "0", false); + test2_run (1, "1", false); + test2_run (512, "512", false); + test2_run (1023, "1023", false); + test2_run (1024, "1K", true); + test2_run (1025, "1025", false); + test2_run (2047, "2047", false); + test2_run (2048, "2K", true); + test2_run (3 * 1024, "3K", true); + + test2_run (1023 * 1024, "1023K", true); + test2_run (1048575, "1048575", false); + test2_run (1048576, "1M", true); + test2_run (1048577, "1048577", false); + + test2_run (UINT64_C (1073741824), "1G", true); + + test2_run (UINT64_C (1099511627776), "1T", true); + test2_run (UINT64_C (1099511627777), "1099511627777", false); + test2_run (UINT64_C (1099511627776) + 1024, "1073741825K", true); + + test2_run (UINT64_C (1125899906842624), "1P", true); + + test2_run ((uint64_t)INT64_MAX+1, "8E", true); + test2_run (UINT64_MAX-1023, "18014398509481983K", true); + test2_run (UINT64_MAX, "18446744073709551615", false); +} - exit (pass ? EXIT_SUCCESS : EXIT_FAILURE); +int +main (int argc, char *argv[]) +{ + test1 (); + test2 (); + exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } diff --git a/common/utils/Makefile.am b/common/utils/Makefile.am index a1602fbb58..901d12ad2e 100644 --- a/common/utils/Makefile.am +++ b/common/utils/Makefile.am @@ -35,8 +35,6 @@ noinst_LTLIBRARIES = libutils.la libutils_la_SOURCES = \ const-string-vector.h \ - human-size.c \ - human-size.h \ nbdkit-string.h \ string-vector.h \ vector.c \ @@ -56,12 +54,8 @@ libutils_la_LIBADD = \ # Unit tests. -TESTS = test-human-size test-vector -check_PROGRAMS = test-human-size test-vector - -test_human_size_SOURCES = test-human-size.c human-size.c human-size.h -test_human_size_CPPFLAGS = -I$(srcdir) -test_human_size_CFLAGS = $(WARNINGS_CFLAGS) +TESTS = test-vector +check_PROGRAMS = test-vector test_vector_SOURCES = test-vector.c vector.c vector.h bench.h test_vector_CPPFLAGS = -I$(srcdir) -I$(top_srcdir)/common/include diff --git a/common/utils/human-size.c b/common/utils/human-size.c deleted file mode 100644 index 14d6801318..0000000000 --- a/common/utils/human-size.c +++ /dev/null @@ -1,56 +0,0 @@ -/* nbd client library in userspace - * Copyright Red Hat - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> -#include <inttypes.h> - -#include "human-size.h" - -char * -human_size (char *buf, uint64_t bytes, bool *human) -{ - static const char ext[][2] = { "E", "P", "T", "G", "M", "K", "" }; - size_t i; - - if (buf == NULL) { - buf = malloc (HUMAN_SIZE_LONGEST); - if (buf == NULL) - return NULL; - } - - /* Work out which extension to use, if any. */ - i = 6; - if (bytes != 0) { - while ((bytes & 1023) == 0) { - bytes >>= 10; - i--; - } - } - - /* Set the flag to true if we're going to add a human-readable extension. */ - if (human) - *human = ext[i][0] != '\0'; - - snprintf (buf, HUMAN_SIZE_LONGEST, "%" PRIu64 "%s", bytes, ext[i]); - return buf; -} diff --git a/common/utils/human-size.h b/common/utils/human-size.h deleted file mode 100644 index 5ab90a0fa3..0000000000 --- a/common/utils/human-size.h +++ /dev/null @@ -1,49 +0,0 @@ -/* nbd client library in userspace - * Copyright Red Hat - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LIBNBD_HUMAN_SIZE_H -#define LIBNBD_HUMAN_SIZE_H - -#include <stdbool.h> -#include <stdint.h> - -/* If you allocate a buffer of at least this length in bytes and pass - * it as the first parameter to human_size, then it will not overrun. - */ -#define HUMAN_SIZE_LONGEST 64 - -/* Convert bytes to a human-readable string. - * - * This is roughly the opposite of nbdkit_parse_size. It will convert - * multiples of powers of 1024 to the appropriate human size with the - * right extension like 'M' or 'G'. Anything that cannot be converted - * is returned as bytes. The *human flag is set to true if the output - * was abbreviated to a human-readable size, or false if it is just - * bytes. - * - * If buf == NULL, a buffer is allocated and returned. In this case - * the returned buffer must be freed. - * - * buf may also be allocated by the caller, in which case it must be - * at least HUMAN_SIZE_LONGEST bytes. - * - * On error the function returns an error and sets errno. - */ -extern char *human_size (char *buf, uint64_t bytes, bool *human); - -#endif /* LIBNBD_HUMAN_SIZE_H */ diff --git a/common/utils/test-human-size.c b/common/utils/test-human-size.c deleted file mode 100644 index 94210e85f2..0000000000 --- a/common/utils/test-human-size.c +++ /dev/null @@ -1,89 +0,0 @@ -/* nbd client library in userspace - * Copyright Red Hat - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> -#include <inttypes.h> -#include <string.h> - -#include "human-size.h" - -static unsigned errors = 0; - -static void -test (uint64_t bytes, const char *expected, bool expected_human_flag) -{ - char actual[HUMAN_SIZE_LONGEST]; - bool actual_human_flag; - - human_size (actual, bytes, &actual_human_flag); - - if (strcmp (actual, expected) == 0 && - actual_human_flag == expected_human_flag) { - printf ("test-human-size: %" PRIu64 " -> \"%s\" (%s) OK\n", - bytes, actual, actual_human_flag ? "true" : "false"); - fflush (stdout); - } - else { - fprintf (stderr, - "test-human-size: error: test case %" PRIu64 " " - "expected \"%s\" (%s) " - "but returned \"%s\" (%s)\n", - bytes, - expected, expected_human_flag ? "true" : "false", - actual, actual_human_flag ? "true" : "false"); - errors++; - } -} - -int -main (int argc, char *argv[]) -{ - test (0, "0", false); - test (1, "1", false); - test (512, "512", false); - test (1023, "1023", false); - test (1024, "1K", true); - test (1025, "1025", false); - test (2047, "2047", false); - test (2048, "2K", true); - test (3 * 1024, "3K", true); - - test (1023 * 1024, "1023K", true); - test (1048575, "1048575", false); - test (1048576, "1M", true); - test (1048577, "1048577", false); - - test (UINT64_C (1073741824), "1G", true); - - test (UINT64_C (1099511627776), "1T", true); - test (UINT64_C (1099511627777), "1099511627777", false); - test (UINT64_C (1099511627776) + 1024, "1073741825K", true); - - test (UINT64_C (1125899906842624), "1P", true); - - test ((uint64_t)INT64_MAX+1, "8E", true); - test (UINT64_MAX-1023, "18014398509481983K", true); - test (UINT64_MAX, "18446744073709551615", false); - - exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); -} -- 2.41.0
Richard W.M. Jones
2023-Sep-03 15:23 UTC
[Libguestfs] [PATCH libnbd 4/5] Revert "copy, info: Include common/utils/human-size.h"
This reverts commit XXX FILL IN LATER XXX --- copy/main.c | 2 +- info/show.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/copy/main.c b/copy/main.c index d2f415dc47..6928a4acde 100644 --- a/copy/main.c +++ b/copy/main.c @@ -39,7 +39,7 @@ #include <libnbd.h> #include "ispowerof2.h" -#include "../utils/human-size.h" +#include "human-size.h" #include "minmax.h" #include "version.h" #include "nbdcopy.h" diff --git a/info/show.c b/info/show.c index 99b7b5b60a..920bbb0a27 100644 --- a/info/show.c +++ b/info/show.c @@ -29,7 +29,7 @@ #include <libnbd.h> #include "ansi-colours.h" -#include "../utils/human-size.h" +#include "human-size.h" #include "string-vector.h" #include "nbdinfo.h" -- 2.41.0
Richard W.M. Jones
2023-Sep-03 15:23 UTC
[Libguestfs] [PATCH libnbd 5/5] copy: Allow human sizes for --queue-size, --request-size, --sparse
Allow these options to be specified using human sizes, for example this now works: nbdcopy --request-size=32M ... --- copy/copy-sparse-allocated.sh | 2 +- copy/copy-sparse-no-extents.sh | 2 +- copy/copy-sparse-request-size.sh | 2 +- copy/main.c | 37 ++++++++++++++++++++------------ copy/nbdcopy.h | 2 +- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/copy/copy-sparse-allocated.sh b/copy/copy-sparse-allocated.sh index c65ddea79f..e1fe9cf463 100755 --- a/copy/copy-sparse-allocated.sh +++ b/copy/copy-sparse-allocated.sh @@ -31,7 +31,7 @@ requires nbdkit eval --version out=copy-sparse-allocated.out cleanup_fn rm -f $out -$VG nbdcopy --allocated --request-size=32768 -- \ +$VG nbdcopy --allocated --request-size=32K -- \ [ nbdkit --exit-with-parent data data=' 1 @1073741823 1 diff --git a/copy/copy-sparse-no-extents.sh b/copy/copy-sparse-no-extents.sh index cff356978b..9368c564e9 100755 --- a/copy/copy-sparse-no-extents.sh +++ b/copy/copy-sparse-no-extents.sh @@ -39,7 +39,7 @@ requires nbdkit eval --version out=copy-sparse-no-extents.out cleanup_fn rm -f $out -$VG nbdcopy --request-size=33554432 --no-extents -S 0 -- \ +$VG nbdcopy --request-size=32M --no-extents -S 0 -- \ [ nbdkit --exit-with-parent data data=' 1 @1073741823 1 diff --git a/copy/copy-sparse-request-size.sh b/copy/copy-sparse-request-size.sh index dc8caeafd1..dd28695f68 100755 --- a/copy/copy-sparse-request-size.sh +++ b/copy/copy-sparse-request-size.sh @@ -39,7 +39,7 @@ requires nbdkit eval --version out=copy-sparse-request-size.out cleanup_fn rm -f $out -$VG nbdcopy --no-extents -S 0 --request-size=1048576 -- \ +$VG nbdcopy --no-extents -S 0 --request-size=1M -- \ [ nbdkit --exit-with-parent data data=' 1 @33554431 1 diff --git a/copy/main.c b/copy/main.c index 6928a4acde..47b1ea8be0 100644 --- a/copy/main.c +++ b/copy/main.c @@ -141,6 +141,8 @@ main (int argc, char *argv[]) }; int c; size_t i; + int64_t i64; + const char *error, *pstr; /* Set prog to basename argv[0]. */ prog = strrchr (argv[0], '/'); @@ -210,26 +212,32 @@ main (int argc, char *argv[]) break; case QUEUE_SIZE_OPTION: - if (sscanf (optarg, "%u", &queue_size) != 1) { - fprintf (stderr, "%s: --queue-size: could not parse: %s\n", - prog, optarg); + i64 = human_size_parse (optarg, &error, &pstr); + if (i64 == -1) { + fprintf (stderr, "%s: --queue-size: %s: %s\n", prog, error, pstr); exit (EXIT_FAILURE); } + if (i64 > UINT_MAX) { + fprintf (stderr, "%s: --queue-size is too large\n", prog); + exit (EXIT_FAILURE); + } + queue_size = i64; break; case REQUEST_SIZE_OPTION: - if (sscanf (optarg, "%u", &request_size) != 1) { - fprintf (stderr, "%s: --request-size: could not parse: %s\n", - prog, optarg); + i64 = human_size_parse (optarg, &error, &pstr); + if (i64 == -1) { + fprintf (stderr, "%s: --request-size: %s: %s\n", prog, error, pstr); exit (EXIT_FAILURE); } - if (request_size < MIN_REQUEST_SIZE || request_size > MAX_REQUEST_SIZE || - !is_power_of_2 (request_size)) { + if (i64 < MIN_REQUEST_SIZE || i64 > MAX_REQUEST_SIZE || + !is_power_of_2 (i64)) { fprintf (stderr, "%s: --request-size: must be a power of 2 within %d-%d\n", prog, MIN_REQUEST_SIZE, MAX_REQUEST_SIZE); exit (EXIT_FAILURE); } + request_size = i64; break; case 'R': @@ -241,17 +249,18 @@ main (int argc, char *argv[]) break; case 'S': - if (sscanf (optarg, "%u", &sparse_size) != 1) { - fprintf (stderr, "%s: --sparse: could not parse: %s\n", - prog, optarg); + i64 = human_size_parse (optarg, &error, &pstr); + if (i64 == -1) { + fprintf (stderr, "%s: --sparse: %s: %s\n", prog, error, pstr); exit (EXIT_FAILURE); } - if (sparse_size != 0 && - (sparse_size < 512 || !is_power_of_2 (sparse_size))) { - fprintf (stderr, "%s: --sparse: must be a power of 2 and >= 512\n", + if (i64 != 0 && + (i64 < 512 || i64 > UINT_MAX || !is_power_of_2 (i64))) { + fprintf (stderr, "%s: --sparse: must be a power of 2, between 512 and UINT_MAX\n", prog); exit (EXIT_FAILURE); } + sparse_size = i64; break; case 'T': diff --git a/copy/nbdcopy.h b/copy/nbdcopy.h index 465b7052e7..ade53d1a05 100644 --- a/copy/nbdcopy.h +++ b/copy/nbdcopy.h @@ -28,7 +28,7 @@ #include "vector.h" #define MIN_REQUEST_SIZE 4096 -#define MAX_REQUEST_SIZE (32 * 1024 * 1024) +#define MAX_REQUEST_SIZE (32 * 1024 * 1024) /* must be <= UNSIGNED_MAX */ /* This must be a multiple of MAX_REQUEST_SIZE. Larger is better up * to a point, but it reduces the effectiveness of threads if the work -- 2.41.0