aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Detsch <adetsch@br.ibm.com>2007-09-19 00:38:12 -0400
committerPaul Mackerras <paulus@samba.org>2007-09-19 01:12:16 -0400
commit36ddbb1380f282b4280c57efdb646dd8647a789f (patch)
treefbae61d4f858f31ef41631f54d2ab3982f02efb4
parent8b0d3121a0b2cf91768ecef635e241b6abc3f1da (diff)
[POWERPC] spufs: Fix race condition on gang->aff_ref_spu
Affinity reference point location (gang->aff_ref_spu) is reset when the whole gang is descheduled. However, the last member of a gang can be descheduled while we are trying to schedule another member of the gang. This was leading to a race condition, and the code was using gang->aff_ref_spu in an unsafe manner. By holding the gang->aff_mutex a little bit longer, and increment gang->aff_sched_count (which controls when gang->aff_ref_spu should be reset) a little bit earlier, the problem is fixed. Signed-off-by: Andre Detsch <adetsch@br.ibm.com> Signed-off-by: Jeremy Kerr <jk@ozlabs.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c49
1 files changed, 32 insertions, 17 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index c784edd40ea7..17806e001e50 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -230,8 +230,6 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
230 230
231 if (ctx->flags & SPU_CREATE_NOSCHED) 231 if (ctx->flags & SPU_CREATE_NOSCHED)
232 atomic_inc(&cbe_spu_info[spu->node].reserved_spus); 232 atomic_inc(&cbe_spu_info[spu->node].reserved_spus);
233 if (!list_empty(&ctx->aff_list))
234 atomic_inc(&ctx->gang->aff_sched_count);
235 233
236 ctx->stats.slb_flt_base = spu->stats.slb_flt; 234 ctx->stats.slb_flt_base = spu->stats.slb_flt;
237 ctx->stats.class2_intr_base = spu->stats.class2_intr; 235 ctx->stats.class2_intr_base = spu->stats.class2_intr;
@@ -392,7 +390,6 @@ static int has_affinity(struct spu_context *ctx)
392 if (list_empty(&ctx->aff_list)) 390 if (list_empty(&ctx->aff_list))
393 return 0; 391 return 0;
394 392
395 mutex_lock(&gang->aff_mutex);
396 if (!gang->aff_ref_spu) { 393 if (!gang->aff_ref_spu) {
397 if (!(gang->aff_flags & AFF_MERGED)) 394 if (!(gang->aff_flags & AFF_MERGED))
398 aff_merge_remaining_ctxs(gang); 395 aff_merge_remaining_ctxs(gang);
@@ -400,7 +397,6 @@ static int has_affinity(struct spu_context *ctx)
400 aff_set_offsets(gang); 397 aff_set_offsets(gang);
401 aff_set_ref_point_location(gang); 398 aff_set_ref_point_location(gang);
402 } 399 }
403 mutex_unlock(&gang->aff_mutex);
404 400
405 return gang->aff_ref_spu != NULL; 401 return gang->aff_ref_spu != NULL;
406} 402}
@@ -418,9 +414,16 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
418 414
419 if (spu->ctx->flags & SPU_CREATE_NOSCHED) 415 if (spu->ctx->flags & SPU_CREATE_NOSCHED)
420 atomic_dec(&cbe_spu_info[spu->node].reserved_spus); 416 atomic_dec(&cbe_spu_info[spu->node].reserved_spus);
421 if (!list_empty(&ctx->aff_list)) 417
422 if (atomic_dec_and_test(&ctx->gang->aff_sched_count)) 418 if (ctx->gang){
423 ctx->gang->aff_ref_spu = NULL; 419 mutex_lock(&ctx->gang->aff_mutex);
420 if (has_affinity(ctx)) {
421 if (atomic_dec_and_test(&ctx->gang->aff_sched_count))
422 ctx->gang->aff_ref_spu = NULL;
423 }
424 mutex_unlock(&ctx->gang->aff_mutex);
425 }
426
424 spu_switch_notify(spu, NULL); 427 spu_switch_notify(spu, NULL);
425 spu_unmap_mappings(ctx); 428 spu_unmap_mappings(ctx);
426 spu_save(&ctx->csa, spu); 429 spu_save(&ctx->csa, spu);
@@ -511,20 +514,32 @@ static void spu_prio_wait(struct spu_context *ctx)
511 514
512static struct spu *spu_get_idle(struct spu_context *ctx) 515static struct spu *spu_get_idle(struct spu_context *ctx)
513{ 516{
514 struct spu *spu; 517 struct spu *spu, *aff_ref_spu;
515 int node, n; 518 int node, n;
516 519
517 if (has_affinity(ctx)) { 520 if (ctx->gang) {
518 node = ctx->gang->aff_ref_spu->node; 521 mutex_lock(&ctx->gang->aff_mutex);
522 if (has_affinity(ctx)) {
523 aff_ref_spu = ctx->gang->aff_ref_spu;
524 atomic_inc(&ctx->gang->aff_sched_count);
525 mutex_unlock(&ctx->gang->aff_mutex);
526 node = aff_ref_spu->node;
519 527
520 mutex_lock(&cbe_spu_info[node].list_mutex); 528 mutex_lock(&cbe_spu_info[node].list_mutex);
521 spu = ctx_location(ctx->gang->aff_ref_spu, ctx->aff_offset, node); 529 spu = ctx_location(aff_ref_spu, ctx->aff_offset, node);
522 if (spu && spu->alloc_state == SPU_FREE) 530 if (spu && spu->alloc_state == SPU_FREE)
523 goto found; 531 goto found;
524 mutex_unlock(&cbe_spu_info[node].list_mutex); 532 mutex_unlock(&cbe_spu_info[node].list_mutex);
525 return NULL;
526 }
527 533
534 mutex_lock(&ctx->gang->aff_mutex);
535 if (atomic_dec_and_test(&ctx->gang->aff_sched_count))
536 ctx->gang->aff_ref_spu = NULL;
537 mutex_unlock(&ctx->gang->aff_mutex);
538
539 return NULL;
540 }
541 mutex_unlock(&ctx->gang->aff_mutex);
542 }
528 node = cpu_to_node(raw_smp_processor_id()); 543 node = cpu_to_node(raw_smp_processor_id());
529 for (n = 0; n < MAX_NUMNODES; n++, node++) { 544 for (n = 0; n < MAX_NUMNODES; n++, node++) {
530 node = (node < MAX_NUMNODES) ? node : 0; 545 node = (node < MAX_NUMNODES) ? node : 0;