Skip to content

Commit 152fcb7

Browse files
efarmangregkh
authored andcommitted
s390/vfio_ccw: Free all memory if cp_init() fails
commit 74186c2 upstream. The routine cp_free() is called to unpin/free any memory once an I/O is completed successfully, or if cp_prefetch() fails. But if cp_init() fails, and cp->initialized is not enabled, the same routine cannot be used to free all the memory. An attempt to address this exists in ccwchain_handle_ccw(), where a single call to ccwchain_free() is made for the currently-processed CCW segment. But this will leak other segments (created as a result of a Transfer in Channel) that had been allocated as part of the same channel program. Address this by performing the cleanup outside of the recursive ccwchain_handle_ccw()/ccwchain_loop_tic() logic. Fixes: 8b515be ("vfio-ccw: Fix memory leak and don't call cp_free in cp_init") Cc: stable@vger.kernel.org Reviewed-by: Farhan Ali <alifm@linux.ibm.com> Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com> Signed-off-by: Eric Farman <farman@linux.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com> [farman@linux.ibm.com: resolve build error] Signed-off-by: Eric Farman <farman@linux.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent b6505a4 commit 152fcb7

1 file changed

Lines changed: 18 additions & 4 deletions

File tree

drivers/s390/cio/vfio_ccw_cp.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -450,9 +450,6 @@ static int ccwchain_handle_ccw(u32 cda, struct channel_program *cp)
450450
/* Loop for tics on this new chain. */
451451
ret = ccwchain_loop_tic(chain, cp);
452452

453-
if (ret)
454-
ccwchain_free(chain);
455-
456453
return ret;
457454
}
458455

@@ -481,6 +478,23 @@ static int ccwchain_loop_tic(struct ccwchain *chain, struct channel_program *cp)
481478
return 0;
482479
}
483480

481+
static int ccwchain_build_ccws(u32 cda, struct channel_program *cp)
482+
{
483+
struct ccwchain *chain, *temp;
484+
int ret;
485+
486+
ret = ccwchain_handle_ccw(cda, cp);
487+
488+
if (ret) {
489+
/* Cleanup if an error occurred */
490+
list_for_each_entry_safe(chain, temp, &cp->ccwchain_list, next) {
491+
ccwchain_free(chain);
492+
}
493+
}
494+
495+
return ret;
496+
}
497+
484498
static int ccwchain_fetch_tic(struct ccw1 *ccw,
485499
struct channel_program *cp)
486500
{
@@ -728,7 +742,7 @@ int cp_init(struct channel_program *cp, union orb *orb)
728742
memcpy(&cp->orb, orb, sizeof(*orb));
729743

730744
/* Build a ccwchain for the first CCW segment */
731-
ret = ccwchain_handle_ccw(orb->cmd.cpa, cp);
745+
ret = ccwchain_build_ccws(orb->cmd.cpa, cp);
732746

733747
if (!ret)
734748
cp->initialized = true;

0 commit comments

Comments
 (0)