mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-25 15:15:25 +00:00
Implement virStorageVolResize() for FS backend
Currently only VIR_STORAGE_VOL_RESIZE_DELTA flag is supported.
This commit is contained in:
parent
055bbf45e4
commit
e545dd4ffe
@ -44,6 +44,11 @@ typedef int (*virStorageBackendDeleteVol)(virConnectPtr conn, virStoragePoolObjP
|
|||||||
typedef int (*virStorageBackendBuildVolFrom)(virConnectPtr conn, virStoragePoolObjPtr pool,
|
typedef int (*virStorageBackendBuildVolFrom)(virConnectPtr conn, virStoragePoolObjPtr pool,
|
||||||
virStorageVolDefPtr origvol, virStorageVolDefPtr newvol,
|
virStorageVolDefPtr origvol, virStorageVolDefPtr newvol,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
|
typedef int (*virStorageBackendVolumeResize)(virConnectPtr conn,
|
||||||
|
virStoragePoolObjPtr pool,
|
||||||
|
virStorageVolDefPtr vol,
|
||||||
|
unsigned long long capacity,
|
||||||
|
unsigned int flags);
|
||||||
|
|
||||||
/* File creation/cloning functions used for cloning between backends */
|
/* File creation/cloning functions used for cloning between backends */
|
||||||
int virStorageBackendCreateRaw(virConnectPtr conn,
|
int virStorageBackendCreateRaw(virConnectPtr conn,
|
||||||
@ -78,6 +83,7 @@ struct _virStorageBackend {
|
|||||||
virStorageBackendCreateVol createVol;
|
virStorageBackendCreateVol createVol;
|
||||||
virStorageBackendRefreshVol refreshVol;
|
virStorageBackendRefreshVol refreshVol;
|
||||||
virStorageBackendDeleteVol deleteVol;
|
virStorageBackendDeleteVol deleteVol;
|
||||||
|
virStorageBackendVolumeResize resizeVol;
|
||||||
};
|
};
|
||||||
|
|
||||||
virStorageBackendPtr virStorageBackendForType(int type);
|
virStorageBackendPtr virStorageBackendForType(int type);
|
||||||
|
@ -1187,6 +1187,56 @@ virStorageBackendFileSystemVolRefresh(virConnectPtr conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
virStorageBackendFilesystemResizeQemuImg(const char *path,
|
||||||
|
unsigned long long capacity)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
char *img_tool;
|
||||||
|
virCommandPtr cmd = NULL;
|
||||||
|
|
||||||
|
/* KVM is usually ahead of qemu on features, so try that first */
|
||||||
|
img_tool = virFindFileInPath("kvm-img");
|
||||||
|
if (!img_tool)
|
||||||
|
img_tool = virFindFileInPath("qemu-img");
|
||||||
|
|
||||||
|
if (!img_tool) {
|
||||||
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("unable to find kvm-img or qemu-img"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = virCommandNew(img_tool);
|
||||||
|
virCommandAddArgList(cmd, "resize", path, NULL);
|
||||||
|
virCommandAddArgFormat(cmd, "%llu", capacity);
|
||||||
|
|
||||||
|
ret = virCommandRun(cmd, NULL);
|
||||||
|
|
||||||
|
VIR_FREE(img_tool);
|
||||||
|
virCommandFree(cmd);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize a volume
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||||
|
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
|
||||||
|
virStorageVolDefPtr vol,
|
||||||
|
unsigned long long capacity,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
virCheckFlags(0, -1);
|
||||||
|
|
||||||
|
if (vol->target.format == VIR_STORAGE_FILE_RAW)
|
||||||
|
return virStorageFileResize(vol->target.path, capacity);
|
||||||
|
else
|
||||||
|
return virStorageBackendFilesystemResizeQemuImg(vol->target.path,
|
||||||
|
capacity);
|
||||||
|
}
|
||||||
|
|
||||||
virStorageBackend virStorageBackendDirectory = {
|
virStorageBackend virStorageBackendDirectory = {
|
||||||
.type = VIR_STORAGE_POOL_DIR,
|
.type = VIR_STORAGE_POOL_DIR,
|
||||||
|
|
||||||
@ -1199,6 +1249,7 @@ virStorageBackend virStorageBackendDirectory = {
|
|||||||
.createVol = virStorageBackendFileSystemVolCreate,
|
.createVol = virStorageBackendFileSystemVolCreate,
|
||||||
.refreshVol = virStorageBackendFileSystemVolRefresh,
|
.refreshVol = virStorageBackendFileSystemVolRefresh,
|
||||||
.deleteVol = virStorageBackendFileSystemVolDelete,
|
.deleteVol = virStorageBackendFileSystemVolDelete,
|
||||||
|
.resizeVol = virStorageBackendFileSystemVolResize,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if WITH_STORAGE_FS
|
#if WITH_STORAGE_FS
|
||||||
@ -1216,6 +1267,7 @@ virStorageBackend virStorageBackendFileSystem = {
|
|||||||
.createVol = virStorageBackendFileSystemVolCreate,
|
.createVol = virStorageBackendFileSystemVolCreate,
|
||||||
.refreshVol = virStorageBackendFileSystemVolRefresh,
|
.refreshVol = virStorageBackendFileSystemVolRefresh,
|
||||||
.deleteVol = virStorageBackendFileSystemVolDelete,
|
.deleteVol = virStorageBackendFileSystemVolDelete,
|
||||||
|
.resizeVol = virStorageBackendFileSystemVolResize,
|
||||||
};
|
};
|
||||||
virStorageBackend virStorageBackendNetFileSystem = {
|
virStorageBackend virStorageBackendNetFileSystem = {
|
||||||
.type = VIR_STORAGE_POOL_NETFS,
|
.type = VIR_STORAGE_POOL_NETFS,
|
||||||
@ -1232,5 +1284,6 @@ virStorageBackend virStorageBackendNetFileSystem = {
|
|||||||
.createVol = virStorageBackendFileSystemVolCreate,
|
.createVol = virStorageBackendFileSystemVolCreate,
|
||||||
.refreshVol = virStorageBackendFileSystemVolRefresh,
|
.refreshVol = virStorageBackendFileSystemVolRefresh,
|
||||||
.deleteVol = virStorageBackendFileSystemVolDelete,
|
.deleteVol = virStorageBackendFileSystemVolDelete,
|
||||||
|
.resizeVol = virStorageBackendFileSystemVolResize,
|
||||||
};
|
};
|
||||||
#endif /* WITH_STORAGE_FS */
|
#endif /* WITH_STORAGE_FS */
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* storage_driver.c: core driver for storage APIs
|
* storage_driver.c: core driver for storage APIs
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2011 Red Hat, Inc.
|
* Copyright (C) 2006-2012 Red Hat, Inc.
|
||||||
* Copyright (C) 2006-2008 Daniel P. Berrange
|
* Copyright (C) 2006-2008 Daniel P. Berrange
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
@ -1695,7 +1695,94 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
storageVolumeResize(virStorageVolPtr obj,
|
||||||
|
unsigned long long capacity,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
|
||||||
|
virStorageBackendPtr backend;
|
||||||
|
virStoragePoolObjPtr pool = NULL;
|
||||||
|
virStorageVolDefPtr vol = NULL;
|
||||||
|
unsigned long long abs_capacity;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
virCheckFlags(VIR_STORAGE_VOL_RESIZE_DELTA, -1);
|
||||||
|
|
||||||
|
storageDriverLock(driver);
|
||||||
|
pool = virStoragePoolObjFindByName(&driver->pools, obj->pool);
|
||||||
|
storageDriverUnlock(driver);
|
||||||
|
|
||||||
|
if (!pool) {
|
||||||
|
virStorageReportError(VIR_ERR_NO_STORAGE_POOL,
|
||||||
|
_("no storage pool with matching uuid"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!virStoragePoolObjIsActive(pool)) {
|
||||||
|
virStorageReportError(VIR_ERR_OPERATION_INVALID,
|
||||||
|
_("storage pool is not active"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
vol = virStorageVolDefFindByName(pool, obj->name);
|
||||||
|
|
||||||
|
if (vol == NULL) {
|
||||||
|
virStorageReportError(VIR_ERR_NO_STORAGE_VOL,
|
||||||
|
_("no storage vol with matching name '%s'"),
|
||||||
|
obj->name);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vol->building) {
|
||||||
|
virStorageReportError(VIR_ERR_OPERATION_INVALID,
|
||||||
|
_("volume '%s' is still being allocated."),
|
||||||
|
vol->name);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & VIR_STORAGE_VOL_RESIZE_DELTA) {
|
||||||
|
abs_capacity = vol->capacity + capacity;
|
||||||
|
flags &= ~VIR_STORAGE_VOL_RESIZE_DELTA;
|
||||||
|
} else {
|
||||||
|
abs_capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abs_capacity < vol->allocation) {
|
||||||
|
virStorageReportError(VIR_ERR_INVALID_ARG,
|
||||||
|
_("can't shrink capacity below "
|
||||||
|
"existing allocation"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abs_capacity > vol->allocation + pool->def->available) {
|
||||||
|
virStorageReportError(VIR_ERR_INVALID_ARG,
|
||||||
|
_("Not enough space left on storage pool"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!backend->resizeVol) {
|
||||||
|
virStorageReportError(VIR_ERR_NO_SUPPORT,
|
||||||
|
_("storage pool does not support changing of "
|
||||||
|
"volume capacity"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backend->resizeVol(obj->conn, pool, vol, abs_capacity, flags) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
vol->capacity = abs_capacity;
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (pool)
|
||||||
|
virStoragePoolObjUnlock(pool);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* If the volume we're wiping is already a sparse file, we simply
|
/* If the volume we're wiping is already a sparse file, we simply
|
||||||
* truncate and extend it to its original size, filling it with
|
* truncate and extend it to its original size, filling it with
|
||||||
@ -2243,6 +2330,7 @@ static virStorageDriver storageDriver = {
|
|||||||
.volGetInfo = storageVolumeGetInfo, /* 0.4.0 */
|
.volGetInfo = storageVolumeGetInfo, /* 0.4.0 */
|
||||||
.volGetXMLDesc = storageVolumeGetXMLDesc, /* 0.4.0 */
|
.volGetXMLDesc = storageVolumeGetXMLDesc, /* 0.4.0 */
|
||||||
.volGetPath = storageVolumeGetPath, /* 0.4.0 */
|
.volGetPath = storageVolumeGetPath, /* 0.4.0 */
|
||||||
|
.volResize = storageVolumeResize, /* 0.9.10 */
|
||||||
|
|
||||||
.poolIsActive = storagePoolIsActive, /* 0.7.3 */
|
.poolIsActive = storagePoolIsActive, /* 0.7.3 */
|
||||||
.poolIsPersistent = storagePoolIsPersistent, /* 0.7.3 */
|
.poolIsPersistent = storagePoolIsPersistent, /* 0.7.3 */
|
||||||
|
@ -931,6 +931,22 @@ virStorageFileFreeMetadata(virStorageFileMetadata *meta)
|
|||||||
VIR_FREE(meta);
|
VIR_FREE(meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virStorageFileResize:
|
||||||
|
*
|
||||||
|
* Change the capacity of the raw storage file at 'path'.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
virStorageFileResize(const char *path, unsigned long long capacity)
|
||||||
|
{
|
||||||
|
if (truncate(path, capacity) < 0) {
|
||||||
|
virReportSystemError(errno, _("Failed to truncate file '%s'"), path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
|
||||||
# ifndef NFS_SUPER_MAGIC
|
# ifndef NFS_SUPER_MAGIC
|
||||||
|
@ -72,6 +72,8 @@ int virStorageFileGetMetadataFromFD(const char *path,
|
|||||||
|
|
||||||
void virStorageFileFreeMetadata(virStorageFileMetadata *meta);
|
void virStorageFileFreeMetadata(virStorageFileMetadata *meta);
|
||||||
|
|
||||||
|
int virStorageFileResize(const char *path, unsigned long long capacity);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
VIR_STORAGE_FILE_SHFS_NFS = (1 << 0),
|
VIR_STORAGE_FILE_SHFS_NFS = (1 << 0),
|
||||||
VIR_STORAGE_FILE_SHFS_GFS2 = (1 << 1),
|
VIR_STORAGE_FILE_SHFS_GFS2 = (1 << 1),
|
||||||
|
Loading…
Reference in New Issue
Block a user