diff options
Diffstat (limited to 'drivers/md/raid5.c')
-rw-r--r-- | drivers/md/raid5.c | 90 |
1 files changed, 44 insertions, 46 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index f1feadeb7bb2..16f5c21963db 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -5514,23 +5514,43 @@ raid5_size(struct mddev *mddev, sector_t sectors, int raid_disks) | |||
5514 | return sectors * (raid_disks - conf->max_degraded); | 5514 | return sectors * (raid_disks - conf->max_degraded); |
5515 | } | 5515 | } |
5516 | 5516 | ||
5517 | static void free_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu) | ||
5518 | { | ||
5519 | safe_put_page(percpu->spare_page); | ||
5520 | kfree(percpu->scribble); | ||
5521 | percpu->spare_page = NULL; | ||
5522 | percpu->scribble = NULL; | ||
5523 | } | ||
5524 | |||
5525 | static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu) | ||
5526 | { | ||
5527 | if (conf->level == 6 && !percpu->spare_page) | ||
5528 | percpu->spare_page = alloc_page(GFP_KERNEL); | ||
5529 | if (!percpu->scribble) | ||
5530 | percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL); | ||
5531 | |||
5532 | if (!percpu->scribble || (conf->level == 6 && !percpu->spare_page)) { | ||
5533 | free_scratch_buffer(conf, percpu); | ||
5534 | return -ENOMEM; | ||
5535 | } | ||
5536 | |||
5537 | return 0; | ||
5538 | } | ||
5539 | |||
5517 | static void raid5_free_percpu(struct r5conf *conf) | 5540 | static void raid5_free_percpu(struct r5conf *conf) |
5518 | { | 5541 | { |
5519 | struct raid5_percpu *percpu; | ||
5520 | unsigned long cpu; | 5542 | unsigned long cpu; |
5521 | 5543 | ||
5522 | if (!conf->percpu) | 5544 | if (!conf->percpu) |
5523 | return; | 5545 | return; |
5524 | 5546 | ||
5525 | get_online_cpus(); | ||
5526 | for_each_possible_cpu(cpu) { | ||
5527 | percpu = per_cpu_ptr(conf->percpu, cpu); | ||
5528 | safe_put_page(percpu->spare_page); | ||
5529 | kfree(percpu->scribble); | ||
5530 | } | ||
5531 | #ifdef CONFIG_HOTPLUG_CPU | 5547 | #ifdef CONFIG_HOTPLUG_CPU |
5532 | unregister_cpu_notifier(&conf->cpu_notify); | 5548 | unregister_cpu_notifier(&conf->cpu_notify); |
5533 | #endif | 5549 | #endif |
5550 | |||
5551 | get_online_cpus(); | ||
5552 | for_each_possible_cpu(cpu) | ||
5553 | free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu)); | ||
5534 | put_online_cpus(); | 5554 | put_online_cpus(); |
5535 | 5555 | ||
5536 | free_percpu(conf->percpu); | 5556 | free_percpu(conf->percpu); |
@@ -5557,15 +5577,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action, | |||
5557 | switch (action) { | 5577 | switch (action) { |
5558 | case CPU_UP_PREPARE: | 5578 | case CPU_UP_PREPARE: |
5559 | case CPU_UP_PREPARE_FROZEN: | 5579 | case CPU_UP_PREPARE_FROZEN: |
5560 | if (conf->level == 6 && !percpu->spare_page) | 5580 | if (alloc_scratch_buffer(conf, percpu)) { |
5561 | percpu->spare_page = alloc_page(GFP_KERNEL); | ||
5562 | if (!percpu->scribble) | ||
5563 | percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL); | ||
5564 | |||
5565 | if (!percpu->scribble || | ||
5566 | (conf->level == 6 && !percpu->spare_page)) { | ||
5567 | safe_put_page(percpu->spare_page); | ||
5568 | kfree(percpu->scribble); | ||
5569 | pr_err("%s: failed memory allocation for cpu%ld\n", | 5581 | pr_err("%s: failed memory allocation for cpu%ld\n", |
5570 | __func__, cpu); | 5582 | __func__, cpu); |
5571 | return notifier_from_errno(-ENOMEM); | 5583 | return notifier_from_errno(-ENOMEM); |
@@ -5573,10 +5585,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action, | |||
5573 | break; | 5585 | break; |
5574 | case CPU_DEAD: | 5586 | case CPU_DEAD: |
5575 | case CPU_DEAD_FROZEN: | 5587 | case CPU_DEAD_FROZEN: |
5576 | safe_put_page(percpu->spare_page); | 5588 | free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu)); |
5577 | kfree(percpu->scribble); | ||
5578 | percpu->spare_page = NULL; | ||
5579 | percpu->scribble = NULL; | ||
5580 | break; | 5589 | break; |
5581 | default: | 5590 | default: |
5582 | break; | 5591 | break; |
@@ -5588,40 +5597,29 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action, | |||
5588 | static int raid5_alloc_percpu(struct r5conf *conf) | 5597 | static int raid5_alloc_percpu(struct r5conf *conf) |
5589 | { | 5598 | { |
5590 | unsigned long cpu; | 5599 | unsigned long cpu; |
5591 | struct page *spare_page; | 5600 | int err = 0; |
5592 | struct raid5_percpu __percpu *allcpus; | ||
5593 | void *scribble; | ||
5594 | int err; | ||
5595 | 5601 | ||
5596 | allcpus = alloc_percpu(struct raid5_percpu); | 5602 | conf->percpu = alloc_percpu(struct raid5_percpu); |
5597 | if (!allcpus) | 5603 | if (!conf->percpu) |
5598 | return -ENOMEM; | 5604 | return -ENOMEM; |
5599 | conf->percpu = allcpus; | 5605 | |
5606 | #ifdef CONFIG_HOTPLUG_CPU | ||
5607 | conf->cpu_notify.notifier_call = raid456_cpu_notify; | ||
5608 | conf->cpu_notify.priority = 0; | ||
5609 | err = register_cpu_notifier(&conf->cpu_notify); | ||
5610 | if (err) | ||
5611 | return err; | ||
5612 | #endif | ||
5600 | 5613 | ||
5601 | get_online_cpus(); | 5614 | get_online_cpus(); |
5602 | err = 0; | ||
5603 | for_each_present_cpu(cpu) { | 5615 | for_each_present_cpu(cpu) { |
5604 | if (conf->level == 6) { | 5616 | err = alloc_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu)); |
5605 | spare_page = alloc_page(GFP_KERNEL); | 5617 | if (err) { |
5606 | if (!spare_page) { | 5618 | pr_err("%s: failed memory allocation for cpu%ld\n", |
5607 | err = -ENOMEM; | 5619 | __func__, cpu); |
5608 | break; | ||
5609 | } | ||
5610 | per_cpu_ptr(conf->percpu, cpu)->spare_page = spare_page; | ||
5611 | } | ||
5612 | scribble = kmalloc(conf->scribble_len, GFP_KERNEL); | ||
5613 | if (!scribble) { | ||
5614 | err = -ENOMEM; | ||
5615 | break; | 5620 | break; |
5616 | } | 5621 | } |
5617 | per_cpu_ptr(conf->percpu, cpu)->scribble = scribble; | ||
5618 | } | 5622 | } |
5619 | #ifdef CONFIG_HOTPLUG_CPU | ||
5620 | conf->cpu_notify.notifier_call = raid456_cpu_notify; | ||
5621 | conf->cpu_notify.priority = 0; | ||
5622 | if (err == 0) | ||
5623 | err = register_cpu_notifier(&conf->cpu_notify); | ||
5624 | #endif | ||
5625 | put_online_cpus(); | 5623 | put_online_cpus(); |
5626 | 5624 | ||
5627 | return err; | 5625 | return err; |