On Fri, Jun 18, 2021 at 1:57 AM Greg KH <gregkh@xxxxxxxxxxxxxxxxxxx> wrote: > > Minor comment nits: > > On Fri, Jun 18, 2021 at 04:48:14AM +0000, Jing Zhang wrote: > > +/* > > + * Common vm/vcpu stats read function to userspace. > > Should you use a real kernel-doc style here? You almost are, might as > well do it "right" :) > Will fix that. > > + * @id: identification string of the stats > > + * @header: stats header for a vm or a vcpu > > + * @desc: start address of an array of stats descriptors for a vm or a vcpu > > + * @stats: start address of stats data block for a vm or a vcpu > > + * @size_stats: the size of stats data block pointed by @stats > > + * @user_buffer: start address of userspace buffer > > + * @size: requested read size from userspace > > + * @offset: the start position from which the content will be read for the > > + * corresponding vm or vcp file descriptor > > + * > > + * The file content of a vm/vcpu file descriptor is now defined as below: > > + * +-------------+ > > + * | Header | > > + * +-------------+ > > + * | Descriptors | > > + * +-------------+ > > + * | Stats Data | > > + * +-------------+ > > Where is the "header id string"? In the header? > Yes, the id string is in the header. > > + * Although this function allows userspace to read any amount of data (as long > > + * as in the limit) from any position, the typical usage would follow below > > + * steps: > > + * 1. Read header from offset 0. Get the offset of descriptors and stats data > > + * and some other necessary information. This is a one-time work for the > > + * lifecycle of the corresponding vm/vcpu stats fd. > > + * 2. Read descriptors from its offset and discover all the stats by parsing > > + * descriptors. This is a one-time work for the lifecycle of the > > + * corresponding vm/vcpu stats fd. > > + * 3. Periodically read stats data from its offset. > > You forgot "2.5. rewind fd pointer position", see below... > Sure, will clarify that. > > + */ > > +ssize_t kvm_stats_read(char *id, struct kvm_stats_header *header, > > + struct _kvm_stats_desc *desc, void *stats, size_t size_stats, > > + char __user *user_buffer, size_t size, loff_t *offset) > > +{ > > + ssize_t len; > > + ssize_t copylen; > > + ssize_t remain = size; > > + size_t size_desc; > > + size_t size_header; > > + void *src; > > + loff_t pos = *offset; > > + char __user *dest = user_buffer; > > + > > + size_header = sizeof(*header); > > + size_desc = header->count * sizeof(*desc); > > + > > + len = KVM_STATS_ID_MAXLEN + size_header + size_desc + size_stats - pos; > > + len = min(len, remain); > > + if (len <= 0) > > + return 0; > > + remain = len; > > + > > + /* Copy kvm stats header. > > + * The header is the first block of content userspace usually read out. > > + * The pos is 0 and the copylen and remain would be the size of header. > > + * The copy of the header would be skipped if offset is larger than the > > + * size of header. That usually happens when userspace reads stats > > + * descriptors and stats data. > > + */ > > Looks like this is the networking "style" of multi-line comments, not > the rest of the kernel. You might want to fix this up to be the normal > style which would be: > > /* > * Copy kvm stats header. > * The header is the first block of content userspace usually read out. > * The pos is 0 and the copylen and remain would be the size of header. > * The copy of the header would be skipped if offset is larger than the > * size of header. That usually happens when userspace reads stats > * descriptors and stats data. > */ > > I do not know how picky the kvm maintainers are about this, that's up to > them :) > > Will fix it. > > + copylen = size_header - pos; > > + copylen = min(copylen, remain); > > + if (copylen > 0) { > > + src = (void *)header + pos; > > + if (copy_to_user(dest, src, copylen)) > > + return -EFAULT; > > + remain -= copylen; > > + pos += copylen; > > + dest += copylen; > > + } > > + > > + /* Copy kvm stats header id string. > > + * The id string is unique for every vm/vcpu, which is stored in kvm > > + * and kvm_vcpu structure. > > + */ > > This header too is skipped if necessary, so you should say that as well. > > Sure, will clarify that. > > + copylen = size_header + KVM_STATS_ID_MAXLEN - pos; > > + copylen = min(copylen, remain); > > + if (copylen > 0) { > > + src = id + pos - size_header; > > + if (copy_to_user(dest, src, copylen)) > > + return -EFAULT; > > + remain -= copylen; > > + pos += copylen; > > + dest += copylen; > > + } > > + > > + /* Copy kvm stats descriptors. > > + * The descriptors copy would be skipped in the typical case that > > + * userspace periodically read stats data, since the pos would be > > + * greater than the end address of descriptors > > + * (header->header.desc_offset + size_desc) causing copylen <= 0. > > + */ > > But you say that it is skipped here. > > > + copylen = header->desc_offset + size_desc - pos; > > + copylen = min(copylen, remain); > > + if (copylen > 0) { > > + src = (void *)desc + pos - header->desc_offset; > > + if (copy_to_user(dest, src, copylen)) > > + return -EFAULT; > > + remain -= copylen; > > + pos += copylen; > > + dest += copylen; > > + } > > + > > + /* Copy kvm stats values */ > > + copylen = header->data_offset + size_stats - pos; > > + copylen = min(copylen, remain); > > + if (copylen > 0) { > > + src = stats + pos - header->data_offset; > > This lets you sync to the end of the header and read just the stats, but > does that mean that userspace keeps needing to "rewind" back to the end > of the header to read the stats again? > > Or can it just keep reading off the end of the previous read? > > It's not quite obvious here, and I mention that above in step "2.5", so > maybe I am wrong, which is fine, but then I'm confused :) Userspace needs to rewind back to read the stats again or just use pread as Paolo mentioned and that's used in the testcase. > > > thanks, > > greg k-h