diff mbox series

[4/6] KVM: Add KVM_(UN)REGISTER_COALESCED_MMIO2 ioctls

Message ID 20240710085259.2125131-5-ilstam@amazon.com (mailing list archive)
State New, archived
Headers show
Series KVM: Improve MMIO Coalescing API | expand

Commit Message

Ilias Stamatis July 10, 2024, 8:52 a.m. UTC
Add 2 new ioctls, KVM_REGISTER_COALESCED_MMIO2 and
KVM_UNREGISTER_COALESCED_MMIO2. These do the same thing as their v1
equivalents except an fd returned by KVM_CREATE_COALESCED_MMIO_BUFFER
needs to be passed as an argument to them.

The fd representing a ring buffer is associated with an MMIO region
registered for coalescing and all writes to that region are accumulated
there. This is in contrast to the v1 API where all regions have to share
the same buffer. Nevertheless, userspace code can still use the same
ring buffer for multiple zones if it wishes to do so.

Userspace can check for the availability of the new API by checking if
the KVM_CAP_COALESCED_MMIO2 capability is supported.

Signed-off-by: Ilias Stamatis <ilstam@amazon.com>
---
 include/uapi/linux/kvm.h  | 16 ++++++++++++++++
 virt/kvm/coalesced_mmio.c | 36 ++++++++++++++++++++++++++++++------
 virt/kvm/coalesced_mmio.h |  7 ++++---
 virt/kvm/kvm_main.c       | 36 +++++++++++++++++++++++++++++++++++-
 4 files changed, 85 insertions(+), 10 deletions(-)

Comments

Paul Durrant July 13, 2024, 6:19 a.m. UTC | #1
On 10/07/2024 10:52, Ilias Stamatis wrote:
> Add 2 new ioctls, KVM_REGISTER_COALESCED_MMIO2 and
> KVM_UNREGISTER_COALESCED_MMIO2. These do the same thing as their v1
> equivalents except an fd returned by KVM_CREATE_COALESCED_MMIO_BUFFER
> needs to be passed as an argument to them.
> 
> The fd representing a ring buffer is associated with an MMIO region
> registered for coalescing and all writes to that region are accumulated
> there. This is in contrast to the v1 API where all regions have to share
> the same buffer. Nevertheless, userspace code can still use the same
> ring buffer for multiple zones if it wishes to do so.
> 
> Userspace can check for the availability of the new API by checking if
> the KVM_CAP_COALESCED_MMIO2 capability is supported.
> 
> Signed-off-by: Ilias Stamatis <ilstam@amazon.com>
> ---
>   include/uapi/linux/kvm.h  | 16 ++++++++++++++++
>   virt/kvm/coalesced_mmio.c | 36 ++++++++++++++++++++++++++++++------
>   virt/kvm/coalesced_mmio.h |  7 ++++---
>   virt/kvm/kvm_main.c       | 36 +++++++++++++++++++++++++++++++++++-
>   4 files changed, 85 insertions(+), 10 deletions(-)
> 

Reviewed-by: Paul Durrant <paul@xen.org>
kernel test robot July 13, 2024, 2:15 p.m. UTC | #2
Hi Ilias,

kernel test robot noticed the following build errors:

[auto build test ERROR on kvm/queue]
[also build test ERROR on mst-vhost/linux-next linus/master v6.10-rc7]
[cannot apply to kvm/linux-next next-20240712]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ilias-Stamatis/KVM-Fix-coalesced_mmio_has_room/20240710-222059
base:   https://git.kernel.org/pub/scm/virt/kvm/kvm.git queue
patch link:    https://lore.kernel.org/r/20240710085259.2125131-5-ilstam%40amazon.com
patch subject: [PATCH 4/6] KVM: Add KVM_(UN)REGISTER_COALESCED_MMIO2 ioctls
config: loongarch-randconfig-001-20240713 (https://download.01.org/0day-ci/archive/20240714/202407140049.CuVivD5M-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 14.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240714/202407140049.CuVivD5M-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202407140049.CuVivD5M-lkp@intel.com/

All errors (new ones prefixed by >>):

   arch/loongarch/kvm/../../../virt/kvm/coalesced_mmio.c: In function 'kvm_vm_ioctl_register_coalesced_mmio':
>> arch/loongarch/kvm/../../../virt/kvm/coalesced_mmio.c:292:24: error: implicit declaration of function 'fget'; did you mean 'sget'? [-Wimplicit-function-declaration]
     292 |                 file = fget(zone->buffer_fd);
         |                        ^~~~
         |                        sget
>> arch/loongarch/kvm/../../../virt/kvm/coalesced_mmio.c:292:22: error: assignment to 'struct file *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     292 |                 file = fget(zone->buffer_fd);
         |                      ^
>> arch/loongarch/kvm/../../../virt/kvm/coalesced_mmio.c:297:25: error: implicit declaration of function 'fput'; did you mean 'iput'? [-Wimplicit-function-declaration]
     297 |                         fput(file);
         |                         ^~~~
         |                         iput


vim +292 arch/loongarch/kvm/../../../virt/kvm/coalesced_mmio.c

   278	
   279	int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
   280						 struct kvm_coalesced_mmio_zone2 *zone,
   281						 bool use_buffer_fd)
   282	{
   283		int ret = 0;
   284		struct file *file;
   285		struct kvm_coalesced_mmio_dev *dev;
   286		struct kvm_coalesced_mmio_buffer_dev *buffer_dev = NULL;
   287	
   288		if (zone->pio != 1 && zone->pio != 0)
   289			return -EINVAL;
   290	
   291		if (use_buffer_fd) {
 > 292			file = fget(zone->buffer_fd);
   293			if (!file)
   294				return -EBADF;
   295	
   296			if (file->f_op != &coalesced_mmio_buffer_ops) {
 > 297				fput(file);
   298				return -EINVAL;
   299			}
   300	
   301			buffer_dev = file->private_data;
   302			if (!buffer_dev->ring) {
   303				fput(file);
   304				return -ENOBUFS;
   305			}
   306		}
   307	
   308		dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev),
   309			      GFP_KERNEL_ACCOUNT);
   310		if (!dev) {
   311			ret = -ENOMEM;
   312			goto out_free_file;
   313		}
   314	
   315		kvm_iodevice_init(&dev->dev, &coalesced_mmio_ops);
   316		dev->kvm = kvm;
   317		dev->zone = *zone;
   318		dev->buffer_dev = buffer_dev;
   319	
   320		mutex_lock(&kvm->slots_lock);
   321		ret = kvm_io_bus_register_dev(kvm,
   322					zone->pio ? KVM_PIO_BUS : KVM_MMIO_BUS,
   323					zone->addr, zone->size, &dev->dev);
   324		if (ret < 0)
   325			goto out_free_dev;
   326		list_add_tail(&dev->list, &kvm->coalesced_zones);
   327		mutex_unlock(&kvm->slots_lock);
   328	
   329		goto out_free_file;
   330	
   331	out_free_dev:
   332		mutex_unlock(&kvm->slots_lock);
   333		kfree(dev);
   334	out_free_file:
   335		if (use_buffer_fd)
   336			fput(file);
   337	
   338		return ret;
   339	}
   340
kernel test robot July 13, 2024, 8:48 p.m. UTC | #3
Hi Ilias,

kernel test robot noticed the following build errors:

[auto build test ERROR on kvm/queue]
[also build test ERROR on mst-vhost/linux-next linus/master v6.10-rc7]
[cannot apply to kvm/linux-next next-20240712]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ilias-Stamatis/KVM-Fix-coalesced_mmio_has_room/20240710-222059
base:   https://git.kernel.org/pub/scm/virt/kvm/kvm.git queue
patch link:    https://lore.kernel.org/r/20240710085259.2125131-5-ilstam%40amazon.com
patch subject: [PATCH 4/6] KVM: Add KVM_(UN)REGISTER_COALESCED_MMIO2 ioctls
config: powerpc-allmodconfig (https://download.01.org/0day-ci/archive/20240714/202407140405.VJSETXg3-lkp@intel.com/config)
compiler: powerpc64-linux-gcc (GCC) 14.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240714/202407140405.VJSETXg3-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202407140405.VJSETXg3-lkp@intel.com/

All errors (new ones prefixed by >>):

   arch/powerpc/kvm/../../../virt/kvm/coalesced_mmio.c: In function 'kvm_vm_ioctl_register_coalesced_mmio':
>> arch/powerpc/kvm/../../../virt/kvm/coalesced_mmio.c:292:24: error: implicit declaration of function 'fget'; did you mean 'sget'? [-Wimplicit-function-declaration]
     292 |                 file = fget(zone->buffer_fd);
         |                        ^~~~
         |                        sget
>> arch/powerpc/kvm/../../../virt/kvm/coalesced_mmio.c:292:22: error: assignment to 'struct file *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     292 |                 file = fget(zone->buffer_fd);
         |                      ^
>> arch/powerpc/kvm/../../../virt/kvm/coalesced_mmio.c:297:25: error: implicit declaration of function 'fput'; did you mean 'iput'? [-Wimplicit-function-declaration]
     297 |                         fput(file);
         |                         ^~~~
         |                         iput


vim +292 arch/powerpc/kvm/../../../virt/kvm/coalesced_mmio.c

   278	
   279	int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
   280						 struct kvm_coalesced_mmio_zone2 *zone,
   281						 bool use_buffer_fd)
   282	{
   283		int ret = 0;
   284		struct file *file;
   285		struct kvm_coalesced_mmio_dev *dev;
   286		struct kvm_coalesced_mmio_buffer_dev *buffer_dev = NULL;
   287	
   288		if (zone->pio != 1 && zone->pio != 0)
   289			return -EINVAL;
   290	
   291		if (use_buffer_fd) {
 > 292			file = fget(zone->buffer_fd);
   293			if (!file)
   294				return -EBADF;
   295	
   296			if (file->f_op != &coalesced_mmio_buffer_ops) {
 > 297				fput(file);
   298				return -EINVAL;
   299			}
   300	
   301			buffer_dev = file->private_data;
   302			if (!buffer_dev->ring) {
   303				fput(file);
   304				return -ENOBUFS;
   305			}
   306		}
   307	
   308		dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev),
   309			      GFP_KERNEL_ACCOUNT);
   310		if (!dev) {
   311			ret = -ENOMEM;
   312			goto out_free_file;
   313		}
   314	
   315		kvm_iodevice_init(&dev->dev, &coalesced_mmio_ops);
   316		dev->kvm = kvm;
   317		dev->zone = *zone;
   318		dev->buffer_dev = buffer_dev;
   319	
   320		mutex_lock(&kvm->slots_lock);
   321		ret = kvm_io_bus_register_dev(kvm,
   322					zone->pio ? KVM_PIO_BUS : KVM_MMIO_BUS,
   323					zone->addr, zone->size, &dev->dev);
   324		if (ret < 0)
   325			goto out_free_dev;
   326		list_add_tail(&dev->list, &kvm->coalesced_zones);
   327		mutex_unlock(&kvm->slots_lock);
   328	
   329		goto out_free_file;
   330	
   331	out_free_dev:
   332		mutex_unlock(&kvm->slots_lock);
   333		kfree(dev);
   334	out_free_file:
   335		if (use_buffer_fd)
   336			fput(file);
   337	
   338		return ret;
   339	}
   340
diff mbox series

Patch

diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 6d6f132e6203..e49dda50b639 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -467,6 +467,16 @@  struct kvm_coalesced_mmio_zone {
 	};
 };
 
+struct kvm_coalesced_mmio_zone2 {
+	__u64 addr;
+	__u32 size;
+	union {
+		__u32 pad;
+		__u32 pio;
+	};
+	int buffer_fd;
+};
+
 struct kvm_coalesced_mmio {
 	__u64 phys_addr;
 	__u32 len;
@@ -917,6 +927,7 @@  struct kvm_enable_cap {
 #define KVM_CAP_MEMORY_ATTRIBUTES 233
 #define KVM_CAP_GUEST_MEMFD 234
 #define KVM_CAP_VM_TYPES 235
+#define KVM_CAP_COALESCED_MMIO2 236
 
 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;
@@ -1548,6 +1559,11 @@  struct kvm_create_guest_memfd {
 	__u64 reserved[6];
 };
 
+/* Available with KVM_CAP_COALESCED_MMIO2 */
 #define KVM_CREATE_COALESCED_MMIO_BUFFER _IO(KVMIO,   0xd5)
+#define KVM_REGISTER_COALESCED_MMIO2 \
+			_IOW(KVMIO,  0xd6, struct kvm_coalesced_mmio_zone2)
+#define KVM_UNREGISTER_COALESCED_MMIO2 \
+			_IOW(KVMIO,  0xd7, struct kvm_coalesced_mmio_zone2)
 
 #endif /* __LINUX_KVM_H */
diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c
index 00439e035d74..8d6d98c01f6e 100644
--- a/virt/kvm/coalesced_mmio.c
+++ b/virt/kvm/coalesced_mmio.c
@@ -277,19 +277,40 @@  int kvm_vm_ioctl_create_coalesced_mmio_buffer(struct kvm *kvm)
 }
 
 int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
-					 struct kvm_coalesced_mmio_zone *zone)
+					 struct kvm_coalesced_mmio_zone2 *zone,
+					 bool use_buffer_fd)
 {
-	int ret;
+	int ret = 0;
+	struct file *file;
 	struct kvm_coalesced_mmio_dev *dev;
 	struct kvm_coalesced_mmio_buffer_dev *buffer_dev = NULL;
 
 	if (zone->pio != 1 && zone->pio != 0)
 		return -EINVAL;
 
+	if (use_buffer_fd) {
+		file = fget(zone->buffer_fd);
+		if (!file)
+			return -EBADF;
+
+		if (file->f_op != &coalesced_mmio_buffer_ops) {
+			fput(file);
+			return -EINVAL;
+		}
+
+		buffer_dev = file->private_data;
+		if (!buffer_dev->ring) {
+			fput(file);
+			return -ENOBUFS;
+		}
+	}
+
 	dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev),
 		      GFP_KERNEL_ACCOUNT);
-	if (!dev)
-		return -ENOMEM;
+	if (!dev) {
+		ret = -ENOMEM;
+		goto out_free_file;
+	}
 
 	kvm_iodevice_init(&dev->dev, &coalesced_mmio_ops);
 	dev->kvm = kvm;
@@ -305,17 +326,20 @@  int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
 	list_add_tail(&dev->list, &kvm->coalesced_zones);
 	mutex_unlock(&kvm->slots_lock);
 
-	return 0;
+	goto out_free_file;
 
 out_free_dev:
 	mutex_unlock(&kvm->slots_lock);
 	kfree(dev);
+out_free_file:
+	if (use_buffer_fd)
+		fput(file);
 
 	return ret;
 }
 
 int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,
-					   struct kvm_coalesced_mmio_zone *zone)
+					   struct kvm_coalesced_mmio_zone2 *zone)
 {
 	struct kvm_coalesced_mmio_dev *dev, *tmp;
 	int r;
diff --git a/virt/kvm/coalesced_mmio.h b/virt/kvm/coalesced_mmio.h
index d1807ce26464..32792adb7cb4 100644
--- a/virt/kvm/coalesced_mmio.h
+++ b/virt/kvm/coalesced_mmio.h
@@ -19,7 +19,7 @@  struct kvm_coalesced_mmio_dev {
 	struct list_head list;
 	struct kvm_io_device dev;
 	struct kvm *kvm;
-	struct kvm_coalesced_mmio_zone zone;
+	struct kvm_coalesced_mmio_zone2 zone;
 	struct kvm_coalesced_mmio_buffer_dev *buffer_dev;
 };
 
@@ -34,9 +34,10 @@  struct kvm_coalesced_mmio_buffer_dev {
 int kvm_coalesced_mmio_init(struct kvm *kvm);
 void kvm_coalesced_mmio_free(struct kvm *kvm);
 int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
-					struct kvm_coalesced_mmio_zone *zone);
+					struct kvm_coalesced_mmio_zone2 *zone,
+					bool use_buffer_fd);
 int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,
-					struct kvm_coalesced_mmio_zone *zone);
+					struct kvm_coalesced_mmio_zone2 *zone);
 int kvm_vm_ioctl_create_coalesced_mmio_buffer(struct kvm *kvm);
 
 #else
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 54df2e88d4f4..683b5d392b5f 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -4815,6 +4815,7 @@  static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
 #ifdef CONFIG_KVM_MMIO
 	case KVM_CAP_COALESCED_MMIO:
 		return KVM_COALESCED_MMIO_PAGE_OFFSET;
+	case KVM_CAP_COALESCED_MMIO2:
 	case KVM_CAP_COALESCED_PIO:
 		return 1;
 #endif
@@ -5153,15 +5154,48 @@  static long kvm_vm_ioctl(struct file *filp,
 #ifdef CONFIG_KVM_MMIO
 	case KVM_REGISTER_COALESCED_MMIO: {
 		struct kvm_coalesced_mmio_zone zone;
+		struct kvm_coalesced_mmio_zone2 zone2;
 
 		r = -EFAULT;
 		if (copy_from_user(&zone, argp, sizeof(zone)))
 			goto out;
-		r = kvm_vm_ioctl_register_coalesced_mmio(kvm, &zone);
+
+		zone2.addr = zone.addr;
+		zone2.size = zone.size;
+		zone2.pio = zone.pio;
+		zone2.buffer_fd = -1;
+
+		r = kvm_vm_ioctl_register_coalesced_mmio(kvm, &zone2, false);
+		break;
+	}
+	case KVM_REGISTER_COALESCED_MMIO2: {
+		struct kvm_coalesced_mmio_zone2 zone;
+
+		r = -EFAULT;
+		if (copy_from_user(&zone, argp, sizeof(zone)))
+			goto out;
+
+		r = kvm_vm_ioctl_register_coalesced_mmio(kvm, &zone, true);
 		break;
 	}
 	case KVM_UNREGISTER_COALESCED_MMIO: {
 		struct kvm_coalesced_mmio_zone zone;
+		struct kvm_coalesced_mmio_zone2 zone2;
+
+		r = -EFAULT;
+		if (copy_from_user(&zone, argp, sizeof(zone)))
+			goto out;
+
+		zone2.addr = zone.addr;
+		zone2.size = zone.size;
+		zone2.pio = zone.pio;
+		zone2.buffer_fd = -1;
+
+		r = kvm_vm_ioctl_unregister_coalesced_mmio(kvm, &zone2);
+		break;
+	}
+	case KVM_UNREGISTER_COALESCED_MMIO2: {
+		struct kvm_coalesced_mmio_zone2 zone;
 
 		r = -EFAULT;
 		if (copy_from_user(&zone, argp, sizeof(zone)))