From patchwork Mon Nov 23 11:24:37 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Borntraeger X-Patchwork-Id: 7679741 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 649E89F750 for ; Mon, 23 Nov 2015 11:24:28 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2E22F20430 for ; Mon, 23 Nov 2015 11:24:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D8D8920443 for ; Mon, 23 Nov 2015 11:24:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752577AbbKWLYU (ORCPT ); Mon, 23 Nov 2015 06:24:20 -0500 Received: from e06smtp13.uk.ibm.com ([195.75.94.109]:58559 "EHLO e06smtp13.uk.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752287AbbKWLYQ (ORCPT ); Mon, 23 Nov 2015 06:24:16 -0500 Received: from localhost by e06smtp13.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 23 Nov 2015 11:24:14 -0000 Received: from d06dlp01.portsmouth.uk.ibm.com (9.149.20.13) by e06smtp13.uk.ibm.com (192.168.101.143) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 23 Nov 2015 11:24:13 -0000 X-IBM-Helo: d06dlp01.portsmouth.uk.ibm.com X-IBM-MailFrom: borntraeger@de.ibm.com X-IBM-RcptTo: kvm@vger.kernel.org Received: from b06cxnps4076.portsmouth.uk.ibm.com (d06relay13.portsmouth.uk.ibm.com [9.149.109.198]) by d06dlp01.portsmouth.uk.ibm.com (Postfix) with ESMTP id 7686F17D8042 for ; Mon, 23 Nov 2015 11:24:37 +0000 (GMT) Received: from d06av08.portsmouth.uk.ibm.com (d06av08.portsmouth.uk.ibm.com [9.149.37.249]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id tANBODFP7733692 for ; Mon, 23 Nov 2015 11:24:13 GMT Received: from d06av08.portsmouth.uk.ibm.com (localhost [127.0.0.1]) by d06av08.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id tANBOCRZ010004 for ; Mon, 23 Nov 2015 04:24:13 -0700 Received: from tuxmaker.boeblingen.de.ibm.com (tuxmaker.boeblingen.de.ibm.com [9.152.85.9]) by d06av08.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id tANBOCjD009989 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Mon, 23 Nov 2015 04:24:12 -0700 Received: by tuxmaker.boeblingen.de.ibm.com (Postfix, from userid 25651) id 4CE4120F534; Mon, 23 Nov 2015 12:24:12 +0100 (CET) From: Christian Borntraeger To: Paolo Bonzini Cc: KVM , Janosch Frank Subject: [PATCH 2/2] KVM: Create debugfs dir and stat files for each VM Date: Mon, 23 Nov 2015 12:24:37 +0100 Message-Id: <1448277877-15747-3-git-send-email-borntraeger@de.ibm.com> X-Mailer: git-send-email 2.3.0 In-Reply-To: <1448277877-15747-1-git-send-email-borntraeger@de.ibm.com> References: <1448277877-15747-1-git-send-email-borntraeger@de.ibm.com> X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 15112311-0013-0000-0000-000007BBA079 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Janosch Frank KVM statistics for VMs (no. of exits, halts and other special instructions) are currently only available in a summarized manner for all VMs. They are exported to userland through files in the kvm debugfs directory and used for performance monitoring, as well as VM problem detection with helper tools like kvm_stat. If a VM has problems and therefore creates a large number of exits, one can not easily find out which one it is, as there is no VM specific data. This patch adds a kvm debugfs subdirectory for each VM on kvm_create_vm(). The subdirectories are named by the VM pid and contain the same type of exported statistics that are already in the kvm debugfs directory, but the exported data is now VM specific. Signed-off-by: Janosch Frank Reviewed-by: Pierre Morel Acked-by: Christian Borntraeger Cc: Dan Carpenter [multiple fixes] Signed-off-by: Christian Borntraeger --- include/linux/kvm_host.h | 7 ++ virt/kvm/kvm_main.c | 194 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 192 insertions(+), 9 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 445a8c7..b7c9e03 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -425,6 +425,8 @@ struct kvm { #endif long tlbs_dirty; struct list_head devices; + struct dentry *debugfs_dentry; + struct kvm_stat_data **debugfs_data; }; #define kvm_err(fmt, ...) \ @@ -1000,6 +1002,11 @@ enum kvm_stat_kind { KVM_STAT_VCPU, }; +struct kvm_stat_data { + int offset; + struct kvm *kvm; +}; + struct kvm_stats_debugfs_item { const char *name; int offset; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index e1f6587..432267d 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -63,6 +63,9 @@ #define CREATE_TRACE_POINTS #include +/* Worst case buffer size needed for holding an integer. */ +#define ITOA_MAX_LEN 12 + MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); @@ -100,6 +103,9 @@ static __read_mostly struct preempt_ops kvm_preempt_ops; struct dentry *kvm_debugfs_dir; EXPORT_SYMBOL_GPL(kvm_debugfs_dir); +static u64 kvm_debugfs_num_entries; +static const struct file_operations *stat_fops_per_vm[]; + static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl, unsigned long arg); #ifdef CONFIG_KVM_COMPAT @@ -539,6 +545,75 @@ static void kvm_free_memslots(struct kvm *kvm, struct kvm_memslots *slots) kvfree(slots); } +static int kvm_destroy_vm_debugfs(struct kvm *kvm) +{ + u64 i; + struct kvm_stat_data **stat_data = kvm->debugfs_data; + + for (i = 0; i < kvm_debugfs_num_entries; i++) + kfree(stat_data[i]); + + kfree(kvm->debugfs_data); + + return 0; +} + +static int kvm_create_vm_debugfs(struct kvm *kvm) +{ + int r = 0, i = 0; + char dir_name[ITOA_MAX_LEN]; + struct kvm_stat_data *stat_data; + struct kvm_stats_debugfs_item *p; + + if (!kvm) + return -EINVAL; + + snprintf(dir_name, sizeof(dir_name), "%d", current->pid); + kvm->debugfs_dentry = debugfs_create_dir(dir_name, kvm_debugfs_dir); + if (!kvm->debugfs_dentry) + return -ENOMEM; + + kvm->debugfs_data = kmalloc(sizeof(*kvm->debugfs_data) * + kvm_debugfs_num_entries, GFP_KERNEL); + if (!kvm->debugfs_data) { + r = -ENOMEM; + goto err_remove_dir; + } + + for (p = debugfs_entries; p->name; p++, i++) { + stat_data = kzalloc(sizeof(*stat_data), GFP_KERNEL); + if (!stat_data) { + r = -ENOMEM; + goto out_err_clean; + } + + stat_data->offset = p->offset; + stat_data->kvm = kvm; + if (!debugfs_create_file(p->name, 0444, + kvm->debugfs_dentry, + stat_data, + stat_fops_per_vm[p->kind])) { + r = -EEXIST; + goto out_err_clean; + } + kvm->debugfs_data[i] = stat_data; + } + + return r; + +out_err_clean: + kfree(stat_data); + for (i--; i >= 0; i--) + kfree(kvm->debugfs_data[i]); + + kfree(kvm->debugfs_data); + +err_remove_dir: + debugfs_remove_recursive(kvm->debugfs_dentry); + + return r; +} + static struct kvm *kvm_create_vm(unsigned long type) { int r, i; @@ -597,6 +672,10 @@ static struct kvm *kvm_create_vm(unsigned long type) list_add(&kvm->vm_list, &vm_list); spin_unlock(&kvm_lock); + r = kvm_create_vm_debugfs(kvm); + if (r) + goto out_err; + preempt_notifier_inc(); return kvm; @@ -646,6 +725,7 @@ static void kvm_destroy_vm(struct kvm *kvm) int i; struct mm_struct *mm = kvm->mm; + kvm_destroy_vm_debugfs(kvm); kvm_arch_sync_events(kvm); spin_lock(&kvm_lock); list_del(&kvm->vm_list); @@ -689,6 +769,7 @@ static int kvm_vm_release(struct inode *inode, struct file *filp) { struct kvm *kvm = filp->private_data; + debugfs_remove_recursive(kvm->debugfs_dentry); kvm_irqfd_release(kvm); kvm_put_kvm(kvm); @@ -3400,15 +3481,108 @@ static struct notifier_block kvm_cpu_notifier = { .notifier_call = kvm_cpu_hotplug, }; +static int kvm_debugfs_open(struct inode *inode, struct file *file, + int (*get)(void *, u64 *), int (*set)(void *, u64), + const char *fmt) +{ + int err; + struct kvm_stat_data *stat_data = (struct kvm_stat_data *) + inode->i_private; + + err = simple_attr_open(inode, file, get, set, fmt); + if (err) + return err; + + kvm_get_kvm(stat_data->kvm); + + return 0; +} + +static int kvm_debugfs_release(struct inode *inode, struct file *file) +{ + struct kvm_stat_data *stat_data = (struct kvm_stat_data *) + inode->i_private; + + simple_attr_release(inode, file); + kvm_put_kvm(stat_data->kvm); + + return 0; +} + +static int vm_stat_get_per_vm(void *data, u64 *val) +{ + struct kvm_stat_data *stat_data = (struct kvm_stat_data *)data; + + *val = *(u32 *)((void *)stat_data->kvm + stat_data->offset); + + return 0; +} + +static int vm_stat_get_per_vm_open(struct inode *inode, struct file *file) +{ + __simple_attr_check_format("%llu\n", 0ull); + return simple_attr_open(inode, file, vm_stat_get_per_vm, + NULL, "%llu\n"); +} + +static const struct file_operations vm_stat_get_per_vm_fops = { + .owner = THIS_MODULE, + .open = vm_stat_get_per_vm_open, + .release = kvm_debugfs_release, + .read = simple_attr_read, + .write = simple_attr_write, + .llseek = generic_file_llseek, +}; + +static int vcpu_stat_get_per_vm(void *data, u64 *val) +{ + int i; + struct kvm_stat_data *stat_data = (struct kvm_stat_data *)data; + struct kvm_vcpu *vcpu; + + *val = 0; + + kvm_for_each_vcpu(i, vcpu, stat_data->kvm) + *val += *(u32 *)((void *)vcpu + stat_data->offset); + + return 0; +} + +static int vcpu_stat_get_per_vm_open(struct inode *inode, struct file *file) +{ + __simple_attr_check_format("%llu\n", 0ull); + return kvm_debugfs_open(inode, file, vcpu_stat_get_per_vm, + NULL, "%llu\n"); +} + +static const struct file_operations vcpu_stat_get_per_vm_fops = { + .owner = THIS_MODULE, + .open = vcpu_stat_get_per_vm_open, + .release = kvm_debugfs_release, + .read = simple_attr_read, + .write = simple_attr_write, + .llseek = generic_file_llseek, +}; + +static const struct file_operations *stat_fops_per_vm[] = { + [KVM_STAT_VCPU] = &vcpu_stat_get_per_vm_fops, + [KVM_STAT_VM] = &vm_stat_get_per_vm_fops, +}; + static int vm_stat_get(void *_offset, u64 *val) { unsigned offset = (long)_offset; struct kvm *kvm; + struct kvm_stat_data stat_tmp = {.offset = offset}; + u64 tmp_val; *val = 0; spin_lock(&kvm_lock); - list_for_each_entry(kvm, &vm_list, vm_list) - *val += *(u32 *)((void *)kvm + offset); + list_for_each_entry(kvm, &vm_list, vm_list) { + stat_tmp.kvm = kvm; + vm_stat_get_per_vm((void *)&stat_tmp, &tmp_val); + *val += tmp_val; + } spin_unlock(&kvm_lock); return 0; } @@ -3419,15 +3593,16 @@ static int vcpu_stat_get(void *_offset, u64 *val) { unsigned offset = (long)_offset; struct kvm *kvm; - struct kvm_vcpu *vcpu; - int i; + struct kvm_stat_data stat_tmp = {.offset = offset}; + u64 tmp_val; *val = 0; spin_lock(&kvm_lock); - list_for_each_entry(kvm, &vm_list, vm_list) - kvm_for_each_vcpu(i, vcpu, kvm) - *val += *(u32 *)((void *)vcpu + offset); - + list_for_each_entry(kvm, &vm_list, vm_list) { + stat_tmp.kvm = kvm; + vcpu_stat_get_per_vm((void *)&stat_tmp, &tmp_val); + *val += tmp_val; + } spin_unlock(&kvm_lock); return 0; } @@ -3448,7 +3623,8 @@ static int kvm_init_debug(void) if (kvm_debugfs_dir == NULL) goto out; - for (p = debugfs_entries; p->name; ++p) { + kvm_debugfs_num_entries = 0; + for (p = debugfs_entries; p->name; ++p, kvm_debugfs_num_entries++) { if (!debugfs_create_file(p->name, 0444, kvm_debugfs_dir, (void *)(long)p->offset, stat_fops[p->kind]))