qga/qmp_guest_fstrim: Return per path fstrim result
The current guest-fstrim support only returns an error if some mountpoint was unable to be trimmed, skipping any possible additional mountpoints. The result of the TRIM operation itself is also discarded. This change returns a per mountpoint result of the TRIM operation. If an error occurs on some mountpoints that error is returned and the guest-fstrim continue with any additional mountpoints. The returned values for errors, minimum and trimmed are dependant on the filesystem, storage stacks and kernel version. Signed-off-by: Justin Ossevoort <justin@quarantainenet.nl> * s/type/struct/ in schema type definitions * moved version annotation for new guest-fstrim return field to the field itself rather than applying to the entire command Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
This commit is contained in:
parent
73a652a1b0
commit
e82855d9aa
@ -1325,8 +1325,12 @@ static void guest_fsfreeze_cleanup(void)
|
|||||||
/*
|
/*
|
||||||
* Walk list of mounted file systems in the guest, and trim them.
|
* Walk list of mounted file systems in the guest, and trim them.
|
||||||
*/
|
*/
|
||||||
void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
|
GuestFilesystemTrimResponse *
|
||||||
|
qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
|
||||||
{
|
{
|
||||||
|
GuestFilesystemTrimResponse *response;
|
||||||
|
GuestFilesystemTrimResultList *list;
|
||||||
|
GuestFilesystemTrimResult *result;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
FsMountList mounts;
|
FsMountList mounts;
|
||||||
struct FsMount *mount;
|
struct FsMount *mount;
|
||||||
@ -1340,39 +1344,59 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
|
|||||||
build_fs_mount_list(&mounts, &local_err);
|
build_fs_mount_list(&mounts, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response = g_malloc0(sizeof(*response));
|
||||||
|
|
||||||
QTAILQ_FOREACH(mount, &mounts, next) {
|
QTAILQ_FOREACH(mount, &mounts, next) {
|
||||||
|
result = g_malloc0(sizeof(*result));
|
||||||
|
result->path = g_strdup(mount->dirname);
|
||||||
|
|
||||||
|
list = g_malloc0(sizeof(*list));
|
||||||
|
list->value = result;
|
||||||
|
list->next = response->paths;
|
||||||
|
response->paths = list;
|
||||||
|
|
||||||
fd = qemu_open(mount->dirname, O_RDONLY);
|
fd = qemu_open(mount->dirname, O_RDONLY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
error_setg_errno(errp, errno, "failed to open %s", mount->dirname);
|
result->error = g_strdup_printf("failed to open: %s",
|
||||||
goto error;
|
strerror(errno));
|
||||||
|
result->has_error = true;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We try to cull filesytems we know won't work in advance, but other
|
/* We try to cull filesytems we know won't work in advance, but other
|
||||||
* filesytems may not implement fstrim for less obvious reasons. These
|
* filesytems may not implement fstrim for less obvious reasons. These
|
||||||
* will report EOPNOTSUPP; we simply ignore these errors. Any other
|
* will report EOPNOTSUPP; while in some other cases ENOTTY will be
|
||||||
* error means an unexpected error, so return it in those cases. In
|
* reported (e.g. CD-ROMs).
|
||||||
* some other cases ENOTTY will be reported (e.g. CD-ROMs).
|
* Any other error means an unexpected error.
|
||||||
*/
|
*/
|
||||||
r.start = 0;
|
r.start = 0;
|
||||||
r.len = -1;
|
r.len = -1;
|
||||||
r.minlen = has_minimum ? minimum : 0;
|
r.minlen = has_minimum ? minimum : 0;
|
||||||
ret = ioctl(fd, FITRIM, &r);
|
ret = ioctl(fd, FITRIM, &r);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (errno != ENOTTY && errno != EOPNOTSUPP) {
|
result->has_error = true;
|
||||||
error_setg_errno(errp, errno, "failed to trim %s",
|
if (errno == ENOTTY || errno == EOPNOTSUPP) {
|
||||||
mount->dirname);
|
result->error = g_strdup("trim not supported");
|
||||||
|
} else {
|
||||||
|
result->error = g_strdup_printf("failed to trim: %s",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
goto error;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result->has_minimum = true;
|
||||||
|
result->minimum = r.minlen;
|
||||||
|
result->has_trimmed = true;
|
||||||
|
result->trimmed = r.len;
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
|
||||||
free_fs_mount_list(&mounts);
|
free_fs_mount_list(&mounts);
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_FSTRIM */
|
#endif /* CONFIG_FSTRIM */
|
||||||
|
|
||||||
@ -2401,9 +2425,11 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp)
|
|||||||
#endif /* CONFIG_FSFREEZE */
|
#endif /* CONFIG_FSFREEZE */
|
||||||
|
|
||||||
#if !defined(CONFIG_FSTRIM)
|
#if !defined(CONFIG_FSTRIM)
|
||||||
void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
|
GuestFilesystemTrimResponse *
|
||||||
|
qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
|
||||||
{
|
{
|
||||||
error_setg(errp, QERR_UNSUPPORTED);
|
error_setg(errp, QERR_UNSUPPORTED);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -493,9 +493,11 @@ static void guest_fsfreeze_cleanup(void)
|
|||||||
* Walk list of mounted file systems in the guest, and discard unused
|
* Walk list of mounted file systems in the guest, and discard unused
|
||||||
* areas.
|
* areas.
|
||||||
*/
|
*/
|
||||||
void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
|
GuestFilesystemTrimResponse *
|
||||||
|
qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
|
||||||
{
|
{
|
||||||
error_setg(errp, QERR_UNSUPPORTED);
|
error_setg(errp, QERR_UNSUPPORTED);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -424,6 +424,30 @@
|
|||||||
{ 'command': 'guest-fsfreeze-thaw',
|
{ 'command': 'guest-fsfreeze-thaw',
|
||||||
'returns': 'int' }
|
'returns': 'int' }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @GuestFilesystemTrimResult
|
||||||
|
#
|
||||||
|
# @path: path that was trimmed
|
||||||
|
# @error: an error message when trim failed
|
||||||
|
# @trimmed: bytes trimmed for this path
|
||||||
|
# @minimum: reported effective minimum for this path
|
||||||
|
#
|
||||||
|
# Since: 2.4
|
||||||
|
##
|
||||||
|
{ 'struct': 'GuestFilesystemTrimResult',
|
||||||
|
'data': {'path': 'str',
|
||||||
|
'*trimmed': 'int', '*minimum': 'int', '*error': 'str'} }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @GuestFilesystemTrimResponse
|
||||||
|
#
|
||||||
|
# @paths: list of @GuestFilesystemTrimResult per path that was trimmed
|
||||||
|
#
|
||||||
|
# Since: 2.4
|
||||||
|
##
|
||||||
|
{ 'struct': 'GuestFilesystemTrimResponse',
|
||||||
|
'data': {'paths': ['GuestFilesystemTrimResult']} }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @guest-fstrim:
|
# @guest-fstrim:
|
||||||
#
|
#
|
||||||
@ -437,12 +461,14 @@
|
|||||||
# fragmented free space, although not all blocks will be discarded.
|
# fragmented free space, although not all blocks will be discarded.
|
||||||
# The default value is zero, meaning "discard every free block".
|
# The default value is zero, meaning "discard every free block".
|
||||||
#
|
#
|
||||||
# Returns: Nothing.
|
# Returns: A @GuestFilesystemTrimResponse which contains the
|
||||||
|
# status of all trimmed paths. (since 2.4)
|
||||||
#
|
#
|
||||||
# Since: 1.2
|
# Since: 1.2
|
||||||
##
|
##
|
||||||
{ 'command': 'guest-fstrim',
|
{ 'command': 'guest-fstrim',
|
||||||
'data': { '*minimum': 'int' } }
|
'data': { '*minimum': 'int' },
|
||||||
|
'returns': 'GuestFilesystemTrimResponse' }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @guest-suspend-disk
|
# @guest-suspend-disk
|
||||||
|
Loading…
Reference in New Issue
Block a user