Re: [PATCH v5 03/10] KVM: s390: pv: Add query interface

Claudio Imbrenda
2022-05-17T11:37:22Z

On Mon, 16 May 2022 09:08:10 +0000
Janosch Frank <frankja@linux.ibm.com> wrote:

> Some of the query information is already available via sysfs but
> having a IOCTL makes the information easier to retrieve.
>
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>

Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>

> ---
> arch/s390/kvm/kvm-s390.c | 76 ++++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/kvm.h | 25 +++++++++++++
> 2 files changed, 101 insertions(+)
>
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index 76ad6408cb2c..5859f243d287 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -2224,6 +2224,42 @@ static int kvm_s390_cpus_to_pv(struct kvm *kvm, u16 *rc, u16 *rrc)
> return r;
> }
>
> +/*
> + * Here we provide user space with a direct interface to query UV
> + * related data like UV maxima and available features as well as
> + * feature specific data.
> + *
> + * To facilitate future extension of the data structures we'll try to
> + * write data up to the maximum requested length.
> + */
> +static ssize_t kvm_s390_handle_pv_info(struct kvm_s390_pv_info *info)
> +{
> + ssize_t len_min;
> +
> + switch (info->header.id) {
> + case KVM_PV_INFO_VM: {
> + len_min = sizeof(info->header) + sizeof(info->vm);
> +
> + if (info->header.len_max < len_min)
> + return -EINVAL;
> +
> + memcpy(info->vm.inst_calls_list,
> + uv_info.inst_calls_list,
> + sizeof(uv_info.inst_calls_list));
> +
> + /* It's max cpuid not max cpus, so it's off by one */
> + info->vm.max_cpus = uv_info.max_guest_cpu_id + 1;
> + info->vm.max_guests = uv_info.max_num_sec_conf;
> + info->vm.max_guest_addr = uv_info.max_sec_stor_addr;
> + info->vm.feature_indication = uv_info.uv_feature_indications;
> +
> + return len_min;
> + }
> + default:
> + return -EINVAL;
> + }
> +}
> +
> static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd)
> {
> int r = 0;
> @@ -2360,6 +2396,46 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd)
> cmd->rc, cmd->rrc);
> break;
> }
> + case KVM_PV_INFO: {
> + struct kvm_s390_pv_info info = {};
> + ssize_t data_len;
> +
> + /*
> + * No need to check the VM protection here.
> + *
> + * Maybe user space wants to query some of the data
> + * when the VM is still unprotected. If we see the
> + * need to fence a new data command we can still
> + * return an error in the info handler.
> + */
> +
> + r = -EFAULT;
> + if (copy_from_user(&info, argp, sizeof(info.header)))
> + break;
> +
> + r = -EINVAL;
> + if (info.header.len_max < sizeof(info.header))
> + break;
> +
> + data_len = kvm_s390_handle_pv_info(&info);
> + if (data_len < 0) {
> + r = data_len;
> + break;
> + }
> + /*
> + * If a data command struct is extended (multiple
> + * times) this can be used to determine how much of it
> + * is valid.
> + */
> + info.header.len_written = data_len;
> +
> + r = -EFAULT;
> + if (copy_to_user(argp, &info, data_len))
> + break;
> +
> + r = 0;
> + break;
> + }
> default:
> r = -ENOTTY;
> }
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 6a184d260c7f..8ac9de7d1386 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1653,6 +1653,30 @@ struct kvm_s390_pv_unp {
> __u64 tweak;
> };
>
> +enum pv_cmd_info_id {
> + KVM_PV_INFO_VM,
> +};
> +
> +struct kvm_s390_pv_info_vm {
> + __u64 inst_calls_list[4];
> + __u64 max_cpus;
> + __u64 max_guests;
> + __u64 max_guest_addr;
> + __u64 feature_indication;
> +};
> +
> +struct kvm_s390_pv_info_header {
> + __u32 id;
> + __u32 len_max;
> + __u32 len_written;
> + __u32 reserved;
> +};
> +
> +struct kvm_s390_pv_info {
> + struct kvm_s390_pv_info_header header;
> + struct kvm_s390_pv_info_vm vm;
> +};
> +
> enum pv_cmd_id {
> KVM_PV_ENABLE,
> KVM_PV_DISABLE,
> @@ -1661,6 +1685,7 @@ enum pv_cmd_id {
> KVM_PV_VERIFY,
> KVM_PV_PREP_RESET,
> KVM_PV_UNSHARE_ALL,
> + KVM_PV_INFO,
> };
>
> struct kvm_pv_cmd {