All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Hildenbrand <david@redhat.com>
To: Christian Borntraeger <borntraeger@de.ibm.com>,
	Janosch Frank <frankja@linux.vnet.ibm.com>
Cc: KVM <kvm@vger.kernel.org>, Cornelia Huck <cohuck@redhat.com>,
	Thomas Huth <thuth@redhat.com>,
	Ulrich Weigand <Ulrich.Weigand@de.ibm.com>,
	Claudio Imbrenda <imbrenda@linux.ibm.com>,
	linux-s390 <linux-s390@vger.kernel.org>,
	Michael Mueller <mimu@linux.ibm.com>,
	Vasily Gorbik <gor@linux.ibm.com>,
	Janosch Frank <frankja@linux.ibm.com>
Subject: Re: [PATCH v4 09/36] KVM: s390: protvirt: Add initial vm and cpu lifecycle handling
Date: Tue, 25 Feb 2020 18:46:09 +0100	[thread overview]
Message-ID: <f80a0b58-5ed2-33b7-5292-2c4899d765b7@redhat.com> (raw)
In-Reply-To: <20200224114107.4646-10-borntraeger@de.ibm.com>

On 24.02.20 12:40, Christian Borntraeger wrote:
> From: Janosch Frank <frankja@linux.ibm.com>
> 
> This contains 3 main changes:
> 1. changes in SIE control block handling for secure guests
> 2. helper functions for create/destroy/unpack secure guests
> 3. KVM_S390_PV_COMMAND ioctl to allow userspace dealing with secure
> machines

side note: I really dislike such patch descriptions (lists!) and
squashing a whole bunch of things that could be nicely split up into
separat patches (with much nicer patch descriptions) into a single
patch. E.g., enable/disable would be sufficiently complicated to review.

This makes review unnecessary complicated. But here we are in v4, so
I'll try my best for (hopefully) the second last time ;)

[...]

> +static int kvm_s390_cpus_from_pv(struct kvm *kvm, u16 *rcp, u16 *rrcp)
> +{
> +	struct kvm_vcpu *vcpu;
> +	bool failed = false;
> +	u16 rc, rrc;
> +	int cc = 0;
> +	int i;
> +
> +	/*
> +	 * we ignore failures and try to destroy as many CPUs as possible.

nit: "We"

> +	 * At the same time we must not free the assigned resources when
> +	 * this fails, as the ultravisor has still access to that memory.
> +	 * So kvm_s390_pv_destroy_cpu can leave a "wanted" memory leak
> +	 * behind.
> +	 * We want to return the first failure rc and rrc though.

nit, ", though".

> +	 */
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		mutex_lock(&vcpu->mutex);
> +		if (kvm_s390_pv_destroy_cpu(vcpu, &rc, &rrc) && !failed) {
> +			*rcp = rc;
> +			*rrcp = rrc;
> +			cc = 1;
> +			failed = true;

no need for "failed". Just check against cc != 0 instead.

> +		}
> +		mutex_unlock(&vcpu->mutex);
> +	}
> +	return cc;

The question will repeat a couple of times in the patch: Do we want to
convert that to a proper error (e.g., EBUSY, EINVAL, EWHATSOEVER)
instead of returning "1" to user space (whoch looks weird).

> +}
> +
> +static int kvm_s390_cpus_to_pv(struct kvm *kvm, u16 *rc, u16 *rrc)
> +{
> +	int i, r = 0;
> +	u16 dummy;
> +
> +	struct kvm_vcpu *vcpu;
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		mutex_lock(&vcpu->mutex);
> +		r = kvm_s390_pv_create_cpu(vcpu, rc, rrc);
> +		mutex_unlock(&vcpu->mutex);
> +		if (r)
> +			break;
> +	}
> +	if (r)
> +		kvm_s390_cpus_from_pv(kvm, &dummy, &dummy);
> +	return r;
> +}

[...]

> @@ -0,0 +1,266 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Hosting Secure Execution virtual machines

Just wondering "Protected Virtualization" vs. "Secure Execution".

[...]

> +int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc)
> +{
> +	int cc = 0;
> +
> +	if (kvm_s390_pv_cpu_get_handle(vcpu)) {
> +		cc = uv_cmd_nodata(kvm_s390_pv_cpu_get_handle(vcpu),
> +				   UVC_CMD_DESTROY_SEC_CPU, rc, rrc);
> +
> +		KVM_UV_EVENT(vcpu->kvm, 3,
> +			     "PROTVIRT DESTROY VCPU %d: rc %x rrc %x",
> +			     vcpu->vcpu_id, *rc, *rrc);
> +		WARN_ONCE(cc, "protvirt destroy cpu failed rc %x rrc %x",
> +			  *rc, *rrc);
> +	}

/* Intended memory leak for something that should never happen. */

> +	if (!cc)
> +		free_pages(vcpu->arch.pv.stor_base,
> +			   get_order(uv_info.guest_cpu_stor_len));

Should we clear arch.pv.handle?

Also, I do wonder if it makes sense to

vcpu->arch.pv.stor_base = NULL;

So really remove any traces and act like the error never happened. Only
skip the freeing. Makes sense? Then we're not stuck with a
half-initialized VM state.


> +	vcpu->arch.sie_block->pv_handle_cpu = 0;
> +	vcpu->arch.sie_block->pv_handle_config = 0;
> +	memset(&vcpu->arch.pv, 0, sizeof(vcpu->arch.pv));
> +	vcpu->arch.sie_block->sdf = 0;
> +	kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
> +
> +	return cc;

Convert to a proper error?

> +}
> +
> +int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc)
> +{
> +	struct uv_cb_csc uvcb = {
> +		.header.cmd = UVC_CMD_CREATE_SEC_CPU,
> +		.header.len = sizeof(uvcb),
> +	};
> +	int cc;
> +
> +	if (kvm_s390_pv_cpu_get_handle(vcpu))
> +		return -EINVAL;
> +
> +	vcpu->arch.pv.stor_base = __get_free_pages(GFP_KERNEL,
> +						   get_order(uv_info.guest_cpu_stor_len));
> +	if (!vcpu->arch.pv.stor_base)
> +		return -ENOMEM;
> +
> +	/* Input */
> +	uvcb.guest_handle = kvm_s390_pv_get_handle(vcpu->kvm);
> +	uvcb.num = vcpu->arch.sie_block->icpua;
> +	uvcb.state_origin = (u64)vcpu->arch.sie_block;
> +	uvcb.stor_origin = (u64)vcpu->arch.pv.stor_base;
> +
> +	cc = uv_call(0, (u64)&uvcb);
> +	*rc = uvcb.header.rc;
> +	*rrc = uvcb.header.rrc;
> +	KVM_UV_EVENT(vcpu->kvm, 3,
> +		     "PROTVIRT CREATE VCPU: cpu %d handle %llx rc %x rrc %x",
> +		     vcpu->vcpu_id, uvcb.cpu_handle, uvcb.header.rc,
> +		     uvcb.header.rrc);
> +
> +	if (cc) {
> +		u16 dummy;
> +
> +		kvm_s390_pv_destroy_cpu(vcpu, &dummy, &dummy);
> +		return -EINVAL;

Ah, here we convert from cc to an actual error :)

> +	}
> +
> +	/* Output */
> +	vcpu->arch.pv.handle = uvcb.cpu_handle;
> +	vcpu->arch.sie_block->pv_handle_cpu = uvcb.cpu_handle;
> +	vcpu->arch.sie_block->pv_handle_config = kvm_s390_pv_get_handle(vcpu->kvm);
> +	vcpu->arch.sie_block->sdf = 2;
> +	kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
> +	return 0;
> +}
> +
> +/* only free resources when the destroy was successful */

s/destroy/deinit/

> +static void kvm_s390_pv_dealloc_vm(struct kvm *kvm)
> +{
> +	vfree(kvm->arch.pv.stor_var);
> +	free_pages(kvm->arch.pv.stor_base,
> +		   get_order(uv_info.guest_base_stor_len));
> +	memset(&kvm->arch.pv, 0, sizeof(kvm->arch.pv));
> +}
> +
> +static int kvm_s390_pv_alloc_vm(struct kvm *kvm)
> +{
> +	unsigned long base = uv_info.guest_base_stor_len;
> +	unsigned long virt = uv_info.guest_virt_var_stor_len;
> +	unsigned long npages = 0, vlen = 0;
> +	struct kvm_memory_slot *memslot;
> +
> +	kvm->arch.pv.stor_var = NULL;
> +	kvm->arch.pv.stor_base = __get_free_pages(GFP_KERNEL, get_order(base));
> +	if (!kvm->arch.pv.stor_base)
> +		return -ENOMEM;
> +
> +	/*
> +	 * Calculate current guest storage for allocation of the
> +	 * variable storage, which is based on the length in MB.
> +	 *
> +	 * Slots are sorted by GFN
> +	 */
> +	mutex_lock(&kvm->slots_lock);
> +	memslot = kvm_memslots(kvm)->memslots;
> +	npages = memslot->base_gfn + memslot->npages;

I remember I asked this question already, maybe I missed the reply :(

1. What if we have multiple slots?
2. What is expected to happen if new slots are added (e.g., memory
hotplug in the future?)

Shouldn't you bail out if there is more than one slot and make sure that
no new ones can be added as long as pv is active (I remember the latter
should be very easy from an arch callback)?

> +	mutex_unlock(&kvm->slots_lock);
> +
> +	kvm->arch.pv.guest_len = npages * PAGE_SIZE;
> +
> +	/* Allocate variable storage */
> +	vlen = ALIGN(virt * ((npages * PAGE_SIZE) / HPAGE_SIZE), PAGE_SIZE);
> +	vlen += uv_info.guest_virt_base_stor_len;
> +	kvm->arch.pv.stor_var = vzalloc(vlen);
> +	if (!kvm->arch.pv.stor_var)
> +		goto out_err;
> +	return 0;
> +
> +out_err:
> +	kvm_s390_pv_dealloc_vm(kvm);
> +	return -ENOMEM;
> +}
> +
> +/* this should not fail, but if it does we must not free the donated memory */
> +int kvm_s390_pv_deinit_vm(struct kvm *kvm, u16 *rc, u16 *rrc)
> +{
> +	int cc;
> +
> +	cc = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm),
> +			   UVC_CMD_DESTROY_SEC_CONF, rc, rrc);

Could convert to

int cc = ...

> +	WRITE_ONCE(kvm->arch.gmap->guest_handle, 0);
> +	atomic_set(&kvm->mm->context.is_protected, 0);
> +	KVM_UV_EVENT(kvm, 3, "PROTVIRT DESTROY VM: rc %x rrc %x", *rc, *rrc);
> +	WARN_ONCE(cc, "protvirt destroy vm failed rc %x rrc %x", *rc, *rrc);
> +	if (!cc)
> +		kvm_s390_pv_dealloc_vm(kvm);

Similar to the VCPU path, should be set all pointers to NULL but skip
the freeing? With a similar comment /* Inteded memory leak ... */

> +	return cc;

Does it make more sense to translate that to a proper error? (EBUSY,
EINVAL etc.) I'd assume we translate that to a proper error - if any.
Returning e.g., "1" does not make too much sense IMHO.

> +}
> +
> +int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc)
> +{
> +	u16 drc, drrc;
> +	int cc, ret;
> +

superfluous empty line.

> +	struct uv_cb_cgc uvcb = {
> +		.header.cmd = UVC_CMD_CREATE_SEC_CONF,
> +		.header.len = sizeof(uvcb)
> +	};

maybe

int ret = kvm_s390_pv_alloc_vm(kvm);

no strong feelings.

> +
> +	ret = kvm_s390_pv_alloc_vm(kvm);
> +	if (ret)
> +		return ret;
> +
> +	/* Inputs */
> +	uvcb.guest_stor_origin = 0; /* MSO is 0 for KVM */
> +	uvcb.guest_stor_len = kvm->arch.pv.guest_len;
> +	uvcb.guest_asce = kvm->arch.gmap->asce;
> +	uvcb.guest_sca = (unsigned long)kvm->arch.sca;
> +	uvcb.conf_base_stor_origin = (u64)kvm->arch.pv.stor_base;
> +	uvcb.conf_virt_stor_origin = (u64)kvm->arch.pv.stor_var;
> +
> +	cc = uv_call(0, (u64)&uvcb);
> +	*rc = uvcb.header.rc;
> +	*rrc = uvcb.header.rrc;
> +	KVM_UV_EVENT(kvm, 3, "PROTVIRT CREATE VM: handle %llx len %llx rc %x rrc %x",
> +		     uvcb.guest_handle, uvcb.guest_stor_len, *rc, *rrc);
> +
> +	/* Outputs */
> +	kvm->arch.pv.handle = uvcb.guest_handle;
> +
> +	if (cc && (uvcb.header.rc & UVC_RC_NEED_DESTROY)) {

So, in case cc!=0 and UVC_RC_NEED_DESTROY is not set, we would return an
error (!=0 from this function) and not even try to deinit the vm?

This is honestly confusing stuff.

> +		if (!kvm_s390_pv_deinit_vm(kvm, &drc, &drrc))
> +			kvm_s390_pv_dealloc_vm(kvm);

kvm_s390_pv_deinit_vm() will already call kvm_s390_pv_dealloc_vm().

> +		return -EINVAL;
> +	}
> +	kvm->arch.gmap->guest_handle = uvcb.guest_handle;
> +	atomic_set(&kvm->mm->context.is_protected, 1);
> +	return cc;

Convert to a proper error?


Feel free to send a new version of this patch only on top. I'll try to
review it very fast :)

-- 
Thanks,

David / dhildenb

  reply	other threads:[~2020-02-25 17:46 UTC|newest]

Thread overview: 101+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-24 11:40 [PATCH v4 00/36] KVM: s390: Add support for protected VMs Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 01/36] mm/gup/writeback: add callbacks for inaccessible pages Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 02/36] KVM: s390/interrupt: do not pin adapter interrupt pages Christian Borntraeger
2020-02-25 10:18   ` Cornelia Huck
2020-02-24 11:40 ` [PATCH v4 03/36] s390/protvirt: introduce host side setup Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 04/36] s390/protvirt: add ultravisor initialization Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 05/36] s390/mm: provide memory management functions for protected KVM guests Christian Borntraeger
2020-02-25 10:32   ` Cornelia Huck
2020-02-24 11:40 ` [PATCH v4 06/36] s390/mm: add (non)secure page access exceptions handlers Christian Borntraeger
2020-02-25 10:37   ` Cornelia Huck
2020-02-24 11:40 ` [PATCH v4 07/36] KVM: s390: protvirt: Add UV debug trace Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 08/36] KVM: s390: add new variants of UV CALL Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 09/36] KVM: s390: protvirt: Add initial vm and cpu lifecycle handling Christian Borntraeger
2020-02-25 17:46   ` David Hildenbrand [this message]
2020-02-25 21:44     ` Christian Borntraeger
2020-02-25 22:29       ` David Hildenbrand
2020-02-25 21:48     ` [PATCH v4.5 " Christian Borntraeger
2020-02-25 22:37       ` David Hildenbrand
2020-02-26  8:12         ` Christian Borntraeger
2020-02-26  8:28           ` David Hildenbrand
2020-02-26  9:12             ` Christian Borntraeger
2020-02-26  9:15               ` David Hildenbrand
2020-02-26 10:01       ` Cornelia Huck
2020-02-26 10:52         ` Christian Borntraeger
2020-02-26 10:38       ` Cornelia Huck
2020-02-26 11:03         ` Christian Borntraeger
2020-02-26 12:26       ` Cornelia Huck
2020-02-26 13:31         ` Christian Borntraeger
2020-02-26 16:54           ` Cornelia Huck
2020-02-26 17:00             ` [PATCH v4.6 " Christian Borntraeger
2020-02-26 17:08               ` Cornelia Huck
2020-02-24 11:40 ` [PATCH v4 10/36] KVM: s390: protvirt: Secure memory is not mergeable Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 11/36] KVM: s390/mm: Make pages accessible before destroying the guest Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 12/36] KVM: s390: protvirt: Handle SE notification interceptions Christian Borntraeger
2020-02-25 11:11   ` Cornelia Huck
2020-02-24 11:40 ` [PATCH v4 13/36] KVM: s390: protvirt: Instruction emulation Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 14/36] KVM: s390: protvirt: Implement interrupt injection Christian Borntraeger
2020-02-25 12:07   ` Cornelia Huck
2020-02-24 11:40 ` [PATCH v4 15/36] KVM: s390: protvirt: Add SCLP interrupt handling Christian Borntraeger
2020-02-25 12:11   ` Cornelia Huck
2020-02-24 11:40 ` [PATCH v4 16/36] KVM: s390: protvirt: Handle spec exception loops Christian Borntraeger
2020-02-24 19:14   ` David Hildenbrand
2020-02-24 11:40 ` [PATCH v4 17/36] KVM: s390: protvirt: Add new gprs location handling Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 18/36] KVM: S390: protvirt: Introduce instruction data area bounce buffer Christian Borntraeger
2020-02-24 19:13   ` David Hildenbrand
2020-02-25  7:50     ` Christian Borntraeger
2020-02-25  8:18       ` David Hildenbrand
2020-02-25 17:21       ` Cornelia Huck
2020-02-25 18:39         ` Christian Borntraeger
2020-02-25 17:19   ` Cornelia Huck
2020-02-25 18:37     ` Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 19/36] KVM: s390: protvirt: handle secure guest prefix pages Christian Borntraeger
2020-02-25 12:15   ` Cornelia Huck
2020-02-24 11:40 ` [PATCH v4 20/36] KVM: s390/mm: handle guest unpin events Christian Borntraeger
2020-02-25 12:18   ` Cornelia Huck
2020-02-25 14:21     ` Christian Borntraeger
2020-02-25 14:30       ` Cornelia Huck
2020-02-24 11:40 ` [PATCH v4 21/36] KVM: s390: protvirt: Write sthyi data to instruction data area Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 22/36] KVM: s390: protvirt: STSI handling Christian Borntraeger
2020-02-24 19:00   ` David Hildenbrand
2020-02-24 11:40 ` [PATCH v4 23/36] KVM: s390: protvirt: disallow one_reg Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 24/36] KVM: s390: protvirt: Do only reset registers that are accessible Christian Borntraeger
2020-02-25 12:32   ` Cornelia Huck
2020-02-25 12:51     ` Janosch Frank
2020-02-25 13:06       ` Cornelia Huck
2020-02-25 13:08         ` Christian Borntraeger
2020-02-25 13:16           ` Cornelia Huck
2020-02-25 13:07     ` Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 25/36] KVM: s390: protvirt: Only sync fmt4 registers Christian Borntraeger
2020-02-25 12:36   ` Cornelia Huck
2020-02-24 11:40 ` [PATCH v4 26/36] KVM: s390: protvirt: Add program exception injection Christian Borntraeger
2020-02-24 11:40 ` [PATCH v4 27/36] KVM: s390: protvirt: UV calls in support of diag308 0, 1 Christian Borntraeger
2020-02-25 12:51   ` Cornelia Huck
2020-02-24 11:40 ` [PATCH v4 28/36] KVM: s390: protvirt: Report CPU state to Ultravisor Christian Borntraeger
2020-02-24 19:05   ` David Hildenbrand
2020-02-25  8:29     ` Christian Borntraeger
2020-02-25  8:41       ` David Hildenbrand
2020-02-25 13:01       ` Cornelia Huck
2020-02-25 13:21         ` Christian Borntraeger
2020-02-25 13:44           ` Cornelia Huck
2020-02-24 11:41 ` [PATCH v4 29/36] KVM: s390: protvirt: Support cmd 5 operation state Christian Borntraeger
2020-02-24 19:08   ` David Hildenbrand
2020-02-25  7:53     ` Christian Borntraeger
2020-02-25 13:21       ` Cornelia Huck
2020-02-24 11:41 ` [PATCH v4 30/36] KVM: s390: protvirt: Mask PSW interrupt bits for interception 104 and 112 Christian Borntraeger
2020-02-24 11:41 ` [PATCH v4 31/36] KVM: s390: protvirt: do not inject interrupts after start Christian Borntraeger
2020-02-24 11:41 ` [PATCH v4 32/36] KVM: s390: protvirt: Add UV cpu reset calls Christian Borntraeger
2020-02-24 11:41 ` [PATCH v4 33/36] DOCUMENTATION: Protected virtual machine introduction and IPL Christian Borntraeger
2020-02-25 16:22   ` Cornelia Huck
2020-02-25 16:42     ` Christian Borntraeger
2020-02-24 11:41 ` [PATCH v4 34/36] s390: protvirt: Add sysfs firmware interface for Ultravisor information Christian Borntraeger
2020-02-25 13:30   ` Cornelia Huck
2020-02-25 13:37   ` Cornelia Huck
2020-02-24 11:41 ` [PATCH v4 35/36] KVM: s390: protvirt: introduce and enable KVM_CAP_S390_PROTECTED Christian Borntraeger
2020-02-25 13:22   ` Cornelia Huck
2020-02-24 11:41 ` [PATCH v4 36/36] KVM: s390: protvirt: Add KVM api documentation Christian Borntraeger
2020-02-25 15:50   ` Cornelia Huck
2020-02-25 19:30     ` Christian Borntraeger
2020-02-27  8:47       ` [PATCH v4.1 " Christian Borntraeger
2020-02-27  9:04         ` Cornelia Huck
2020-02-26  9:35 ` [PATCH v4 00/36] KVM: s390: Add support for protected VMs Christian Borntraeger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f80a0b58-5ed2-33b7-5292-2c4899d765b7@redhat.com \
    --to=david@redhat.com \
    --cc=Ulrich.Weigand@de.ibm.com \
    --cc=borntraeger@de.ibm.com \
    --cc=cohuck@redhat.com \
    --cc=frankja@linux.ibm.com \
    --cc=frankja@linux.vnet.ibm.com \
    --cc=gor@linux.ibm.com \
    --cc=imbrenda@linux.ibm.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=mimu@linux.ibm.com \
    --cc=thuth@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.