mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-10-29 17:33:09 +00:00
VolumeCreateXMLFrom FS storage backend implementation.
Add an extra 'inputvol' parameter to the file volume building routines. This allows us to easily reuse the duplicate functionality.
This commit is contained in:
parent
4aa0959d60
commit
2d1de285b3
@ -1,3 +1,8 @@
|
|||||||
|
Tue May 19 09:39:01 EDT 2009 Cole Robinson <crobinso@redhat.com>
|
||||||
|
|
||||||
|
* src/storage_backend_fs.c: VolumeCreateXMLFrom FS storage
|
||||||
|
backend implementation.
|
||||||
|
|
||||||
Tue May 19 09:36:48 EDT 2009 Cole Robinson <crobinso@redhat.com>
|
Tue May 19 09:36:48 EDT 2009 Cole Robinson <crobinso@redhat.com>
|
||||||
|
|
||||||
* src/storage_backend.h src/storage_driver.c: Storage driver
|
* src/storage_backend.h src/storage_driver.c: Storage driver
|
||||||
|
@ -62,7 +62,9 @@ static int qcowXGetBackingStore(virConnectPtr, char **,
|
|||||||
static int vmdk4GetBackingStore(virConnectPtr, char **,
|
static int vmdk4GetBackingStore(virConnectPtr, char **,
|
||||||
const unsigned char *, size_t);
|
const unsigned char *, size_t);
|
||||||
|
|
||||||
typedef int (*createFile)(virConnectPtr conn, virStorageVolDefPtr vol);
|
typedef int (*createFile)(virConnectPtr conn,
|
||||||
|
virStorageVolDefPtr vol,
|
||||||
|
virStorageVolDefPtr inputvol);
|
||||||
|
|
||||||
static int track_allocation_progress = 0;
|
static int track_allocation_progress = 0;
|
||||||
|
|
||||||
@ -1011,15 +1013,29 @@ virStorageBackendFileSystemVolCreate(virConnectPtr conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int createRaw(virConnectPtr conn,
|
static int createRaw(virConnectPtr conn,
|
||||||
virStorageVolDefPtr vol) {
|
virStorageVolDefPtr vol,
|
||||||
int fd;
|
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,
|
if ((fd = open(vol->target.path, O_RDWR | O_CREAT | O_EXCL,
|
||||||
vol->target.perms.mode)) < 0) {
|
vol->target.perms.mode)) < 0) {
|
||||||
virReportSystemError(conn, errno,
|
virReportSystemError(conn, errno,
|
||||||
_("cannot create path '%s'"),
|
_("cannot create path '%s'"),
|
||||||
vol->target.path);
|
vol->target.path);
|
||||||
return -1;
|
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
|
/* Seek to the final size, so the capacity is available upfront
|
||||||
@ -1028,15 +1044,66 @@ static int createRaw(virConnectPtr conn,
|
|||||||
virReportSystemError(conn, errno,
|
virReportSystemError(conn, errno,
|
||||||
_("cannot extend file '%s'"),
|
_("cannot extend file '%s'"),
|
||||||
vol->target.path);
|
vol->target.path);
|
||||||
close(fd);
|
goto cleanup;
|
||||||
return -1;
|
}
|
||||||
|
|
||||||
|
remain = vol->capacity;
|
||||||
|
|
||||||
|
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 */
|
/* Pre-allocate any data if requested */
|
||||||
/* XXX slooooooooooooooooow on non-extents-based file systems */
|
/* XXX slooooooooooooooooow on non-extents-based file systems */
|
||||||
if (vol->allocation) {
|
if (remain) {
|
||||||
if (track_allocation_progress) {
|
if (track_allocation_progress) {
|
||||||
unsigned long long remain = vol->allocation;
|
|
||||||
|
|
||||||
while (remain) {
|
while (remain) {
|
||||||
/* Allocate in chunks of 512MiB: big-enough chunk
|
/* Allocate in chunks of 512MiB: big-enough chunk
|
||||||
@ -1053,20 +1120,18 @@ static int createRaw(virConnectPtr conn,
|
|||||||
virReportSystemError(conn, r,
|
virReportSystemError(conn, r,
|
||||||
_("cannot fill file '%s'"),
|
_("cannot fill file '%s'"),
|
||||||
vol->target.path);
|
vol->target.path);
|
||||||
close(fd);
|
goto cleanup;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
remain -= bytes;
|
remain -= bytes;
|
||||||
}
|
}
|
||||||
} else { /* No progress bars to be shown */
|
} else { /* No progress bars to be shown */
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if ((r = safezero(fd, 0, 0, vol->allocation)) != 0) {
|
if ((r = safezero(fd, 0, 0, remain)) != 0) {
|
||||||
virReportSystemError(conn, r,
|
virReportSystemError(conn, r,
|
||||||
_("cannot fill file '%s'"),
|
_("cannot fill file '%s'"),
|
||||||
vol->target.path);
|
vol->target.path);
|
||||||
close(fd);
|
goto cleanup;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1075,14 +1140,39 @@ static int createRaw(virConnectPtr conn,
|
|||||||
virReportSystemError(conn, errno,
|
virReportSystemError(conn, errno,
|
||||||
_("cannot close file '%s'"),
|
_("cannot close file '%s'"),
|
||||||
vol->target.path);
|
vol->target.path);
|
||||||
return -1;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
fd = -1;
|
||||||
|
|
||||||
return 0;
|
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,
|
static int createFileDir(virConnectPtr conn,
|
||||||
virStorageVolDefPtr vol) {
|
virStorageVolDefPtr vol,
|
||||||
|
virStorageVolDefPtr inputvol) {
|
||||||
|
if (inputvol) {
|
||||||
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s",
|
||||||
|
_("cannot copy from volume to a directory volume"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (mkdir(vol->target.path, vol->target.perms.mode) < 0) {
|
if (mkdir(vol->target.path, vol->target.perms.mode) < 0) {
|
||||||
virReportSystemError(conn, errno,
|
virReportSystemError(conn, errno,
|
||||||
_("cannot create path '%s'"),
|
_("cannot create path '%s'"),
|
||||||
@ -1095,20 +1185,56 @@ static int createFileDir(virConnectPtr conn,
|
|||||||
|
|
||||||
#if HAVE_QEMU_IMG
|
#if HAVE_QEMU_IMG
|
||||||
static int createQemuImg(virConnectPtr conn,
|
static int createQemuImg(virConnectPtr conn,
|
||||||
virStorageVolDefPtr vol) {
|
virStorageVolDefPtr vol,
|
||||||
|
virStorageVolDefPtr inputvol) {
|
||||||
|
char size[100];
|
||||||
|
|
||||||
const char *type = virStorageVolFormatFileSystemTypeToString(vol->target.format);
|
const char *type = virStorageVolFormatFileSystemTypeToString(vol->target.format);
|
||||||
const char *backingType = vol->backingStore.path ?
|
const char *backingType = vol->backingStore.path ?
|
||||||
virStorageVolFormatFileSystemTypeToString(vol->backingStore.format) : NULL;
|
virStorageVolFormatFileSystemTypeToString(vol->backingStore.format) : NULL;
|
||||||
char size[100];
|
|
||||||
|
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 **imgargv;
|
||||||
const char *imgargvnormal[] = {
|
const char *imgargvnormal[] = {
|
||||||
QEMU_IMG, "create", "-f", type, vol->target.path, size, NULL,
|
QEMU_IMG, "create",
|
||||||
|
"-f", type,
|
||||||
|
vol->target.path,
|
||||||
|
size,
|
||||||
|
NULL,
|
||||||
};
|
};
|
||||||
/* XXX including "backingType" here too, once QEMU accepts
|
/* XXX including "backingType" here too, once QEMU accepts
|
||||||
* the patches to specify it. It'll probably be -F backingType */
|
* the patches to specify it. It'll probably be -F backingType */
|
||||||
const char *imgargvbacking[] = {
|
const char *imgargvbacking[] = {
|
||||||
QEMU_IMG, "create", "-f", type, "-b", vol->backingStore.path, vol->target.path, size, NULL,
|
QEMU_IMG, "create",
|
||||||
|
"-f", type,
|
||||||
|
"-b", vol->backingStore.path,
|
||||||
|
vol->target.path,
|
||||||
|
size,
|
||||||
|
NULL,
|
||||||
};
|
};
|
||||||
|
const char *convargv[] = {
|
||||||
|
QEMU_IMG, "convert",
|
||||||
|
"-f", inputType,
|
||||||
|
"-O", type,
|
||||||
|
inputPath,
|
||||||
|
vol->target.path,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (inputvol) {
|
||||||
|
imgargv = convargv;
|
||||||
|
} else if (vol->backingStore.path) {
|
||||||
|
imgargv = imgargvbacking;
|
||||||
|
} else {
|
||||||
|
imgargv = imgargvnormal;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == NULL) {
|
if (type == NULL) {
|
||||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
@ -1116,9 +1242,27 @@ static int createQemuImg(virConnectPtr conn,
|
|||||||
vol->target.format);
|
vol->target.format);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (vol->backingStore.path == NULL) {
|
if (inputvol && inputType == NULL) {
|
||||||
imgargv = imgargvnormal;
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
} else {
|
_("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 (!inputBackingPath ||
|
||||||
|
!STREQ(inputBackingPath, vol->backingStore.path)) {
|
||||||
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("a different backing store can not "
|
||||||
|
"be specified."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (backingType == NULL) {
|
if (backingType == NULL) {
|
||||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
_("unknown storage vol backing store type %d"),
|
_("unknown storage vol backing store type %d"),
|
||||||
@ -1131,8 +1275,6 @@ static int createQemuImg(virConnectPtr conn,
|
|||||||
vol->backingStore.path);
|
vol->backingStore.path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
imgargv = imgargvbacking;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Size in KB */
|
/* Size in KB */
|
||||||
@ -1151,10 +1293,18 @@ static int createQemuImg(virConnectPtr conn,
|
|||||||
* with a partially functional qcow-create. Go figure ??!?
|
* with a partially functional qcow-create. Go figure ??!?
|
||||||
*/
|
*/
|
||||||
static int createQemuCreate(virConnectPtr conn,
|
static int createQemuCreate(virConnectPtr conn,
|
||||||
virStorageVolDefPtr vol) {
|
virStorageVolDefPtr vol,
|
||||||
|
virStorageVolDefPtr inputvol) {
|
||||||
char size[100];
|
char size[100];
|
||||||
const char *imgargv[4];
|
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) {
|
if (vol->target.format != VIR_STORAGE_VOL_FILE_QCOW2) {
|
||||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
_("unsupported storage vol type %d"),
|
_("unsupported storage vol type %d"),
|
||||||
@ -1184,19 +1334,22 @@ static int createQemuCreate(virConnectPtr conn,
|
|||||||
}
|
}
|
||||||
#endif /* HAVE_QEMU_IMG, elif HAVE_QCOW_CREATE */
|
#endif /* HAVE_QEMU_IMG, elif HAVE_QCOW_CREATE */
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocate a new file as a volume. This is either done directly
|
|
||||||
* for raw/sparse files, or by calling qemu-img/qcow-create for
|
|
||||||
* special kinds of files
|
|
||||||
*/
|
|
||||||
static int
|
static int
|
||||||
virStorageBackendFileSystemVolBuild(virConnectPtr conn,
|
_virStorageBackendFileSystemVolBuild(virConnectPtr conn,
|
||||||
virStorageVolDefPtr vol)
|
virStorageVolDefPtr vol,
|
||||||
|
virStorageVolDefPtr inputvol)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
createFile create_func;
|
createFile create_func;
|
||||||
|
|
||||||
if (vol->target.format == VIR_STORAGE_VOL_FILE_RAW) {
|
if (vol->target.format == VIR_STORAGE_VOL_FILE_RAW &&
|
||||||
|
(!inputvol ||
|
||||||
|
(inputvol->type == VIR_STORAGE_VOL_BLOCK ||
|
||||||
|
inputvol->target.format == VIR_STORAGE_VOL_FILE_RAW))) {
|
||||||
|
/* Raw file creation
|
||||||
|
* Raw -> Raw copying
|
||||||
|
* Block dev -> Raw copying
|
||||||
|
*/
|
||||||
create_func = createRaw;
|
create_func = createRaw;
|
||||||
} else if (vol->target.format == VIR_STORAGE_VOL_FILE_DIR) {
|
} else if (vol->target.format == VIR_STORAGE_VOL_FILE_DIR) {
|
||||||
create_func = createFileDir;
|
create_func = createFileDir;
|
||||||
@ -1213,7 +1366,7 @@ virStorageBackendFileSystemVolBuild(virConnectPtr conn,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create_func(conn, vol) < 0)
|
if (create_func(conn, vol, inputvol) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ((fd = open(vol->target.path, O_RDONLY)) < 0) {
|
if ((fd = open(vol->target.path, O_RDONLY)) < 0) {
|
||||||
@ -1259,6 +1412,27 @@ virStorageBackendFileSystemVolBuild(virConnectPtr conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a new file as a volume. This is either done directly
|
||||||
|
* for raw/sparse files, or by calling qemu-img/qcow-create for
|
||||||
|
* special kinds of files
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
virStorageBackendFileSystemVolBuild(virConnectPtr conn,
|
||||||
|
virStorageVolDefPtr vol) {
|
||||||
|
return _virStorageBackendFileSystemVolBuild(conn, vol, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a storage vol using 'inputvol' as input
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
virStorageBackendFileSystemVolBuildFrom(virConnectPtr conn,
|
||||||
|
virStorageVolDefPtr vol,
|
||||||
|
virStorageVolDefPtr inputvol,
|
||||||
|
unsigned int flags ATTRIBUTE_UNUSED) {
|
||||||
|
return _virStorageBackendFileSystemVolBuild(conn, vol, inputvol);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a volume - just unlinks for now
|
* Remove a volume - just unlinks for now
|
||||||
@ -1301,6 +1475,7 @@ virStorageBackend virStorageBackendDirectory = {
|
|||||||
.refreshPool = virStorageBackendFileSystemRefresh,
|
.refreshPool = virStorageBackendFileSystemRefresh,
|
||||||
.deletePool = virStorageBackendFileSystemDelete,
|
.deletePool = virStorageBackendFileSystemDelete,
|
||||||
.buildVol = virStorageBackendFileSystemVolBuild,
|
.buildVol = virStorageBackendFileSystemVolBuild,
|
||||||
|
.buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
|
||||||
.createVol = virStorageBackendFileSystemVolCreate,
|
.createVol = virStorageBackendFileSystemVolCreate,
|
||||||
.refreshVol = virStorageBackendFileSystemVolRefresh,
|
.refreshVol = virStorageBackendFileSystemVolRefresh,
|
||||||
.deleteVol = virStorageBackendFileSystemVolDelete,
|
.deleteVol = virStorageBackendFileSystemVolDelete,
|
||||||
@ -1316,6 +1491,7 @@ virStorageBackend virStorageBackendFileSystem = {
|
|||||||
.stopPool = virStorageBackendFileSystemStop,
|
.stopPool = virStorageBackendFileSystemStop,
|
||||||
.deletePool = virStorageBackendFileSystemDelete,
|
.deletePool = virStorageBackendFileSystemDelete,
|
||||||
.buildVol = virStorageBackendFileSystemVolBuild,
|
.buildVol = virStorageBackendFileSystemVolBuild,
|
||||||
|
.buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
|
||||||
.createVol = virStorageBackendFileSystemVolCreate,
|
.createVol = virStorageBackendFileSystemVolCreate,
|
||||||
.refreshVol = virStorageBackendFileSystemVolRefresh,
|
.refreshVol = virStorageBackendFileSystemVolRefresh,
|
||||||
.deleteVol = virStorageBackendFileSystemVolDelete,
|
.deleteVol = virStorageBackendFileSystemVolDelete,
|
||||||
@ -1330,6 +1506,7 @@ virStorageBackend virStorageBackendNetFileSystem = {
|
|||||||
.stopPool = virStorageBackendFileSystemStop,
|
.stopPool = virStorageBackendFileSystemStop,
|
||||||
.deletePool = virStorageBackendFileSystemDelete,
|
.deletePool = virStorageBackendFileSystemDelete,
|
||||||
.buildVol = virStorageBackendFileSystemVolBuild,
|
.buildVol = virStorageBackendFileSystemVolBuild,
|
||||||
|
.buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
|
||||||
.createVol = virStorageBackendFileSystemVolCreate,
|
.createVol = virStorageBackendFileSystemVolCreate,
|
||||||
.refreshVol = virStorageBackendFileSystemVolRefresh,
|
.refreshVol = virStorageBackendFileSystemVolRefresh,
|
||||||
.deleteVol = virStorageBackendFileSystemVolDelete,
|
.deleteVol = virStorageBackendFileSystemVolDelete,
|
||||||
|
Loading…
Reference in New Issue
Block a user