On 1/30/19 8:36 AM, Richard W.M. Jones wrote:
 Using ‘nbdkit --filter=xz file disk.xz’ and loop mounting eventually
 results in this error:
 
 nbdkit: file[1]: debug: xz: pwrite count=4096 offset=1048576 flags=0x0
 nbdkit: file[1]: debug: pwrite count=4096 offset=1048576 fua=0
 nbdkit: file[1]: error: pwrite: Bad file descriptor
 nbdkit: file[1]: debug: sending error reply: Bad file descriptor
 
 Since the filter did not intercept can_write, it was passed through to
 the layer below (the file plugin).  The filter opens the file plugin
 passing readonly=1, but in the case where there are no filters, nbdkit
 core would never call can_write() (assuming that because we opened the
 server readonly, it would return false).  However with the filter,
 can_write is called and returns the default (true).  This caused
 writes to be generated which were also passed through to the plugin
 which generates "Bad file descriptor" because:
 
  EBADF  fd is not a valid file descriptor or is not open for writing.
 
 This change also disables zero and trim because the server logic
 disables those when the top backend->can_write returns false. 
ACK.
 ---
  filters/xz/xz.c | 8 ++++++++
  1 file changed, 8 insertions(+)
 
 diff --git a/filters/xz/xz.c b/filters/xz/xz.c
 index 28a6a81..5ff791e 100644
 --- a/filters/xz/xz.c
 +++ b/filters/xz/xz.c
 @@ -173,6 +173,13 @@ xz_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, void
*handle)
    return xzfile_get_size (h->xz);
  }
  
 +static int
 +xz_can_write (struct nbdkit_next_ops *next_ops, void *nxdata,
 +              void *handle) 
Perhaps worth a comment in the code, similar to cow.c's comment about
the override returning a constant because the filter enforces a
particular behavior that might be different from the backend's default
behavior.
 +{
 +  return 0;
 +}
 +
  /* Read data from the file. */
  static int
  xz_pread (struct nbdkit_next_ops *next_ops, void *nxdata,
 @@ -225,6 +232,7 @@ static struct nbdkit_filter filter = {
    .close             = xz_close,
    .prepare           = xz_prepare,
    .get_size          = xz_get_size,
 +  .can_write         = xz_can_write,
    .pread             = xz_pread,
  };
  
  
-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  
qemu.org | 
libvirt.org