Richard W.M. Jones
2020-Apr-04 16:06 UTC
[Libguestfs] [PATCH nbdkit 0/2] Generalize the tmpdisk plugin.
Patch 1/2 is uncontroversial. Patch 2/2 is an interesting idea I had to generalize this plugin. It already uses a complete embedded shell script to do most of the work. What if, instead of making special cases for "type" and "label" params, we simply turn any other plugin parameters into script variables? This part of it works fine. However there is another problem which is noted in the "XXX" comment in the second commit message. Rich.
Richard W.M. Jones
2020-Apr-04 16:06 UTC
[Libguestfs] [PATCH nbdkit 1/2] tmpdisk: Generate the default command from a shell script fragment.
Neutral refactoring. Makes the code a bit easier to handle and simplifies future commits. --- plugins/tmpdisk/Makefile.am | 17 ++++++++- plugins/tmpdisk/tmpdisk.c | 22 +++--------- plugins/tmpdisk/default-command.sh.in | 51 +++++++++++++++++++++++++++ .gitignore | 1 + 4 files changed, 72 insertions(+), 19 deletions(-) diff --git a/plugins/tmpdisk/Makefile.am b/plugins/tmpdisk/Makefile.am index 34061771..20aeb05f 100644 --- a/plugins/tmpdisk/Makefile.am +++ b/plugins/tmpdisk/Makefile.am @@ -31,11 +31,26 @@ include $(top_srcdir)/common-rules.mk -EXTRA_DIST = nbdkit-tmpdisk-plugin.pod +EXTRA_DIST = \ + default-command.sh.in \ + nbdkit-tmpdisk-plugin.pod \ + $(NULL) + +# The default command we use (if we don't use command=) comes from a +# shell script which is turned into a C source file. +BUILT_SOURCES = default-command.c + +default-command.c: default-command.sh.in Makefile + rm -f $@ $@-t + echo 'const char *command =' > $@-t + $(SED) -e '/^#/d' -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $< >> $@-t + echo ';' >> $@-t + mv $@-t $@ plugin_LTLIBRARIES = nbdkit-tmpdisk-plugin.la nbdkit_tmpdisk_plugin_la_SOURCES = \ + default-command.c \ tmpdisk.c \ $(top_srcdir)/include/nbdkit-plugin.h \ $(NULL) diff --git a/plugins/tmpdisk/tmpdisk.c b/plugins/tmpdisk/tmpdisk.c index a5aacc9d..5e8df151 100644 --- a/plugins/tmpdisk/tmpdisk.c +++ b/plugins/tmpdisk/tmpdisk.c @@ -55,24 +55,10 @@ static int64_t size = -1; static const char *label = NULL; static const char *type = "ext4"; -static const char *command - "labelopt='-L'\n" - "case \"$type\" in\n" - " ext?)\n" - " extra='-F' ;;\n" - " *fat|msdos)\n" - " extra='-I' ;;\n" - " ntfs)\n" - " extra='-Q -F'\n" - " labelopt='-n' ;;\n" - " xfs)\n" - " extra='-f' ;;\n" - "esac\n" - "if [ \"x$label\" = \"x\" ]; then\n" - " mkfs -t \"$type\" $extra \"$disk\"\n" - "else\n" - " mkfs -t \"$type\" $extra $labelopt \"$label\" \"$disk\"\n" - "fi\n"; +/* This comes from default-command.c which is generated from + * default-command.sh.in. + */ +extern const char *command; static void tmpdisk_load (void) diff --git a/plugins/tmpdisk/default-command.sh.in b/plugins/tmpdisk/default-command.sh.in new file mode 100644 index 00000000..251e0b7b --- /dev/null +++ b/plugins/tmpdisk/default-command.sh.in @@ -0,0 +1,51 @@ +# nbdkit +# -*- mode: shell-script -*- +# Copyright (C) 2017-2020 Red Hat Inc. +# +# 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. + +labelopt='-L' + +case "$type" in + ext?) + extra='-F' ;; + *fat|msdos) + extra='-I' ;; + ntfs) + extra='-Q -F' + labelopt='-n' ;; + xfs) + extra='-f' ;; +esac + +if [ "x$label" = "x" ]; then + mkfs -t "$type" $extra "$disk" +else + mkfs -t "$type" $extra $labelopt "$label" "$disk" +fi diff --git a/.gitignore b/.gitignore index 4bb035e1..c44fb40d 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ plugins/*/*.3 /plugins/rust/Cargo.toml /plugins/rust/target /plugins/tar/nbdkit-tar-plugin +/plugins/tmpdisk/default-command.c /podwrapper.pl /server/nbdkit /server/nbdkit.pc -- 2.25.0
Richard W.M. Jones
2020-Apr-04 16:06 UTC
[Libguestfs] [PATCH nbdkit 2/2] tmpdisk: Pass any parameters as shell variables to the command.
This allows us to be much more flexible about what commands can be used. It also means we do not need to encode any special behaviour for type or label parameters. XXX However one problem which is not addressed here: The $disk passed to the shell script fragment must be updated, not replaced. This is because currently the plugin has a file descriptor opened on this file. If it is deleted by the script then the fd becomes invalid and the plugin will no longer work. It's unclear if it is safe (from a security point of view) for the plugin to reopen the disk by name after the script has run. --- plugins/tmpdisk/nbdkit-tmpdisk-plugin.pod | 86 +++++++++++++---------- plugins/tmpdisk/tmpdisk.c | 71 +++++++++++++------ plugins/tmpdisk/default-command.sh.in | 3 + 3 files changed, 102 insertions(+), 58 deletions(-) diff --git a/plugins/tmpdisk/nbdkit-tmpdisk-plugin.pod b/plugins/tmpdisk/nbdkit-tmpdisk-plugin.pod index 925a5091..bdc15786 100644 --- a/plugins/tmpdisk/nbdkit-tmpdisk-plugin.pod +++ b/plugins/tmpdisk/nbdkit-tmpdisk-plugin.pod @@ -4,9 +4,9 @@ nbdkit-tmpdisk-plugin - create a fresh temporary filesystem for each client =head1 SYNOPSIS - nbdkit tmpdisk [size=]SIZE - [type=ext4|xfs|vfat|...] [label=LABEL] - [command=COMMAND] + nbdkit tmpdisk [size=]SIZE [type=ext4|xfs|vfat|...] [label=LABEL] + + nbdkit tmpdisk [size=]SIZE command=COMMAND =head1 DESCRIPTION @@ -23,12 +23,46 @@ this plugin sees a different disk. The size of the disk is chosen using the C<size> parameter. The filesystem type is C<ext4> but this can be changed using the C<type> -parameter (controlling the I<-t> option of mkfs). +parameter (controlling the I<-t> option of mkfs). The filesystem +label may be set using C<label>. -Instead of running mkfs you can run an arbitrary C<command> to create -the disk. +=head2 The command parameter -=head2 Example +Instead of running mkfs you can run an arbitrary command (a shell +script fragment) to initialize the disk. + +The other parameters to the plugin are turned into shell variables +passed to the command. For example C<type> becomes the shell variable +C<$type>, etc. Any parameters you want can be passed to the plugin +and will be turned into shell variables (not only C<type> and +C<label>) making this a very flexible method to create temporary disks +of all kinds. + +Two special variables are also passed to the shell script fragment: + +=over 4 + +=item C<$disk> + +The absolute path of the file that the command must initialize. This +file is created by nbdkit before the command runs. + +=item C<$size> + +The virtual size in bytes, which is the same as the file size. + +=back + +=head2 Security considerations + +Because each client gets a new disk, the amount of disk space +required on the server can be as much as +S<<< I<number of clients> × I<size parameter> >>>. It is therefore +best to limit the number of clients using L<nbdkit-limit-filter(1)> or +take steps to limit where clients can connect from using +L<nbdkit-ip-filter(1)>, firewalls, or TLS client certificates. + +=head1 EXAMPLES One use for this is to create a kind of "remote L<tmpfs(5)>" for thin clients. On the server you would run (see L<nbdkit-service(1)>): @@ -45,14 +79,10 @@ containing: Clients would see a fresh, empty C</var/scratch> directory after boot. -=head2 Security considerations +Using C<command> allows you to easily override any mkfs option, for +example: -Because each client gets a new disk, the amount of disk space -required on the server can be as much as -S<<< I<number of clients> × I<size parameter> >>>. It is therefore -best to limit the number of clients using L<nbdkit-limit-filter(1)> or -take steps to limit where clients can connect from using -L<nbdkit-ip-filter(1)>, firewalls, or TLS client certificates. + nbdkit tmpdisk 16G command='mke2fs -F -t ext4 $disk -N 10000' =head1 PARAMETERS @@ -61,30 +91,8 @@ L<nbdkit-ip-filter(1)>, firewalls, or TLS client certificates. =item B<command='>COMMANDB<'> Instead of running L<mkfs(8)> to create the initial filesystem, run -C<COMMAND> (which usually must be quoted to protect it from the -shell). The following shell variables may be used in C<COMMAND>: - -=over 4 - -=item C<$disk> - -The absolute path of the file that the command must initialize. This -file is created by nbdkit before the command runs. - -=item C<$label> - -The filesystem label (from the C<label> parameter). - -=item C<$size> - -The virtual size in bytes, which is the same as the file size. - -=item C<$type> - -The filesystem type (from the C<type> parameter), defaulting to -C<ext4>. (Commands can ignore this if it is not relevant). - -=back +C<COMMAND> (a shell script fragment which usually must be quoted to +protect it from the shell). See L</The command parameter> above. =item B<label=>LABEL @@ -139,11 +147,13 @@ C<nbdkit-tmpdisk-plugin> first appeared in nbdkit 1.20. L<nbdkit(1)>, L<nbdkit-plugin(3)>, L<nbdkit-data-plugin(1)>, +L<nbdkit-eval-plugin(1)>, L<nbdkit-file-plugin(1)>, L<nbdkit-ip-filter(1)>, L<nbdkit-limit-filter(1)>, L<nbdkit-linuxdisk-plugin(1)>, L<nbdkit-memory-plugin(1)>, +L<nbdkit-sh-plugin(1)>, L<nbdkit-loop(1)>, L<nbdkit-tls(1)>, L<mkfs(8)>. diff --git a/plugins/tmpdisk/tmpdisk.c b/plugins/tmpdisk/tmpdisk.c index 5e8df151..56dbb4cd 100644 --- a/plugins/tmpdisk/tmpdisk.c +++ b/plugins/tmpdisk/tmpdisk.c @@ -52,8 +52,12 @@ static const char *tmpdir = "/var/tmp"; static int64_t size = -1; -static const char *label = NULL; -static const char *type = "ext4"; + +/* Shell variables. */ +static struct var { + struct var *next; + const char *key, *value; +} *vars; /* This comes from default-command.c which is generated from * default-command.sh.in. @@ -70,29 +74,49 @@ tmpdisk_load (void) tmpdir = s; } +static void +tmpdisk_unload (void) +{ + struct var *v, *v_next; + + for (v = vars; v != NULL; v = v_next) { + v_next = v->next; + free (v); + } +} + static int tmpdisk_config (const char *key, const char *value) { if (strcmp (key, "command") == 0) { command = value; } - else if (strcmp (key, "label") == 0) { - if (strcmp (value, "") == 0) - label = NULL; - else - label = value; - } else if (strcmp (key, "size") == 0) { size = nbdkit_parse_size (value); if (size == -1) return -1; } - else if (strcmp (key, "type") == 0) { - type = value; + + /* This parameter cannot be set on the command line since it is used + * to pass the disk name to the command. + */ + else if (strcmp (key, "disk") == 0) { + nbdkit_error ("'disk' parameter cannot be set on the command line"); + return -1; } + + /* Any other parameter will be forwarded to a shell variable. */ else { - nbdkit_error ("unknown parameter '%s'", key); - return -1; + struct var *v_next = vars; + + vars = malloc (sizeof *vars); + if (vars == NULL) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + vars->next = v_next; + vars->key = key; + vars->value = value; } return 0; @@ -163,6 +187,7 @@ run_command (const char *disk) CLEANUP_FREE char *cmd = NULL; size_t len = 0; int r; + struct var *v; fp = open_memstream (&cmd, &len); if (fp == NULL) { @@ -173,21 +198,26 @@ run_command (const char *disk) /* Avoid stdin/stdout leaking (because of nbdkit -s). */ fprintf (fp, "exec </dev/null >/dev/null\n"); - /* Set the shell variables. */ + /* Set the standard shell variables. */ fprintf (fp, "disk="); shell_quote (disk, fp); putc ('\n', fp); - if (label) { - fprintf (fp, "label="); - shell_quote (label, fp); - putc ('\n', fp); - } fprintf (fp, "size=%" PRIi64 "\n", size); - fprintf (fp, "type="); - shell_quote (type, fp); putc ('\n', fp); + /* The other parameters/shell variables. */ + for (v = vars; v != NULL; v = v->next) { + /* Keys probably can never contain shell-unsafe chars (because of + * nbdkit's own restrictions), but quoting it makes it safe. + */ + shell_quote (v->key, fp); + putc ('=', fp); + shell_quote (v->value, fp); + putc ('\n', fp); + } putc ('\n', fp); + + /* The command. */ fprintf (fp, "%s", command); if (fclose (fp) == EOF) { @@ -414,6 +444,7 @@ static struct nbdkit_plugin plugin = { .version = PACKAGE_VERSION, .load = tmpdisk_load, + .unload = tmpdisk_unload, .config = tmpdisk_config, .config_complete = tmpdisk_config_complete, .config_help = tmpdisk_config_help, diff --git a/plugins/tmpdisk/default-command.sh.in b/plugins/tmpdisk/default-command.sh.in index 251e0b7b..87c86f1e 100644 --- a/plugins/tmpdisk/default-command.sh.in +++ b/plugins/tmpdisk/default-command.sh.in @@ -30,6 +30,9 @@ # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. +# If not set, default to ext4. +type="${type:-ext4}" + labelopt='-L' case "$type" in -- 2.25.0
Richard W.M. Jones
2020-Apr-04 20:01 UTC
Re: [Libguestfs] [PATCH nbdkit 2/2] tmpdisk: Pass any parameters as shell variables to the command.
On Sat, Apr 04, 2020 at 05:06:32PM +0100, Richard W.M. Jones wrote:> This allows us to be much more flexible about what commands can be > used. It also means we do not need to encode any special behaviour > for type or label parameters. > > XXX > However one problem which is not addressed here: The $disk passed to > the shell script fragment must be updated, not replaced. This is > because currently the plugin has a file descriptor opened on this > file. If it is deleted by the script then the fd becomes invalid and > the plugin will no longer work. It's unclear if it is safe (from a > security point of view) for the plugin to reopen the disk by name > after the script has run.I realise I didn't say why this is a problem for the consumer of the plugin (which is different from why it may or may not be a security problem). Common commands you might want to use include: nbdkit tmpdisk 16G command='virt-builder -o $disk $os --size $size' nbdkit tmpdisk 16G command='qemu-img create -f $fmt $disk $size' The problem is that these commands will delete and recreate the output file, so will not work with the plugin as written. (Note that for qemu-img create, the -n parameter is not sufficient - left as an interesting puzzle for the reader to work out why.) If the plugin is allowed to close and reopen $disk, and recalcuate the size, then these commands would be fine. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org
Richard W.M. Jones
2020-Apr-07 15:18 UTC
Re: [Libguestfs] [PATCH nbdkit 1/2] tmpdisk: Generate the default command from a shell script fragment.
On Sat, Apr 04, 2020 at 05:06:31PM +0100, Richard W.M. Jones wrote:> Neutral refactoring. Makes the code a bit easier to handle and > simplifies future commits. > --- > plugins/tmpdisk/Makefile.am | 17 ++++++++- > plugins/tmpdisk/tmpdisk.c | 22 +++--------- > plugins/tmpdisk/default-command.sh.in | 51 +++++++++++++++++++++++++++ > .gitignore | 1 + > 4 files changed, 72 insertions(+), 19 deletions(-)I pushed this one since it's an uncontroversial simplification of the code. I'm going to have another go at part 2 of this patch series, since I've thought about the security implications and think I have a way that may be safe (will post for review first obviously). Rich.> diff --git a/plugins/tmpdisk/Makefile.am b/plugins/tmpdisk/Makefile.am > index 34061771..20aeb05f 100644 > --- a/plugins/tmpdisk/Makefile.am > +++ b/plugins/tmpdisk/Makefile.am > @@ -31,11 +31,26 @@ > > include $(top_srcdir)/common-rules.mk > > -EXTRA_DIST = nbdkit-tmpdisk-plugin.pod > +EXTRA_DIST = \ > + default-command.sh.in \ > + nbdkit-tmpdisk-plugin.pod \ > + $(NULL) > + > +# The default command we use (if we don't use command=) comes from a > +# shell script which is turned into a C source file. > +BUILT_SOURCES = default-command.c > + > +default-command.c: default-command.sh.in Makefile > + rm -f $@ $@-t > + echo 'const char *command =' > $@-t > + $(SED) -e '/^#/d' -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $< >> $@-t > + echo ';' >> $@-t > + mv $@-t $@ > > plugin_LTLIBRARIES = nbdkit-tmpdisk-plugin.la > > nbdkit_tmpdisk_plugin_la_SOURCES = \ > + default-command.c \ > tmpdisk.c \ > $(top_srcdir)/include/nbdkit-plugin.h \ > $(NULL) > diff --git a/plugins/tmpdisk/tmpdisk.c b/plugins/tmpdisk/tmpdisk.c > index a5aacc9d..5e8df151 100644 > --- a/plugins/tmpdisk/tmpdisk.c > +++ b/plugins/tmpdisk/tmpdisk.c > @@ -55,24 +55,10 @@ static int64_t size = -1; > static const char *label = NULL; > static const char *type = "ext4"; > > -static const char *command > - "labelopt='-L'\n" > - "case \"$type\" in\n" > - " ext?)\n" > - " extra='-F' ;;\n" > - " *fat|msdos)\n" > - " extra='-I' ;;\n" > - " ntfs)\n" > - " extra='-Q -F'\n" > - " labelopt='-n' ;;\n" > - " xfs)\n" > - " extra='-f' ;;\n" > - "esac\n" > - "if [ \"x$label\" = \"x\" ]; then\n" > - " mkfs -t \"$type\" $extra \"$disk\"\n" > - "else\n" > - " mkfs -t \"$type\" $extra $labelopt \"$label\" \"$disk\"\n" > - "fi\n"; > +/* This comes from default-command.c which is generated from > + * default-command.sh.in. > + */ > +extern const char *command; > > static void > tmpdisk_load (void) > diff --git a/plugins/tmpdisk/default-command.sh.in b/plugins/tmpdisk/default-command.sh.in > new file mode 100644 > index 00000000..251e0b7b > --- /dev/null > +++ b/plugins/tmpdisk/default-command.sh.in > @@ -0,0 +1,51 @@ > +# nbdkit > +# -*- mode: shell-script -*- > +# Copyright (C) 2017-2020 Red Hat Inc. > +# > +# 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. > + > +labelopt='-L' > + > +case "$type" in > + ext?) > + extra='-F' ;; > + *fat|msdos) > + extra='-I' ;; > + ntfs) > + extra='-Q -F' > + labelopt='-n' ;; > + xfs) > + extra='-f' ;; > +esac > + > +if [ "x$label" = "x" ]; then > + mkfs -t "$type" $extra "$disk" > +else > + mkfs -t "$type" $extra $labelopt "$label" "$disk" > +fi > diff --git a/.gitignore b/.gitignore > index 4bb035e1..c44fb40d 100644 > --- a/.gitignore > +++ b/.gitignore > @@ -76,6 +76,7 @@ plugins/*/*.3 > /plugins/rust/Cargo.toml > /plugins/rust/target > /plugins/tar/nbdkit-tar-plugin > +/plugins/tmpdisk/default-command.c > /podwrapper.pl > /server/nbdkit > /server/nbdkit.pc > -- > 2.25.0 > > _______________________________________________ > Libguestfs mailing list > Libguestfs@redhat.com > https://www.redhat.com/mailman/listinfo/libguestfs-- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 100 libraries supported. http://fedoraproject.org/wiki/MinGW
Reasonably Related Threads
- [PATCH nbdkit v2] tmpdisk: Pass any parameters as shell variables to the command.
- [PATCH nbdkit v3] tmpdisk: Pass any parameters as shell variables to the command.
- [PATCH nbdkit v2] New tmpdisk plugin.
- Re: [PATCH nbdkit v2] New tmpdisk plugin.
- [PATCH nbdkit v2] tmpdisk: Generalize the tmpdisk plugin