After a retry, if the second connection has fewer permissions than the first, but we blindly call next_ops->FOO, we end up triggering an assertion failure in backend.c. This is particularly noticeable when the force_readonly flag is in effect, as that makes it much easier for there to be fewer permissions than before.
Add testsuite coverage of pwrite to demonstrate. Signed-off-by: Eric Blake <[email protected]> --- filters/retry/retry.c | 58 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/filters/retry/retry.c b/filters/retry/retry.c index 59e7d4b8..00dbd091 100644 --- a/filters/retry/retry.c +++ b/filters/retry/retry.c @@ -106,6 +106,7 @@ retry_config (nbdkit_next_config *next, void *nxdata, struct retry_handle { int readonly; /* Save original readonly setting. */ + unsigned reopens; }; static void * @@ -123,6 +124,7 @@ retry_open (nbdkit_next_open *next, void *nxdata, int readonly) } h->readonly = readonly; + h->reopens = 0; return h; } @@ -132,6 +134,7 @@ retry_close (void *handle) { struct retry_handle *h = handle; + nbdkit_debug ("reopens needed: %u", h->reopens); free (h); } @@ -179,6 +182,7 @@ do_retry (struct retry_handle *h, data->delay *= 2; /* Reopen the connection. */ + h->reopens++; if (next_ops->reopen (nxdata, h->readonly || force_readonly) == -1) { /* If the reopen fails we treat it the same way as a command * failing. @@ -218,7 +222,16 @@ retry_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, int r; again: - r = next_ops->pwrite (nxdata, buf, count, offset, flags, err); + if (h->reopens && force_readonly) { + *err = EROFS; + return -1; + } + if (next_ops->can_write (nxdata) != 1) { + *err = EROFS; + r = -1; + } + else + r = next_ops->pwrite (nxdata, buf, count, offset, flags, err); if (r == -1 && do_retry (h, &data, next_ops, nxdata, err)) goto again; return r; @@ -236,7 +249,16 @@ retry_trim (struct nbdkit_next_ops *next_ops, void *nxdata, int r; again: - r = next_ops->trim (nxdata, count, offset, flags, err); + if (h->reopens && force_readonly) { + *err = EROFS; + return -1; + } + if (next_ops->can_trim (nxdata) != 1) { + *err = EROFS; + r = -1; + } + else + r = next_ops->trim (nxdata, count, offset, flags, err); if (r == -1 && do_retry (h, &data, next_ops, nxdata, err)) goto again; return r; @@ -253,7 +275,12 @@ retry_flush (struct nbdkit_next_ops *next_ops, void *nxdata, int r; again: - r = next_ops->flush (nxdata, flags, err); + if (next_ops->can_flush (nxdata) != 1) { + *err = EIO; + r = -1; + } + else + r = next_ops->flush (nxdata, flags, err); if (r == -1 && do_retry (h, &data, next_ops, nxdata, err)) goto again; return r; @@ -271,7 +298,16 @@ retry_zero (struct nbdkit_next_ops *next_ops, void *nxdata, int r; again: - r = next_ops->zero (nxdata, count, offset, flags, err); + if (h->reopens && force_readonly) { + *err = EROFS; + return -1; + } + if (next_ops->can_zero (nxdata) < NBDKIT_ZERO_EMULATE) { + *err = EROFS; + r = -1; + } + else + r = next_ops->zero (nxdata, count, offset, flags, err); if (r == -1 && do_retry (h, &data, next_ops, nxdata, err)) goto again; return r; @@ -289,7 +325,12 @@ retry_extents (struct nbdkit_next_ops *next_ops, void *nxdata, int r; again: - r = next_ops->extents (nxdata, count, offset, flags, extents, err); + if (next_ops->can_extents (nxdata) != 1) { + *err = EIO; + r = -1; + } + else + r = next_ops->extents (nxdata, count, offset, flags, extents, err); if (r == -1 && do_retry (h, &data, next_ops, nxdata, err)) goto again; return r; @@ -307,7 +348,12 @@ retry_cache (struct nbdkit_next_ops *next_ops, void *nxdata, int r; again: - r = next_ops->cache (nxdata, count, offset, flags, err); + if (next_ops->can_cache (nxdata) != 1) { + *err = EIO; + r = -1; + } + else + r = next_ops->cache (nxdata, count, offset, flags, err); if (r == -1 && do_retry (h, &data, next_ops, nxdata, err)) goto again; return r; -- 2.21.0 _______________________________________________ Libguestfs mailing list [email protected] https://www.redhat.com/mailman/listinfo/libguestfs
