![]() |
|
|||
0001 // SPDX-License-Identifier: GPL-2.0-only 0002 /* 0003 * KVM binary statistics interface implementation 0004 * 0005 * Copyright 2021 Google LLC 0006 */ 0007 0008 #include <linux/kvm_host.h> 0009 #include <linux/kvm.h> 0010 #include <linux/errno.h> 0011 #include <linux/uaccess.h> 0012 0013 /** 0014 * kvm_stats_read() - Common function to read from the binary statistics 0015 * file descriptor. 0016 * 0017 * @id: identification string of the stats 0018 * @header: stats header for a vm or a vcpu 0019 * @desc: start address of an array of stats descriptors for a vm or a vcpu 0020 * @stats: start address of stats data block for a vm or a vcpu 0021 * @size_stats: the size of stats data block pointed by @stats 0022 * @user_buffer: start address of userspace buffer 0023 * @size: requested read size from userspace 0024 * @offset: the start position from which the content will be read for the 0025 * corresponding vm or vcp file descriptor 0026 * 0027 * The file content of a vm/vcpu file descriptor is now defined as below: 0028 * +-------------+ 0029 * | Header | 0030 * +-------------+ 0031 * | id string | 0032 * +-------------+ 0033 * | Descriptors | 0034 * +-------------+ 0035 * | Stats Data | 0036 * +-------------+ 0037 * Although this function allows userspace to read any amount of data (as long 0038 * as in the limit) from any position, the typical usage would follow below 0039 * steps: 0040 * 1. Read header from offset 0. Get the offset of descriptors and stats data 0041 * and some other necessary information. This is a one-time work for the 0042 * lifecycle of the corresponding vm/vcpu stats fd. 0043 * 2. Read id string from its offset. This is a one-time work for the lifecycle 0044 * of the corresponding vm/vcpu stats fd. 0045 * 3. Read descriptors from its offset and discover all the stats by parsing 0046 * descriptors. This is a one-time work for the lifecycle of the 0047 * corresponding vm/vcpu stats fd. 0048 * 4. Periodically read stats data from its offset using pread. 0049 * 0050 * Return: the number of bytes that has been successfully read 0051 */ 0052 ssize_t kvm_stats_read(char *id, const struct kvm_stats_header *header, 0053 const struct _kvm_stats_desc *desc, 0054 void *stats, size_t size_stats, 0055 char __user *user_buffer, size_t size, loff_t *offset) 0056 { 0057 ssize_t len; 0058 ssize_t copylen; 0059 ssize_t remain = size; 0060 size_t size_desc; 0061 size_t size_header; 0062 void *src; 0063 loff_t pos = *offset; 0064 char __user *dest = user_buffer; 0065 0066 size_header = sizeof(*header); 0067 size_desc = header->num_desc * sizeof(*desc); 0068 0069 len = KVM_STATS_NAME_SIZE + size_header + size_desc + size_stats - pos; 0070 len = min(len, remain); 0071 if (len <= 0) 0072 return 0; 0073 remain = len; 0074 0075 /* 0076 * Copy kvm stats header. 0077 * The header is the first block of content userspace usually read out. 0078 * The pos is 0 and the copylen and remain would be the size of header. 0079 * The copy of the header would be skipped if offset is larger than the 0080 * size of header. That usually happens when userspace reads stats 0081 * descriptors and stats data. 0082 */ 0083 copylen = size_header - pos; 0084 copylen = min(copylen, remain); 0085 if (copylen > 0) { 0086 src = (void *)header + pos; 0087 if (copy_to_user(dest, src, copylen)) 0088 return -EFAULT; 0089 remain -= copylen; 0090 pos += copylen; 0091 dest += copylen; 0092 } 0093 0094 /* 0095 * Copy kvm stats header id string. 0096 * The id string is unique for every vm/vcpu, which is stored in kvm 0097 * and kvm_vcpu structure. 0098 * The id string is part of the stat header from the perspective of 0099 * userspace, it is usually read out together with previous constant 0100 * header part and could be skipped for later descriptors and stats 0101 * data readings. 0102 */ 0103 copylen = header->id_offset + KVM_STATS_NAME_SIZE - pos; 0104 copylen = min(copylen, remain); 0105 if (copylen > 0) { 0106 src = id + pos - header->id_offset; 0107 if (copy_to_user(dest, src, copylen)) 0108 return -EFAULT; 0109 remain -= copylen; 0110 pos += copylen; 0111 dest += copylen; 0112 } 0113 0114 /* 0115 * Copy kvm stats descriptors. 0116 * The descriptors copy would be skipped in the typical case that 0117 * userspace periodically read stats data, since the pos would be 0118 * greater than the end address of descriptors 0119 * (header->header.desc_offset + size_desc) causing copylen <= 0. 0120 */ 0121 copylen = header->desc_offset + size_desc - pos; 0122 copylen = min(copylen, remain); 0123 if (copylen > 0) { 0124 src = (void *)desc + pos - header->desc_offset; 0125 if (copy_to_user(dest, src, copylen)) 0126 return -EFAULT; 0127 remain -= copylen; 0128 pos += copylen; 0129 dest += copylen; 0130 } 0131 0132 /* Copy kvm stats values */ 0133 copylen = header->data_offset + size_stats - pos; 0134 copylen = min(copylen, remain); 0135 if (copylen > 0) { 0136 src = stats + pos - header->data_offset; 0137 if (copy_to_user(dest, src, copylen)) 0138 return -EFAULT; 0139 pos += copylen; 0140 } 0141 0142 *offset = pos; 0143 return len; 0144 }
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.1.0 LXR engine. The LXR team |
![]() ![]() |