summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Cohen <eli@mellanox.com>2012-10-17 18:42:59 +0200
committerRoland Dreier <roland@purestorage.com>2012-10-18 19:29:02 +0200
commitbef83ed92caca45a394344a14b0234aea977da6e (patch)
tree8a9e4ffe42d5cd520b5d8df7bb5129a3645939c0
parentIB/mlx4: Fix QP1 P_Key processing in the Primary Physical Function (PPF) (diff)
downloadlinux-bef83ed92caca45a394344a14b0234aea977da6e.tar.xz
linux-bef83ed92caca45a394344a14b0234aea977da6e.zip
IB/mlx4: Synchronize cleanup of MCGs in MCG paravirtualization
A client re-register event invokes cleanup of all MCGs. This is required to protect against misbehaved guests leading to corruption of join/leave database. However, since cleaning up the MCGs is a heavy operation, it is pushed to a work queue for further processing. Client re-register is also propagated to ULPs (e.g IPoIB). However, since the cleanup is performed in a workqueue, the ULP could leave and re-join groups before the cleanup occurs. In this case, when the cleanup takes place, it prunes the (newly-joined) MCGs and the ULP is left without actual MCGs while believing it joined them. Fix this by setting the flushing flag before invoking the cleanup task and clearing it after flushing is complete. Signed-off-by: Eli Cohen <eli@mellanox.com> Reviewed-by: Jack Morgenstein <jackm@dev.mellanox.co.il> Signed-off-by: Roland Dreier <roland@purestorage.com>
-rw-r--r--drivers/infiniband/hw/mlx4/mcg.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c
index 44ff480f79f5..25b2cdff00f8 100644
--- a/drivers/infiniband/hw/mlx4/mcg.c
+++ b/drivers/infiniband/hw/mlx4/mcg.c
@@ -1075,10 +1075,6 @@ static void _mlx4_ib_mcg_port_cleanup(struct mlx4_ib_demux_ctx *ctx, int destroy
unsigned long end;
int count;
- if (ctx->flushing)
- return;
-
- ctx->flushing = 1;
for (i = 0; i < MAX_VFS; ++i)
clean_vf_mcast(ctx, i);
@@ -1108,9 +1104,6 @@ static void _mlx4_ib_mcg_port_cleanup(struct mlx4_ib_demux_ctx *ctx, int destroy
force_clean_group(group);
}
mutex_unlock(&ctx->mcg_table_lock);
-
- if (!destroy_wq)
- ctx->flushing = 0;
}
struct clean_work {
@@ -1124,6 +1117,7 @@ static void mcg_clean_task(struct work_struct *work)
struct clean_work *cw = container_of(work, struct clean_work, work);
_mlx4_ib_mcg_port_cleanup(cw->ctx, cw->destroy_wq);
+ cw->ctx->flushing = 0;
kfree(cw);
}
@@ -1131,13 +1125,20 @@ void mlx4_ib_mcg_port_cleanup(struct mlx4_ib_demux_ctx *ctx, int destroy_wq)
{
struct clean_work *work;
+ if (ctx->flushing)
+ return;
+
+ ctx->flushing = 1;
+
if (destroy_wq) {
_mlx4_ib_mcg_port_cleanup(ctx, destroy_wq);
+ ctx->flushing = 0;
return;
}
work = kmalloc(sizeof *work, GFP_KERNEL);
if (!work) {
+ ctx->flushing = 0;
mcg_warn("failed allocating work for cleanup\n");
return;
}