On 02/21/22 23:00, Eric Blake wrote:
We were previously enforcing minimum block size with EINVAL for
too-small requests. Advertise this to the client.
---
filters/swab/nbdkit-swab-filter.pod | 6 ++++++
filters/swab/swab.c | 24 +++++++++++++++++++++++-
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/filters/swab/nbdkit-swab-filter.pod b/filters/swab/nbdkit-swab-filter.pod
index f8500150..030a0852 100644
--- a/filters/swab/nbdkit-swab-filter.pod
+++ b/filters/swab/nbdkit-swab-filter.pod
@@ -34,6 +34,11 @@ the last few bytes, combine this filter with
L<nbdkit-truncate-filter(1)>; fortunately, sector-based disk images
are already suitably sized.
+Note that this filter fails operations that are not aligned to the
+swab-bits boundaries; if you need byte-level access, apply the
+L<nbdkit-blocksize-filter(1)> before this one, to get
+read-modify-write access to individual bytes.
+
=head1 PARAMETERS
I understand that the alignment of requests is enforced, but what
happens if the client sends a request (correctly aligned) that is 17
bytes in size, for example?
... Aha, so is_aligned() doesn't only check "offset", it also checks
"count". That wasn't clear to me from the addition to
"filters/swab/nbdkit-swab-filter.pod". I suggest spelling that out more
explicitly.
=over 4
@@ -90,6 +95,7 @@ L<nbdkit(1)>,
L<nbdkit-file-plugin(1)>,
L<nbdkit-pattern-plugin(1)>,
L<nbdkit-filter(3)>,
+L<nbdkit-blocksize-filter(1)>.
L<nbdkit-truncate-filter(1)>.
=head1 AUTHORS
diff --git a/filters/swab/swab.c b/filters/swab/swab.c
index 68776eee..6e8dc981 100644
--- a/filters/swab/swab.c
+++ b/filters/swab/swab.c
@@ -44,6 +44,7 @@
#include "byte-swapping.h"
#include "isaligned.h"
#include "cleanup.h"
+#include "minmax.h"
#include "rounding.h"
/* Can only be 8 (filter disabled), 16, 32 or 64. */
@@ -85,8 +86,28 @@ swab_get_size (nbdkit_next *next,
return ROUND_DOWN (size, bits/8);
}
+/* Block size constraints. */
+static int
+swab_block_size (nbdkit_next *next, void *handle,
+ uint32_t *minimum, uint32_t *preferred, uint32_t *maximum)
+{
+ if (next->block_size (next, minimum, preferred, maximum) == -1)
+ return -1;
+
+ if (*minimum == 0) { /* No constraints set by the plugin. */
+ *minimum = bits/8;
+ *preferred = 512;
+ *maximum = 0xffffffff;
+ }
+ else {
+ *minimum = MAX (*minimum, bits/8);
+ }
Given that the count too must be a whole multiple of the swap-block size
(correctly so), what if the underlying plugin specifies a minimum block
size of 17?
I think that will take effect here, and then this filter will specify
such a minimum block size (17) that it will, in turn, reject
unconditionally. That kind of defeats the purpose of exposing a "minimum
block size".
Wouldn't it be better if, on the "else" branch, we rounded up
"*minimum"?
*minimum = ROUND_UP (*minimum, bits/8);
Thanks,
Laszlo
+
+ return 0;
+}
+
/* The request must be aligned.
- * XXX We could lift this restriction with more work.
+ * If you want finer alignment, use the blocksize filter.
*/
static bool
is_aligned (uint32_t count, uint64_t offset, int *err)
@@ -220,6 +241,7 @@ static struct nbdkit_filter filter = {
.config = swab_config,
.config_help = swab_config_help,
.get_size = swab_get_size,
+ .block_size = swab_block_size,
.pread = swab_pread,
.pwrite = swab_pwrite,
.trim = swab_trim,