mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-23 11:52:20 +00:00
storage: Move most of the FS creation functions to common backend.
These will be used by other pool cloning implementations.
This commit is contained in:
parent
1b16bf4ec7
commit
6d7d465a04
@ -95,6 +95,419 @@ static virStorageBackendPtr backends[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static int track_allocation_progress = 0;
|
||||
|
||||
enum {
|
||||
TOOL_QEMU_IMG,
|
||||
TOOL_KVM_IMG,
|
||||
TOOL_QCOW_CREATE,
|
||||
};
|
||||
|
||||
int
|
||||
virStorageBackendCreateRaw(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
virStorageVolDefPtr inputvol)
|
||||
{
|
||||
int fd = -1;
|
||||
int inputfd = -1;
|
||||
int ret = -1;
|
||||
unsigned long long remain;
|
||||
char *buf = NULL;
|
||||
|
||||
if ((fd = open(vol->target.path, O_RDWR | O_CREAT | O_EXCL,
|
||||
vol->target.perms.mode)) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("cannot create path '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (inputvol) {
|
||||
if ((inputfd = open(inputvol->target.path, O_RDONLY)) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("could not open input path '%s'"),
|
||||
inputvol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Seek to the final size, so the capacity is available upfront
|
||||
* for progress reporting */
|
||||
if (ftruncate(fd, vol->capacity) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("cannot extend file '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
remain = vol->allocation;
|
||||
|
||||
if (inputfd != -1) {
|
||||
int amtread = -1;
|
||||
size_t bytes = 1024 * 1024;
|
||||
char zerobuf[512];
|
||||
|
||||
bzero(&zerobuf, sizeof(zerobuf));
|
||||
|
||||
if (VIR_ALLOC_N(buf, bytes) < 0) {
|
||||
virReportOOMError(conn);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (amtread != 0) {
|
||||
int amtleft;
|
||||
|
||||
if (remain < bytes)
|
||||
bytes = remain;
|
||||
|
||||
if ((amtread = saferead(inputfd, buf, bytes)) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("failed reading from file '%s'"),
|
||||
inputvol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
remain -= amtread;
|
||||
|
||||
/* Loop over amt read in 512 byte increments, looking for sparse
|
||||
* blocks */
|
||||
amtleft = amtread;
|
||||
do {
|
||||
int interval = ((512 > amtleft) ? amtleft : 512);
|
||||
int offset = amtread - amtleft;
|
||||
|
||||
if (memcmp(buf+offset, zerobuf, interval) == 0) {
|
||||
if (lseek(fd, interval, SEEK_CUR) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("cannot extend file '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
} else if (safewrite(fd, buf+offset, interval) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("failed writing to file '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
|
||||
}
|
||||
} while ((amtleft -= 512) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (remain) {
|
||||
if (track_allocation_progress) {
|
||||
|
||||
while (remain) {
|
||||
/* Allocate in chunks of 512MiB: big-enough chunk
|
||||
* size and takes approx. 9s on ext3. A progress
|
||||
* update every 9s is a fair-enough trade-off
|
||||
*/
|
||||
unsigned long long bytes = 512 * 1024 * 1024;
|
||||
int r;
|
||||
|
||||
if (bytes > remain)
|
||||
bytes = remain;
|
||||
if ((r = safezero(fd, 0, vol->allocation - remain,
|
||||
bytes)) != 0) {
|
||||
virReportSystemError(conn, r,
|
||||
_("cannot fill file '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
remain -= bytes;
|
||||
}
|
||||
} else { /* No progress bars to be shown */
|
||||
int r;
|
||||
|
||||
if ((r = safezero(fd, 0, 0, remain)) != 0) {
|
||||
virReportSystemError(conn, r,
|
||||
_("cannot fill file '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (close(fd) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("cannot close file '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
fd = -1;
|
||||
|
||||
if (inputfd != -1 && close(inputfd) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("cannot close file '%s'"),
|
||||
inputvol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
inputfd = -1;
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
if (inputfd != -1)
|
||||
close(inputfd);
|
||||
VIR_FREE(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
virStorageBackendCreateQemuImg(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
virStorageVolDefPtr inputvol)
|
||||
{
|
||||
char size[100];
|
||||
char *create_tool;
|
||||
short use_kvmimg;
|
||||
|
||||
const char *type = virStorageVolFormatFileSystemTypeToString(vol->target.format);
|
||||
const char *backingType = vol->backingStore.path ?
|
||||
virStorageVolFormatFileSystemTypeToString(vol->backingStore.format) : NULL;
|
||||
|
||||
const char *inputBackingPath = (inputvol ? inputvol->backingStore.path
|
||||
: NULL);
|
||||
const char *inputPath = inputvol ? inputvol->target.path : NULL;
|
||||
/* Treat input block devices as 'raw' format */
|
||||
const char *inputType = inputPath ?
|
||||
virStorageVolFormatFileSystemTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ? VIR_STORAGE_VOL_FILE_RAW : inputvol->target.format) :
|
||||
NULL;
|
||||
|
||||
const char **imgargv;
|
||||
const char *imgargvnormal[] = {
|
||||
NULL, "create",
|
||||
"-f", type,
|
||||
vol->target.path,
|
||||
size,
|
||||
NULL,
|
||||
};
|
||||
/* Extra NULL fields are for including "backingType" when using
|
||||
* kvm-img. It's -F backingType
|
||||
*/
|
||||
const char *imgargvbacking[] = {
|
||||
NULL, "create",
|
||||
"-f", type,
|
||||
"-b", vol->backingStore.path,
|
||||
vol->target.path,
|
||||
size,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
const char *convargv[] = {
|
||||
NULL, "convert",
|
||||
"-f", inputType,
|
||||
"-O", type,
|
||||
inputPath,
|
||||
vol->target.path,
|
||||
NULL,
|
||||
};
|
||||
|
||||
if (type == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("unknown storage vol type %d"),
|
||||
vol->target.format);
|
||||
return -1;
|
||||
}
|
||||
if (inputvol && inputType == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("unknown storage vol type %d"),
|
||||
inputvol->target.format);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vol->backingStore.path) {
|
||||
|
||||
/* XXX: Not strictly required: qemu-img has an option a different
|
||||
* backing store, not really sure what use it serves though, and it
|
||||
* may cause issues with lvm. Untested essentially.
|
||||
*/
|
||||
if (inputvol &&
|
||||
(!inputBackingPath ||
|
||||
STRNEQ(inputBackingPath, vol->backingStore.path))) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
"%s", _("a different backing store can not "
|
||||
"be specified."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (backingType == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("unknown storage vol backing store type %d"),
|
||||
vol->backingStore.format);
|
||||
return -1;
|
||||
}
|
||||
if (access(vol->backingStore.path, R_OK) != 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("inaccessible backing store volume %s"),
|
||||
vol->backingStore.path);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((create_tool = virFindFileInPath("kvm-img")) != NULL)
|
||||
use_kvmimg = 1;
|
||||
else if ((create_tool = virFindFileInPath("qemu-img")) != NULL)
|
||||
use_kvmimg = 0;
|
||||
else {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("unable to find kvm-img or qemu-img"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inputvol) {
|
||||
convargv[0] = create_tool;
|
||||
imgargv = convargv;
|
||||
} else if (vol->backingStore.path) {
|
||||
imgargvbacking[0] = create_tool;
|
||||
if (use_kvmimg) {
|
||||
imgargvbacking[6] = "-F";
|
||||
imgargvbacking[7] = backingType;
|
||||
imgargvbacking[8] = vol->target.path;
|
||||
imgargvbacking[9] = size;
|
||||
}
|
||||
imgargv = imgargvbacking;
|
||||
} else {
|
||||
imgargvnormal[0] = create_tool;
|
||||
imgargv = imgargvnormal;
|
||||
}
|
||||
|
||||
|
||||
/* Size in KB */
|
||||
snprintf(size, sizeof(size), "%llu", vol->capacity/1024);
|
||||
|
||||
if (virRun(conn, imgargv, NULL) < 0) {
|
||||
VIR_FREE(imgargv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
VIR_FREE(imgargv[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Xen removed the fully-functional qemu-img, and replaced it
|
||||
* with a partially functional qcow-create. Go figure ??!?
|
||||
*/
|
||||
static int
|
||||
virStorageBackendCreateQcowCreate(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
virStorageVolDefPtr inputvol)
|
||||
{
|
||||
char size[100];
|
||||
const char *imgargv[4];
|
||||
|
||||
if (inputvol) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
"%s",
|
||||
_("cannot copy from volume with qcow-create"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vol->target.format != VIR_STORAGE_VOL_FILE_QCOW2) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("unsupported storage vol type %d"),
|
||||
vol->target.format);
|
||||
return -1;
|
||||
}
|
||||
if (vol->backingStore.path != NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_NO_SUPPORT,
|
||||
_("copy-on-write image not supported with "
|
||||
"qcow-create"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Size in MB - yes different units to qemu-img :-( */
|
||||
snprintf(size, sizeof(size), "%llu", vol->capacity/1024/1024);
|
||||
|
||||
imgargv[0] = virFindFileInPath("qcow-create");
|
||||
imgargv[1] = size;
|
||||
imgargv[2] = vol->target.path;
|
||||
imgargv[3] = NULL;
|
||||
|
||||
if (virRun(conn, imgargv, NULL) < 0) {
|
||||
VIR_FREE(imgargv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
VIR_FREE(imgargv[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
createFile
|
||||
virStorageBackendFSImageToolTypeToFunc(virConnectPtr conn, int tool_type)
|
||||
{
|
||||
switch (tool_type) {
|
||||
case TOOL_KVM_IMG:
|
||||
case TOOL_QEMU_IMG:
|
||||
return virStorageBackendCreateQemuImg;
|
||||
case TOOL_QCOW_CREATE:
|
||||
return virStorageBackendCreateQcowCreate;
|
||||
default:
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("Unknown file create tool type '%d'."),
|
||||
tool_type);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
virStorageBackendFindFSImageTool(char **tool)
|
||||
{
|
||||
int tool_type = -1;
|
||||
char *tmp = NULL;
|
||||
|
||||
if ((tmp = virFindFileInPath("kvm-img")) != NULL) {
|
||||
tool_type = TOOL_KVM_IMG;
|
||||
} else if ((tmp = virFindFileInPath("qemu-img")) != NULL) {
|
||||
tool_type = TOOL_QEMU_IMG;
|
||||
} else if ((tmp = virFindFileInPath("qcow-create")) != NULL) {
|
||||
tool_type = TOOL_QCOW_CREATE;
|
||||
}
|
||||
|
||||
if (tool)
|
||||
*tool = tmp;
|
||||
else
|
||||
VIR_FREE(tmp);
|
||||
|
||||
return tool_type;
|
||||
}
|
||||
|
||||
createFile
|
||||
virStorageBackendGetBuildVolFromFunction(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
virStorageVolDefPtr inputvol)
|
||||
{
|
||||
int tool_type;
|
||||
|
||||
if (!inputvol)
|
||||
return NULL;
|
||||
|
||||
/* If either volume is a non-raw file vol, we need to use an external
|
||||
* tool for converting
|
||||
*/
|
||||
if ((vol->type == VIR_STORAGE_VOL_FILE &&
|
||||
vol->target.format != VIR_STORAGE_VOL_FILE_RAW) ||
|
||||
(inputvol->type == VIR_STORAGE_VOL_FILE &&
|
||||
inputvol->target.format != VIR_STORAGE_VOL_FILE_RAW)) {
|
||||
|
||||
if ((tool_type = virStorageBackendFindFSImageTool(NULL)) != -1) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
"%s", _("creation of non-raw file images is "
|
||||
"not supported without qemu-img."));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return virStorageBackendFSImageToolTypeToFunc(conn, tool_type);
|
||||
}
|
||||
|
||||
return virStorageBackendCreateRaw;
|
||||
}
|
||||
|
||||
#if defined(UDEVADM) || defined(UDEVSETTLE)
|
||||
void virWaitForDevices(virConnectPtr conn)
|
||||
|
@ -40,6 +40,22 @@ typedef int (*virStorageBackendRefreshVol)(virConnectPtr conn, virStoragePoolObj
|
||||
typedef int (*virStorageBackendDeleteVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, unsigned int flags);
|
||||
typedef int (*virStorageBackendBuildVolFrom)(virConnectPtr conn, virStorageVolDefPtr origvol, virStorageVolDefPtr newvol, unsigned int flags);
|
||||
|
||||
typedef int (*createFile)(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
virStorageVolDefPtr inputvol);
|
||||
|
||||
/* File creation/cloning functions used for cloning between backends */
|
||||
int virStorageBackendCreateRaw(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
virStorageVolDefPtr inputvol);
|
||||
createFile
|
||||
virStorageBackendGetBuildVolFromFunction(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
virStorageVolDefPtr inputvol);
|
||||
int virStorageBackendFindFSImageTool(char **tool);
|
||||
createFile virStorageBackendFSImageToolTypeToFunc(virConnectPtr conn,
|
||||
int tool_type);
|
||||
|
||||
|
||||
typedef struct _virStorageBackend virStorageBackend;
|
||||
typedef virStorageBackend *virStorageBackendPtr;
|
||||
|
@ -55,12 +55,6 @@ enum {
|
||||
BACKING_STORE_ERROR,
|
||||
};
|
||||
|
||||
enum {
|
||||
TOOL_QEMU_IMG,
|
||||
TOOL_KVM_IMG,
|
||||
TOOL_QCOW_CREATE,
|
||||
};
|
||||
|
||||
static int cowGetBackingStore(virConnectPtr, char **,
|
||||
const unsigned char *, size_t);
|
||||
static int qcowXGetBackingStore(virConnectPtr, char **,
|
||||
@ -68,12 +62,6 @@ static int qcowXGetBackingStore(virConnectPtr, char **,
|
||||
static int vmdk4GetBackingStore(virConnectPtr, char **,
|
||||
const unsigned char *, size_t);
|
||||
|
||||
typedef int (*createFile)(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
virStorageVolDefPtr inputvol);
|
||||
|
||||
static int track_allocation_progress = 0;
|
||||
|
||||
/* Either 'magic' or 'extension' *must* be provided */
|
||||
struct FileTypeInfo {
|
||||
int type; /* One of the constants above */
|
||||
@ -1018,157 +1006,6 @@ virStorageBackendFileSystemVolCreate(virConnectPtr conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int createRaw(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
virStorageVolDefPtr inputvol) {
|
||||
int fd = -1;
|
||||
int inputfd = -1;
|
||||
int ret = -1;
|
||||
unsigned long long remain;
|
||||
char *buf = NULL;
|
||||
|
||||
if ((fd = open(vol->target.path, O_RDWR | O_CREAT | O_EXCL,
|
||||
vol->target.perms.mode)) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("cannot create path '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (inputvol) {
|
||||
if ((inputfd = open(inputvol->target.path, O_RDONLY)) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("could not open input path '%s'"),
|
||||
inputvol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Seek to the final size, so the capacity is available upfront
|
||||
* for progress reporting */
|
||||
if (ftruncate(fd, vol->capacity) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("cannot extend file '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
remain = vol->allocation;
|
||||
|
||||
if (inputfd != -1) {
|
||||
int amtread = -1;
|
||||
size_t bytes = 1024 * 1024;
|
||||
char zerobuf[512];
|
||||
|
||||
bzero(&zerobuf, sizeof(zerobuf));
|
||||
|
||||
if (VIR_ALLOC_N(buf, bytes) < 0) {
|
||||
virReportOOMError(conn);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (amtread != 0) {
|
||||
int amtleft;
|
||||
|
||||
if (remain < bytes)
|
||||
bytes = remain;
|
||||
|
||||
if ((amtread = saferead(inputfd, buf, bytes)) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("failed reading from file '%s'"),
|
||||
inputvol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
remain -= amtread;
|
||||
|
||||
/* Loop over amt read in 512 byte increments, looking for sparse
|
||||
* blocks */
|
||||
amtleft = amtread;
|
||||
do {
|
||||
int interval = ((512 > amtleft) ? amtleft : 512);
|
||||
int offset = amtread - amtleft;
|
||||
|
||||
if (memcmp(buf+offset, zerobuf, interval) == 0) {
|
||||
if (lseek(fd, interval, SEEK_CUR) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("cannot extend file '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
} else if (safewrite(fd, buf+offset, interval) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("failed writing to file '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
|
||||
}
|
||||
} while ((amtleft -= 512) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pre-allocate any data if requested */
|
||||
/* XXX slooooooooooooooooow on non-extents-based file systems */
|
||||
if (remain) {
|
||||
if (track_allocation_progress) {
|
||||
|
||||
while (remain) {
|
||||
/* Allocate in chunks of 512MiB: big-enough chunk
|
||||
* size and takes approx. 9s on ext3. A progress
|
||||
* update every 9s is a fair-enough trade-off
|
||||
*/
|
||||
unsigned long long bytes = 512 * 1024 * 1024;
|
||||
int r;
|
||||
|
||||
if (bytes > remain)
|
||||
bytes = remain;
|
||||
if ((r = safezero(fd, 0, vol->allocation - remain,
|
||||
bytes)) != 0) {
|
||||
virReportSystemError(conn, r,
|
||||
_("cannot fill file '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
remain -= bytes;
|
||||
}
|
||||
} else { /* No progress bars to be shown */
|
||||
int r;
|
||||
|
||||
if ((r = safezero(fd, 0, 0, remain)) != 0) {
|
||||
virReportSystemError(conn, r,
|
||||
_("cannot fill file '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (close(fd) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("cannot close file '%s'"),
|
||||
vol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
fd = -1;
|
||||
|
||||
if (inputfd != -1 && close(inputfd) < 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("cannot close file '%s'"),
|
||||
inputvol->target.path);
|
||||
goto cleanup;
|
||||
}
|
||||
inputfd = -1;
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
if (inputfd != -1)
|
||||
close(inputfd);
|
||||
VIR_FREE(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int createFileDir(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
virStorageVolDefPtr inputvol) {
|
||||
@ -1189,257 +1026,6 @@ static int createFileDir(virConnectPtr conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int createQemuImg(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
virStorageVolDefPtr inputvol) {
|
||||
char size[100];
|
||||
char *create_tool;
|
||||
short use_kvmimg;
|
||||
|
||||
const char *type = virStorageVolFormatFileSystemTypeToString(vol->target.format);
|
||||
const char *backingType = vol->backingStore.path ?
|
||||
virStorageVolFormatFileSystemTypeToString(vol->backingStore.format) : NULL;
|
||||
|
||||
const char *inputBackingPath = (inputvol ? inputvol->backingStore.path
|
||||
: NULL);
|
||||
const char *inputPath = inputvol ? inputvol->target.path : NULL;
|
||||
/* Treat input block devices as 'raw' format */
|
||||
const char *inputType = inputPath ?
|
||||
virStorageVolFormatFileSystemTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ? VIR_STORAGE_VOL_FILE_RAW : inputvol->target.format) :
|
||||
NULL;
|
||||
|
||||
const char **imgargv;
|
||||
const char *imgargvnormal[] = {
|
||||
NULL, "create",
|
||||
"-f", type,
|
||||
vol->target.path,
|
||||
size,
|
||||
NULL,
|
||||
};
|
||||
/* Extra NULL fields are for including "backingType" when using
|
||||
* kvm-img. It's -F backingType
|
||||
*/
|
||||
const char *imgargvbacking[] = {
|
||||
NULL, "create",
|
||||
"-f", type,
|
||||
"-b", vol->backingStore.path,
|
||||
vol->target.path,
|
||||
size,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
const char *convargv[] = {
|
||||
NULL, "convert",
|
||||
"-f", inputType,
|
||||
"-O", type,
|
||||
inputPath,
|
||||
vol->target.path,
|
||||
NULL,
|
||||
};
|
||||
|
||||
if (type == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("unknown storage vol type %d"),
|
||||
vol->target.format);
|
||||
return -1;
|
||||
}
|
||||
if (inputvol && inputType == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("unknown storage vol type %d"),
|
||||
inputvol->target.format);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vol->backingStore.path) {
|
||||
|
||||
/* XXX: Not strictly required: qemu-img has an option a different
|
||||
* backing store, not really sure what use it serves though, and it
|
||||
* may cause issues with lvm. Untested essentially.
|
||||
*/
|
||||
if (inputvol &&
|
||||
(!inputBackingPath ||
|
||||
STRNEQ(inputBackingPath, vol->backingStore.path))) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
"%s", _("a different backing store can not "
|
||||
"be specified."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (backingType == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("unknown storage vol backing store type %d"),
|
||||
vol->backingStore.format);
|
||||
return -1;
|
||||
}
|
||||
if (access(vol->backingStore.path, R_OK) != 0) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("inaccessible backing store volume %s"),
|
||||
vol->backingStore.path);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((create_tool = virFindFileInPath("kvm-img")) != NULL)
|
||||
use_kvmimg = 1;
|
||||
else if ((create_tool = virFindFileInPath("qemu-img")) != NULL)
|
||||
use_kvmimg = 0;
|
||||
else {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("unable to find kvm-img or qemu-img"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inputvol) {
|
||||
convargv[0] = create_tool;
|
||||
imgargv = convargv;
|
||||
} else if (vol->backingStore.path) {
|
||||
imgargvbacking[0] = create_tool;
|
||||
if (use_kvmimg) {
|
||||
imgargvbacking[6] = "-F";
|
||||
imgargvbacking[7] = backingType;
|
||||
imgargvbacking[8] = vol->target.path;
|
||||
imgargvbacking[9] = size;
|
||||
}
|
||||
imgargv = imgargvbacking;
|
||||
} else {
|
||||
imgargvnormal[0] = create_tool;
|
||||
imgargv = imgargvnormal;
|
||||
}
|
||||
|
||||
|
||||
/* Size in KB */
|
||||
snprintf(size, sizeof(size), "%llu", vol->capacity/1024);
|
||||
|
||||
if (virRun(conn, imgargv, NULL) < 0) {
|
||||
VIR_FREE(imgargv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
VIR_FREE(imgargv[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Xen removed the fully-functional qemu-img, and replaced it
|
||||
* with a partially functional qcow-create. Go figure ??!?
|
||||
*/
|
||||
static int createQemuCreate(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
virStorageVolDefPtr inputvol) {
|
||||
char size[100];
|
||||
const char *imgargv[4];
|
||||
|
||||
if (inputvol) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
"%s",
|
||||
_("cannot copy from volume with qcow-create"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vol->target.format != VIR_STORAGE_VOL_FILE_QCOW2) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("unsupported storage vol type %d"),
|
||||
vol->target.format);
|
||||
return -1;
|
||||
}
|
||||
if (vol->backingStore.path != NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_NO_SUPPORT,
|
||||
_("copy-on-write image not supported with "
|
||||
"qcow-create"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Size in MB - yes different units to qemu-img :-( */
|
||||
snprintf(size, sizeof(size), "%llu", vol->capacity/1024/1024);
|
||||
|
||||
imgargv[0] = virFindFileInPath("qcow-create");
|
||||
imgargv[1] = size;
|
||||
imgargv[2] = vol->target.path;
|
||||
imgargv[3] = NULL;
|
||||
|
||||
if (virRun(conn, imgargv, NULL) < 0) {
|
||||
VIR_FREE(imgargv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
VIR_FREE(imgargv[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static createFile
|
||||
toolTypeToFunction(virConnectPtr conn, int tool_type)
|
||||
{
|
||||
switch (tool_type) {
|
||||
case TOOL_KVM_IMG:
|
||||
case TOOL_QEMU_IMG:
|
||||
return createQemuImg;
|
||||
case TOOL_QCOW_CREATE:
|
||||
return createQemuCreate;
|
||||
default:
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("Unknown file create tool type '%d'."),
|
||||
tool_type);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
findImageTool(char **tool)
|
||||
{
|
||||
int tool_type = -1;
|
||||
char *tmp = NULL;
|
||||
|
||||
if ((tmp = virFindFileInPath("kvm-img")) != NULL) {
|
||||
tool_type = TOOL_KVM_IMG;
|
||||
} else if ((tmp = virFindFileInPath("qemu-img")) != NULL) {
|
||||
tool_type = TOOL_QEMU_IMG;
|
||||
} else if ((tmp = virFindFileInPath("qcow-create")) != NULL) {
|
||||
tool_type = TOOL_QCOW_CREATE;
|
||||
}
|
||||
|
||||
if (tool)
|
||||
*tool = tmp;
|
||||
else
|
||||
VIR_FREE(tmp);
|
||||
|
||||
return tool_type;
|
||||
}
|
||||
|
||||
static createFile
|
||||
buildVolFromFunction(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
virStorageVolDefPtr inputvol)
|
||||
{
|
||||
int tool_type;
|
||||
|
||||
if (!inputvol)
|
||||
return NULL;
|
||||
|
||||
/* If either volume is a non-raw file vol, we need to use an external
|
||||
* tool for converting
|
||||
*/
|
||||
if ((vol->type == VIR_STORAGE_VOL_FILE &&
|
||||
vol->target.format != VIR_STORAGE_VOL_FILE_RAW) ||
|
||||
(inputvol->type == VIR_STORAGE_VOL_FILE &&
|
||||
inputvol->target.format != VIR_STORAGE_VOL_FILE_RAW)) {
|
||||
|
||||
if ((tool_type = findImageTool(NULL)) != -1) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
"%s", _("creation of non-raw file images is "
|
||||
"not supported without qemu-img."));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return toolTypeToFunction(conn, tool_type);
|
||||
}
|
||||
|
||||
return createRaw;
|
||||
}
|
||||
|
||||
static int
|
||||
_virStorageBackendFileSystemVolBuild(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
@ -1450,15 +1036,18 @@ _virStorageBackendFileSystemVolBuild(virConnectPtr conn,
|
||||
int tool_type;
|
||||
|
||||
if (inputvol) {
|
||||
create_func = buildVolFromFunction(conn, vol, inputvol);
|
||||
create_func = virStorageBackendGetBuildVolFromFunction(conn, vol,
|
||||
inputvol);
|
||||
if (!create_func)
|
||||
return -1;
|
||||
} else if (vol->target.format == VIR_STORAGE_VOL_FILE_RAW) {
|
||||
create_func = createRaw;
|
||||
create_func = virStorageBackendCreateRaw;
|
||||
} else if (vol->target.format == VIR_STORAGE_VOL_FILE_DIR) {
|
||||
create_func = createFileDir;
|
||||
} else if ((tool_type = findImageTool(NULL)) != -1) {
|
||||
if ((create_func = toolTypeToFunction(conn, tool_type)) == NULL)
|
||||
} else if ((tool_type = virStorageBackendFindFSImageTool(NULL)) != -1) {
|
||||
create_func = virStorageBackendFSImageToolTypeToFunc(conn, tool_type);
|
||||
|
||||
if (!create_func)
|
||||
return -1;
|
||||
} else {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
|
Loading…
x
Reference in New Issue
Block a user