diff options
author | Andre Detsch <adetsch@br.ibm.com> | 2007-09-19 00:38:12 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-09-19 01:12:16 -0400 |
commit | 36ddbb1380f282b4280c57efdb646dd8647a789f (patch) | |
tree | fbae61d4f858f31ef41631f54d2ab3982f02efb4 /arch | |
parent | 8b0d3121a0b2cf91768ecef635e241b6abc3f1da (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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/sched.c | 49 |
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 | ||
512 | static struct spu *spu_get_idle(struct spu_context *ctx) | 515 | static 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; |