From patchwork Wed Jun 13 05:41:28 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 164542 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 23ECBB6FD1 for ; Wed, 13 Jun 2012 15:42:16 +1000 (EST) Received: from localhost ([::1]:36614 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SegLO-0002s3-2m for incoming@patchwork.ozlabs.org; Wed, 13 Jun 2012 01:42:14 -0400 Received: from eggs.gnu.org ([208.118.235.92]:49806) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SegKq-0001GH-P2 for qemu-devel@nongnu.org; Wed, 13 Jun 2012 01:41:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SegKo-0006ts-N8 for qemu-devel@nongnu.org; Wed, 13 Jun 2012 01:41:40 -0400 Received: from mail-we0-f173.google.com ([74.125.82.173]:50144) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SegKo-0006tN-Br for qemu-devel@nongnu.org; Wed, 13 Jun 2012 01:41:38 -0400 Received: by werf3 with SMTP id f3so235485wer.4 for ; Tue, 12 Jun 2012 22:41:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=iL4FSKn6fAj8CwHgSEiQMj4/1WaPhcxzwPHfiZbDmP8=; b=qVXWJTd2nQefJIBTyQ2giXoMWRFN5fC6fPIA9FGjTCuIFsCQ3NMukXTXu3BNt/LUVW naVlTlBy8zRuvdxOjZCl1mPVc9+k0OwgVLJ/PEjQshlB5G/tiacTPCDLOHpe2TfD49/e iZ2rzuth2RGfCMozgCZwVVzkG5RFCLc//WsfcVc7qod6YCZyhL+X6kZlkFqy5Ma5bJDO FHyxfiYyxdUN8LNEwDZT/1FfLMnRXNjZ1fIW5gTJHL9k9T5aUMqE3ng8f3nbdZVQi9ym 5Dqp5Hap6bNAosMcbHkFByngI+SSjH2LKffkDrdoJMNRNYnh0/cRv+n/vBi2qdWr9SP9 EThw== Received: by 10.180.98.39 with SMTP id ef7mr34691639wib.21.1339566096009; Tue, 12 Jun 2012 22:41:36 -0700 (PDT) Received: from yakj.lan (93-34-204-25.ip51.fastwebnet.it. [93.34.204.25]) by mx.google.com with ESMTPS id n6sm5811413wie.7.2012.06.12.22.41.34 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 12 Jun 2012 22:41:35 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Wed, 13 Jun 2012 07:41:28 +0200 Message-Id: <1339566088-22542-3-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.7.10.2 In-Reply-To: <1339566088-22542-1-git-send-email-pbonzini@redhat.com> References: <1339566088-22542-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 74.125.82.173 Cc: mdroth@linux.vnet.ibm.com, lcapitulino@redhat.com Subject: [Qemu-devel] [PATCH v2 2/2] qemu-ga: add guest-fstrim command X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 Reviewed-by: Michal Privoznik --- 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 #include -#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