Skip to content

Commit 6e97eba

Browse files
yishaihawilliam
authored andcommitted
vfio: Split migration ops from main device ops
vfio core checks whether the driver sets some migration op (e.g. set_state/get_state) and accordingly calls its op. However, currently mlx5 driver sets the above ops without regards to its migration caps. This might lead to unexpected usage/Oops if user space may call to the above ops even if the driver doesn't support migration. As for example, the migration state_mutex is not initialized in that case. The cleanest way to manage that seems to split the migration ops from the main device ops, this will let the driver setting them separately from the main ops when it's applicable. As part of that, validate ops construction on registration and include a check for VFIO_MIGRATION_STOP_COPY since the uAPI claims it must be set in migration_flags. HISI driver was changed as well to match this scheme. This scheme may enable down the road to come with some extra group of ops (e.g. DMA log) that can be set without regards to the other options based on driver caps. Fixes: 6fadb02 ("vfio/mlx5: Implement vfio_pci driver for mlx5 devices") Reviewed-by: Kevin Tian <[email protected]> Signed-off-by: Yishai Hadas <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alex Williamson <[email protected]>
1 parent 2b1c190 commit 6e97eba

File tree

7 files changed

+51
-24
lines changed

7 files changed

+51
-24
lines changed

drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,7 +1185,7 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
11851185
if (ret)
11861186
return ret;
11871187

1188-
if (core_vdev->ops->migration_set_state) {
1188+
if (core_vdev->mig_ops) {
11891189
ret = hisi_acc_vf_qm_init(hisi_acc_vdev);
11901190
if (ret) {
11911191
vfio_pci_core_disable(vdev);
@@ -1208,6 +1208,11 @@ static void hisi_acc_vfio_pci_close_device(struct vfio_device *core_vdev)
12081208
vfio_pci_core_close_device(core_vdev);
12091209
}
12101210

1211+
static const struct vfio_migration_ops hisi_acc_vfio_pci_migrn_state_ops = {
1212+
.migration_set_state = hisi_acc_vfio_pci_set_device_state,
1213+
.migration_get_state = hisi_acc_vfio_pci_get_device_state,
1214+
};
1215+
12111216
static const struct vfio_device_ops hisi_acc_vfio_pci_migrn_ops = {
12121217
.name = "hisi-acc-vfio-pci-migration",
12131218
.open_device = hisi_acc_vfio_pci_open_device,
@@ -1219,8 +1224,6 @@ static const struct vfio_device_ops hisi_acc_vfio_pci_migrn_ops = {
12191224
.mmap = hisi_acc_vfio_pci_mmap,
12201225
.request = vfio_pci_core_request,
12211226
.match = vfio_pci_core_match,
1222-
.migration_set_state = hisi_acc_vfio_pci_set_device_state,
1223-
.migration_get_state = hisi_acc_vfio_pci_get_device_state,
12241227
};
12251228

12261229
static const struct vfio_device_ops hisi_acc_vfio_pci_ops = {
@@ -1272,6 +1275,8 @@ static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device
12721275
if (!ret) {
12731276
vfio_pci_core_init_device(&hisi_acc_vdev->core_device, pdev,
12741277
&hisi_acc_vfio_pci_migrn_ops);
1278+
hisi_acc_vdev->core_device.vdev.mig_ops =
1279+
&hisi_acc_vfio_pci_migrn_state_ops;
12751280
} else {
12761281
pci_warn(pdev, "migration support failed, continue with generic interface\n");
12771282
vfio_pci_core_init_device(&hisi_acc_vdev->core_device, pdev,

drivers/vfio/pci/mlx5/cmd.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ void mlx5vf_cmd_remove_migratable(struct mlx5vf_pci_core_device *mvdev)
108108
destroy_workqueue(mvdev->cb_wq);
109109
}
110110

111-
void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev)
111+
void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev,
112+
const struct vfio_migration_ops *mig_ops)
112113
{
113114
struct pci_dev *pdev = mvdev->core_device.pdev;
114115
int ret;
@@ -149,6 +150,7 @@ void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev)
149150
mvdev->core_device.vdev.migration_flags =
150151
VFIO_MIGRATION_STOP_COPY |
151152
VFIO_MIGRATION_P2P;
153+
mvdev->core_device.vdev.mig_ops = mig_ops;
152154

153155
end:
154156
mlx5_vf_put_core_dev(mvdev->mdev);

drivers/vfio/pci/mlx5/cmd.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ int mlx5vf_cmd_suspend_vhca(struct mlx5vf_pci_core_device *mvdev, u16 op_mod);
6262
int mlx5vf_cmd_resume_vhca(struct mlx5vf_pci_core_device *mvdev, u16 op_mod);
6363
int mlx5vf_cmd_query_vhca_migration_state(struct mlx5vf_pci_core_device *mvdev,
6464
size_t *state_size);
65-
void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev);
65+
void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev,
66+
const struct vfio_migration_ops *mig_ops);
6667
void mlx5vf_cmd_remove_migratable(struct mlx5vf_pci_core_device *mvdev);
6768
void mlx5vf_cmd_close_migratable(struct mlx5vf_pci_core_device *mvdev);
6869
int mlx5vf_cmd_save_vhca_state(struct mlx5vf_pci_core_device *mvdev,

drivers/vfio/pci/mlx5/main.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,11 @@ static void mlx5vf_pci_close_device(struct vfio_device *core_vdev)
574574
vfio_pci_core_close_device(core_vdev);
575575
}
576576

577+
static const struct vfio_migration_ops mlx5vf_pci_mig_ops = {
578+
.migration_set_state = mlx5vf_pci_set_device_state,
579+
.migration_get_state = mlx5vf_pci_get_device_state,
580+
};
581+
577582
static const struct vfio_device_ops mlx5vf_pci_ops = {
578583
.name = "mlx5-vfio-pci",
579584
.open_device = mlx5vf_pci_open_device,
@@ -585,8 +590,6 @@ static const struct vfio_device_ops mlx5vf_pci_ops = {
585590
.mmap = vfio_pci_core_mmap,
586591
.request = vfio_pci_core_request,
587592
.match = vfio_pci_core_match,
588-
.migration_set_state = mlx5vf_pci_set_device_state,
589-
.migration_get_state = mlx5vf_pci_get_device_state,
590593
};
591594

592595
static int mlx5vf_pci_probe(struct pci_dev *pdev,
@@ -599,7 +602,7 @@ static int mlx5vf_pci_probe(struct pci_dev *pdev,
599602
if (!mvdev)
600603
return -ENOMEM;
601604
vfio_pci_core_init_device(&mvdev->core_device, pdev, &mlx5vf_pci_ops);
602-
mlx5vf_cmd_set_migratable(mvdev);
605+
mlx5vf_cmd_set_migratable(mvdev, &mlx5vf_pci_mig_ops);
603606
dev_set_drvdata(&pdev->dev, &mvdev->core_device);
604607
ret = vfio_pci_core_register_device(&mvdev->core_device);
605608
if (ret)

drivers/vfio/pci/vfio_pci_core.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,6 +1855,13 @@ int vfio_pci_core_register_device(struct vfio_pci_core_device *vdev)
18551855
if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL)
18561856
return -EINVAL;
18571857

1858+
if (vdev->vdev.mig_ops) {
1859+
if (!(vdev->vdev.mig_ops->migration_get_state &&
1860+
vdev->vdev.mig_ops->migration_set_state) ||
1861+
!(vdev->vdev.migration_flags & VFIO_MIGRATION_STOP_COPY))
1862+
return -EINVAL;
1863+
}
1864+
18581865
/*
18591866
* Prevent binding to PFs with VFs enabled, the VFs might be in use
18601867
* by the host or other users. We cannot capture the VFs if they

drivers/vfio/vfio.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,8 +1541,7 @@ vfio_ioctl_device_feature_mig_device_state(struct vfio_device *device,
15411541
struct file *filp = NULL;
15421542
int ret;
15431543

1544-
if (!device->ops->migration_set_state ||
1545-
!device->ops->migration_get_state)
1544+
if (!device->mig_ops)
15461545
return -ENOTTY;
15471546

15481547
ret = vfio_check_feature(flags, argsz,
@@ -1558,15 +1557,16 @@ vfio_ioctl_device_feature_mig_device_state(struct vfio_device *device,
15581557
if (flags & VFIO_DEVICE_FEATURE_GET) {
15591558
enum vfio_device_mig_state curr_state;
15601559

1561-
ret = device->ops->migration_get_state(device, &curr_state);
1560+
ret = device->mig_ops->migration_get_state(device,
1561+
&curr_state);
15621562
if (ret)
15631563
return ret;
15641564
mig.device_state = curr_state;
15651565
goto out_copy;
15661566
}
15671567

15681568
/* Handle the VFIO_DEVICE_FEATURE_SET */
1569-
filp = device->ops->migration_set_state(device, mig.device_state);
1569+
filp = device->mig_ops->migration_set_state(device, mig.device_state);
15701570
if (IS_ERR(filp) || !filp)
15711571
goto out_copy;
15721572

@@ -1589,8 +1589,7 @@ static int vfio_ioctl_device_feature_migration(struct vfio_device *device,
15891589
};
15901590
int ret;
15911591

1592-
if (!device->ops->migration_set_state ||
1593-
!device->ops->migration_get_state)
1592+
if (!device->mig_ops)
15941593
return -ENOTTY;
15951594

15961595
ret = vfio_check_feature(flags, argsz, VFIO_DEVICE_FEATURE_GET,

include/linux/vfio.h

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ struct vfio_device_set {
3232
struct vfio_device {
3333
struct device *dev;
3434
const struct vfio_device_ops *ops;
35+
/*
36+
* mig_ops is a static property of the vfio_device which must be set
37+
* prior to registering the vfio_device.
38+
*/
39+
const struct vfio_migration_ops *mig_ops;
3540
struct vfio_group *group;
3641
struct vfio_device_set *dev_set;
3742
struct list_head dev_set_list;
@@ -61,16 +66,6 @@ struct vfio_device {
6166
* match, -errno for abort (ex. match with insufficient or incorrect
6267
* additional args)
6368
* @device_feature: Optional, fill in the VFIO_DEVICE_FEATURE ioctl
64-
* @migration_set_state: Optional callback to change the migration state for
65-
* devices that support migration. It's mandatory for
66-
* VFIO_DEVICE_FEATURE_MIGRATION migration support.
67-
* The returned FD is used for data transfer according to the FSM
68-
* definition. The driver is responsible to ensure that FD reaches end
69-
* of stream or error whenever the migration FSM leaves a data transfer
70-
* state or before close_device() returns.
71-
* @migration_get_state: Optional callback to get the migration state for
72-
* devices that support migration. It's mandatory for
73-
* VFIO_DEVICE_FEATURE_MIGRATION migration support.
7469
*/
7570
struct vfio_device_ops {
7671
char *name;
@@ -87,6 +82,21 @@ struct vfio_device_ops {
8782
int (*match)(struct vfio_device *vdev, char *buf);
8883
int (*device_feature)(struct vfio_device *device, u32 flags,
8984
void __user *arg, size_t argsz);
85+
};
86+
87+
/**
88+
* @migration_set_state: Optional callback to change the migration state for
89+
* devices that support migration. It's mandatory for
90+
* VFIO_DEVICE_FEATURE_MIGRATION migration support.
91+
* The returned FD is used for data transfer according to the FSM
92+
* definition. The driver is responsible to ensure that FD reaches end
93+
* of stream or error whenever the migration FSM leaves a data transfer
94+
* state or before close_device() returns.
95+
* @migration_get_state: Optional callback to get the migration state for
96+
* devices that support migration. It's mandatory for
97+
* VFIO_DEVICE_FEATURE_MIGRATION migration support.
98+
*/
99+
struct vfio_migration_ops {
90100
struct file *(*migration_set_state)(
91101
struct vfio_device *device,
92102
enum vfio_device_mig_state new_state);

0 commit comments

Comments
 (0)