Re: [PATCH v2 2/4] KVM: introduce "xinterface" API for external interactionwith guests

From: Avi Kivity
Date: Tue Oct 06 2009 - 12:21:22 EST


On 10/06/2009 03:31 PM, Gregory Haskins wrote:

slots would be one implementation, if you can think of others then you'd
add them.
I'm more interested in *how* you'd add them more than "if" we would add
them. What I am getting at are the logistics of such a beast.

Add alternative ioctls, or have one ioctl with a 'type' field.

For instance, would I have /dev/slots-vas with ioctls for adding slots,
and /dev/foo-vas for adding foos? And each one would instantiate a
different vas_struct object with its own vas_struct->ops? Or were you
thinking of something different.

I think a single /dev/foo is sufficient, unless some of those address spaces are backed by real devices.

If you can't, I think it indicates that the whole thing isn't necessary
and we're better off with slots and virtual memory.
I'm not sure if we are talking about the same thing yet, but if we are,
there are uses of a generalized interface outside of slots/virtual
memory (Ira's physical box being a good example).

I'm not sure Ira's case is not best supported by virtual memory.

In any case, I think the best approach is what I already proposed.
KVM's arrangement of memory is going to tend to be KVM specific, and
what better place to implement the interface than close to the kvm.ko core.

The only thing missing is dma, which you don't deal with anyway.

Afaict I do support dma in the generalized vbus::memctx, though I do not
use it on anything related to KVM or xinterface. Can you elaborate on
the problem here? Does the SG interface in 4/4 help get us closer to
what you envision?

There's no dma method in there. Mapping to physical addresses is equivalent to get_user_pages(), so it doesn't add anything over virtual memory slots.

You'd have to copy the entire range since you don't know what the guest
might put there. I guess it's acceptable for small areas.
? The vmap is presumably part of an ABI between guest and host, so the
host should always know what structure is present within the region, and
what is relevant from within that structure to migrate once that state
is "frozen".

I was thinking of the case where the page is shared with some other (guest-private) data. But dirtying that data would be tracked by kvm, so it isn't a problem.

These regions (for vbus, anyway) equate to things like virtqueue
metadata, and presumably the same problem exists for virtio-net in
userspace as it does here, since that is another form of a "vmap". So
whatever solution works for virtio-net migrating its virtqueues in
userspace should be close to what will work here. The primary
difference is the location of the serializer.

Actually, virtio doesn't serialize this data, instead it marks the page dirty and lets normal RAM migration move it.


rmb()s are only needed if an external agent can issue writes, otherwise
you'd need one after every statement.
I was following lessons learned here:

http://lkml.org/lkml/2009/7/7/175

Perhaps mb() or barrier() are more appropriate than rmb()? I'm CC'ing
David Howells in case he has more insight.

I'm not sure I understand the reference. Callers and callees don't need memory barriers since they're guaranteed program order. You only need memory barriers when you have an external agent (a device, or another cpu). What external agent can touch things during ->release()?

A simple per-vcpu cache (in struct kvm_vcpu) is likely to give better
results.

per-vcpu will not work well here, unfortunately, since this is an
external interface mechanism. The callers will generally be from a
kthread or some other non-vcpu related context. Even if we could figure
out a vcpu to use as a basis, we would require some kind of
heavier-weight synchronization which would not be as desirable.

Therefore, I opted to go per-cpu and use the presumably lighterweight
get_cpu/put_cpu() instead.

This just assumes a low context switch rate.
It primarily assumes a low _migration_ rate, since you do not typically
have two contexts on the same cpu pounding on the memslots.

Why not? If you're overcommitted, you will, especially if you have multiple guests doing request/reply interaction (perhaps with each other).

And even if
you did, there's a good chance for locality between the threads, since
the IO activity is likely related. For the odd times where locality
fails to yield a hit, the time-slice or migration rate should be
sufficiently infrequent enough to still yield high 90s hit rates for
when it matters. For low-volume, the lookup is in the noise so I am not
as concerned.

IOW: Where the lookup hurts the most is trying to walk an SG list, since
each pointer is usually within the same slot. For this case, at least,
this cache helps immensely, at least according to profiles.

I'm wary of adding per-cpu data where it's easier to have a per-caller or per-vcpu cache.

How about a gfn_to_pfn_cached(..., struct gfn_to_pfn_cache *cache)?
Each user can place it in a natural place.
Sounds good. I will incorporate this into the split patch.

Note that for slots, typically most accesses hit just one slot (the largest). For guests below 4G, there's only one large slot, for guests above 4G there are two.

+static unsigned long
+xinterface_copy_to(struct kvm_xinterface *intf, unsigned long gpa,
+ const void *src, unsigned long n)
+{
+ struct _xinterface *_intf = to_intf(intf);
+ unsigned long dst;
+ bool kthread = !current->mm;
+
+ down_read(&_intf->kvm->slots_lock);
+
+ dst = gpa_to_hva(_intf, gpa);
+ if (!dst)
+ goto out;
+
+ if (kthread)
+ use_mm(_intf->mm);
+
+ if (kthread || _intf->mm == current->mm)
+ n = copy_to_user((void *)dst, src, n);
+ else
+ n = _slow_copy_to_user(_intf, dst, src, n);


Can't you switch the mm temporarily instead of this?

Thats actually what I do for the fast-path (use_mm() does a switch_to()
internally).

The slow-path is only there for completeness for when switching is not
possible (such as if called with an mm already active i.e.
process-context).
Still, why can't you switch temporarily?
I am not an mm expert, but iiuc you cannot call switch_to() from
anything other than kthread context. Thats what the doc says, anyway.

Can you provide a pointer? I don't see why this limitation exists.

In practice, however, this doesnt happen. Virtually
100% of the calls in vbus hit the fast-path here, and I suspect most
xinterface clients would find the same conditions as well.

So you have 100% untested code here.

Actually, no. Before Michael enlightened me recently regarding
switch_to/use_mm, the '_slow_xx' functions were my _only_ path. So they
have indeed multiple months (and multiple GB) of testing, as it turns
out. I only recently optimized them away to "backup" duty.

I meant, unexercised. This will bitrot quickly.

--
error compiling committee.c: too many arguments to function

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/