On 22.08.19 21:01, Nir Soffer wrote:
...
> > > @@ -1794,6 +1815,8 @@ static int handle_aiocb_truncate(void
> *opaque)
> > > /* posix_fallocate() doesn't set errno. */
> > > error_setg_errno(errp, -result,
> > > "Could not preallocate new
> data");
> > > + } else if (current_length == 0) {
> > > + allocate_first_block(fd);
> >
> > Should posix_fallocate() not take care of precisely this?
> >
> >
> > Only if the filesystem does not support fallocate() (e.g. NFS < 4.2).
> >
> > In this case posix_fallocate() is doing:
> >
> > for (offset += (len - 1) % increment; len > 0; offset += increment)
> > {
> > len -= increment;
> > if (offset < st.st_size)
> > {
> > unsigned char c;
> > ssize_t rsize = __pread (fd, &c, 1, offset);
> > if (rsize < 0)
> > return errno;
> > /* If there is a non-zero byte, the block must have been
> > allocated already. */
> > else if (rsize == 1 && c != 0)
> > continue;
> > }
> > if (__pwrite (fd, "", 1, offset) != 1)
> > return errno;
> > }
> >
> >
> https://code.woboq.org/userspace/glibc/sysdeps/posix/posix_fallocate.c.html#96
> >
> > So opening a file with O_DIRECT will break preallocation=falloc on
> such
> > filesystems,
>
> But won’t the function above just fail with EINVAL?
> allocate_first_block() is executed only in case of success.
>
>
> Sure, but if posix_fallocate() fails, we fail qemu-img create/convert.
Exactly. But if posix_fallocate() works, it should have allocated the
first block.
Only if the file system does not support fallocate(). posix_fallocate() first try
fallocate(), and fall back to manual preallocation:
Here is an example using fallocate --posix:
$ sudo mount -t glusterfs gluster1:/gv0 /tmp/gv0
(gv0 is gluster volume backed by XFS on top of VDO device with 4k sector size)
$ fallocate -l 1g --posix empty.raw
$ dd if=empty.raw bs=1 count=1 of=/dev/null iflag=direct status=none
$ dd if=/dev/zero bs=1 count=1 of=empty.raw conv=notrunc status=none
$ dd if=empty.raw bs=1 count=1 of=/dev/null iflag=direct status=none
dd: error reading 'empty.raw': Invalid argument
$ dd if=empty.raw bs=512 count=1 of=/dev/null iflag=direct status=none
dd: error reading 'empty.raw': Invalid argument
$ dd if=empty.raw bs=4096 count=1 of=/dev/null iflag=direct status=none
Here is example using gluster storage with sector size of 512 bytes.
$ sudo mount -t glusterfs gluster1:/gv1 /tmp/gv1
$ fallocate -l 1g --posix empty.raw
$ dd if=empty.raw bs=1 count=1 of=/dev/null iflag=direct status=none
$ dd if=/dev/zero bs=1 count=1 of=empty.raw conv=notrunc status=none
$ dd if=empty.raw bs=1 count=1 of=/dev/null iflag=direct status=none
dd: error reading 'empty.raw': Invalid argument
$ dd if=empty.raw bs=512 count=1 of=/dev/null iflag=direct status=none
So we must allocated using write() after calling posix_fallocate().
Nir