Commit 292d06b9 authored by Max Reitz's avatar Max Reitz
Browse files

block/file-posix: Let post-EOF fallocate serialize



The XFS kernel driver has a bug that may cause data corruption for qcow2
images as of qemu commit c8bb23cb.  We can work around it by
treating post-EOF fallocates as serializing up until infinity (INT64_MAX
in practice).

Cc: qemu-stable@nongnu.org
Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
Message-id: 20191101152510.11719-4-mreitz@redhat.com
Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
parent c28107e9
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -2721,6 +2721,42 @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
    RawPosixAIOData acb;
    ThreadPoolFunc *handler;

#ifdef CONFIG_FALLOCATE
    if (offset + bytes > bs->total_sectors * BDRV_SECTOR_SIZE) {
        BdrvTrackedRequest *req;
        uint64_t end;

        /*
         * This is a workaround for a bug in the Linux XFS driver,
         * where writes submitted through the AIO interface will be
         * discarded if they happen beyond a concurrently running
         * fallocate() that increases the file length (i.e., both the
         * write and the fallocate() happen beyond the EOF).
         *
         * To work around it, we extend the tracked request for this
         * zero write until INT64_MAX (effectively infinity), and mark
         * it as serializing.
         *
         * We have to enable this workaround for all filesystems and
         * AIO modes (not just XFS with aio=native), because for
         * remote filesystems we do not know the host configuration.
         */

        req = bdrv_co_get_self_request(bs);
        assert(req);
        assert(req->type == BDRV_TRACKED_WRITE);
        assert(req->offset <= offset);
        assert(req->offset + req->bytes >= offset + bytes);

        end = INT64_MAX & -(uint64_t)bs->bl.request_alignment;
        req->bytes = end - req->offset;
        req->overlap_bytes = req->bytes;

        bdrv_mark_request_serialising(req, bs->bl.request_alignment);
        bdrv_wait_serialising_requests(req);
    }
#endif

    acb = (RawPosixAIOData) {
        .bs             = bs,
        .aio_fildes     = s->fd,