Commit 9f63b07e authored by Max Reitz's avatar Max Reitz
Browse files

block/file-posix: Extract raw_regular_truncate()



This functionality is part of raw_create() which we will be able to
reuse nicely in raw_truncate().

Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
Reviewed-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: default avatarPhilippe Mathieu-Daudé <f4bug@amsat.org>
Message-id: 20170613202107.10125-7-mreitz@redhat.com
Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
parent 7dacd8bd
Loading
Loading
Loading
Loading
+78 −66
Original line number Diff line number Diff line
@@ -1624,6 +1624,81 @@ static void raw_close(BlockDriverState *bs)
    }
}

static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc,
                                Error **errp)
{
    int result = 0;
    char *buf;

    switch (prealloc) {
#ifdef CONFIG_POSIX_FALLOCATE
    case PREALLOC_MODE_FALLOC:
        /*
         * Truncating before posix_fallocate() makes it about twice slower on
         * file systems that do not support fallocate(), trying to check if a
         * block is allocated before allocating it, so don't do that here.
         */
        result = -posix_fallocate(fd, 0, offset);
        if (result != 0) {
            /* posix_fallocate() doesn't set errno. */
            error_setg_errno(errp, -result,
                             "Could not preallocate data for the new file");
        }
        return result;
#endif
    case PREALLOC_MODE_FULL:
    {
        int64_t num = 0, left = offset;

        /*
         * Knowing the final size from the beginning could allow the file
         * system driver to do less allocations and possibly avoid
         * fragmentation of the file.
         */
        if (ftruncate(fd, offset) != 0) {
            result = -errno;
            error_setg_errno(errp, -result, "Could not resize file");
            return result;
        }

        buf = g_malloc0(65536);

        while (left > 0) {
            num = MIN(left, 65536);
            result = write(fd, buf, num);
            if (result < 0) {
                result = -errno;
                error_setg_errno(errp, -result,
                                 "Could not write to the new file");
                break;
            }
            left -= result;
        }
        if (result >= 0) {
            result = fsync(fd);
            if (result < 0) {
                result = -errno;
                error_setg_errno(errp, -result,
                                 "Could not flush new file to disk");
            }
        }
        g_free(buf);
        return result;
    }
    case PREALLOC_MODE_OFF:
        if (ftruncate(fd, offset) != 0) {
            result = -errno;
            error_setg_errno(errp, -result, "Could not resize file");
        }
        return result;
    default:
        result = -ENOTSUP;
        error_setg(errp, "Unsupported preallocation mode: %s",
                   PreallocMode_lookup[prealloc]);
        return result;
    }
}

static int raw_truncate(BlockDriverState *bs, int64_t offset,
                        PreallocMode prealloc, Error **errp)
{
@@ -1892,72 +1967,9 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
#endif
    }

    switch (prealloc) {
#ifdef CONFIG_POSIX_FALLOCATE
    case PREALLOC_MODE_FALLOC:
        /*
         * Truncating before posix_fallocate() makes it about twice slower on
         * file systems that do not support fallocate(), trying to check if a
         * block is allocated before allocating it, so don't do that here.
         */
        result = -posix_fallocate(fd, 0, total_size);
        if (result != 0) {
            /* posix_fallocate() doesn't set errno. */
            error_setg_errno(errp, -result,
                             "Could not preallocate data for the new file");
        }
        break;
#endif
    case PREALLOC_MODE_FULL:
    {
        int64_t num = 0, left = total_size;

        /*
         * Knowing the final size from the beginning could allow the file
         * system driver to do less allocations and possibly avoid
         * fragmentation of the file.
         */
        if (ftruncate(fd, total_size) != 0) {
            result = -errno;
            error_setg_errno(errp, -result, "Could not resize file");
            goto out_close;
        }

        buf = g_malloc0(65536);

        while (left > 0) {
            num = MIN(left, 65536);
            result = write(fd, buf, num);
    result = raw_regular_truncate(fd, total_size, prealloc, errp);
    if (result < 0) {
                result = -errno;
                error_setg_errno(errp, -result,
                                 "Could not write to the new file");
                break;
            }
            left -= result;
        }
        if (result >= 0) {
            result = fsync(fd);
            if (result < 0) {
                result = -errno;
                error_setg_errno(errp, -result,
                                 "Could not flush new file to disk");
            }
        }
        g_free(buf);
        break;
    }
    case PREALLOC_MODE_OFF:
        if (ftruncate(fd, total_size) != 0) {
            result = -errno;
            error_setg_errno(errp, -result, "Could not resize file");
        }
        break;
    default:
        result = -ENOTSUP;
        error_setg(errp, "Unsupported preallocation mode: %s",
                   PreallocMode_lookup[prealloc]);
        break;
        goto out_close;
    }

out_close: