[Libguestfs] [nbdkit PATCH 0/3] Make ext2 a filter

Eric Blake eblake at redhat.com
Wed Feb 12 02:18:59 UTC 2020


I'm impressed that I was able to whip this out in just one day of
hacking.  Below, I'll include a diff between the plugin and the
filter as of patch 1, if it aids review.

Eric Blake (3):
  filters: Add ext2 filter
  ext2: Deprecate ext2 plugin
  ext2: Add mode for letting client exportname choose file from image

 TODO                                |   5 -
 configure.ac                        |   8 +-
 filters/ext2/Makefile.am            |  75 +++++
 filters/ext2/ext2.c                 | 415 +++++++++++++++++++++++++
 filters/ext2/io.c                   | 466 ++++++++++++++++++++++++++++
 filters/ext2/io.h                   |  57 ++++
 filters/ext2/nbdkit-ext2-filter.pod | 102 ++++++
 plugins/ext2/nbdkit-ext2-plugin.pod |  12 +-
 tests/Makefile.am                   |   2 +-
 tests/test-ext2.c                   |  28 +-
 10 files changed, 1153 insertions(+), 17 deletions(-)
 create mode 100644 filters/ext2/Makefile.am
 create mode 100644 filters/ext2/ext2.c
 create mode 100644 filters/ext2/io.c
 create mode 100644 filters/ext2/io.h
 create mode 100644 filters/ext2/nbdkit-ext2-filter.pod

 {plugins => filters}/ext2/ext2.c | 173 ++++++++++++++++++++++++---------------
 1 file changed, 105 insertions(+), 68 deletions(-)
diff --git a/plugins/ext2/ext2.c b/filters/ext2/ext2.c
index 6698d99f..d53743cd 100644
--- a/plugins/ext2/ext2.c
+++ b/filters/ext2/ext2.c
@@ -1,5 +1,5 @@
 /* nbdkit
- * Copyright (C) 2017-2019 Red Hat Inc.
+ * 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
@@ -35,6 +35,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <inttypes.h>
+#include <errno.h>

 /* Inlining is broken in the ext2fs header file.  Disable it by
  * defining the following:
@@ -44,10 +45,12 @@

 #define NBDKIT_API_VERSION 2

-#include <nbdkit-plugin.h>
+#include <nbdkit-filter.h>

-/* Disk image and filename parameters. */
-static char *disk;
+#include "cleanup.h"
+#include "io.h"
+
+/* Filename parameter. */
 static char *file;

 static void
@@ -59,25 +62,16 @@ ext2_load (void)
 static void
 ext2_unload (void)
 {
-  free (disk);
   free (file);
 }

 static int
-ext2_config (const char *key, const char *value)
+ext2_config (nbdkit_next_config *next, void *nxdata,
+             const char *key, const char *value)
 {
-  if (strcmp (key, "disk") == 0) {
-    if (disk != NULL) {
-      nbdkit_error ("disk parameter specified more than once");
-      return -1;
-    }
-    disk = nbdkit_absolute_path (value);
-    if (disk == NULL)
-      return -1;
-  }
-  else if (strcmp (key, "file") == 0) {
+  if (strcmp (key, "ext2file") == 0) {
     if (file != NULL) {
-      nbdkit_error ("file parameter specified more than once");
+      nbdkit_error ("ext2file parameter specified more than once");
       return -1;
     }
     file = strdup (value);
@@ -85,20 +79,17 @@ ext2_config (const char *key, const char *value)
       nbdkit_error ("strdup: %m");
       return -1;
     }
+    return 0;
   }
-  else {
-    nbdkit_error ("unknown parameter '%s'", key);
-    return -1;
-  }
-
-  return 0;
+  else
+    return next (nxdata, key, value);
 }

 static int
-ext2_config_complete (void)
+ext2_config_complete (nbdkit_next_config_complete *next, void *nxdata)
 {
-  if (disk == NULL || file == NULL) {
-    nbdkit_error ("you must supply disk=<DISK> and file=<FILE> parameters "
+  if (file == NULL) {
+    nbdkit_error ("you must supply ext2file=<FILE> parameter "
                   "after the plugin name on the command line");
     return -1;
   }
@@ -108,46 +99,78 @@ ext2_config_complete (void)
     return -1;
   }

-  return 0;
+  return next (nxdata);
 }

 #define ext2_config_help \
-  "disk=<FILENAME>  (required) Raw ext2, ext3 or ext4 filesystem.\n" \
-  "file=<FILENAME>  (required) File to serve inside the disk image."
+  "ext2file=<FILENAME>  (required) File to serve inside the disk image."

 /* The per-connection handle. */
 struct handle {
   ext2_filsys fs;               /* Filesystem handle. */
   ext2_ino_t ino;               /* Inode of open file. */
   ext2_file_t file;             /* File handle. */
+  struct nbdkit_next next;      /* "name" parameter to ext2fs_open. */
 };

 /* Create the per-connection handle. */
 static void *
-ext2_open (int readonly)
+ext2_open (nbdkit_next_open *next, void *nxdata, int readonly)
 {
   struct handle *h;
+
+  /* Request write access to the underlying plugin, for journal replay. */
+  if (next (nxdata, 0) == -1)
+    return NULL;
+
+  h = calloc (1, sizeof *h);
+  if (h == NULL) {
+    nbdkit_error ("calloc: %m");
+    return NULL;
+  }
+
+  return h;
+}
+
+static int
+ext2_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle,
+              int readonly)
+{
+  struct handle *h = handle;
   errcode_t err;
   int fs_flags;
   int file_flags;
   struct ext2_inode inode;
-
-  h = malloc (sizeof *h);
-  if (h == NULL) {
-    nbdkit_error ("malloc: %m");
-    return NULL;
-  }
+  int64_t r;
+  CLEANUP_FREE char *name = NULL;

   fs_flags = 0;
 #ifdef EXT2_FLAG_64BITS
   fs_flags |= EXT2_FLAG_64BITS;
 #endif
+  r = next_ops->get_size (nxdata);
+  if (r == -1)
+    return -1;
+  r = next_ops->can_write (nxdata);
+  if (r == -1)
+    return -1;
+  if (r == 0)
+    readonly = 1;
+
   if (!readonly)
     fs_flags |= EXT2_FLAG_RW;

-  err = ext2fs_open (disk, fs_flags, 0, 0, unix_io_manager, &h->fs);
+  h->next.next_ops = next_ops;
+  h->next.nxdata = nxdata;
+  name = nbdkit_io_encode (&h->next);
+  if (!name) {
+    nbdkit_error ("nbdkit_io_encode: %m");
+    return -1;
+  }
+
+  err = ext2fs_open (name, fs_flags, 0, 0, nbdkit_io_manager, &h->fs);
   if (err != 0) {
-    nbdkit_error ("%s: open: %s", disk, error_message (err));
+    nbdkit_error ("open: %s", error_message (err));
     goto err0;
   }

@@ -158,7 +181,7 @@ ext2_open (int readonly)
     err = ext2fs_namei (h->fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
                         &file[1], &h->ino);
     if (err != 0) {
-      nbdkit_error ("%s: %s: namei: %s", disk, file, error_message (err));
+      nbdkit_error ("%s: namei: %s", file, error_message (err));
       goto err1;
     }
   }
@@ -168,12 +191,11 @@ ext2_open (int readonly)
    */
   err = ext2fs_read_inode (h->fs, h->ino, &inode);
   if (err != 0) {
-    nbdkit_error ("%s: %s: inode: %s", disk, file, error_message (err));
+    nbdkit_error ("%s: inode: %s", file, error_message (err));
     goto err1;
   }
   if (!LINUX_S_ISREG (inode.i_mode)) {
-    nbdkit_error ("%s: %s: must be a regular file in the disk image",
-                  disk, file);
+    nbdkit_error ("%s: must be a regular file in the disk image", file);
     goto err1;
   }

@@ -182,17 +204,17 @@ ext2_open (int readonly)
     file_flags |= EXT2_FILE_WRITE;
   err = ext2fs_file_open2 (h->fs, h->ino, NULL, file_flags, &h->file);
   if (err != 0) {
-    nbdkit_error ("%s: %s: open: %s", disk, file, error_message (err));
+    nbdkit_error ("%s: open: %s", file, error_message (err));
     goto err1;
   }

-  return h;
+  return 0;

  err1:
   ext2fs_close (h->fs);
+  h->fs = NULL;
  err0:
-  free (h);
-  return NULL;
+  return -1;
 }

 /* Free up the per-connection handle. */
@@ -201,19 +223,21 @@ ext2_close (void *handle)
 {
   struct handle *h = handle;

-  ext2fs_file_close (h->file);
-  ext2fs_close (h->fs);
+  if (h->fs) {
+    ext2fs_file_close (h->file);
+    ext2fs_close (h->fs);
+  }
   free (h);
 }

 static int
-ext2_can_fua (void *handle)
+ext2_can_fua (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle)
 {
   return NBDKIT_FUA_NATIVE;
 }

 static int
-ext2_can_cache (void *handle)
+ext2_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle)
 {
   /* Let nbdkit call pread to populate the file system cache. */
   return NBDKIT_CACHE_EMULATE;
@@ -231,11 +255,14 @@ ext2_can_cache (void *handle)
  * but if we allowed parallel work on those handles then we would get
  * data corruption, so we need to serialize connections.
  */
-#define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS
+static int ext2_thread_model (void)
+{
+  return NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS;
+}

 /* Get the disk size. */
 static int64_t
-ext2_get_size (void *handle)
+ext2_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle)
 {
   struct handle *h = handle;
   errcode_t err;
@@ -243,7 +270,7 @@ ext2_get_size (void *handle)

   err = ext2fs_file_get_lsize (h->file, (__u64 *) &size);
   if (err != 0) {
-    nbdkit_error ("%s: %s: lsize: %s", disk, file, error_message (err));
+    nbdkit_error ("%s: lsize: %s", file, error_message (err));
     return -1;
   }
   return (int64_t) size;
@@ -251,8 +278,9 @@ ext2_get_size (void *handle)

 /* Read data. */
 static int
-ext2_pread (void *handle, void *buf, uint32_t count, uint64_t offset,
-            uint32_t flags)
+ext2_pread (struct nbdkit_next_ops *next_ops, void *nxdata,
+            void *handle, void *buf, uint32_t count, uint64_t offset,
+            uint32_t flags, int *errp)
 {
   struct handle *h = handle;
   errcode_t err;
@@ -265,13 +293,15 @@ ext2_pread (void *handle, void *buf, uint32_t count, uint64_t offset,
      */
     err = ext2fs_file_llseek (h->file, offset, EXT2_SEEK_SET, NULL);
     if (err != 0) {
-      nbdkit_error ("%s: %s: llseek: %s", disk, file, error_message (err));
+      nbdkit_error ("%s: llseek: %s", file, error_message (err));
+      *errp = errno;
       return -1;
     }

     err = ext2fs_file_read (h->file, buf, (unsigned int) count, &got);
     if (err != 0) {
-      nbdkit_error ("%s: %s: read: %s", disk, file, error_message (err));
+      nbdkit_error ("%s: read: %s", file, error_message (err));
+      *errp = errno;
       return -1;
     }

@@ -285,8 +315,9 @@ ext2_pread (void *handle, void *buf, uint32_t count, uint64_t offset,

 /* Write data to the file. */
 static int
-ext2_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
-             uint32_t flags)
+ext2_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata,
+             void *handle, const void *buf, uint32_t count, uint64_t offset,
+             uint32_t flags, int *errp)
 {
   struct handle *h = handle;
   errcode_t err;
@@ -295,13 +326,15 @@ ext2_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
   while (count > 0) {
     err = ext2fs_file_llseek (h->file, offset, EXT2_SEEK_SET, NULL);
     if (err != 0) {
-      nbdkit_error ("%s: %s: llseek: %s", disk, file, error_message (err));
+      nbdkit_error ("%s: llseek: %s", file, error_message (err));
+      *errp = errno;
       return -1;
     }

     err = ext2fs_file_write (h->file, buf, (unsigned int) count, &written);
     if (err != 0) {
-      nbdkit_error ("%s: %s: write: %s", disk, file, error_message (err));
+      nbdkit_error ("%s: write: %s", file, error_message (err));
+      *errp = errno;
       return -1;
     }

@@ -313,7 +346,8 @@ ext2_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
   if ((flags & NBDKIT_FLAG_FUA) != 0) {
     err = ext2fs_file_flush (h->file);
     if (err != 0) {
-      nbdkit_error ("%s: %s: flush: %s", disk, file, error_message (err));
+      nbdkit_error ("%s: flush: %s", file, error_message (err));
+      *errp = errno;
       return -1;
     }
   }
@@ -322,14 +356,16 @@ ext2_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
 }

 static int
-ext2_flush (void *handle, uint32_t flags)
+ext2_flush (struct nbdkit_next_ops *next_ops, void *nxdata,
+            void *handle, uint32_t flags, int *errp)
 {
   struct handle *h = handle;
   errcode_t err;

   err = ext2fs_file_flush (h->file);
   if (err != 0) {
-    nbdkit_error ("%s: %s: flush: %s", disk, file, error_message (err));
+    nbdkit_error ("%s: flush: %s", file, error_message (err));
+    *errp = errno;
     return -1;
   }

@@ -341,15 +377,17 @@ ext2_flush (void *handle, uint32_t flags)
  * is very obscure.
  */

-static struct nbdkit_plugin plugin = {
+static struct nbdkit_filter filter = {
   .name              = "ext2",
-  .version           = PACKAGE_VERSION,
+  .longname          = "nbdkit ext2 filter",
   .load              = ext2_load,
   .unload            = ext2_unload,
   .config            = ext2_config,
   .config_complete   = ext2_config_complete,
   .config_help       = ext2_config_help,
+  .thread_model      = ext2_thread_model,
   .open              = ext2_open,
+  .prepare           = ext2_prepare,
   .close             = ext2_close,
   .can_fua           = ext2_can_fua,
   .can_cache         = ext2_can_cache,
@@ -357,7 +395,6 @@ static struct nbdkit_plugin plugin = {
   .pread             = ext2_pread,
   .pwrite            = ext2_pwrite,
   .flush             = ext2_flush,
-  .errno_is_preserved = 1,
 };

-NBDKIT_REGISTER_PLUGIN(plugin)
+NBDKIT_REGISTER_FILTER(filter)


-- 
2.24.1




More information about the Libguestfs mailing list