[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v2 2/2] qemu-ga: add guest-fstrim command
From: |
Michal Privoznik |
Subject: |
Re: [Qemu-devel] [PATCH v2 2/2] qemu-ga: add guest-fstrim command |
Date: |
Wed, 13 Jun 2012 10:11:22 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:13.0) Gecko/20120608 Thunderbird/13.0 |
On 13.06.2012 07:41, Paolo Bonzini wrote:
> FITRIM is a mounted filesystem feature to discard (or "trim") blocks which
> are not in use by the filesystem. This is useful for solid-state drives
> (SSDs) and thinly-provisioned storage. Provide access to the feature
> from the host so that filesystems can be trimmed periodically or before
> migration.
>
> Here is an example using scsi_debug:
>
> # modprobe scsi_debug lbpu=1 lbpws=1
> # sg_vpd -p0xb2 /dev/sdb
> Logical block provisioning VPD page (SBC):
> Unmap command supported (LBPU): 1
> Write same (16) with unmap bit supported (LBWS): 1
> Write same (10) with unmap bit supported (LBWS10): 0
> # mke2fs /dev/sdb
> # cat /sys/bus/pseudo/drivers/scsi_debug/map
> 1-616,16257-16383
> # mount /dev/sdb /run/media/pbonzini/test
> # dd if=/dev/zero of=/run/media/pbonzini/test/file
> # cat map
> 1-616,645-1588,1599-4026,4029-16383
> # rm /run/media/pbonzini/test/file
> # ./qemu-ga /dev/fd/0
> {"execute":"guest-fstrim"}
> {"return": {}}
> # cat map
> 1-612
>
> Signed-off-by: Paolo Bonzini <address@hidden>
> ---
Reviewed-by: Michal Privoznik <address@hidden>
> v1->v2: fix version number, define mount list functions also for CONFIG_FSTRIM
>
> qapi-schema-guest.json | 20 +++++++++++++
> qga/commands-posix.c | 78
> ++++++++++++++++++++++++++++++++++++++++++++++--
> qga/commands-win32.c | 11 +++++++
> 3 files changed, 106 insertions(+), 3 deletions(-)
>
> diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json
> index d4055d2..d955cf1 100644
> --- a/qapi-schema-guest.json
> +++ b/qapi-schema-guest.json
> @@ -351,6 +351,26 @@
> 'returns': 'int' }
>
> ##
> +# @guest-fstrim:
> +#
> +# Discard (or "trim") blocks which are not in use by the filesystem.
> +#
> +# @minimum:
> +# Minimum contiguous free range to discard, in bytes. Free ranges
> +# smaller than this may be ignored (this is a hint and the guest
> +# may not respect it). By increasing this value, the fstrim
> +# operation will complete more quickly for filesystems with badly
> +# fragmented free space, although not all blocks will be discarded.
> +# The default value is zero, meaning "discard every free block".
> +#
> +# Returns: Nothing.
> +#
> +# Since: 1.2
> +##
> +{ 'command': 'guest-fstrim',
> + 'data': { '*minimum': 'int' } }
> +
> +##
> # @guest-suspend-disk
> #
> # Suspend guest to disk.
> diff --git a/qga/commands-posix.c b/qga/commands-posix.c
> index b1a7ce6..5fcbef4 100644
> --- a/qga/commands-posix.c
> +++ b/qga/commands-posix.c
> @@ -38,9 +38,12 @@ extern char **environ;
> #include <sys/socket.h>
> #include <net/if.h>
>
> -#if defined(__linux__) && defined(FIFREEZE)
> +#ifdef FIFREEZE
> #define CONFIG_FSFREEZE
> #endif
> +#ifdef FITRIM
> +#define CONFIG_FSTRIM
> +#endif
> #endif
>
> void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
> @@ -312,8 +315,7 @@ static void guest_file_init(void)
> /* linux-specific implementations. avoid this if at all possible. */
> #if defined(__linux__)
>
> -#if defined(CONFIG_FSFREEZE)
> -
> +#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
> typedef struct FsMount {
> char *dirname;
> char *devtype;
> @@ -378,6 +380,9 @@ static int build_fs_mount_list(FsMountList *mounts)
>
> return 0;
> }
> +#endif
> +
> +#if defined(CONFIG_FSFREEZE)
>
> /*
> * Return status of freeze/thaw
> @@ -525,6 +530,65 @@ static void guest_fsfreeze_cleanup(void)
> }
> #endif /* CONFIG_FSFREEZE */
>
> +#if defined(CONFIG_FSTRIM)
> +/*
> + * Walk list of mounted file systems in the guest, and trim them.
> + */
> +void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
> +{
> + int ret = 0;
> + FsMountList mounts;
> + struct FsMount *mount;
> + int fd;
> + char err_msg[512];
> + struct fstrim_range r = {
> + .start = 0,
> + .len = -1,
> + .minlen = has_minimum ? minimum : 0,
> + };
> +
> + slog("guest-fstrim called");
> +
> + QTAILQ_INIT(&mounts);
> + ret = build_fs_mount_list(&mounts);
> + if (ret < 0) {
> + return;
> + }
> +
> + QTAILQ_FOREACH(mount, &mounts, next) {
> + fd = qemu_open(mount->dirname, O_RDONLY);
> + if (fd == -1) {
> + sprintf(err_msg, "failed to open %s, %s", mount->dirname,
> + strerror(errno));
> + error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
> + goto error;
> + }
> +
> + /* We try to cull filesytems we know won't work in advance, but other
> + * filesytems may not implement fstrim for less obvious reasons.
> These
> + * will report EOPNOTSUPP; we simply ignore these errors. Any other
> + * error means an unexpected error, so return it in those cases. In
> + * some other cases ENOTTY will be reported (e.g. CD-ROMs).
> + */
> + ret = ioctl(fd, FITRIM, &r);
> + if (ret == -1) {
> + if (errno != ENOTTY && errno != EOPNOTSUPP) {
> + sprintf(err_msg, "failed to trim %s, %s",
> + mount->dirname, strerror(errno));
> + error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
> + close(fd);
> + goto error;
> + }
> + }
> + close(fd);
> + }
> +
> +error:
> + free_fs_mount_list(&mounts);
> +}
> +#endif /* CONFIG_FSTRIM */
> +
> +
> #define LINUX_SYS_STATE_FILE "/sys/power/state"
> #define SUSPEND_SUPPORTED 0
> #define SUSPEND_NOT_SUPPORTED 1
> @@ -918,7 +982,15 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err)
>
> return 0;
> }
> +#endif /* CONFIG_FSFREEZE */
> +
> +#if !defined(CONFIG_FSTRIM)
> +void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
> +{
> + error_set(err, QERR_UNSUPPORTED);
>
> + return;
> +}
> #endif
>
> /* register init/cleanup routines for stateful command groups */
> diff --git a/qga/commands-win32.c b/qga/commands-win32.c
> index eb8d140..54bc546 100644
> --- a/qga/commands-win32.c
> +++ b/qga/commands-win32.c
> @@ -173,6 +173,17 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err)
> return 0;
> }
>
> +/*
> + * Walk list of mounted file systems in the guest, and discard unused
> + * areas.
> + */
> +void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
> +{
> + error_set(err, QERR_UNSUPPORTED);
> +
> + return;
> +}
> +
> typedef enum {
> GUEST_SUSPEND_MODE_DISK,
> GUEST_SUSPEND_MODE_RAM
>