We already have support in the file driver for punching holes
during .zero with the may_trim flag (via FALLOC_FL_PUNCH_HOLE),
so we should use the same mechanism to support .trim. Note that
the NBD spec says that trim is advisory (we can return success
even if we did nothing); but at the same time, it's nicer to
avoid advertising the feature if we know for sure we can't do
it, so we also need .can_trim. Note that there's still an
element of runtime behavior, as FALLOC_FL_PUNCH_HOLE doesn't
work on all filesystems; there we fall back on the NBD
protocol allowing us to be advisory for all but a handful of
errno values that we can directly report back over NBD.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
I couldn't test --filter=log results on trim commands without
at least one plugin that supports trim ;)
plugins/file/file.c | 47 ++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 44 insertions(+), 3 deletions(-)
diff --git a/plugins/file/file.c b/plugins/file/file.c
index 1fe4191..081848b 100644
--- a/plugins/file/file.c
+++ b/plugins/file/file.c
@@ -1,5 +1,5 @@
/* nbdkit
- * Copyright (C) 2013 Red Hat Inc.
+ * Copyright (C) 2013-2018 Red Hat Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -175,6 +175,18 @@ file_get_size (void *handle)
return statbuf.st_size;
}
+static int
+file_can_trim (void *handle)
+{
+ /* Trim is advisory, but we prefer to advertise it only when we can
+ * actually (attempt to) punch holes. */
+#ifdef FALLOC_FL_PUNCH_HOLE
+ return 1;
+#else
+ return 0;
+#endif
+}
+
/* Read data from the file. */
static int
file_pread (void *handle, void *buf, uint32_t count, uint64_t offset)
@@ -219,7 +231,7 @@ file_pwrite (void *handle, const void *buf, uint32_t count, uint64_t
offset)
return 0;
}
-/* Write data to the file. */
+/* Write zeroes to the file. */
static int
file_zero (void *handle, uint32_t count, uint64_t offset, int may_trim)
{
@@ -268,6 +280,33 @@ file_flush (void *handle)
return 0;
}
+/* Punch a hole in the file. */
+static int
+file_trim (void *handle, uint32_t count, uint64_t offset)
+{
+ int r = -1;
+#ifdef FALLOC_FL_PUNCH_HOLE
+ struct handle *h = handle;
+
+ /* Trim is advisory; we don't care if it fails for anything other
+ * than EIO or EPERM. */
+ r = fallocate (h->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ offset, count);
+ if (r < 0) {
+ if (errno != EPERM && errno != EIO) {
+ nbdkit_debug ("ignoring failed fallocate during trim: %m");
+ r = 0;
+ }
+ else
+ nbdkit_error ("fallocate: %m");
+ }
+#else
+ /* Based on .can_trim, this should not be reached. */
+ errno = EOPNOTSUPP;
+#endif
+ return r;
+}
+
static struct nbdkit_plugin plugin = {
.name = "file",
.longname = "nbdkit file plugin",
@@ -279,10 +318,12 @@ static struct nbdkit_plugin plugin = {
.open = file_open,
.close = file_close,
.get_size = file_get_size,
+ .can_trim = file_can_trim,
.pread = file_pread,
.pwrite = file_pwrite,
- .zero = file_zero,
.flush = file_flush,
+ .trim = file_trim,
+ .zero = file_zero,
.errno_is_preserved = 1,
};
--
2.14.3