| From 77ca2d089e33408695e05a2d506241513dffc365 Mon Sep 17 00:00:00 2001 |
| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Tue, 6 Apr 2010 16:51:31 +0200 |
| Subject: [PATCH] md: raid5: Make raid5_percpu handling RT aware |
| |
| __raid_run_ops() disables preemption with get_cpu() around the access |
| to the raid5_percpu variables. That causes scheduling while atomic |
| spews on RT. |
| |
| Serialize the access to the percpu data with a lock and keep the code |
| preemptible. |
| |
| Reported-by: Udo van den Heuvel <udovdh@xs4all.nl> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Tested-by: Udo van den Heuvel <udovdh@xs4all.nl> |
| |
| diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c |
| index 2e38cfac5b1d..a6fd1ce1d524 100644 |
| --- a/drivers/md/raid5.c |
| +++ b/drivers/md/raid5.c |
| @@ -2058,8 +2058,9 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) |
| struct raid5_percpu *percpu; |
| unsigned long cpu; |
| |
| - cpu = get_cpu(); |
| + cpu = get_cpu_light(); |
| percpu = per_cpu_ptr(conf->percpu, cpu); |
| + spin_lock(&percpu->lock); |
| if (test_bit(STRIPE_OP_BIOFILL, &ops_request)) { |
| ops_run_biofill(sh); |
| overlap_clear++; |
| @@ -2118,7 +2119,8 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) |
| if (test_and_clear_bit(R5_Overlap, &dev->flags)) |
| wake_up(&sh->raid_conf->wait_for_overlap); |
| } |
| - put_cpu(); |
| + spin_unlock(&percpu->lock); |
| + put_cpu_light(); |
| } |
| |
| static void free_stripe(struct kmem_cache *sc, struct stripe_head *sh) |
| @@ -6758,6 +6760,7 @@ static int raid456_cpu_up_prepare(unsigned int cpu, struct hlist_node *node) |
| __func__, cpu); |
| return -ENOMEM; |
| } |
| + spin_lock_init(&per_cpu_ptr(conf->percpu, cpu)->lock); |
| return 0; |
| } |
| |
| @@ -6768,7 +6771,6 @@ static int raid5_alloc_percpu(struct r5conf *conf) |
| conf->percpu = alloc_percpu(struct raid5_percpu); |
| if (!conf->percpu) |
| return -ENOMEM; |
| - |
| err = cpuhp_state_add_instance(CPUHP_MD_RAID5_PREPARE, &conf->node); |
| if (!err) { |
| conf->scribble_disks = max(conf->raid_disks, |
| diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h |
| index 625c7f16fd6b..87991db86e18 100644 |
| --- a/drivers/md/raid5.h |
| +++ b/drivers/md/raid5.h |
| @@ -613,6 +613,7 @@ struct r5conf { |
| int recovery_disabled; |
| /* per cpu variables */ |
| struct raid5_percpu { |
| + spinlock_t lock; /* Protection for -RT */ |
| struct page *spare_page; /* Used when checking P/Q in raid6 */ |
| struct flex_array *scribble; /* space for constructing buffer |
| * lists and performing address |
| -- |
| 2.1.4 |
| |