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,
|
||||
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);
|
||||
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;
|
||||
result = raw_regular_truncate(fd, total_size, prealloc, errp);
|
||||
if (result < 0) {
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
out_close:
|
||||
|
Loading…
Reference in New Issue
Block a user