Skip to contentSkip to conversation

Some vfio-ccw fixes

RFC Superseded Farhan Ali 4 participants 23 messages Jul 8, 2019 – Jul 12, 2019

Subsystems (5)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore

Farhan Ali

author
#0 lore raw

v2 cover Some vfio-ccw fixes

Hi,

While trying to chase down the problem regarding the stacktraces, I have also found some minor problems in the code.

Would appreciate any review or feedback regarding them.

Thanks
Farhan

ChangeLog
---------
v1 -> v2
- Update docs for csch/hsch since we can support those instructions now (patch 5)
- Fix the memory leak where we fail to free a ccwchain (patch 2)
- Add fixes tag where appropriate.
- Fix comment instead of the order when setting orb.cmd.c64 (patch 1)

Farhan Ali (5):
vfio-ccw: Fix misleading comment when setting orb.cmd.c64
vfio-ccw: Fix memory leak and don't call cp_free in cp_init
vfio-ccw: Set pa_nr to 0 if memory allocation fails for pa_iova_pfn
vfio-ccw: Don't call cp_free if we are processing a channel program
vfio-ccw: Update documentation for csch/hsch

 Documentation/s390/vfio-ccw.rst | 31 ++++++++++++++++++++++++++++---
 drivers/s390/cio/vfio_ccw_cp.c  | 19 ++++++++++++-------
 drivers/s390/cio/vfio_ccw_drv.c |  2 +-
 3 files changed, 41 insertions(+), 11 deletions(-)
Signature · 1 line
2.7.4
author
#1 lore raw

RFC v2 1/5 vfio-ccw: Fix misleading comment when setting orb.cmd.c64

The comment is misleading because it tells us that we should set orb.cmd.c64 before calling ccwchain_calc_length, otherwise the function ccwchain_calc_length would return an error. This is not completely accurate.

We want to allow an orb without cmd.c64, and this is fine as long as the channel program does not use IDALs. But we do want to reject any channel program that uses IDALs and does not set the flag, which what we do in ccwchain_calc_length.

After we have done the ccw processing, it should be safe to set cmd.c64, since we will convert them into IDALs.

---
 drivers/s390/cio/vfio_ccw_cp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/s390/cio/vfio_ccw_cp.c +2 -2
index d6a8dff..7622b72 100644
@@ -645,8 +645,8 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
 	if (ret)
 		cp_free(cp);
 
-	/* It is safe to force: if not set but idals used
-	 * ccwchain_calc_length returns an error.
+	/* It is safe to force: if it was not set but idals used
+	 * ccwchain_calc_length would have returned an error.
 	 */
 	cp->orb.cmd.c64 = 1;
 
Signature · 1 line
2.7.4
author
#7 lore raw

RFC v2 3/5 vfio-ccw: Set pa_nr to 0 if memory allocation fails for pa_iova_pfn

In reply to Farhan Ali

So we don't call try to call vfio_unpin_pages() incorrectly.

Fixes 0a19e61e6d4c ("vfio: ccw: introduce channel program interfaces")
---
 drivers/s390/cio/vfio_ccw_cp.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/s390/cio/vfio_ccw_cp.c +3 -1
index 31a04a5..1b93863 100644
@@ -72,8 +72,10 @@ static int pfn_array_alloc(struct pfn_array *pa, u64 iova, unsigned int len)
 				  sizeof(*pa->pa_iova_pfn) +
 				  sizeof(*pa->pa_pfn),
 				  GFP_KERNEL);
-	if (unlikely(!pa->pa_iova_pfn))
+	if (unlikely(!pa->pa_iova_pfn)) {
+		pa->pa_nr = 0;
 		return -ENOMEM;
+	}
 	pa->pa_pfn = pa->pa_iova_pfn + pa->pa_nr;
 
 	pa->pa_iova_pfn[0] = pa->pa_iova >> PAGE_SHIFT;
Signature · 1 line
2.7.4
author
#9 lore raw

RFC v2 4/5 vfio-ccw: Don't call cp_free if we are processing a channel program

In reply to Farhan Ali

There is a small window where it's possible that we could be working on an interrupt (queued in the workqueue) and setting up a channel program (i.e allocating memory, pinning pages, translating address). This can lead to allocating and freeing the channel program at the same time and can cause memory corruption.

Let's not call cp_free if we are currently processing a channel program. The only way we know for sure that we don't have a thread setting up a channel program is when the state is set to VFIO_CCW_STATE_CP_PENDING.

---
 drivers/s390/cio/vfio_ccw_drv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/s390/cio/vfio_ccw_drv.c +1 -1
index 4e3a903..0357165 100644
@@ -92,7 +92,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
 		     (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
 	if (scsw_is_solicited(&irb->scsw)) {
 		cp_update_scsw(&private->cp, &irb->scsw);
-		if (is_final)
+		if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING)
 			cp_free(&private->cp);
 	}
 	mutex_lock(&private->io_mutex);
Signature · 1 line
2.7.4
author
#20 lore raw

RFC v2 5/5 vfio-ccw: Update documentation for csch/hsch

In reply to Farhan Ali

We now support CLEAR SUBCHANNEL and HALT SUBCHANNEL via ccw_cmd_region.

---
 Documentation/s390/vfio-ccw.rst | 31 ++++++++++++++++++++++++++++---
 1 file changed, 28 insertions(+), 3 deletions(-)
Documentation/s390/vfio-ccw.rst +28 -3
index 1f6d0b5..40e4110 100644
@@ -180,6 +180,13 @@ The process of how these work together.
    add it to an iommu_group and a vfio_group. Then we could pass through
    the mdev to a guest.
 
+
+VFIO-CCW Regions
+----------------
+
+The vfio-ccw driver exposes MMIO regions to accept requests from and return
+results to userspace.
+
 vfio-ccw I/O region
 -------------------
 
@@ -205,6 +212,25 @@ irb_area stores the I/O result.
 
 ret_code stores a return code for each access of the region.
 
+This region is always available.
+
+vfio-ccw cmd region
+-------------------
+
+The vfio-ccw cmd region is used to accept asynchronous instructions
+from userspace.
+
+#define VFIO_CCW_ASYNC_CMD_HSCH (1 << 0)
+#define VFIO_CCW_ASYNC_CMD_CSCH (1 << 1)
+struct ccw_cmd_region {
+       __u32 command;
+       __u32 ret_code;
+} __packed;
+
+This region is exposed via region type VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD.
+
+CLEAR SUBCHANNEL and HALT SUBCHANNEL currently uses this region.
+
 vfio-ccw operation details
 --------------------------
 
@@ -306,9 +332,8 @@ Together with the corresponding work in QEMU, we can bring the passed
 through DASD/ECKD device online in a guest now and use it as a block
 device.
 
-While the current code allows the guest to start channel programs via
-START SUBCHANNEL, support for HALT SUBCHANNEL or CLEAR SUBCHANNEL is
-not yet implemented.
+The current code allows the guest to start channel programs via
+START SUBCHANNEL, and supports HALT SUBCHANNEL or CLEAR SUBCHANNEL.
 
 vfio-ccw supports classic (command mode) channel I/O only. Transport
 mode (HPF) is not supported.
Signature · 1 line
2.7.4
author
#3 lore raw

RFC v2 2/5 vfio-ccw: Fix memory leak and don't call cp_free in cp_init

In reply to Farhan Ali

We don't set cp->initialized to true so calling cp_free will just return and not do anything.

Also fix a memory leak where we fail to free a ccwchain on an error.

Fixes 812271b910 ("s390/cio: Squash cp_free() and cp_unpin_free()")
---
 drivers/s390/cio/vfio_ccw_cp.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/s390/cio/vfio_ccw_cp.c +7 -4
index 7622b72..31a04a5 100644
@@ -421,7 +421,7 @@ static int ccwchain_loop_tic(struct ccwchain *chain,
 static int ccwchain_handle_ccw(u32 cda, struct channel_program *cp)
 {
 	struct ccwchain *chain;
-	int len;
+	int len, ret;
 
 	/* Copy 2K (the most we support today) of possible CCWs */
 	len = copy_from_iova(cp->mdev, cp->guest_cp, cda,
@@ -448,7 +448,12 @@ static int ccwchain_handle_ccw(u32 cda, struct channel_program *cp)
 	memcpy(chain->ch_ccw, cp->guest_cp, len * sizeof(struct ccw1));
 
 	/* Loop for tics on this new chain. */
-	return ccwchain_loop_tic(chain, cp);
+	ret = ccwchain_loop_tic(chain, cp);
+
+	if (ret)
+		ccwchain_free(chain);
+
+	return ret;
 }
 
 /* Loop for TICs. */
@@ -642,8 +647,6 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
 
 	/* Build a ccwchain for the first CCW segment */
 	ret = ccwchain_handle_ccw(orb->cmd.cpa, cp);
-	if (ret)
-		cp_free(cp);
 
 	/* It is safe to force: if it was not set but idals used
 	 * ccwchain_calc_length would have returned an error.
Signature · 1 line
2.7.4
Reviewed-by on v2 1/5
#2 lore raw

Re: [RFC v2 1/5] vfio-ccw: Fix misleading comment when setting orb.cmd.c64

In reply to Farhan Ali
Quoted 5 lines · On Mon, 8 Jul 2019 16:10:34 -0400 Farhan Ali <[email protected]> wrote:

The comment is misleading because it tells us that we should set orb.cmd.c64 before calling ccwchain_calc_length, otherwise the function ccwchain_calc_length would return an error. This is not completely accurate.

Quoted 7 lines

We want to allow an orb without cmd.c64, and this is fine as long as the channel program does not use IDALs. But we do want to reject any channel program that uses IDALs and does not set the flag, which what we do in ccwchain_calc_length.

After we have done the ccw processing, it should be safe to set cmd.c64, since we will convert them into IDALs.

"After we have done the ccw processing, we need to set cmd.c64, as we use IDALs for all translated channel programs." ?

Quoted 1 line
Fixes fb9e7880af35 ("vfio: ccw: push down unsupported IDA check")
Quoted 10 lines
---
 drivers/s390/cio/vfio_ccw_cp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/s390/cio/vfio_ccw_cp.c +0 -0
index d6a8dff..7622b72 100644

drivers/s390/cio/vfio_ccw_cp.c int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) · line 649

Quoted 7 lines
drivers/s390/cio/vfio_ccw_cp.c +2 -2
@@ -645,8 +645,8 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
 	if (ret)
 		cp_free(cp);
 
-	/* It is safe to force: if not set but idals used
-	 * ccwchain_calc_length returns an error.
+	/* It is safe to force: if it was not set but idals used
+	 * ccwchain_calc_length would have returned an error.

Thanks, much clearer.

drivers/s390/cio/vfio_ccw_cp.c int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) · line 652

Quoted 3 lines
drivers/s390/cio/vfio_ccw_cp.c +0 -0
 	 */
 	cp->orb.cmd.c64 = 1;
 
#4 lore raw

Re: [RFC v2 2/5] vfio-ccw: Fix memory leak and don't call cp_free in cp_init

In reply to Farhan Ali
Quoted 11 lines · On Mon, 8 Jul 2019 16:10:35 -0400 Farhan Ali <[email protected]> wrote:

We don't set cp->initialized to true so calling cp_free will just return and not do anything.

Also fix a memory leak where we fail to free a ccwchain on an error.

Fixes 812271b910 ("s390/cio: Squash cp_free() and cp_unpin_free()")
---
 drivers/s390/cio/vfio_ccw_cp.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

(...)

drivers/s390/cio/vfio_ccw_cp.c int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) · line 646

Quoted 6 lines
drivers/s390/cio/vfio_ccw_cp.c +0 -2
@@ -642,8 +647,6 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
 
 	/* Build a ccwchain for the first CCW segment */
 	ret = ccwchain_handle_ccw(orb->cmd.cpa, cp);
-	if (ret)
-		cp_free(cp);

Now that I look again: it's a bit odd that we set the bit in all cases, even if we have an error. We could move that into the !ret branch that sets ->initialized; but it does not really hurt.

drivers/s390/cio/vfio_ccw_cp.c int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) · line 652

Quoted 3 lines
drivers/s390/cio/vfio_ccw_cp.c +0 -0
 	/* It is safe to force: if it was not set but idals used
 	 * ccwchain_calc_length would have returned an error.

The rest of the patch looks good to me.

Reviewed-by on v2 3/5
#8 lore raw

Re: [RFC v2 3/5] vfio-ccw: Set pa_nr to 0 if memory allocation fails for pa_iova_pfn

In reply to Farhan Ali
Quoted 3 lines · On Mon, 8 Jul 2019 16:10:36 -0400 Farhan Ali <[email protected]> wrote:

So we don't call try to call vfio_unpin_pages() incorrectly.

Fixes 0a19e61e6d4c ("vfio: ccw: introduce channel program interfaces")

So that was there since the beginning :)

Quoted 12 lines
---
 drivers/s390/cio/vfio_ccw_cp.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/s390/cio/vfio_ccw_cp.c +0 -0
index 31a04a5..1b93863 100644
@@ -72,8 +72,10 @@ static int pfn_array_alloc(struct pfn_array *pa, u64 iova, unsigned int len)
 				  sizeof(*pa->pa_iova_pfn) +

drivers/s390/cio/vfio_ccw_cp.c static int pfn_array_alloc(struct pfn_array *pa, u64 iova, unsigned int len) · line 81

Quoted 10 lines
drivers/s390/cio/vfio_ccw_cp.c +3 -1
 				  sizeof(*pa->pa_pfn),
 				  GFP_KERNEL);
-	if (unlikely(!pa->pa_iova_pfn))
+	if (unlikely(!pa->pa_iova_pfn)) {
+		pa->pa_nr = 0;
 		return -ENOMEM;
+	}
 	pa->pa_pfn = pa->pa_iova_pfn + pa->pa_nr;
 
 	pa->pa_iova_pfn[0] = pa->pa_iova >> PAGE_SHIFT;
#21 lore raw

Re: [RFC v2 5/5] vfio-ccw: Update documentation for csch/hsch

In reply to Farhan Ali
Quoted 3 lines · On Mon, 8 Jul 2019 16:10:38 -0400 Farhan Ali <[email protected]> wrote:

We now support CLEAR SUBCHANNEL and HALT SUBCHANNEL via ccw_cmd_region.

Thanks, I forgot about this.

Fixes d5afd5d135c8 ("vfio-ccw: add handling for async channel instructions")
Quoted 35 lines
---
 Documentation/s390/vfio-ccw.rst | 31 ++++++++++++++++++++++++++++---
 1 file changed, 28 insertions(+), 3 deletions(-)
Documentation/s390/vfio-ccw.rst +15 -0
index 1f6d0b5..40e4110 100644
@@ -180,6 +180,13 @@ The process of how these work together.
    add it to an iommu_group and a vfio_group. Then we could pass through
    the mdev to a guest.
 
+
+VFIO-CCW Regions
+----------------
+
+The vfio-ccw driver exposes MMIO regions to accept requests from and return
+results to userspace.
+
 vfio-ccw I/O region
 -------------------
 
@@ -205,6 +212,25 @@ irb_area stores the I/O result.
 
 ret_code stores a return code for each access of the region.
 
+This region is always available.
+
+vfio-ccw cmd region
+-------------------
+
+The vfio-ccw cmd region is used to accept asynchronous instructions
+from userspace.
+

Documentation/s390/vfio-ccw.rst irb_area stores the I/O result. · line 232

Quoted 10 lines
Documentation/s390/vfio-ccw.rst +10 -0
+#define VFIO_CCW_ASYNC_CMD_HSCH (1 << 0)
+#define VFIO_CCW_ASYNC_CMD_CSCH (1 << 1)
+struct ccw_cmd_region {
+       __u32 command;
+       __u32 ret_code;
+} __packed;
+
+This region is exposed via region type VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD.
+
+CLEAR SUBCHANNEL and HALT SUBCHANNEL currently uses this region.

"Currently, CLEAR SUBCHANNEL and HALT SUBCHANNEL use this region". ?

Documentation/s390/vfio-ccw.rst Together with the corresponding work in QEMU, we can bring the passed · line 336

Quoted 13 lines
Documentation/s390/vfio-ccw.rst +3 -3
+
 vfio-ccw operation details
 --------------------------
 
@@ -306,9 +332,8 @@ Together with the corresponding work in QEMU, we can bring the passed
 through DASD/ECKD device online in a guest now and use it as a block
 device.
 
-While the current code allows the guest to start channel programs via
-START SUBCHANNEL, support for HALT SUBCHANNEL or CLEAR SUBCHANNEL is
-not yet implemented.
+The current code allows the guest to start channel programs via
+START SUBCHANNEL, and supports HALT SUBCHANNEL or CLEAR SUBCHANNEL.

"The current code allows the guest to start channel programs via START SUBCHANNEL, and to issue HALT SUBCHANNEL and CLEAR SUBCHANNEL." ?

Quoted 3 lines
Documentation/s390/vfio-ccw.rst +0 -0
 vfio-ccw supports classic (command mode) channel I/O only. Transport
 mode (HPF) is not supported.
Reviewed-by on v2 4/5
#10 lore raw

Re: [RFC v2 4/5] vfio-ccw: Don't call cp_free if we are processing a channel program

In reply to Farhan Ali
Quoted 9 lines · On Mon, 8 Jul 2019 16:10:37 -0400 Farhan Ali <[email protected]> wrote:

There is a small window where it's possible that we could be working on an interrupt (queued in the workqueue) and setting up a channel program (i.e allocating memory, pinning pages, translating address). This can lead to allocating and freeing the channel program at the same time and can cause memory corruption.

Let's not call cp_free if we are currently processing a channel program. The only way we know for sure that we don't have a thread setting up a channel program is when the state is set to VFIO_CCW_STATE_CP_PENDING.

Can we pinpoint a commit that introduced this bug, or has it been there since the beginning?

Quoted 11 lines
---
 drivers/s390/cio/vfio_ccw_drv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/s390/cio/vfio_ccw_drv.c +0 -0
index 4e3a903..0357165 100644

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 98

Quoted 8 lines
drivers/s390/cio/vfio_ccw_drv.c +1 -1
@@ -92,7 +92,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
 		     (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
 	if (scsw_is_solicited(&irb->scsw)) {
 		cp_update_scsw(&private->cp, &irb->scsw);
-		if (is_final)
+		if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING)
 			cp_free(&private->cp);
 	}
 	mutex_lock(&private->io_mutex);
author
#22 lore raw

Re: [RFC v2 5/5] vfio-ccw: Update documentation for csch/hsch

In reply to Cornelia Huck
Quoted 11 lines · Cornelia Huck
Quoted 3 lines · On Mon, 8 Jul 2019 16:10:38 -0400 Farhan Ali <[email protected]> wrote:

We now support CLEAR SUBCHANNEL and HALT SUBCHANNEL via ccw_cmd_region.

Thanks, I forgot about this.

Fixes d5afd5d135c8 ("vfio-ccw: add handling for async channel instructions")

I don't know if this warranted a fixes tag but I will add it.

Quoted 39 lines
Quoted 39 lines
---
  Documentation/s390/vfio-ccw.rst | 31 ++++++++++++++++++++++++++++---
  1 file changed, 28 insertions(+), 3 deletions(-)
Documentation/s390/vfio-ccw.rst +19 -0
index 1f6d0b5..40e4110 100644
@@ -180,6 +180,13 @@ The process of how these work together.
     add it to an iommu_group and a vfio_group. Then we could pass through
     the mdev to a guest.
 
+
+VFIO-CCW Regions
+----------------
+
+The vfio-ccw driver exposes MMIO regions to accept requests from and return
+results to userspace.
+
  vfio-ccw I/O region
  -------------------
 
@@ -205,6 +212,25 @@ irb_area stores the I/O result.
 
  ret_code stores a return code for each access of the region.
 
+This region is always available.
+
+vfio-ccw cmd region
+-------------------
+
+The vfio-ccw cmd region is used to accept asynchronous instructions
+from userspace.
+
+#define VFIO_CCW_ASYNC_CMD_HSCH (1 << 0)
+#define VFIO_CCW_ASYNC_CMD_CSCH (1 << 1)
+struct ccw_cmd_region {
+       __u32 command;
Quoted 9 lines

Documentation/s390/vfio-ccw.rst irb_area stores the I/O result. · line 232

Quoted 6 lines
Documentation/s390/vfio-ccw.rst +6 -0
+       __u32 ret_code;
+} __packed;
+
+This region is exposed via region type VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD.
+
+CLEAR SUBCHANNEL and HALT SUBCHANNEL currently uses this region.

"Currently, CLEAR SUBCHANNEL and HALT SUBCHANNEL use this region". ?

This sounds better to me :)

Quoted 8 lines
Quoted 8 lines
Documentation/s390/vfio-ccw.rst +1 -0
+
  vfio-ccw operation details
  --------------------------
 
@@ -306,9 +332,8 @@ Together with the corresponding work in QEMU, we can bring the passed
  through DASD/ECKD device online in a guest now and use it as a block
  device.
 
Quoted 9 lines

Documentation/s390/vfio-ccw.rst Together with the corresponding work in QEMU, we can bring the passed · line 336

Quoted 5 lines
Documentation/s390/vfio-ccw.rst +2 -3
-While the current code allows the guest to start channel programs via
-START SUBCHANNEL, support for HALT SUBCHANNEL or CLEAR SUBCHANNEL is
-not yet implemented.
+The current code allows the guest to start channel programs via
+START SUBCHANNEL, and supports HALT SUBCHANNEL or CLEAR SUBCHANNEL.

"The current code allows the guest to start channel programs via START SUBCHANNEL, and to issue HALT SUBCHANNEL and CLEAR SUBCHANNEL." ?

Same. I will update with the changes you requested.

Quoted 5 lines

Documentation/s390/vfio-ccw.rst Together with the corresponding work in QEMU, we can bring the passed · line 339

Quoted 3 lines
Documentation/s390/vfio-ccw.rst +0 -0
  vfio-ccw supports classic (command mode) channel I/O only. Transport
  mode (HPF) is not supported.

Thanks for taking a look.

Thanks
Farhan

author
#11 lore raw

Re: [RFC v2 4/5] vfio-ccw: Don't call cp_free if we are processing a channel program

In reply to Cornelia Huck
Quoted 9 lines · Cornelia Huck
Quoted 6 lines · On Mon, 8 Jul 2019 16:10:37 -0400 Farhan Ali <[email protected]> wrote:

There is a small window where it's possible that we could be working on an interrupt (queued in the workqueue) and setting up a channel program (i.e allocating memory, pinning pages, translating address). This can lead to allocating and freeing the channel program at the same time and can cause memory corruption.

Quoted 7 lines
Quoted 3 lines

Let's not call cp_free if we are currently processing a channel program. The only way we know for sure that we don't have a thread setting up a channel program is when the state is set to VFIO_CCW_STATE_CP_PENDING.

Can we pinpoint a commit that introduced this bug, or has it been there since the beginning?

I think the problem was always there.

Quoted 6 lines
Quoted 6 lines
---
  drivers/s390/cio/vfio_ccw_drv.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
Quoted 17 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 98

Quoted 13 lines
drivers/s390/cio/vfio_ccw_drv.c +1 -1
index 4e3a903..0357165 100644
@@ -92,7 +92,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
  		     (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
  	if (scsw_is_solicited(&irb->scsw)) {
  		cp_update_scsw(&private->cp, &irb->scsw);
-		if (is_final)
+		if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING)
  			cp_free(&private->cp);
  	}
  	mutex_lock(&private->io_mutex);

Thanks for reviewing.

Thanks
Farhan

author
#5 lore raw

Re: [RFC v2 2/5] vfio-ccw: Fix memory leak and don't call cp_free in cp_init

In reply to Cornelia Huck
Quoted 19 lines · Cornelia Huck
Quoted 11 lines · On Mon, 8 Jul 2019 16:10:35 -0400 Farhan Ali <[email protected]> wrote:

We don't set cp->initialized to true so calling cp_free will just return and not do anything.

Also fix a memory leak where we fail to free a ccwchain on an error.

Fixes 812271b910 ("s390/cio: Squash cp_free() and cp_unpin_free()")
---
  drivers/s390/cio/vfio_ccw_cp.c | 11 +++++++----
  1 file changed, 7 insertions(+), 4 deletions(-)

(...)

Quoted 2 lines
(quoted diff) +0 -0
@@ -642,8 +647,6 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
 
Quoted 8 lines

drivers/s390/cio/vfio_ccw_cp.c int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) · line 646

Quoted 4 lines
drivers/s390/cio/vfio_ccw_cp.c +0 -2
  	/* Build a ccwchain for the first CCW segment */
  	ret = ccwchain_handle_ccw(orb->cmd.cpa, cp);
-	if (ret)
-		cp_free(cp);

Now that I look again: it's a bit odd that we set the bit in all cases, even if we have an error. We could move that into the !ret branch that sets ->initialized; but it does not really hurt.

By setting the bit, I am assuming you meant cmd.c64?

Yes, it doesn't harm anything but for better code readability you have a good point. I will move it into !ret branch in the first patch since I think it would be more appropriate there, no?

Quoted 8 lines

drivers/s390/cio/vfio_ccw_cp.c int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) · line 652

Quoted 4 lines
drivers/s390/cio/vfio_ccw_cp.c +0 -0
  	/* It is safe to force: if it was not set but idals used
  	 * ccwchain_calc_length would have returned an error.

The rest of the patch looks good to me.

#6 lore raw

Re: [RFC v2 2/5] vfio-ccw: Fix memory leak and don't call cp_free in cp_init

Quoted 29 lines · On Tue, 9 Jul 2019 10:07:57 -0400 Farhan Ali <[email protected]> wrote:
Quoted 19 lines · Cornelia Huck
Quoted 11 lines · On Mon, 8 Jul 2019 16:10:35 -0400 Farhan Ali <[email protected]> wrote:

We don't set cp->initialized to true so calling cp_free will just return and not do anything.

Also fix a memory leak where we fail to free a ccwchain on an error.

Fixes 812271b910 ("s390/cio: Squash cp_free() and cp_unpin_free()")
---
  drivers/s390/cio/vfio_ccw_cp.c | 11 +++++++----
  1 file changed, 7 insertions(+), 4 deletions(-)  

(...)

Quoted 2 lines
(quoted diff) +0 -0
@@ -642,8 +647,6 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
 
Quoted 8 lines

drivers/s390/cio/vfio_ccw_cp.c int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) · line 646

Quoted 4 lines
drivers/s390/cio/vfio_ccw_cp.c +0 -2
  	/* Build a ccwchain for the first CCW segment */
  	ret = ccwchain_handle_ccw(orb->cmd.cpa, cp);
-	if (ret)
-		cp_free(cp);  

Now that I look again: it's a bit odd that we set the bit in all cases, even if we have an error. We could move that into the !ret branch that sets ->initialized; but it does not really hurt.

Quoted 5 lines

By setting the bit, I am assuming you meant cmd.c64?

Yes, it doesn't harm anything but for better code readability you have a good point. I will move it into !ret branch in the first patch since I think it would be more appropriate there, no?

Yes to all of that :)

Quoted 10 lines
Quoted 9 lines

drivers/s390/cio/vfio_ccw_cp.c int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) · line 652

Quoted 5 lines
drivers/s390/cio/vfio_ccw_cp.c +0 -0
  	/* It is safe to force: if it was not set but idals used
  	 * ccwchain_calc_length would have returned an error.  

The rest of the patch looks good to me.

reviewer
#12 lore raw

Re: [RFC v2 4/5] vfio-ccw: Don't call cp_free if we are processing a channel program

In reply to Farhan Ali
Quoted 16 lines · On Tue, 9 Jul 2019 09:46:51 -0400 Farhan Ali <[email protected]> wrote:
Quoted 13 lines · Cornelia Huck
Quoted 9 lines · On Mon, 8 Jul 2019 16:10:37 -0400 Farhan Ali <[email protected]> wrote:

There is a small window where it's possible that we could be working on an interrupt (queued in the workqueue) and setting up a channel program (i.e allocating memory, pinning pages, translating address). This can lead to allocating and freeing the channel program at the same time and can cause memory corruption.

Let's not call cp_free if we are currently processing a channel program. The only way we know for sure that we don't have a thread setting up a channel program is when the state is set to VFIO_CCW_STATE_CP_PENDING.

Quoted 6 lines
Quoted 3 lines

Can we pinpoint a commit that introduced this bug, or has it been there since the beginning?

I think the problem was always there.

I think it became relevant with the async stuff. Because after the async stuff was added we start getting solicited interrupts that are not about channel program is done. At least this is how I remember the discussion.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
---
  drivers/s390/cio/vfio_ccw_drv.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
Quoted 10 lines
Quoted 10 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 95

Quoted 10 lines
drivers/s390/cio/vfio_ccw_drv.c +1 -1
index 4e3a903..0357165 100644
@@ -92,7 +92,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
  		     (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
  	if (scsw_is_solicited(&irb->scsw)) {
  		cp_update_scsw(&private->cp, &irb->scsw);
-		if (is_final)
+		if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING)

Ain't private->state potentially used by multiple threads of execution? Do we need to use atomic operations or external synchronization to avoid this being another gamble? Or am I missing something?

Quoted 11 lines
Quoted 7 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 98

Quoted 3 lines
drivers/s390/cio/vfio_ccw_drv.c +0 -0
  			cp_free(&private->cp);
  	}
  	mutex_lock(&private->io_mutex);

Thanks for reviewing.

Thanks
Farhan

author
#13 lore raw

Re: [RFC v2 4/5] vfio-ccw: Don't call cp_free if we are processing a channel program

Quoted 36 lines · Halil Pasic
Quoted 16 lines · On Tue, 9 Jul 2019 09:46:51 -0400 Farhan Ali <[email protected]> wrote:
Quoted 13 lines · Cornelia Huck
Quoted 9 lines · On Mon, 8 Jul 2019 16:10:37 -0400 Farhan Ali <[email protected]> wrote:

There is a small window where it's possible that we could be working on an interrupt (queued in the workqueue) and setting up a channel program (i.e allocating memory, pinning pages, translating address). This can lead to allocating and freeing the channel program at the same time and can cause memory corruption.

Let's not call cp_free if we are currently processing a channel program. The only way we know for sure that we don't have a thread setting up a channel program is when the state is set to VFIO_CCW_STATE_CP_PENDING.

Quoted 6 lines
Quoted 3 lines

Can we pinpoint a commit that introduced this bug, or has it been there since the beginning?

I think the problem was always there.

I think it became relevant with the async stuff. Because after the async stuff was added we start getting solicited interrupts that are not about channel program is done. At least this is how I remember the discussion.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
---
   drivers/s390/cio/vfio_ccw_drv.c | 2 +-
   1 file changed, 1 insertion(+), 1 deletion(-)
Quoted 12 lines
Quoted 10 lines
Quoted 10 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 95

Quoted 10 lines
drivers/s390/cio/vfio_ccw_drv.c +1 -1
index 4e3a903..0357165 100644
@@ -92,7 +92,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
   		     (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
   	if (scsw_is_solicited(&irb->scsw)) {
   		cp_update_scsw(&private->cp, &irb->scsw);
-		if (is_final)
+		if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING)

Ain't private->state potentially used by multiple threads of execution?

yes

One of the paths I can think of is a machine check from the host which will ultimately call vfio_ccw_sch_event callback which could set state to NOT_OPER or IDLE.

Quoted 2 lines

Do we need to use atomic operations or external synchronization to avoid this being another gamble? Or am I missing something?

I think we probably should think about atomic operations for synchronizing the state (and it could be a separate add on patch?).

But for preventing 2 threads from stomping on the cp the check should be enough, unless I am missing something?

Quoted 14 lines
Quoted 12 lines
Quoted 8 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 98

Quoted 4 lines
drivers/s390/cio/vfio_ccw_drv.c +0 -0
   			cp_free(&private->cp);
   	}
   	mutex_lock(&private->io_mutex);

Thanks for reviewing.

Thanks
Farhan

#14 lore raw

Re: [RFC v2 4/5] vfio-ccw: Don't call cp_free if we are processing a channel program

Quoted 50 lines · On Tue, 9 Jul 2019 17:27:47 -0400 Farhan Ali <[email protected]> wrote:
Quoted 36 lines · Halil Pasic
Quoted 16 lines · On Tue, 9 Jul 2019 09:46:51 -0400 Farhan Ali <[email protected]> wrote:
Quoted 13 lines · Cornelia Huck
Quoted 9 lines · On Mon, 8 Jul 2019 16:10:37 -0400 Farhan Ali <[email protected]> wrote:

There is a small window where it's possible that we could be working on an interrupt (queued in the workqueue) and setting up a channel program (i.e allocating memory, pinning pages, translating address). This can lead to allocating and freeing the channel program at the same time and can cause memory corruption.

Let's not call cp_free if we are currently processing a channel program. The only way we know for sure that we don't have a thread setting up a channel program is when the state is set to VFIO_CCW_STATE_CP_PENDING.

Quoted 6 lines
Quoted 3 lines

Can we pinpoint a commit that introduced this bug, or has it been there since the beginning?

I think the problem was always there.

I think it became relevant with the async stuff. Because after the async stuff was added we start getting solicited interrupts that are not about channel program is done. At least this is how I remember the discussion.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
---
   drivers/s390/cio/vfio_ccw_drv.c | 2 +-
   1 file changed, 1 insertion(+), 1 deletion(-)
Quoted 12 lines
Quoted 10 lines
Quoted 10 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 95

Quoted 10 lines
drivers/s390/cio/vfio_ccw_drv.c +1 -1
index 4e3a903..0357165 100644
@@ -92,7 +92,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
   		     (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
   	if (scsw_is_solicited(&irb->scsw)) {
   		cp_update_scsw(&private->cp, &irb->scsw);
-		if (is_final)
+		if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING)  

Ain't private->state potentially used by multiple threads of execution?

Quoted 5 lines

yes

One of the paths I can think of is a machine check from the host which will ultimately call vfio_ccw_sch_event callback which could set state to NOT_OPER or IDLE.

Now I went through the machine check rabbit hole because I thought freeing the cp in there might be a good idea, but it's not that easy (who'd have thought...)

If I read the POP correctly, an IPI or IPR in the subchannel CRW will indicate that the subchannel has been restored to a state after an I/O reset; in particular, that means that the subchannel does not have any I/O pending. However, that does not seem to be the case e.g. for an IPM (the doc does not seem to be very clear on that, though.) We can't unconditionally do something, as we do not know what event we're being called for (please disregard the positively ancient "we're called for IPI" comment in css_process_crw(), I think I added that one in the Linux 2.4 or 2.5 timeframe...) tl;dr We can't rely on anything...

Quoted 6 lines
Quoted 3 lines

Do we need to use atomic operations or external synchronization to avoid this being another gamble? Or am I missing something?

I think we probably should think about atomic operations for synchronizing the state (and it could be a separate add on patch?).

+1 to thinking about some atomicity changes later.

Quoted 3 lines

But for preventing 2 threads from stomping on the cp the check should be enough, unless I am missing something?

I think so. Plus, the patch is small enough that we can merge it right away, and figure out a more generic change later.

Quoted 15 lines
Quoted 15 lines
Quoted 13 lines
Quoted 9 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 98

Quoted 5 lines
drivers/s390/cio/vfio_ccw_drv.c +0 -0
   			cp_free(&private->cp);
   	}
   	mutex_lock(&private->io_mutex);  

Thanks for reviewing.

Thanks
Farhan

author
#15 lore raw

Re: [RFC v2 4/5] vfio-ccw: Don't call cp_free if we are processing a channel program

Quoted 55 lines · Cornelia Huck
Quoted 52 lines · On Tue, 9 Jul 2019 17:27:47 -0400 Farhan Ali <[email protected]> wrote:
Quoted 36 lines · Halil Pasic
Quoted 16 lines · On Tue, 9 Jul 2019 09:46:51 -0400 Farhan Ali <[email protected]> wrote:
Quoted 13 lines · Cornelia Huck
Quoted 9 lines · On Mon, 8 Jul 2019 16:10:37 -0400 Farhan Ali <[email protected]> wrote:

There is a small window where it's possible that we could be working on an interrupt (queued in the workqueue) and setting up a channel program (i.e allocating memory, pinning pages, translating address). This can lead to allocating and freeing the channel program at the same time and can cause memory corruption.

Let's not call cp_free if we are currently processing a channel program. The only way we know for sure that we don't have a thread setting up a channel program is when the state is set to VFIO_CCW_STATE_CP_PENDING.

Quoted 6 lines
Quoted 3 lines

Can we pinpoint a commit that introduced this bug, or has it been there since the beginning?

I think the problem was always there.

I think it became relevant with the async stuff. Because after the async stuff was added we start getting solicited interrupts that are not about channel program is done. At least this is how I remember the discussion.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
---
    drivers/s390/cio/vfio_ccw_drv.c | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)
Quoted 12 lines
Quoted 10 lines
Quoted 10 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 95

Quoted 10 lines
drivers/s390/cio/vfio_ccw_drv.c +1 -1
index 4e3a903..0357165 100644
@@ -92,7 +92,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
    		     (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
    	if (scsw_is_solicited(&irb->scsw)) {
    		cp_update_scsw(&private->cp, &irb->scsw);
-		if (is_final)
+		if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING)

Ain't private->state potentially used by multiple threads of execution?

yes

Quoted 7 lines
Quoted 3 lines

One of the paths I can think of is a machine check from the host which will ultimately call vfio_ccw_sch_event callback which could set state to NOT_OPER or IDLE.

Now I went through the machine check rabbit hole because I thought freeing the cp in there might be a good idea, but it's not that easy (who'd have thought...)

Thanks for taking a deeper look :)

Quoted 10 lines

If I read the POP correctly, an IPI or IPR in the subchannel CRW will indicate that the subchannel has been restored to a state after an I/O reset; in particular, that means that the subchannel does not have any I/O pending. However, that does not seem to be the case e.g. for an IPM (the doc does not seem to be very clear on that, though.) We can't unconditionally do something, as we do not know what event we're being called for (please disregard the positively ancient "we're called for IPI" comment in css_process_crw(), I think I added that one in the Linux 2.4 or 2.5 timeframe...) tl;dr We can't rely on anything...

Yes, the CRW infrastructure in Linux does not convey the exact event back to the subchannel driver.

Quoted 8 lines
Quoted 7 lines
Quoted 4 lines

Do we need to use atomic operations or external synchronization to avoid this being another gamble? Or am I missing something?

I think we probably should think about atomic operations for synchronizing the state (and it could be a separate add on patch?).

Quoted 8 lines

+1 to thinking about some atomicity changes later.

Quoted 3 lines

But for preventing 2 threads from stomping on the cp the check should be enough, unless I am missing something?

I think so. Plus, the patch is small enough that we can merge it right away, and figure out a more generic change later.

I will send out a v3 soon if no one else has any other suggestions.

Quoted 18 lines
Quoted 16 lines
Quoted 16 lines
Quoted 14 lines
Quoted 10 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 98

Quoted 6 lines
drivers/s390/cio/vfio_ccw_drv.c +0 -0
    			cp_free(&private->cp);
    	}
    	mutex_lock(&private->io_mutex);

Thanks for reviewing.

Thanks
Farhan

maintainer
#16 lore raw

Re: [RFC v2 4/5] vfio-ccw: Don't call cp_free if we are processing a channel program

Quoted 7 lines · Farhan Ali
Quoted 4 lines · Cornelia Huck
Quoted 1 line · On Tue, 9 Jul 2019 17:27:47 -0400 Farhan Ali <[email protected]> wrote:

On 07/09/2019 10:21 AM, Halil Pasic wrote:

Quoted 8 lines
Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

Do we need to use atomic operations or external synchronization to avoid
this being another gamble? Or am I missing something?

I think we probably should think about atomic operations for synchronizing the state (and it could be a separate add on patch?).

+1 to thinking about some atomicity changes later.

+1

Quoted 10 lines
Quoted 7 lines
Quoted 4 lines

But for preventing 2 threads from stomping on the cp the check should be enough, unless I am missing something?

I think so. Plus, the patch is small enough that we can merge it right away, and figure out a more generic change later.

I will send out a v3 soon if no one else has any other suggestions.

I thumbed through them and think they look good with Conny's suggestions. Nothing else jumps to mind for me.

reviewer
#17 lore raw

Re: [RFC v2 4/5] vfio-ccw: Don't call cp_free if we are processing a channel program

In reply to Farhan Ali
Quoted 26 lines · On Tue, 9 Jul 2019 17:27:47 -0400 Farhan Ali <[email protected]> wrote:
Quoted 23 lines · Halil Pasic
Quoted 20 lines · On Tue, 9 Jul 2019 09:46:51 -0400 Farhan Ali <[email protected]> wrote:
Quoted 16 lines · Cornelia Huck
Quoted 9 lines · On Mon, 8 Jul 2019 16:10:37 -0400 Farhan Ali <[email protected]> wrote:

There is a small window where it's possible that we could be working on an interrupt (queued in the workqueue) and setting up a channel program (i.e allocating memory, pinning pages, translating address). This can lead to allocating and freeing the channel program at the same time and can cause memory corruption.

Let's not call cp_free if we are currently processing a channel program. The only way we know for sure that we don't have a thread setting up a channel program is when the state is set to VFIO_CCW_STATE_CP_PENDING.

Can we pinpoint a commit that introduced this bug, or has it been there since the beginning?

Quoted 7 lines
Quoted 7 lines
Quoted 2 lines

I think the problem was always there.

I think it became relevant with the async stuff. Because after the async stuff was added we start getting solicited interrupts that are not about channel program is done. At least this is how I remember the discussion.

You seem to have ignored this comment. BTW wasn't the cp->is_initialized make 'Make it safe to call the cp accessors in any case, so we can call them unconditionally.'?

@Connie: Your opinion as the author of that patch and of the cited sentence?

Quoted 25 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
---
   drivers/s390/cio/vfio_ccw_drv.c | 2 +-
   1 file changed, 1 insertion(+), 1 deletion(-)
Quoted 12 lines
Quoted 10 lines
Quoted 10 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 95

Quoted 10 lines
drivers/s390/cio/vfio_ccw_drv.c +1 -1
index 4e3a903..0357165 100644
@@ -92,7 +92,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
   		     (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
   	if (scsw_is_solicited(&irb->scsw)) {
   		cp_update_scsw(&private->cp, &irb->scsw);
-		if (is_final)
+		if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING)

Ain't private->state potentially used by multiple threads of execution?

yes

One of the paths I can think of is a machine check from the host which will ultimately call vfio_ccw_sch_event callback which could set state to NOT_OPER or IDLE.

Quoted 9 lines
Quoted 2 lines

Do we need to use atomic operations or external synchronization to avoid this being another gamble? Or am I missing something?

I think we probably should think about atomic operations for synchronizing the state (and it could be a separate add on patch?).

But for preventing 2 threads from stomping on the cp the check should be enough, unless I am missing something?

Usually programming languages don't like incorrectly synchronized programs. One tends to end up in undefined behavior land -- form language perspective. That doesn't actually mean you are bound to see strange stuff. With implementation spec + ABI spec + platform/architecture spec one may end up with things being well defined. But it that is a much deeper rabbit hole.

The nice thing about condition state == VFIO_CCW_STATE_CP_PENDING is that it can tolerate stale state values. The bad case at hand (you free but you should not) would be we see a stale VFIO_CCW_STATE_CP_PENDING but we are actually VFIO_CCW_STATE_CP_PROCESSING. That is pretty difficult to imagine because one can enter VFIO_CCW_STATE_CP_PROCESSING only form VFIO_CCW_STATE_CP_PENDING afair. On s390x torn reads/writes (i.e. observing something that ain't either the old nor the new value) on an int shouldn't be a concern.

The other bad case (where you don't free albeit you should) looks a bit trickier.

I'm not a fan of keeping races around without good reasons. And I don't see good reasons here. I'm no fan of needlessly complicated solutions either.

But seems, at least with my beliefs about races, I'm the oddball here.

Regards,
Halil

Quoted 14 lines
Quoted 14 lines
Quoted 12 lines
Quoted 8 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 98

Quoted 4 lines
drivers/s390/cio/vfio_ccw_drv.c +0 -0
   			cp_free(&private->cp);
   	}
   	mutex_lock(&private->io_mutex);

Thanks for reviewing.

Thanks
Farhan

maintainer
#18 lore raw

Re: [RFC v2 4/5] vfio-ccw: Don't call cp_free if we are processing a channel program

Quoted 32 lines · Halil Pasic
Quoted 29 lines · On Tue, 9 Jul 2019 17:27:47 -0400 Farhan Ali <[email protected]> wrote:
Quoted 26 lines · Halil Pasic
Quoted 22 lines · On Tue, 9 Jul 2019 09:46:51 -0400 Farhan Ali <[email protected]> wrote:
Quoted 9 lines · Cornelia Huck
Quoted 6 lines · On Mon, 8 Jul 2019 16:10:37 -0400 Farhan Ali <[email protected]> wrote:

There is a small window where it's possible that we could be working on an interrupt (queued in the workqueue) and setting up a channel program (i.e allocating memory, pinning pages, translating address). This can lead to allocating and freeing the channel program at the same time and can cause memory corruption.

Quoted 7 lines
Quoted 3 lines

Let's not call cp_free if we are currently processing a channel program. The only way we know for sure that we don't have a thread setting up a channel program is when the state is set to VFIO_CCW_STATE_CP_PENDING.

Can we pinpoint a commit that introduced this bug, or has it been there since the beginning?

I think the problem was always there.

Quoted 6 lines
Quoted 4 lines
Quoted 4 lines

I think it became relevant with the async stuff. Because after the async stuff was added we start getting solicited interrupts that are not about channel program is done. At least this is how I remember the discussion.

You seem to have ignored this comment.

I read both comments as being in agreement with one another. The problem has always been there, but didn't mean anything until we had another mechanism (async) to drive additional interrupts. Hence the v3 patch including the async patch in a Fixes tag.

BTW wasn't the cp->is_initialized

Quoted 47 lines

make 'Make it safe to call the cp accessors in any case, so we can call them unconditionally.'?

@Connie: Your opinion as the author of that patch and of the cited sentence?

Quoted 25 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
---
   drivers/s390/cio/vfio_ccw_drv.c | 2 +-
   1 file changed, 1 insertion(+), 1 deletion(-)
Quoted 12 lines
Quoted 10 lines
Quoted 10 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 95

Quoted 10 lines
drivers/s390/cio/vfio_ccw_drv.c +1 -1
index 4e3a903..0357165 100644
@@ -92,7 +92,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
   		     (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
   	if (scsw_is_solicited(&irb->scsw)) {
   		cp_update_scsw(&private->cp, &irb->scsw);
-		if (is_final)
+		if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING)

Ain't private->state potentially used by multiple threads of execution?

yes

One of the paths I can think of is a machine check from the host which will ultimately call vfio_ccw_sch_event callback which could set state to NOT_OPER or IDLE.

Quoted 9 lines
Quoted 2 lines

Do we need to use atomic operations or external synchronization to avoid this being another gamble? Or am I missing something?

I think we probably should think about atomic operations for synchronizing the state (and it could be a separate add on patch?).

But for preventing 2 threads from stomping on the cp the check should be enough, unless I am missing something?

Usually programming languages don't like incorrectly synchronized programs. One tends to end up in undefined behavior land -- form language perspective. That doesn't actually mean you are bound to see strange stuff. With implementation spec + ABI spec + platform/architecture spec one may end up with things being well defined. But it that is a much deeper rabbit hole.

Quoted 7 lines

The nice thing about condition state == VFIO_CCW_STATE_CP_PENDING is that it can tolerate stale state values. The bad case at hand (you free but you should not) would be we see a stale VFIO_CCW_STATE_CP_PENDING but we are actually VFIO_CCW_STATE_CP_PROCESSING. That is pretty difficult to imagine because one can enter VFIO_CCW_STATE_CP_PROCESSING only form VFIO_CCW_STATE_CP_PENDING afair.

I think you're backwards here. The path is IDLE -> CP_PROCESSING -> (CP_PENDING | IDLE)

On s390x torn reads/writes (i.e.

Quoted 5 lines

observing something that ain't either the old nor the new value) on an int shouldn't be a concern.

The other bad case (where you don't free albeit you should) looks a bit trickier.

I'm afraid I don't understand your intention with the above paragraphs. :(

Quoted 7 lines

I'm not a fan of keeping races around without good reasons. And I don't see good reasons here. I'm no fan of needlessly complicated solutions either.

But seems, at least with my beliefs about races, I'm the oddball here.

The "race" here is that we have one synchronous operation (SSCH) and two asynchronous operations (HSCH, CSCH), both of which interact with one another and generate interrupts that pass through this chunk of code.

I have not fully considered this patch yet, but the race is a concern to all of us oddballs. I have not chimed in any great detail because I only got through the first couple patches in v1 before going on holiday, and the discussions on v1/v2 are numerous.

- Eric

Quoted 19 lines

Regards,
Halil

Quoted 14 lines
Quoted 14 lines
Quoted 12 lines
Quoted 8 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 98

Quoted 4 lines
drivers/s390/cio/vfio_ccw_drv.c +0 -0
   			cp_free(&private->cp);
   	}
   	mutex_lock(&private->io_mutex);

Thanks for reviewing.

Thanks
Farhan

reviewer
#19 lore raw

Re: [RFC v2 4/5] vfio-ccw: Don't call cp_free if we are processing a channel program

Quoted 35 lines · On Thu, 11 Jul 2019 16:09:22 -0400 Eric Farman <[email protected]> wrote:
Quoted 32 lines · Halil Pasic
Quoted 29 lines · On Tue, 9 Jul 2019 17:27:47 -0400 Farhan Ali <[email protected]> wrote:
Quoted 26 lines · Halil Pasic
Quoted 22 lines · On Tue, 9 Jul 2019 09:46:51 -0400 Farhan Ali <[email protected]> wrote:
Quoted 9 lines · Cornelia Huck
Quoted 6 lines · On Mon, 8 Jul 2019 16:10:37 -0400 Farhan Ali <[email protected]> wrote:

There is a small window where it's possible that we could be working on an interrupt (queued in the workqueue) and setting up a channel program (i.e allocating memory, pinning pages, translating address). This can lead to allocating and freeing the channel program at the same time and can cause memory corruption.

Quoted 7 lines
Quoted 3 lines

Let's not call cp_free if we are currently processing a channel program. The only way we know for sure that we don't have a thread setting up a channel program is when the state is set to VFIO_CCW_STATE_CP_PENDING.

Can we pinpoint a commit that introduced this bug, or has it been there since the beginning?

I think the problem was always there.

Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
Quoted 4 lines

I think it became relevant with the async stuff. Because after the async stuff was added we start getting solicited interrupts that are not about channel program is done. At least this is how I remember the discussion.

You seem to have ignored this comment.

I read both comments as being in agreement with one another.

Which both comments do you see in agreement? The one that states 'was always there' and the one that states 'was introduced by the async series'?

Quoted 5 lines

The
problem has always been there, but didn't mean anything until we had another mechanism (async) to drive additional interrupts. Hence the v3 patch including the async patch in a Fixes tag.

Sorry, when I started writing this response, there was no v3 out yet. Later I've seen the Fixes tag in v3. I'm not sure it is the correct one though. Hence my question about cp->is_initialized.

Quoted 12 lines
Quoted 12 lines

BTW wasn't the cp->is_initialized
make 'Make it safe to call the cp accessors in any case, so we can call them unconditionally.'?

@Connie: Your opinion as the author of that patch and of the cited sentence?

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
---
   drivers/s390/cio/vfio_ccw_drv.c | 2 +-
   1 file changed, 1 insertion(+), 1 deletion(-)
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 94

Quoted 8 lines
drivers/s390/cio/vfio_ccw_drv.c +0 -0
index 4e3a903..0357165 100644
@@ -92,7 +92,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
   		     (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
   	if (scsw_is_solicited(&irb->scsw)) {
   		cp_update_scsw(&private->cp, &irb->scsw);

<BACKREF_1>

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
Quoted 2 lines

drivers/s390/cio/vfio_ccw_drv.c static void vfio_ccw_sch_io_todo(struct work_struct *work) · line 95

Quoted 2 lines
drivers/s390/cio/vfio_ccw_drv.c +1 -1
-		if (is_final)
+		if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING)

Ain't private->state potentially used by multiple threads of execution?

yes

</BACKREF_1>

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

One of the paths I can think of is a machine check from the host which will ultimately call vfio_ccw_sch_event callback which could set state to NOT_OPER or IDLE.

<BACKREF_2>

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 2 lines

Do we need to use atomic operations or external synchronization to avoid this being another gamble? Or am I missing something?

I think we probably should think about atomic operations for synchronizing the state (and it could be a separate add on patch?).

</BACKREF_2>

Quoted 19 lines
Quoted 11 lines
Quoted 3 lines

But for preventing 2 threads from stomping on the cp the check should be enough, unless I am missing something?

Usually programming languages don't like incorrectly synchronized programs. One tends to end up in undefined behavior land -- form language perspective. That doesn't actually mean you are bound to see strange stuff. With implementation spec + ABI spec + platform/architecture spec one may end up with things being well defined. But it that is a much deeper rabbit hole.

Quoted 7 lines

The nice thing about condition state == VFIO_CCW_STATE_CP_PENDING is that it can tolerate stale state values. The bad case at hand (you free but you should not) would be we see a stale VFIO_CCW_STATE_CP_PENDING but we are actually VFIO_CCW_STATE_CP_PROCESSING. That is pretty difficult to imagine because one can enter VFIO_CCW_STATE_CP_PROCESSING only form VFIO_CCW_STATE_CP_PENDING afair.

Quoted 2 lines

I think you're backwards here. The path is IDLE -> CP_PROCESSING -> (CP_PENDING | IDLE)

That is what I tried to say. The backwards twist probably comes from the fact that I'm discussing what can happen if we read stale value from state.

Quoted 10 lines
Quoted 7 lines

On s390x torn reads/writes (i.e.
observing something that ain't either the old nor the new value) on an int shouldn't be a concern.

The other bad case (where you don't free albeit you should) looks a bit trickier.

I'm afraid I don't understand your intention with the above paragraphs. :(

All three paragraphs are about discussing what can happen or can not happen in practice. The paragraph before those three is about the so called academic aspects.

Quoted 5 lines
Quoted 5 lines

I'm not a fan of keeping races around without good reasons. And I don't see good reasons here. I'm no fan of needlessly complicated solutions either.

Quoted 7 lines
Quoted 2 lines

But seems, at least with my beliefs about races, I'm the oddball here.

The "race" here is that we have one synchronous operation (SSCH) and two asynchronous operations (HSCH, CSCH), both of which interact with one another and generate interrupts that pass through this chunk of code.

I don't agree. Please consider the stuff between the <BACKREF_[12]> tags. In my reading Farhan agrees that we have a data race on private->state.

If you did not get that, no wonder my email makes little sense.

Quoted 2 lines

I have not fully considered this patch yet, but the race is a concern to all of us oddballs.

Yes, but seems to a different extent. The rest of the guys are fine with just plainly accessing private->state in <BACKREF_1>, and do different logic based on the value, even though nobody seems to argue that the accesses to private->state involve race.

Quoted 3 lines

I have not chimed in any great detail because I
only got through the first couple patches in v1 before going on holiday, and the discussions on v1/v2 are numerous.

My email was mostly addressed to Farhan, the author of the patch. No need to for apologies. :)

Regards,
Halil