Richard W.M. Jones
2022-Feb-16 16:20 UTC
[Libguestfs] [PATCH nbdkit 4/6] eval, sh: Implement block_size method
The main reason to implement block_size in these plugins first is so we then have an easy way to implement tests of the feature. --- plugins/eval/nbdkit-eval-plugin.pod | 2 + plugins/sh/nbdkit-sh-plugin.pod | 10 +++++ plugins/sh/methods.h | 3 ++ plugins/eval/eval.c | 2 + plugins/sh/methods.c | 66 +++++++++++++++++++++++++++++ plugins/sh/sh.c | 1 + 6 files changed, 84 insertions(+) diff --git a/plugins/eval/nbdkit-eval-plugin.pod b/plugins/eval/nbdkit-eval-plugin.pod index 22167ec5..fa9784ae 100644 --- a/plugins/eval/nbdkit-eval-plugin.pod +++ b/plugins/eval/nbdkit-eval-plugin.pod @@ -70,6 +70,8 @@ features): =item B<after_fork=>SCRIPT +=item B<block_size=>SCRIPT + =item B<cache=>SCRIPT =item B<can_cache=>SCRIPT diff --git a/plugins/sh/nbdkit-sh-plugin.pod b/plugins/sh/nbdkit-sh-plugin.pod index c4cb9fac..aede1c65 100644 --- a/plugins/sh/nbdkit-sh-plugin.pod +++ b/plugins/sh/nbdkit-sh-plugin.pod @@ -372,6 +372,16 @@ L<nbdkit-plugin(3)/PARSING SIZE PARAMETERS>). This method is required. +=item C<block_size> + + /path/to/script block_size <handle> + +This script should print three numbers on stdout, separated by +whitespace. These are (in order) the minimum block size, the +preferred block size, and the maximum block size. You can print the +sizes in bytes or use any format understood by C<nbdkit_parse_size> +such as C<1M> (see L<nbdkit-plugin(3)/PARSING SIZE PARAMETERS>). + =item C<can_write> =item C<can_flush> diff --git a/plugins/sh/methods.h b/plugins/sh/methods.h index 42eb560c..d405ef00 100644 --- a/plugins/sh/methods.h +++ b/plugins/sh/methods.h @@ -51,6 +51,9 @@ extern void *sh_open (int readonly); extern void sh_close (void *handle); extern const char *sh_export_description (void *handle); extern int64_t sh_get_size (void *handle); +extern int sh_block_size (void *handle, + uint32_t *minimum, uint32_t *preferred, + uint32_t *maximum); extern int sh_pread (void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags); extern int sh_pwrite (void *handle, const void *buf, uint32_t count, diff --git a/plugins/eval/eval.c b/plugins/eval/eval.c index b312a59c..8ce7a650 100644 --- a/plugins/eval/eval.c +++ b/plugins/eval/eval.c @@ -55,6 +55,7 @@ static char *missing; static const char *known_methods[] = { "after_fork", + "block_size", "cache", "can_cache", "can_extents", @@ -402,6 +403,7 @@ static struct nbdkit_plugin plugin = { .export_description = sh_export_description, .get_size = sh_get_size, + .block_size = sh_block_size, .can_write = sh_can_write, .can_flush = sh_can_flush, .is_rotational = sh_is_rotational, diff --git a/plugins/sh/methods.c b/plugins/sh/methods.c index 51bc89e5..1216c212 100644 --- a/plugins/sh/methods.c +++ b/plugins/sh/methods.c @@ -526,6 +526,72 @@ sh_get_size (void *handle) } } +int +sh_block_size (void *handle, + uint32_t *minimum, uint32_t *preferred, uint32_t *maximum) +{ + const char *method = "block_size"; + const char *script = get_script (method); + struct sh_handle *h = handle; + const char *args[] = { script, method, h->h, NULL }; + CLEANUP_FREE char *s = NULL; + size_t slen; + const char *delim = " \t\n"; + char *sp, *p; + int64_t r; + + switch (call_read (&s, &slen, args)) { + case OK: + if ((p = strtok_r (s, delim, &sp)) == NULL) { + parse_error: + nbdkit_error ("%s: %s method cannot be parsed", script, method); + return -1; + } + r = nbdkit_parse_size (p); + if (r == -1 || r > UINT32_MAX) + goto parse_error; + *minimum = r; + + if ((p = strtok_r (NULL, delim, &sp)) == NULL) + goto parse_error; + r = nbdkit_parse_size (p); + if (r == -1 || r > UINT32_MAX) + goto parse_error; + *preferred = r; + + if ((p = strtok_r (NULL, delim, &sp)) == NULL) + goto parse_error; + r = nbdkit_parse_size (p); + if (r == -1 || r > UINT32_MAX) + goto parse_error; + *maximum = r; + +#if 0 + nbdkit_debug ("setting block_size: " + "minimum=%" PRIu32 " " + "preferred=%" PRIu32 " " + "maximum=%" PRIu32, + *minimum, *preferred, *maximum); +#endif + return 0; + + case MISSING: + *minimum = *preferred = *maximum = 0; + return 0; + + case ERROR: + return -1; + + case RET_FALSE: + nbdkit_error ("%s: %s method returned unexpected code (3/false)", + script, method); + errno = EIO; + return -1; + + default: abort (); + } +} + int sh_pread (void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags) diff --git a/plugins/sh/sh.c b/plugins/sh/sh.c index db75d386..35972104 100644 --- a/plugins/sh/sh.c +++ b/plugins/sh/sh.c @@ -307,6 +307,7 @@ static struct nbdkit_plugin plugin = { .export_description = sh_export_description, .get_size = sh_get_size, + .block_size = sh_block_size, .can_write = sh_can_write, .can_flush = sh_can_flush, .is_rotational = sh_is_rotational, -- 2.35.1
Eric Blake
2022-Feb-16 18:16 UTC
[Libguestfs] [PATCH nbdkit 4/6] eval, sh: Implement block_size method
On Wed, Feb 16, 2022 at 04:20:39PM +0000, Richard W.M. Jones wrote:> The main reason to implement block_size in these plugins first is so > we then have an easy way to implement tests of the feature. > --- > plugins/eval/nbdkit-eval-plugin.pod | 2 + > plugins/sh/nbdkit-sh-plugin.pod | 10 +++++ > plugins/sh/methods.h | 3 ++ > plugins/eval/eval.c | 2 + > plugins/sh/methods.c | 66 +++++++++++++++++++++++++++++ > plugins/sh/sh.c | 1 + > 6 files changed, 84 insertions(+) > > +int > +sh_block_size (void *handle, > + uint32_t *minimum, uint32_t *preferred, uint32_t *maximum) > +{ > + const char *method = "block_size"; > + const char *script = get_script (method); > + struct sh_handle *h = handle; > + const char *args[] = { script, method, h->h, NULL }; > + CLEANUP_FREE char *s = NULL; > + size_t slen; > + const char *delim = " \t\n"; > + char *sp, *p; > + int64_t r; > + > + switch (call_read (&s, &slen, args)) { > + case OK: > + if ((p = strtok_r (s, delim, &sp)) == NULL) { > + parse_error: > + nbdkit_error ("%s: %s method cannot be parsed", script, method); > + return -1; > + } > + r = nbdkit_parse_size (p); > + if (r == -1 || r > UINT32_MAX) > + goto parse_error; > + *minimum = r; > + > + if ((p = strtok_r (NULL, delim, &sp)) == NULL) > + goto parse_error; > + r = nbdkit_parse_size (p); > + if (r == -1 || r > UINT32_MAX) > + goto parse_error; > + *preferred = r; > + > + if ((p = strtok_r (NULL, delim, &sp)) == NULL) > + goto parse_error; > + r = nbdkit_parse_size (p); > + if (r == -1 || r > UINT32_MAX) > + goto parse_error; > + *maximum = r; > + > +#if 0 > + nbdkit_debug ("setting block_size: " > + "minimum=%" PRIu32 " " > + "preferred=%" PRIu32 " " > + "maximum=%" PRIu32, > + *minimum, *preferred, *maximum); > +#endif > + return 0;Do we care about checking that there is no trailing garbage after the three numbers? Otherwise, yes, this makes a good first plugin for an implementation ;) -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org