2022-11-04 14:24:24

by Eric Farman

[permalink] [raw]
Subject: [PATCH v3 0/7] vfio-ccw parent rework

Hi Alex,

Here's the (last?) update to the vfio-ccw lifecycle changes that I've sent
recently, and were previously discussed at various points [1][2].

Patches 1-5 rework the behavior of the vfio-ccw driver's private struct.
In summary, the mdev pieces are split out of vfio_ccw_private and into a
new vfio_ccw_parent struct that will continue to follow today's lifecycle.
The remainder (bulk) of the private struct moves to follow the mdev
probe/remove pair. There's opportunity for further separation of the
things in the private struct, which would simplify some of the vfio-ccw
code, but it got too hairy as I started that. Once vfio-ccw is no longer
considered unique, those cleanups can happen at our leisure.

Patch 6 removes the trickery where vfio-ccw uses vfio_init_device instead of
vfio_alloc_device, and thus removes vfio_init_device from the outside world.

Patch 7 removes vfio_free_device from vfio-ccw and the other drivers (hello,
CC list!), letting it be handled by vfio_device_release directly.

I believe this covers everything in this space; let me know if not!

Thanks,
Eric

[1] https://lore.kernel.org/kvm/[email protected]/
[2] https://lore.kernel.org/kvm/[email protected]/

v2->v3:
- [MR] Added r-b to remaining patches (Thank you!)
- Patch 1:
[gfx checkpatch] Whitespace
[EF] Remove put_device(&parent->dev)
[MR] Fix error exit when alloc of parent fails
[MR] Check for !private on sch_probe error path
- Patch 3:
[EF] Fix error exit when alloc of private fails
- Patch 6:
[AW] Added ack (Thank you!)
- Patch 7:
[CH, AK] Added r-b (Thank you!)
[AW] Added ack (Thank you!)
v2: https://lore.kernel.org/kvm/[email protected]/
v1: https://lore.kernel.org/kvm/[email protected]/

Eric Farman (7):
vfio/ccw: create a parent struct
vfio/ccw: remove private->sch
vfio/ccw: move private initialization to callback
vfio/ccw: move private to mdev lifecycle
vfio/ccw: remove release completion
vfio/ccw: replace vfio_init_device with _alloc_
vfio: Remove vfio_free_device

drivers/gpu/drm/i915/gvt/kvmgt.c | 1 -
drivers/s390/cio/vfio_ccw_chp.c | 5 +-
drivers/s390/cio/vfio_ccw_drv.c | 173 +++++++++++---------------
drivers/s390/cio/vfio_ccw_fsm.c | 27 ++--
drivers/s390/cio/vfio_ccw_ops.c | 107 +++++++++++-----
drivers/s390/cio/vfio_ccw_private.h | 37 ++++--
drivers/s390/crypto/vfio_ap_ops.c | 6 -
drivers/vfio/fsl-mc/vfio_fsl_mc.c | 1 -
drivers/vfio/pci/vfio_pci_core.c | 1 -
drivers/vfio/platform/vfio_amba.c | 1 -
drivers/vfio/platform/vfio_platform.c | 1 -
drivers/vfio/vfio_main.c | 32 ++---
include/linux/vfio.h | 3 -
samples/vfio-mdev/mbochs.c | 1 -
samples/vfio-mdev/mdpy.c | 1 -
samples/vfio-mdev/mtty.c | 1 -
16 files changed, 196 insertions(+), 202 deletions(-)

--
2.34.1



2022-11-04 14:24:41

by Eric Farman

[permalink] [raw]
Subject: [PATCH v3 4/7] vfio/ccw: move private to mdev lifecycle

Now that the mdev parent data is split out into its own struct,
it is safe to move the remaining private data to follow the
mdev probe/remove lifecycle. The mdev parent data will remain
where it is, and follow the subchannel and the css driver
interfaces.

Signed-off-by: Eric Farman <[email protected]>
Reviewed-by: Matthew Rosato <[email protected]>
---
drivers/s390/cio/vfio_ccw_drv.c | 16 +---------------
drivers/s390/cio/vfio_ccw_ops.c | 26 +++++++++++++-------------
drivers/s390/cio/vfio_ccw_private.h | 2 ++
3 files changed, 16 insertions(+), 28 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index fbc26338ceab..9fbd1b27a1ac 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -152,7 +152,7 @@ static void vfio_ccw_sch_irq(struct subchannel *sch)
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_INTERRUPT);
}

-static void vfio_ccw_free_private(struct vfio_ccw_private *private)
+void vfio_ccw_free_private(struct vfio_ccw_private *private)
{
struct vfio_ccw_crw *crw, *temp;

@@ -180,7 +180,6 @@ static void vfio_ccw_free_parent(struct device *dev)
static int vfio_ccw_sch_probe(struct subchannel *sch)
{
struct pmcw *pmcw = &sch->schib.pmcw;
- struct vfio_ccw_private *private;
struct vfio_ccw_parent *parent;
int ret = -ENOMEM;

@@ -201,14 +200,7 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
if (ret)
goto out_free;

- private = kzalloc(sizeof(*private), GFP_KERNEL);
- if (!private) {
- device_unregister(&parent->dev);
- return -ENOMEM;
- }
-
dev_set_drvdata(&sch->dev, parent);
- dev_set_drvdata(&parent->dev, private);

parent->mdev_type.sysfs_name = "io";
parent->mdev_type.pretty_name = "I/O subchannel (Non-QDIO)";
@@ -227,25 +219,19 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
out_unreg:
device_unregister(&parent->dev);
out_free:
- dev_set_drvdata(&parent->dev, NULL);
dev_set_drvdata(&sch->dev, NULL);
- if (private)
- vfio_ccw_free_private(private);
return ret;
}

static void vfio_ccw_sch_remove(struct subchannel *sch)
{
struct vfio_ccw_parent *parent = dev_get_drvdata(&sch->dev);
- struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);

mdev_unregister_parent(&parent->parent);

device_unregister(&parent->dev);
dev_set_drvdata(&sch->dev, NULL);

- vfio_ccw_free_private(private);
-
VFIO_CCW_MSG_EVENT(4, "unbound from subchannel %x.%x.%04x\n",
sch->schid.cssid, sch->schid.ssid,
sch->schid.sch_no);
diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index eb0b8cc210bb..e45d4acb109b 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -100,15 +100,20 @@ static int vfio_ccw_mdev_probe(struct mdev_device *mdev)
{
struct subchannel *sch = to_subchannel(mdev->dev.parent);
struct vfio_ccw_parent *parent = dev_get_drvdata(&sch->dev);
- struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);
+ struct vfio_ccw_private *private;
int ret;

- if (private->state == VFIO_CCW_STATE_NOT_OPER)
- return -ENODEV;
+ private = kzalloc(sizeof(*private), GFP_KERNEL);
+ if (!private)
+ return -ENOMEM;

ret = vfio_init_device(&private->vdev, &mdev->dev, &vfio_ccw_dev_ops);
- if (ret)
+ if (ret) {
+ kfree(private);
return ret;
+ }
+
+ dev_set_drvdata(&parent->dev, private);

VFIO_CCW_MSG_EVENT(2, "sch %x.%x.%04x: create\n",
sch->schid.cssid,
@@ -122,6 +127,7 @@ static int vfio_ccw_mdev_probe(struct mdev_device *mdev)
return 0;

err_put_vdev:
+ dev_set_drvdata(&parent->dev, NULL);
vfio_put_device(&private->vdev);
return ret;
}
@@ -131,15 +137,6 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
struct vfio_ccw_private *private =
container_of(vdev, struct vfio_ccw_private, vdev);

- /*
- * We cannot free vfio_ccw_private here because it includes
- * parent info which must be free'ed by css driver.
- *
- * Use a workaround by memset'ing the core device part and
- * then notifying the remove path that all active references
- * to this device have been released.
- */
- memset(vdev, 0, sizeof(*vdev));
complete(&private->release_comp);
}

@@ -156,6 +153,7 @@ static void vfio_ccw_mdev_remove(struct mdev_device *mdev)

vfio_unregister_group_dev(&private->vdev);

+ dev_set_drvdata(&parent->dev, NULL);
vfio_put_device(&private->vdev);
/*
* Wait for all active references on mdev are released so it
@@ -166,6 +164,8 @@ static void vfio_ccw_mdev_remove(struct mdev_device *mdev)
* cycle.
*/
wait_for_completion(&private->release_comp);
+
+ vfio_ccw_free_private(private);
}

static int vfio_ccw_mdev_open_device(struct vfio_device *vdev)
diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h
index 55d636225cff..747aba5f5272 100644
--- a/drivers/s390/cio/vfio_ccw_private.h
+++ b/drivers/s390/cio/vfio_ccw_private.h
@@ -134,6 +134,8 @@ int vfio_ccw_sch_quiesce(struct subchannel *sch);
void vfio_ccw_sch_io_todo(struct work_struct *work);
void vfio_ccw_crw_todo(struct work_struct *work);

+void vfio_ccw_free_private(struct vfio_ccw_private *private);
+
extern struct mdev_driver vfio_ccw_mdev_driver;

/*
--
2.34.1


2022-11-04 14:24:54

by Eric Farman

[permalink] [raw]
Subject: [PATCH v3 6/7] vfio/ccw: replace vfio_init_device with _alloc_

Now that we have a reasonable separation of structs that follow
the subchannel and mdev lifecycles, there's no reason we can't
call the official vfio_alloc_device routine for our private data,
and behave like everyone else.

Signed-off-by: Eric Farman <[email protected]>
Reviewed-by: Kevin Tian <[email protected]>
Acked-by: Alex Williamson <[email protected]>
Reviewed-by: Matthew Rosato <[email protected]>
---
drivers/s390/cio/vfio_ccw_drv.c | 18 ------------------
drivers/s390/cio/vfio_ccw_ops.c | 28 ++++++++++++++++++----------
drivers/s390/cio/vfio_ccw_private.h | 2 --
drivers/vfio/vfio_main.c | 10 +++++-----
include/linux/vfio.h | 2 --
5 files changed, 23 insertions(+), 37 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index 9fbd1b27a1ac..c2a65808605a 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -152,24 +152,6 @@ static void vfio_ccw_sch_irq(struct subchannel *sch)
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_INTERRUPT);
}

-void vfio_ccw_free_private(struct vfio_ccw_private *private)
-{
- struct vfio_ccw_crw *crw, *temp;
-
- list_for_each_entry_safe(crw, temp, &private->crw, next) {
- list_del(&crw->next);
- kfree(crw);
- }
-
- kmem_cache_free(vfio_ccw_crw_region, private->crw_region);
- kmem_cache_free(vfio_ccw_schib_region, private->schib_region);
- kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region);
- kmem_cache_free(vfio_ccw_io_region, private->io_region);
- kfree(private->cp.guest_cp);
- mutex_destroy(&private->io_mutex);
- kfree(private);
-}
-
static void vfio_ccw_free_parent(struct device *dev)
{
struct vfio_ccw_parent *parent = container_of(dev, struct vfio_ccw_parent, dev);
diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index 8a929a9cf3c6..1155f8bcedd9 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -102,15 +102,10 @@ static int vfio_ccw_mdev_probe(struct mdev_device *mdev)
struct vfio_ccw_private *private;
int ret;

- private = kzalloc(sizeof(*private), GFP_KERNEL);
- if (!private)
- return -ENOMEM;
-
- ret = vfio_init_device(&private->vdev, &mdev->dev, &vfio_ccw_dev_ops);
- if (ret) {
- kfree(private);
- return ret;
- }
+ private = vfio_alloc_device(vfio_ccw_private, vdev, &mdev->dev,
+ &vfio_ccw_dev_ops);
+ if (IS_ERR(private))
+ return PTR_ERR(private);

dev_set_drvdata(&parent->dev, private);

@@ -135,8 +130,21 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
{
struct vfio_ccw_private *private =
container_of(vdev, struct vfio_ccw_private, vdev);
+ struct vfio_ccw_crw *crw, *temp;
+
+ list_for_each_entry_safe(crw, temp, &private->crw, next) {
+ list_del(&crw->next);
+ kfree(crw);
+ }
+
+ kmem_cache_free(vfio_ccw_crw_region, private->crw_region);
+ kmem_cache_free(vfio_ccw_schib_region, private->schib_region);
+ kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region);
+ kmem_cache_free(vfio_ccw_io_region, private->io_region);
+ kfree(private->cp.guest_cp);
+ mutex_destroy(&private->io_mutex);

- vfio_ccw_free_private(private);
+ vfio_free_device(vdev);
}

static void vfio_ccw_mdev_remove(struct mdev_device *mdev)
diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h
index 2278fd38d34e..b441ae6700fd 100644
--- a/drivers/s390/cio/vfio_ccw_private.h
+++ b/drivers/s390/cio/vfio_ccw_private.h
@@ -131,8 +131,6 @@ int vfio_ccw_sch_quiesce(struct subchannel *sch);
void vfio_ccw_sch_io_todo(struct work_struct *work);
void vfio_ccw_crw_todo(struct work_struct *work);

-void vfio_ccw_free_private(struct vfio_ccw_private *private);
-
extern struct mdev_driver vfio_ccw_mdev_driver;

/*
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 2d168793d4e1..2901b8ad5be9 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -348,6 +348,9 @@ static void vfio_device_release(struct device *dev)
device->ops->release(device);
}

+static int vfio_init_device(struct vfio_device *device, struct device *dev,
+ const struct vfio_device_ops *ops);
+
/*
* Allocate and initialize vfio_device so it can be registered to vfio
* core.
@@ -386,11 +389,9 @@ EXPORT_SYMBOL_GPL(_vfio_alloc_device);

/*
* Initialize a vfio_device so it can be registered to vfio core.
- *
- * Only vfio-ccw driver should call this interface.
*/
-int vfio_init_device(struct vfio_device *device, struct device *dev,
- const struct vfio_device_ops *ops)
+static int vfio_init_device(struct vfio_device *device, struct device *dev,
+ const struct vfio_device_ops *ops)
{
int ret;

@@ -422,7 +423,6 @@ int vfio_init_device(struct vfio_device *device, struct device *dev,
ida_free(&vfio.device_ida, device->index);
return ret;
}
-EXPORT_SYMBOL_GPL(vfio_init_device);

/*
* The helper called by driver @release callback to free the device
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index e7cebeb875dd..ba809268a48e 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -176,8 +176,6 @@ struct vfio_device *_vfio_alloc_device(size_t size, struct device *dev,
dev, ops), \
struct dev_struct, member)

-int vfio_init_device(struct vfio_device *device, struct device *dev,
- const struct vfio_device_ops *ops);
void vfio_free_device(struct vfio_device *device);
static inline void vfio_put_device(struct vfio_device *device)
{
--
2.34.1


2022-11-04 14:25:10

by Eric Farman

[permalink] [raw]
Subject: [PATCH v3 1/7] vfio/ccw: create a parent struct

Move the stuff associated with the mdev parent (and thus the
subchannel struct) into its own struct, and leave the rest in
the existing private structure.

The subchannel will point to the parent, and the parent will point
to the private, for the areas where one or both are needed. Further
separation of these structs will follow.

Signed-off-by: Eric Farman <[email protected]>
Reviewed-by: Matthew Rosato <[email protected]>
---
drivers/s390/cio/vfio_ccw_drv.c | 98 +++++++++++++++++++++++------
drivers/s390/cio/vfio_ccw_ops.c | 8 ++-
drivers/s390/cio/vfio_ccw_private.h | 20 ++++--
3 files changed, 101 insertions(+), 25 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index 7f5402fe857a..444b32047397 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -36,10 +36,19 @@ debug_info_t *vfio_ccw_debug_trace_id;
*/
int vfio_ccw_sch_quiesce(struct subchannel *sch)
{
- struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_parent *parent = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);
DECLARE_COMPLETION_ONSTACK(completion);
int iretry, ret = 0;

+ /*
+ * Probably an impossible situation, after being called through
+ * FSM callbacks. But in the event it did, register a warning
+ * and return as if things were fine.
+ */
+ if (WARN_ON(!private))
+ return 0;
+
iretry = 255;
do {

@@ -121,7 +130,23 @@ static void vfio_ccw_crw_todo(struct work_struct *work)
*/
static void vfio_ccw_sch_irq(struct subchannel *sch)
{
- struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_parent *parent = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);
+
+ /*
+ * The subchannel should still be disabled at this point,
+ * so an interrupt would be quite surprising. As with an
+ * interrupt while the FSM is closed, let's attempt to
+ * disable the subchannel again.
+ */
+ if (!private) {
+ VFIO_CCW_MSG_EVENT(2, "sch %x.%x.%04x: unexpected interrupt\n",
+ sch->schid.cssid, sch->schid.ssid,
+ sch->schid.sch_no);
+
+ cio_disable_subchannel(sch);
+ return;
+ }

inc_irq_stat(IRQIO_CIO);
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_INTERRUPT);
@@ -201,10 +226,19 @@ static void vfio_ccw_free_private(struct vfio_ccw_private *private)
mutex_destroy(&private->io_mutex);
kfree(private);
}
+
+static void vfio_ccw_free_parent(struct device *dev)
+{
+ struct vfio_ccw_parent *parent = container_of(dev, struct vfio_ccw_parent, dev);
+
+ kfree(parent);
+}
+
static int vfio_ccw_sch_probe(struct subchannel *sch)
{
struct pmcw *pmcw = &sch->schib.pmcw;
struct vfio_ccw_private *private;
+ struct vfio_ccw_parent *parent;
int ret = -ENOMEM;

if (pmcw->qf) {
@@ -213,38 +247,58 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
return -ENODEV;
}

+ parent = kzalloc(sizeof(*parent), GFP_KERNEL);
+ if (!parent)
+ return -ENOMEM;
+
+ dev_set_name(&parent->dev, "parent");
+ parent->dev.parent = &sch->dev;
+ parent->dev.release = &vfio_ccw_free_parent;
+ ret = device_register(&parent->dev);
+ if (ret)
+ goto out_free;
+
private = vfio_ccw_alloc_private(sch);
- if (IS_ERR(private))
+ if (IS_ERR(private)) {
+ device_unregister(&parent->dev);
return PTR_ERR(private);
+ }

- dev_set_drvdata(&sch->dev, private);
+ dev_set_drvdata(&sch->dev, parent);
+ dev_set_drvdata(&parent->dev, private);

- private->mdev_type.sysfs_name = "io";
- private->mdev_type.pretty_name = "I/O subchannel (Non-QDIO)";
- private->mdev_types[0] = &private->mdev_type;
- ret = mdev_register_parent(&private->parent, &sch->dev,
+ parent->mdev_type.sysfs_name = "io";
+ parent->mdev_type.pretty_name = "I/O subchannel (Non-QDIO)";
+ parent->mdev_types[0] = &parent->mdev_type;
+ ret = mdev_register_parent(&parent->parent, &sch->dev,
&vfio_ccw_mdev_driver,
- private->mdev_types, 1);
+ parent->mdev_types, 1);
if (ret)
- goto out_free;
+ goto out_unreg;

VFIO_CCW_MSG_EVENT(4, "bound to subchannel %x.%x.%04x\n",
sch->schid.cssid, sch->schid.ssid,
sch->schid.sch_no);
return 0;

+out_unreg:
+ device_unregister(&parent->dev);
out_free:
+ dev_set_drvdata(&parent->dev, NULL);
dev_set_drvdata(&sch->dev, NULL);
- vfio_ccw_free_private(private);
+ if (private)
+ vfio_ccw_free_private(private);
return ret;
}

static void vfio_ccw_sch_remove(struct subchannel *sch)
{
- struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_parent *parent = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);

- mdev_unregister_parent(&private->parent);
+ mdev_unregister_parent(&parent->parent);

+ device_unregister(&parent->dev);
dev_set_drvdata(&sch->dev, NULL);

vfio_ccw_free_private(private);
@@ -256,7 +310,11 @@ static void vfio_ccw_sch_remove(struct subchannel *sch)

static void vfio_ccw_sch_shutdown(struct subchannel *sch)
{
- struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_parent *parent = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);
+
+ if (WARN_ON(!private))
+ return;

vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLOSE);
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER);
@@ -274,7 +332,8 @@ static void vfio_ccw_sch_shutdown(struct subchannel *sch)
*/
static int vfio_ccw_sch_event(struct subchannel *sch, int process)
{
- struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_parent *parent = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);
unsigned long flags;
int rc = -EAGAIN;

@@ -287,8 +346,10 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process)

rc = 0;

- if (cio_update_schib(sch))
- vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER);
+ if (cio_update_schib(sch)) {
+ if (private)
+ vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER);
+ }

out_unlock:
spin_unlock_irqrestore(sch->lock, flags);
@@ -326,7 +387,8 @@ static void vfio_ccw_queue_crw(struct vfio_ccw_private *private,
static int vfio_ccw_chp_event(struct subchannel *sch,
struct chp_link *link, int event)
{
- struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_parent *parent = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);
int mask = chp_ssd_get_mask(&sch->ssd_info, link);
int retry = 255;

diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index 6ae4d012d800..dc084883d872 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -55,7 +55,9 @@ static int vfio_ccw_mdev_init_dev(struct vfio_device *vdev)

static int vfio_ccw_mdev_probe(struct mdev_device *mdev)
{
- struct vfio_ccw_private *private = dev_get_drvdata(mdev->dev.parent);
+ struct subchannel *sch = to_subchannel(mdev->dev.parent);
+ struct vfio_ccw_parent *parent = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);
int ret;

if (private->state == VFIO_CCW_STATE_NOT_OPER)
@@ -100,7 +102,9 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)

static void vfio_ccw_mdev_remove(struct mdev_device *mdev)
{
- struct vfio_ccw_private *private = dev_get_drvdata(mdev->dev.parent);
+ struct subchannel *sch = to_subchannel(mdev->dev.parent);
+ struct vfio_ccw_parent *parent = dev_get_drvdata(&sch->dev);
+ struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);

VFIO_CCW_MSG_EVENT(2, "sch %x.%x.%04x: remove\n",
private->sch->schid.cssid,
diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h
index bd5fb81456af..1f598d58d969 100644
--- a/drivers/s390/cio/vfio_ccw_private.h
+++ b/drivers/s390/cio/vfio_ccw_private.h
@@ -67,6 +67,21 @@ struct vfio_ccw_crw {
struct crw crw;
};

+/**
+ * struct vfio_ccw_parent
+ *
+ * @dev: embedded device struct
+ * @parent: parent data structures for mdevs created
+ * @mdev_type(s): identifying information for mdevs created
+ */
+struct vfio_ccw_parent {
+ struct device dev;
+
+ struct mdev_parent parent;
+ struct mdev_type mdev_type;
+ struct mdev_type *mdev_types[1];
+};
+
/**
* struct vfio_ccw_private
* @vdev: Embedded VFIO device
@@ -89,7 +104,6 @@ struct vfio_ccw_crw {
* @io_work: work for deferral process of I/O handling
* @crw_work: work for deferral process of CRW handling
* @release_comp: synchronization helper for vfio device release
- * @parent: parent data structures for mdevs created
*/
struct vfio_ccw_private {
struct vfio_device vdev;
@@ -116,10 +130,6 @@ struct vfio_ccw_private {
struct work_struct crw_work;

struct completion release_comp;
-
- struct mdev_parent parent;
- struct mdev_type mdev_type;
- struct mdev_type *mdev_types[1];
} __aligned(8);

int vfio_ccw_sch_quiesce(struct subchannel *sch);
--
2.34.1


2022-11-04 14:25:59

by Eric Farman

[permalink] [raw]
Subject: [PATCH v3 2/7] vfio/ccw: remove private->sch

These places all rely on the ability to jump from a private
struct back to the subchannel struct. Rather than keeping a
copy in our back pocket, let's use the relationship provided
by the vfio_device embedded within the private.

Signed-off-by: Eric Farman <[email protected]>
Reviewed-by: Matthew Rosato <[email protected]>
---
drivers/s390/cio/vfio_ccw_chp.c | 5 +++--
drivers/s390/cio/vfio_ccw_drv.c | 3 +--
drivers/s390/cio/vfio_ccw_fsm.c | 27 ++++++++++++---------------
drivers/s390/cio/vfio_ccw_ops.c | 12 ++++++------
drivers/s390/cio/vfio_ccw_private.h | 7 ++++---
5 files changed, 26 insertions(+), 28 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_chp.c b/drivers/s390/cio/vfio_ccw_chp.c
index 13b26a1c7988..d3f3a611f95b 100644
--- a/drivers/s390/cio/vfio_ccw_chp.c
+++ b/drivers/s390/cio/vfio_ccw_chp.c
@@ -16,6 +16,7 @@ static ssize_t vfio_ccw_schib_region_read(struct vfio_ccw_private *private,
char __user *buf, size_t count,
loff_t *ppos)
{
+ struct subchannel *sch = to_subchannel(private->vdev.dev->parent);
unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS;
loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK;
struct ccw_schib_region *region;
@@ -27,12 +28,12 @@ static ssize_t vfio_ccw_schib_region_read(struct vfio_ccw_private *private,
mutex_lock(&private->io_mutex);
region = private->region[i].data;

- if (cio_update_schib(private->sch)) {
+ if (cio_update_schib(sch)) {
ret = -ENODEV;
goto out;
}

- memcpy(region, &private->sch->schib, sizeof(*region));
+ memcpy(region, &sch->schib, sizeof(*region));

if (copy_to_user(buf, (void *)region + pos, count)) {
ret = -EFAULT;
diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index 444b32047397..2c680a556383 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -160,7 +160,6 @@ static struct vfio_ccw_private *vfio_ccw_alloc_private(struct subchannel *sch)
if (!private)
return ERR_PTR(-ENOMEM);

- private->sch = sch;
mutex_init(&private->io_mutex);
private->state = VFIO_CCW_STATE_STANDBY;
INIT_LIST_HEAD(&private->crw);
@@ -395,7 +394,7 @@ static int vfio_ccw_chp_event(struct subchannel *sch,
if (!private || !mask)
return 0;

- trace_vfio_ccw_chp_event(private->sch->schid, mask, event);
+ trace_vfio_ccw_chp_event(sch->schid, mask, event);
VFIO_CCW_MSG_EVENT(2, "sch %x.%x.%04x: mask=0x%x event=%d\n",
sch->schid.cssid,
sch->schid.ssid, sch->schid.sch_no,
diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c
index a59c758869f8..e67fad897af3 100644
--- a/drivers/s390/cio/vfio_ccw_fsm.c
+++ b/drivers/s390/cio/vfio_ccw_fsm.c
@@ -18,15 +18,13 @@

static int fsm_io_helper(struct vfio_ccw_private *private)
{
- struct subchannel *sch;
+ struct subchannel *sch = to_subchannel(private->vdev.dev->parent);
union orb *orb;
int ccode;
__u8 lpm;
unsigned long flags;
int ret;

- sch = private->sch;
-
spin_lock_irqsave(sch->lock, flags);

orb = cp_get_orb(&private->cp, (u32)(addr_t)sch, sch->lpm);
@@ -80,13 +78,11 @@ static int fsm_io_helper(struct vfio_ccw_private *private)

static int fsm_do_halt(struct vfio_ccw_private *private)
{
- struct subchannel *sch;
+ struct subchannel *sch = to_subchannel(private->vdev.dev->parent);
unsigned long flags;
int ccode;
int ret;

- sch = private->sch;
-
spin_lock_irqsave(sch->lock, flags);

VFIO_CCW_TRACE_EVENT(2, "haltIO");
@@ -121,13 +117,11 @@ static int fsm_do_halt(struct vfio_ccw_private *private)

static int fsm_do_clear(struct vfio_ccw_private *private)
{
- struct subchannel *sch;
+ struct subchannel *sch = to_subchannel(private->vdev.dev->parent);
unsigned long flags;
int ccode;
int ret;

- sch = private->sch;
-
spin_lock_irqsave(sch->lock, flags);

VFIO_CCW_TRACE_EVENT(2, "clearIO");
@@ -160,7 +154,7 @@ static int fsm_do_clear(struct vfio_ccw_private *private)
static void fsm_notoper(struct vfio_ccw_private *private,
enum vfio_ccw_event event)
{
- struct subchannel *sch = private->sch;
+ struct subchannel *sch = to_subchannel(private->vdev.dev->parent);

VFIO_CCW_MSG_EVENT(2, "sch %x.%x.%04x: notoper event %x state %x\n",
sch->schid.cssid,
@@ -228,7 +222,7 @@ static void fsm_async_retry(struct vfio_ccw_private *private,
static void fsm_disabled_irq(struct vfio_ccw_private *private,
enum vfio_ccw_event event)
{
- struct subchannel *sch = private->sch;
+ struct subchannel *sch = to_subchannel(private->vdev.dev->parent);

/*
* An interrupt in a disabled state means a previous disable was not
@@ -238,7 +232,9 @@ static void fsm_disabled_irq(struct vfio_ccw_private *private,
}
inline struct subchannel_id get_schid(struct vfio_ccw_private *p)
{
- return p->sch->schid;
+ struct subchannel *sch = to_subchannel(p->vdev.dev->parent);
+
+ return sch->schid;
}

/*
@@ -360,10 +356,11 @@ static void fsm_async_request(struct vfio_ccw_private *private,
static void fsm_irq(struct vfio_ccw_private *private,
enum vfio_ccw_event event)
{
+ struct subchannel *sch = to_subchannel(private->vdev.dev->parent);
struct irb *irb = this_cpu_ptr(&cio_irb);

VFIO_CCW_TRACE_EVENT(6, "IRQ");
- VFIO_CCW_TRACE_EVENT(6, dev_name(&private->sch->dev));
+ VFIO_CCW_TRACE_EVENT(6, dev_name(&sch->dev));

memcpy(&private->irb, irb, sizeof(*irb));

@@ -376,7 +373,7 @@ static void fsm_irq(struct vfio_ccw_private *private,
static void fsm_open(struct vfio_ccw_private *private,
enum vfio_ccw_event event)
{
- struct subchannel *sch = private->sch;
+ struct subchannel *sch = to_subchannel(private->vdev.dev->parent);
int ret;

spin_lock_irq(sch->lock);
@@ -397,7 +394,7 @@ static void fsm_open(struct vfio_ccw_private *private,
static void fsm_close(struct vfio_ccw_private *private,
enum vfio_ccw_event event)
{
- struct subchannel *sch = private->sch;
+ struct subchannel *sch = to_subchannel(private->vdev.dev->parent);
int ret;

spin_lock_irq(sch->lock);
diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index dc084883d872..79c50cb7dcb8 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -68,9 +68,9 @@ static int vfio_ccw_mdev_probe(struct mdev_device *mdev)
return ret;

VFIO_CCW_MSG_EVENT(2, "sch %x.%x.%04x: create\n",
- private->sch->schid.cssid,
- private->sch->schid.ssid,
- private->sch->schid.sch_no);
+ sch->schid.cssid,
+ sch->schid.ssid,
+ sch->schid.sch_no);

ret = vfio_register_emulated_iommu_dev(&private->vdev);
if (ret)
@@ -107,9 +107,9 @@ static void vfio_ccw_mdev_remove(struct mdev_device *mdev)
struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);

VFIO_CCW_MSG_EVENT(2, "sch %x.%x.%04x: remove\n",
- private->sch->schid.cssid,
- private->sch->schid.ssid,
- private->sch->schid.sch_no);
+ sch->schid.cssid,
+ sch->schid.ssid,
+ sch->schid.sch_no);

vfio_unregister_group_dev(&private->vdev);

diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h
index 1f598d58d969..b28af2f63963 100644
--- a/drivers/s390/cio/vfio_ccw_private.h
+++ b/drivers/s390/cio/vfio_ccw_private.h
@@ -85,7 +85,6 @@ struct vfio_ccw_parent {
/**
* struct vfio_ccw_private
* @vdev: Embedded VFIO device
- * @sch: pointer to the subchannel
* @state: internal state of the device
* @completion: synchronization helper of the I/O completion
* @io_region: MMIO region to input/output I/O arguments/results
@@ -107,7 +106,6 @@ struct vfio_ccw_parent {
*/
struct vfio_ccw_private {
struct vfio_device vdev;
- struct subchannel *sch;
int state;
struct completion *completion;
struct ccw_io_region *io_region;
@@ -172,7 +170,10 @@ extern fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS];
static inline void vfio_ccw_fsm_event(struct vfio_ccw_private *private,
enum vfio_ccw_event event)
{
- trace_vfio_ccw_fsm_event(private->sch->schid, private->state, event);
+ struct subchannel *sch = to_subchannel(private->vdev.dev->parent);
+
+ if (sch)
+ trace_vfio_ccw_fsm_event(sch->schid, private->state, event);
vfio_ccw_jumptable[private->state][event](private, event);
}

--
2.34.1


2022-11-04 14:26:37

by Eric Farman

[permalink] [raw]
Subject: [PATCH v3 5/7] vfio/ccw: remove release completion

There's enough separation between the parent and private structs now,
that it is fine to remove the release completion hack.

Signed-off-by: Eric Farman <[email protected]>
Reviewed-by: Kevin Tian <[email protected]>
Reviewed-by: Matthew Rosato <[email protected]>
---
drivers/s390/cio/vfio_ccw_ops.c | 14 +-------------
drivers/s390/cio/vfio_ccw_private.h | 3 ---
2 files changed, 1 insertion(+), 16 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index e45d4acb109b..8a929a9cf3c6 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -54,7 +54,6 @@ static int vfio_ccw_mdev_init_dev(struct vfio_device *vdev)
INIT_LIST_HEAD(&private->crw);
INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo);
INIT_WORK(&private->crw_work, vfio_ccw_crw_todo);
- init_completion(&private->release_comp);

private->cp.guest_cp = kcalloc(CCWCHAIN_LEN_MAX, sizeof(struct ccw1),
GFP_KERNEL);
@@ -137,7 +136,7 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
struct vfio_ccw_private *private =
container_of(vdev, struct vfio_ccw_private, vdev);

- complete(&private->release_comp);
+ vfio_ccw_free_private(private);
}

static void vfio_ccw_mdev_remove(struct mdev_device *mdev)
@@ -155,17 +154,6 @@ static void vfio_ccw_mdev_remove(struct mdev_device *mdev)

dev_set_drvdata(&parent->dev, NULL);
vfio_put_device(&private->vdev);
- /*
- * Wait for all active references on mdev are released so it
- * is safe to defer kfree() to a later point.
- *
- * TODO: the clean fix is to split parent/mdev info from ccw
- * private structure so each can be managed in its own life
- * cycle.
- */
- wait_for_completion(&private->release_comp);
-
- vfio_ccw_free_private(private);
}

static int vfio_ccw_mdev_open_device(struct vfio_device *vdev)
diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h
index 747aba5f5272..2278fd38d34e 100644
--- a/drivers/s390/cio/vfio_ccw_private.h
+++ b/drivers/s390/cio/vfio_ccw_private.h
@@ -102,7 +102,6 @@ struct vfio_ccw_parent {
* @req_trigger: eventfd ctx for signaling userspace to return device
* @io_work: work for deferral process of I/O handling
* @crw_work: work for deferral process of CRW handling
- * @release_comp: synchronization helper for vfio device release
*/
struct vfio_ccw_private {
struct vfio_device vdev;
@@ -126,8 +125,6 @@ struct vfio_ccw_private {
struct eventfd_ctx *req_trigger;
struct work_struct io_work;
struct work_struct crw_work;
-
- struct completion release_comp;
} __aligned(8);

int vfio_ccw_sch_quiesce(struct subchannel *sch);
--
2.34.1


2022-11-04 14:33:36

by Eric Farman

[permalink] [raw]
Subject: [PATCH v3 7/7] vfio: Remove vfio_free_device

With the "mess" sorted out, we should be able to inline the
vfio_free_device call introduced by commit cb9ff3f3b84c
("vfio: Add helpers for unifying vfio_device life cycle")
and remove them from driver release callbacks.

Signed-off-by: Eric Farman <[email protected]>
Reviewed-by: Jason Gunthorpe <[email protected]>
Reviewed-by: Kevin Tian <[email protected]>
Reviewed-by: Cornelia Huck <[email protected]>
Reviewed-by: Tony Krowiak <[email protected]> # vfio-ap part
Acked-by: Alex Williamson <[email protected]>
Reviewed-by: Matthew Rosato <[email protected]>
---
drivers/gpu/drm/i915/gvt/kvmgt.c | 1 -
drivers/s390/cio/vfio_ccw_ops.c | 2 --
drivers/s390/crypto/vfio_ap_ops.c | 6 ------
drivers/vfio/fsl-mc/vfio_fsl_mc.c | 1 -
drivers/vfio/pci/vfio_pci_core.c | 1 -
drivers/vfio/platform/vfio_amba.c | 1 -
drivers/vfio/platform/vfio_platform.c | 1 -
drivers/vfio/vfio_main.c | 22 ++++------------------
include/linux/vfio.h | 1 -
samples/vfio-mdev/mbochs.c | 1 -
samples/vfio-mdev/mdpy.c | 1 -
samples/vfio-mdev/mtty.c | 1 -
12 files changed, 4 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c
index 7a45e5360caf..eee6805e67de 100644
--- a/drivers/gpu/drm/i915/gvt/kvmgt.c
+++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
@@ -1461,7 +1461,6 @@ static void intel_vgpu_release_dev(struct vfio_device *vfio_dev)
struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);

intel_gvt_destroy_vgpu(vgpu);
- vfio_free_device(vfio_dev);
}

static const struct vfio_device_ops intel_vgpu_dev_ops = {
diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index 1155f8bcedd9..598a3814d428 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -143,8 +143,6 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
kmem_cache_free(vfio_ccw_io_region, private->io_region);
kfree(private->cp.guest_cp);
mutex_destroy(&private->io_mutex);
-
- vfio_free_device(vdev);
}

static void vfio_ccw_mdev_remove(struct mdev_device *mdev)
diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index 0b4cc8c597ae..f108c0f14712 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -765,11 +765,6 @@ static void vfio_ap_mdev_unlink_fr_queues(struct ap_matrix_mdev *matrix_mdev)
}
}

-static void vfio_ap_mdev_release_dev(struct vfio_device *vdev)
-{
- vfio_free_device(vdev);
-}
-
static void vfio_ap_mdev_remove(struct mdev_device *mdev)
{
struct ap_matrix_mdev *matrix_mdev = dev_get_drvdata(&mdev->dev);
@@ -1784,7 +1779,6 @@ static const struct attribute_group vfio_queue_attr_group = {

static const struct vfio_device_ops vfio_ap_matrix_dev_ops = {
.init = vfio_ap_mdev_init_dev,
- .release = vfio_ap_mdev_release_dev,
.open_device = vfio_ap_mdev_open_device,
.close_device = vfio_ap_mdev_close_device,
.ioctl = vfio_ap_mdev_ioctl,
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
index b16874e913e4..7b8889f55007 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
@@ -568,7 +568,6 @@ static void vfio_fsl_mc_release_dev(struct vfio_device *core_vdev)

vfio_fsl_uninit_device(vdev);
mutex_destroy(&vdev->igate);
- vfio_free_device(core_vdev);
}

static int vfio_fsl_mc_remove(struct fsl_mc_device *mc_dev)
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index badc9d828cac..9be2d5be5d95 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -2109,7 +2109,6 @@ void vfio_pci_core_release_dev(struct vfio_device *core_vdev)
mutex_destroy(&vdev->vma_lock);
kfree(vdev->region);
kfree(vdev->pm_save);
- vfio_free_device(core_vdev);
}
EXPORT_SYMBOL_GPL(vfio_pci_core_release_dev);

diff --git a/drivers/vfio/platform/vfio_amba.c b/drivers/vfio/platform/vfio_amba.c
index eaea63e5294c..18faf2678b99 100644
--- a/drivers/vfio/platform/vfio_amba.c
+++ b/drivers/vfio/platform/vfio_amba.c
@@ -95,7 +95,6 @@ static void vfio_amba_release_dev(struct vfio_device *core_vdev)

vfio_platform_release_common(vdev);
kfree(vdev->name);
- vfio_free_device(core_vdev);
}

static void vfio_amba_remove(struct amba_device *adev)
diff --git a/drivers/vfio/platform/vfio_platform.c b/drivers/vfio/platform/vfio_platform.c
index 82cedcebfd90..9910451dc341 100644
--- a/drivers/vfio/platform/vfio_platform.c
+++ b/drivers/vfio/platform/vfio_platform.c
@@ -83,7 +83,6 @@ static void vfio_platform_release_dev(struct vfio_device *core_vdev)
container_of(core_vdev, struct vfio_platform_device, vdev);

vfio_platform_release_common(vdev);
- vfio_free_device(core_vdev);
}

static int vfio_platform_remove(struct platform_device *pdev)
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 2901b8ad5be9..9835757e2bee 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -339,13 +339,10 @@ static void vfio_device_release(struct device *dev)
vfio_release_device_set(device);
ida_free(&vfio.device_ida, device->index);

- /*
- * kvfree() cannot be done here due to a life cycle mess in
- * vfio-ccw. Before the ccw part is fixed all drivers are
- * required to support @release and call vfio_free_device()
- * from there.
- */
- device->ops->release(device);
+ if (device->ops->release)
+ device->ops->release(device);
+
+ kvfree(device);
}

static int vfio_init_device(struct vfio_device *device, struct device *dev,
@@ -424,17 +421,6 @@ static int vfio_init_device(struct vfio_device *device, struct device *dev,
return ret;
}

-/*
- * The helper called by driver @release callback to free the device
- * structure. Drivers which don't have private data to clean can
- * simply use this helper as its @release.
- */
-void vfio_free_device(struct vfio_device *device)
-{
- kvfree(device);
-}
-EXPORT_SYMBOL_GPL(vfio_free_device);
-
static struct vfio_group *vfio_noiommu_group_alloc(struct device *dev,
enum vfio_group_type type)
{
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index ba809268a48e..e7480154825e 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -176,7 +176,6 @@ struct vfio_device *_vfio_alloc_device(size_t size, struct device *dev,
dev, ops), \
struct dev_struct, member)

-void vfio_free_device(struct vfio_device *device);
static inline void vfio_put_device(struct vfio_device *device)
{
put_device(&device->device);
diff --git a/samples/vfio-mdev/mbochs.c b/samples/vfio-mdev/mbochs.c
index 117a8d799f71..8b5a3a778a25 100644
--- a/samples/vfio-mdev/mbochs.c
+++ b/samples/vfio-mdev/mbochs.c
@@ -594,7 +594,6 @@ static void mbochs_release_dev(struct vfio_device *vdev)
atomic_add(mdev_state->type->mbytes, &mbochs_avail_mbytes);
kfree(mdev_state->pages);
kfree(mdev_state->vconfig);
- vfio_free_device(vdev);
}

static void mbochs_remove(struct mdev_device *mdev)
diff --git a/samples/vfio-mdev/mdpy.c b/samples/vfio-mdev/mdpy.c
index 946e8cfde6fd..721fb06c6413 100644
--- a/samples/vfio-mdev/mdpy.c
+++ b/samples/vfio-mdev/mdpy.c
@@ -283,7 +283,6 @@ static void mdpy_release_dev(struct vfio_device *vdev)

vfree(mdev_state->memblk);
kfree(mdev_state->vconfig);
- vfio_free_device(vdev);
}

static void mdpy_remove(struct mdev_device *mdev)
diff --git a/samples/vfio-mdev/mtty.c b/samples/vfio-mdev/mtty.c
index e72085fc1376..3c2a421b9b69 100644
--- a/samples/vfio-mdev/mtty.c
+++ b/samples/vfio-mdev/mtty.c
@@ -784,7 +784,6 @@ static void mtty_release_dev(struct vfio_device *vdev)

atomic_add(mdev_state->nr_ports, &mdev_avail_ports);
kfree(mdev_state->vconfig);
- vfio_free_device(vdev);
}

static void mtty_remove(struct mdev_device *mdev)
--
2.34.1


2022-11-04 14:50:44

by Eric Farman

[permalink] [raw]
Subject: [PATCH v3 3/7] vfio/ccw: move private initialization to callback

There's already a device initialization callback that is used to
initialize the release completion workaround that was introduced
by commit ebb72b765fb49 ("vfio/ccw: Use the new device life cycle
helpers").

Move the other elements of the vfio_ccw_private struct that
require distinct initialization over to that routine.

With that done, the vfio_ccw_alloc_private routine only does a
kzalloc, so fold it inline.

Signed-off-by: Eric Farman <[email protected]>
Reviewed-by: Matthew Rosato <[email protected]>
---
drivers/s390/cio/vfio_ccw_drv.c | 74 ++++-------------------------
drivers/s390/cio/vfio_ccw_ops.c | 43 +++++++++++++++++
drivers/s390/cio/vfio_ccw_private.h | 7 ++-
3 files changed, 58 insertions(+), 66 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index 2c680a556383..fbc26338ceab 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -23,10 +23,10 @@
#include "vfio_ccw_private.h"

struct workqueue_struct *vfio_ccw_work_q;
-static struct kmem_cache *vfio_ccw_io_region;
-static struct kmem_cache *vfio_ccw_cmd_region;
-static struct kmem_cache *vfio_ccw_schib_region;
-static struct kmem_cache *vfio_ccw_crw_region;
+struct kmem_cache *vfio_ccw_io_region;
+struct kmem_cache *vfio_ccw_cmd_region;
+struct kmem_cache *vfio_ccw_schib_region;
+struct kmem_cache *vfio_ccw_crw_region;

debug_info_t *vfio_ccw_debug_msg_id;
debug_info_t *vfio_ccw_debug_trace_id;
@@ -79,7 +79,7 @@ int vfio_ccw_sch_quiesce(struct subchannel *sch)
return ret;
}

-static void vfio_ccw_sch_io_todo(struct work_struct *work)
+void vfio_ccw_sch_io_todo(struct work_struct *work)
{
struct vfio_ccw_private *private;
struct irb *irb;
@@ -115,7 +115,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
eventfd_signal(private->io_trigger, 1);
}

-static void vfio_ccw_crw_todo(struct work_struct *work)
+void vfio_ccw_crw_todo(struct work_struct *work)
{
struct vfio_ccw_private *private;

@@ -152,62 +152,6 @@ static void vfio_ccw_sch_irq(struct subchannel *sch)
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_INTERRUPT);
}

-static struct vfio_ccw_private *vfio_ccw_alloc_private(struct subchannel *sch)
-{
- struct vfio_ccw_private *private;
-
- private = kzalloc(sizeof(*private), GFP_KERNEL);
- if (!private)
- return ERR_PTR(-ENOMEM);
-
- mutex_init(&private->io_mutex);
- private->state = VFIO_CCW_STATE_STANDBY;
- INIT_LIST_HEAD(&private->crw);
- INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo);
- INIT_WORK(&private->crw_work, vfio_ccw_crw_todo);
-
- private->cp.guest_cp = kcalloc(CCWCHAIN_LEN_MAX, sizeof(struct ccw1),
- GFP_KERNEL);
- if (!private->cp.guest_cp)
- goto out_free_private;
-
- private->io_region = kmem_cache_zalloc(vfio_ccw_io_region,
- GFP_KERNEL | GFP_DMA);
- if (!private->io_region)
- goto out_free_cp;
-
- private->cmd_region = kmem_cache_zalloc(vfio_ccw_cmd_region,
- GFP_KERNEL | GFP_DMA);
- if (!private->cmd_region)
- goto out_free_io;
-
- private->schib_region = kmem_cache_zalloc(vfio_ccw_schib_region,
- GFP_KERNEL | GFP_DMA);
-
- if (!private->schib_region)
- goto out_free_cmd;
-
- private->crw_region = kmem_cache_zalloc(vfio_ccw_crw_region,
- GFP_KERNEL | GFP_DMA);
-
- if (!private->crw_region)
- goto out_free_schib;
- return private;
-
-out_free_schib:
- kmem_cache_free(vfio_ccw_schib_region, private->schib_region);
-out_free_cmd:
- kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region);
-out_free_io:
- kmem_cache_free(vfio_ccw_io_region, private->io_region);
-out_free_cp:
- kfree(private->cp.guest_cp);
-out_free_private:
- mutex_destroy(&private->io_mutex);
- kfree(private);
- return ERR_PTR(-ENOMEM);
-}
-
static void vfio_ccw_free_private(struct vfio_ccw_private *private)
{
struct vfio_ccw_crw *crw, *temp;
@@ -257,10 +201,10 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
if (ret)
goto out_free;

- private = vfio_ccw_alloc_private(sch);
- if (IS_ERR(private)) {
+ private = kzalloc(sizeof(*private), GFP_KERNEL);
+ if (!private) {
device_unregister(&parent->dev);
- return PTR_ERR(private);
+ return -ENOMEM;
}

dev_set_drvdata(&sch->dev, parent);
diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index 79c50cb7dcb8..eb0b8cc210bb 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -49,8 +49,51 @@ static int vfio_ccw_mdev_init_dev(struct vfio_device *vdev)
struct vfio_ccw_private *private =
container_of(vdev, struct vfio_ccw_private, vdev);

+ mutex_init(&private->io_mutex);
+ private->state = VFIO_CCW_STATE_STANDBY;
+ INIT_LIST_HEAD(&private->crw);
+ INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo);
+ INIT_WORK(&private->crw_work, vfio_ccw_crw_todo);
init_completion(&private->release_comp);
+
+ private->cp.guest_cp = kcalloc(CCWCHAIN_LEN_MAX, sizeof(struct ccw1),
+ GFP_KERNEL);
+ if (!private->cp.guest_cp)
+ goto out_free_private;
+
+ private->io_region = kmem_cache_zalloc(vfio_ccw_io_region,
+ GFP_KERNEL | GFP_DMA);
+ if (!private->io_region)
+ goto out_free_cp;
+
+ private->cmd_region = kmem_cache_zalloc(vfio_ccw_cmd_region,
+ GFP_KERNEL | GFP_DMA);
+ if (!private->cmd_region)
+ goto out_free_io;
+
+ private->schib_region = kmem_cache_zalloc(vfio_ccw_schib_region,
+ GFP_KERNEL | GFP_DMA);
+ if (!private->schib_region)
+ goto out_free_cmd;
+
+ private->crw_region = kmem_cache_zalloc(vfio_ccw_crw_region,
+ GFP_KERNEL | GFP_DMA);
+ if (!private->crw_region)
+ goto out_free_schib;
+
return 0;
+
+out_free_schib:
+ kmem_cache_free(vfio_ccw_schib_region, private->schib_region);
+out_free_cmd:
+ kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region);
+out_free_io:
+ kmem_cache_free(vfio_ccw_io_region, private->io_region);
+out_free_cp:
+ kfree(private->cp.guest_cp);
+out_free_private:
+ mutex_destroy(&private->io_mutex);
+ return -ENOMEM;
}

static int vfio_ccw_mdev_probe(struct mdev_device *mdev)
diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h
index b28af2f63963..55d636225cff 100644
--- a/drivers/s390/cio/vfio_ccw_private.h
+++ b/drivers/s390/cio/vfio_ccw_private.h
@@ -131,6 +131,8 @@ struct vfio_ccw_private {
} __aligned(8);

int vfio_ccw_sch_quiesce(struct subchannel *sch);
+void vfio_ccw_sch_io_todo(struct work_struct *work);
+void vfio_ccw_crw_todo(struct work_struct *work);

extern struct mdev_driver vfio_ccw_mdev_driver;

@@ -178,7 +180,10 @@ static inline void vfio_ccw_fsm_event(struct vfio_ccw_private *private,
}

extern struct workqueue_struct *vfio_ccw_work_q;
-
+extern struct kmem_cache *vfio_ccw_io_region;
+extern struct kmem_cache *vfio_ccw_cmd_region;
+extern struct kmem_cache *vfio_ccw_schib_region;
+extern struct kmem_cache *vfio_ccw_crw_region;

/* s390 debug feature, similar to base cio */
extern debug_info_t *vfio_ccw_debug_msg_id;
--
2.34.1


2022-11-10 21:13:13

by Alex Williamson

[permalink] [raw]
Subject: Re: [PATCH v3 0/7] vfio-ccw parent rework

On Fri, 4 Nov 2022 15:20:00 +0100
Eric Farman <[email protected]> wrote:

> Hi Alex,
>
> Here's the (last?) update to the vfio-ccw lifecycle changes that I've sent
> recently, and were previously discussed at various points [1][2].
>
> Patches 1-5 rework the behavior of the vfio-ccw driver's private struct.
> In summary, the mdev pieces are split out of vfio_ccw_private and into a
> new vfio_ccw_parent struct that will continue to follow today's lifecycle.
> The remainder (bulk) of the private struct moves to follow the mdev
> probe/remove pair. There's opportunity for further separation of the
> things in the private struct, which would simplify some of the vfio-ccw
> code, but it got too hairy as I started that. Once vfio-ccw is no longer
> considered unique, those cleanups can happen at our leisure.
>
> Patch 6 removes the trickery where vfio-ccw uses vfio_init_device instead of
> vfio_alloc_device, and thus removes vfio_init_device from the outside world.
>
> Patch 7 removes vfio_free_device from vfio-ccw and the other drivers (hello,
> CC list!), letting it be handled by vfio_device_release directly.
>
> I believe this covers everything in this space; let me know if not!
>
> Thanks,
> Eric
>
> [1] https://lore.kernel.org/kvm/[email protected]/
> [2] https://lore.kernel.org/kvm/[email protected]/
>
> v2->v3:
> - [MR] Added r-b to remaining patches (Thank you!)
> - Patch 1:
> [gfx checkpatch] Whitespace
> [EF] Remove put_device(&parent->dev)
> [MR] Fix error exit when alloc of parent fails
> [MR] Check for !private on sch_probe error path
> - Patch 3:
> [EF] Fix error exit when alloc of private fails
> - Patch 6:
> [AW] Added ack (Thank you!)
> - Patch 7:
> [CH, AK] Added r-b (Thank you!)
> [AW] Added ack (Thank you!)
> v2: https://lore.kernel.org/kvm/[email protected]/
> v1: https://lore.kernel.org/kvm/[email protected]/
>
> Eric Farman (7):
> vfio/ccw: create a parent struct
> vfio/ccw: remove private->sch
> vfio/ccw: move private initialization to callback
> vfio/ccw: move private to mdev lifecycle
> vfio/ccw: remove release completion
> vfio/ccw: replace vfio_init_device with _alloc_
> vfio: Remove vfio_free_device
>
> drivers/gpu/drm/i915/gvt/kvmgt.c | 1 -
> drivers/s390/cio/vfio_ccw_chp.c | 5 +-
> drivers/s390/cio/vfio_ccw_drv.c | 173 +++++++++++---------------
> drivers/s390/cio/vfio_ccw_fsm.c | 27 ++--
> drivers/s390/cio/vfio_ccw_ops.c | 107 +++++++++++-----
> drivers/s390/cio/vfio_ccw_private.h | 37 ++++--
> drivers/s390/crypto/vfio_ap_ops.c | 6 -
> drivers/vfio/fsl-mc/vfio_fsl_mc.c | 1 -
> drivers/vfio/pci/vfio_pci_core.c | 1 -
> drivers/vfio/platform/vfio_amba.c | 1 -
> drivers/vfio/platform/vfio_platform.c | 1 -
> drivers/vfio/vfio_main.c | 32 ++---
> include/linux/vfio.h | 3 -
> samples/vfio-mdev/mbochs.c | 1 -
> samples/vfio-mdev/mdpy.c | 1 -
> samples/vfio-mdev/mtty.c | 1 -
> 16 files changed, 196 insertions(+), 202 deletions(-)
>

Applied to vfio next branch for v6.2. Thanks,

Alex