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: Max Reitz <mreitz@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Message-id: 20170613202107.10125-7-mreitz@redhat.com Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
parent
7dacd8bd3d
commit
9f63b07ee7
|
@ -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,
|
static int raw_truncate(BlockDriverState *bs, int64_t offset,
|
||||||
PreallocMode prealloc, Error **errp)
|
PreallocMode prealloc, Error **errp)
|
||||||
{
|
{
|
||||||
|
@ -1892,72 +1967,9 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (prealloc) {
|
result = raw_regular_truncate(fd, total_size, prealloc, errp);
|
||||||
#ifdef CONFIG_POSIX_FALLOCATE
|
if (result < 0) {
|
||||||
case PREALLOC_MODE_FALLOC:
|
goto out_close;
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out_close:
|
out_close:
|
||||||
|
|
Loading…
Reference in New Issue