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