diff options
-rw-r--r-- | drivers/md/raid5-cache.c | 17 | ||||
-rw-r--r-- | drivers/md/raid5-log.h | 81 | ||||
-rw-r--r-- | drivers/md/raid5.c | 48 | ||||
-rw-r--r-- | drivers/md/raid5.h | 30 |
4 files changed, 107 insertions, 69 deletions
diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c index 5c8640c86b90..5f82dabdda6f 100644 --- a/drivers/md/raid5-cache.c +++ b/drivers/md/raid5-cache.c | |||
@@ -344,6 +344,8 @@ void r5c_handle_cached_data_endio(struct r5conf *conf, | |||
344 | } | 344 | } |
345 | } | 345 | } |
346 | 346 | ||
347 | void r5l_wake_reclaim(struct r5l_log *log, sector_t space); | ||
348 | |||
347 | /* Check whether we should flush some stripes to free up stripe cache */ | 349 | /* Check whether we should flush some stripes to free up stripe cache */ |
348 | void r5c_check_stripe_cache_usage(struct r5conf *conf) | 350 | void r5c_check_stripe_cache_usage(struct r5conf *conf) |
349 | { | 351 | { |
@@ -2749,9 +2751,7 @@ void r5c_finish_stripe_write_out(struct r5conf *conf, | |||
2749 | } | 2751 | } |
2750 | } | 2752 | } |
2751 | 2753 | ||
2752 | int | 2754 | int r5c_cache_data(struct r5l_log *log, struct stripe_head *sh) |
2753 | r5c_cache_data(struct r5l_log *log, struct stripe_head *sh, | ||
2754 | struct stripe_head_state *s) | ||
2755 | { | 2755 | { |
2756 | struct r5conf *conf = sh->raid_conf; | 2756 | struct r5conf *conf = sh->raid_conf; |
2757 | int pages = 0; | 2757 | int pages = 0; |
@@ -2914,6 +2914,10 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev) | |||
2914 | { | 2914 | { |
2915 | struct request_queue *q = bdev_get_queue(rdev->bdev); | 2915 | struct request_queue *q = bdev_get_queue(rdev->bdev); |
2916 | struct r5l_log *log; | 2916 | struct r5l_log *log; |
2917 | char b[BDEVNAME_SIZE]; | ||
2918 | |||
2919 | pr_debug("md/raid:%s: using device %s as journal\n", | ||
2920 | mdname(conf->mddev), bdevname(rdev->bdev, b)); | ||
2917 | 2921 | ||
2918 | if (PAGE_SIZE != 4096) | 2922 | if (PAGE_SIZE != 4096) |
2919 | return -EINVAL; | 2923 | return -EINVAL; |
@@ -3016,8 +3020,13 @@ io_kc: | |||
3016 | return -EINVAL; | 3020 | return -EINVAL; |
3017 | } | 3021 | } |
3018 | 3022 | ||
3019 | void r5l_exit_log(struct r5l_log *log) | 3023 | void r5l_exit_log(struct r5conf *conf) |
3020 | { | 3024 | { |
3025 | struct r5l_log *log = conf->log; | ||
3026 | |||
3027 | conf->log = NULL; | ||
3028 | synchronize_rcu(); | ||
3029 | |||
3021 | flush_work(&log->disable_writeback_work); | 3030 | flush_work(&log->disable_writeback_work); |
3022 | md_unregister_thread(&log->reclaim_thread); | 3031 | md_unregister_thread(&log->reclaim_thread); |
3023 | mempool_destroy(log->meta_pool); | 3032 | mempool_destroy(log->meta_pool); |
diff --git a/drivers/md/raid5-log.h b/drivers/md/raid5-log.h new file mode 100644 index 000000000000..2da4bd3bbd79 --- /dev/null +++ b/drivers/md/raid5-log.h | |||
@@ -0,0 +1,81 @@ | |||
1 | #ifndef _RAID5_LOG_H | ||
2 | #define _RAID5_LOG_H | ||
3 | |||
4 | extern int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev); | ||
5 | extern void r5l_exit_log(struct r5conf *conf); | ||
6 | extern int r5l_write_stripe(struct r5l_log *log, struct stripe_head *head_sh); | ||
7 | extern void r5l_write_stripe_run(struct r5l_log *log); | ||
8 | extern void r5l_flush_stripe_to_raid(struct r5l_log *log); | ||
9 | extern void r5l_stripe_write_finished(struct stripe_head *sh); | ||
10 | extern int r5l_handle_flush_request(struct r5l_log *log, struct bio *bio); | ||
11 | extern void r5l_quiesce(struct r5l_log *log, int state); | ||
12 | extern bool r5l_log_disk_error(struct r5conf *conf); | ||
13 | extern bool r5c_is_writeback(struct r5l_log *log); | ||
14 | extern int | ||
15 | r5c_try_caching_write(struct r5conf *conf, struct stripe_head *sh, | ||
16 | struct stripe_head_state *s, int disks); | ||
17 | extern void | ||
18 | r5c_finish_stripe_write_out(struct r5conf *conf, struct stripe_head *sh, | ||
19 | struct stripe_head_state *s); | ||
20 | extern void r5c_release_extra_page(struct stripe_head *sh); | ||
21 | extern void r5c_use_extra_page(struct stripe_head *sh); | ||
22 | extern void r5l_wake_reclaim(struct r5l_log *log, sector_t space); | ||
23 | extern void r5c_handle_cached_data_endio(struct r5conf *conf, | ||
24 | struct stripe_head *sh, int disks, struct bio_list *return_bi); | ||
25 | extern int r5c_cache_data(struct r5l_log *log, struct stripe_head *sh); | ||
26 | extern void r5c_make_stripe_write_out(struct stripe_head *sh); | ||
27 | extern void r5c_flush_cache(struct r5conf *conf, int num); | ||
28 | extern void r5c_check_stripe_cache_usage(struct r5conf *conf); | ||
29 | extern void r5c_check_cached_full_stripe(struct r5conf *conf); | ||
30 | extern struct md_sysfs_entry r5c_journal_mode; | ||
31 | extern void r5c_update_on_rdev_error(struct mddev *mddev); | ||
32 | extern bool r5c_big_stripe_cached(struct r5conf *conf, sector_t sect); | ||
33 | |||
34 | static inline int log_stripe(struct stripe_head *sh, struct stripe_head_state *s) | ||
35 | { | ||
36 | struct r5conf *conf = sh->raid_conf; | ||
37 | |||
38 | if (conf->log) { | ||
39 | if (!test_bit(STRIPE_R5C_CACHING, &sh->state)) { | ||
40 | /* writing out phase */ | ||
41 | if (s->waiting_extra_page) | ||
42 | return 0; | ||
43 | return r5l_write_stripe(conf->log, sh); | ||
44 | } else if (test_bit(STRIPE_LOG_TRAPPED, &sh->state)) { | ||
45 | /* caching phase */ | ||
46 | return r5c_cache_data(conf->log, sh); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | return -EAGAIN; | ||
51 | } | ||
52 | |||
53 | static inline void log_stripe_write_finished(struct stripe_head *sh) | ||
54 | { | ||
55 | struct r5conf *conf = sh->raid_conf; | ||
56 | |||
57 | if (conf->log) | ||
58 | r5l_stripe_write_finished(sh); | ||
59 | } | ||
60 | |||
61 | static inline void log_write_stripe_run(struct r5conf *conf) | ||
62 | { | ||
63 | if (conf->log) | ||
64 | r5l_write_stripe_run(conf->log); | ||
65 | } | ||
66 | |||
67 | static inline void log_exit(struct r5conf *conf) | ||
68 | { | ||
69 | if (conf->log) | ||
70 | r5l_exit_log(conf); | ||
71 | } | ||
72 | |||
73 | static inline int log_init(struct r5conf *conf, struct md_rdev *journal_dev) | ||
74 | { | ||
75 | if (journal_dev) | ||
76 | return r5l_init_log(conf, journal_dev); | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | #endif | ||
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 013398ce2080..f575f40d2acb 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -64,6 +64,7 @@ | |||
64 | #include "raid5.h" | 64 | #include "raid5.h" |
65 | #include "raid0.h" | 65 | #include "raid0.h" |
66 | #include "bitmap.h" | 66 | #include "bitmap.h" |
67 | #include "raid5-log.h" | ||
67 | 68 | ||
68 | #define UNSUPPORTED_MDDEV_FLAGS (1L << MD_FAILFAST_SUPPORTED) | 69 | #define UNSUPPORTED_MDDEV_FLAGS (1L << MD_FAILFAST_SUPPORTED) |
69 | 70 | ||
@@ -997,18 +998,8 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) | |||
997 | 998 | ||
998 | might_sleep(); | 999 | might_sleep(); |
999 | 1000 | ||
1000 | if (!test_bit(STRIPE_R5C_CACHING, &sh->state)) { | 1001 | if (log_stripe(sh, s) == 0) |
1001 | /* writing out phase */ | 1002 | return; |
1002 | if (s->waiting_extra_page) | ||
1003 | return; | ||
1004 | if (r5l_write_stripe(conf->log, sh) == 0) | ||
1005 | return; | ||
1006 | } else { /* caching phase */ | ||
1007 | if (test_bit(STRIPE_LOG_TRAPPED, &sh->state)) { | ||
1008 | r5c_cache_data(conf->log, sh, s); | ||
1009 | return; | ||
1010 | } | ||
1011 | } | ||
1012 | 1003 | ||
1013 | should_defer = conf->batch_bio_dispatch && conf->group_cnt; | 1004 | should_defer = conf->batch_bio_dispatch && conf->group_cnt; |
1014 | 1005 | ||
@@ -3345,7 +3336,7 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, | |||
3345 | if (bi) | 3336 | if (bi) |
3346 | bitmap_end = 1; | 3337 | bitmap_end = 1; |
3347 | 3338 | ||
3348 | r5l_stripe_write_finished(sh); | 3339 | log_stripe_write_finished(sh); |
3349 | 3340 | ||
3350 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) | 3341 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) |
3351 | wake_up(&conf->wait_for_overlap); | 3342 | wake_up(&conf->wait_for_overlap); |
@@ -3764,7 +3755,7 @@ returnbi: | |||
3764 | discard_pending = 1; | 3755 | discard_pending = 1; |
3765 | } | 3756 | } |
3766 | 3757 | ||
3767 | r5l_stripe_write_finished(sh); | 3758 | log_stripe_write_finished(sh); |
3768 | 3759 | ||
3769 | if (!discard_pending && | 3760 | if (!discard_pending && |
3770 | test_bit(R5_Discard, &sh->dev[sh->pd_idx].flags)) { | 3761 | test_bit(R5_Discard, &sh->dev[sh->pd_idx].flags)) { |
@@ -4754,7 +4745,7 @@ static void handle_stripe(struct stripe_head *sh) | |||
4754 | 4745 | ||
4755 | if (s.just_cached) | 4746 | if (s.just_cached) |
4756 | r5c_handle_cached_data_endio(conf, sh, disks, &s.return_bi); | 4747 | r5c_handle_cached_data_endio(conf, sh, disks, &s.return_bi); |
4757 | r5l_stripe_write_finished(sh); | 4748 | log_stripe_write_finished(sh); |
4758 | 4749 | ||
4759 | /* Now we might consider reading some blocks, either to check/generate | 4750 | /* Now we might consider reading some blocks, either to check/generate |
4760 | * parity, or to satisfy requests | 4751 | * parity, or to satisfy requests |
@@ -6168,7 +6159,7 @@ static int handle_active_stripes(struct r5conf *conf, int group, | |||
6168 | 6159 | ||
6169 | for (i = 0; i < batch_size; i++) | 6160 | for (i = 0; i < batch_size; i++) |
6170 | handle_stripe(batch[i]); | 6161 | handle_stripe(batch[i]); |
6171 | r5l_write_stripe_run(conf->log); | 6162 | log_write_stripe_run(conf); |
6172 | 6163 | ||
6173 | cond_resched(); | 6164 | cond_resched(); |
6174 | 6165 | ||
@@ -6745,8 +6736,8 @@ static void free_conf(struct r5conf *conf) | |||
6745 | { | 6736 | { |
6746 | int i; | 6737 | int i; |
6747 | 6738 | ||
6748 | if (conf->log) | 6739 | log_exit(conf); |
6749 | r5l_exit_log(conf->log); | 6740 | |
6750 | if (conf->shrinker.nr_deferred) | 6741 | if (conf->shrinker.nr_deferred) |
6751 | unregister_shrinker(&conf->shrinker); | 6742 | unregister_shrinker(&conf->shrinker); |
6752 | 6743 | ||
@@ -7436,14 +7427,8 @@ static int raid5_run(struct mddev *mddev) | |||
7436 | blk_queue_max_hw_sectors(mddev->queue, UINT_MAX); | 7427 | blk_queue_max_hw_sectors(mddev->queue, UINT_MAX); |
7437 | } | 7428 | } |
7438 | 7429 | ||
7439 | if (journal_dev) { | 7430 | if (log_init(conf, journal_dev)) |
7440 | char b[BDEVNAME_SIZE]; | 7431 | goto abort; |
7441 | |||
7442 | pr_debug("md/raid:%s: using device %s as journal\n", | ||
7443 | mdname(mddev), bdevname(journal_dev->bdev, b)); | ||
7444 | if (r5l_init_log(conf, journal_dev)) | ||
7445 | goto abort; | ||
7446 | } | ||
7447 | 7432 | ||
7448 | return 0; | 7433 | return 0; |
7449 | abort: | 7434 | abort: |
@@ -7557,17 +7542,13 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev) | |||
7557 | 7542 | ||
7558 | print_raid5_conf(conf); | 7543 | print_raid5_conf(conf); |
7559 | if (test_bit(Journal, &rdev->flags) && conf->log) { | 7544 | if (test_bit(Journal, &rdev->flags) && conf->log) { |
7560 | struct r5l_log *log; | ||
7561 | /* | 7545 | /* |
7562 | * we can't wait pending write here, as this is called in | 7546 | * we can't wait pending write here, as this is called in |
7563 | * raid5d, wait will deadlock. | 7547 | * raid5d, wait will deadlock. |
7564 | */ | 7548 | */ |
7565 | if (atomic_read(&mddev->writes_pending)) | 7549 | if (atomic_read(&mddev->writes_pending)) |
7566 | return -EBUSY; | 7550 | return -EBUSY; |
7567 | log = conf->log; | 7551 | log_exit(conf); |
7568 | conf->log = NULL; | ||
7569 | synchronize_rcu(); | ||
7570 | r5l_exit_log(log); | ||
7571 | return 0; | 7552 | return 0; |
7572 | } | 7553 | } |
7573 | if (rdev == p->rdev) | 7554 | if (rdev == p->rdev) |
@@ -7636,7 +7617,6 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev) | |||
7636 | int last = conf->raid_disks - 1; | 7617 | int last = conf->raid_disks - 1; |
7637 | 7618 | ||
7638 | if (test_bit(Journal, &rdev->flags)) { | 7619 | if (test_bit(Journal, &rdev->flags)) { |
7639 | char b[BDEVNAME_SIZE]; | ||
7640 | if (conf->log) | 7620 | if (conf->log) |
7641 | return -EBUSY; | 7621 | return -EBUSY; |
7642 | 7622 | ||
@@ -7645,9 +7625,7 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev) | |||
7645 | * The array is in readonly mode if journal is missing, so no | 7625 | * The array is in readonly mode if journal is missing, so no |
7646 | * write requests running. We should be safe | 7626 | * write requests running. We should be safe |
7647 | */ | 7627 | */ |
7648 | r5l_init_log(conf, rdev); | 7628 | log_init(conf, rdev); |
7649 | pr_debug("md/raid:%s: using device %s as journal\n", | ||
7650 | mdname(mddev), bdevname(rdev->bdev, b)); | ||
7651 | return 0; | 7629 | return 0; |
7652 | } | 7630 | } |
7653 | if (mddev->recovery_disabled == conf->recovery_disabled) | 7631 | if (mddev->recovery_disabled == conf->recovery_disabled) |
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 985cdc4850c2..6dd295a80ee1 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h | |||
@@ -779,34 +779,4 @@ extern struct stripe_head * | |||
779 | raid5_get_active_stripe(struct r5conf *conf, sector_t sector, | 779 | raid5_get_active_stripe(struct r5conf *conf, sector_t sector, |
780 | int previous, int noblock, int noquiesce); | 780 | int previous, int noblock, int noquiesce); |
781 | extern int raid5_calc_degraded(struct r5conf *conf); | 781 | extern int raid5_calc_degraded(struct r5conf *conf); |
782 | extern int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev); | ||
783 | extern void r5l_exit_log(struct r5l_log *log); | ||
784 | extern int r5l_write_stripe(struct r5l_log *log, struct stripe_head *head_sh); | ||
785 | extern void r5l_write_stripe_run(struct r5l_log *log); | ||
786 | extern void r5l_flush_stripe_to_raid(struct r5l_log *log); | ||
787 | extern void r5l_stripe_write_finished(struct stripe_head *sh); | ||
788 | extern int r5l_handle_flush_request(struct r5l_log *log, struct bio *bio); | ||
789 | extern void r5l_quiesce(struct r5l_log *log, int state); | ||
790 | extern bool r5l_log_disk_error(struct r5conf *conf); | ||
791 | extern bool r5c_is_writeback(struct r5l_log *log); | ||
792 | extern int | ||
793 | r5c_try_caching_write(struct r5conf *conf, struct stripe_head *sh, | ||
794 | struct stripe_head_state *s, int disks); | ||
795 | extern void | ||
796 | r5c_finish_stripe_write_out(struct r5conf *conf, struct stripe_head *sh, | ||
797 | struct stripe_head_state *s); | ||
798 | extern void r5c_release_extra_page(struct stripe_head *sh); | ||
799 | extern void r5c_use_extra_page(struct stripe_head *sh); | ||
800 | extern void r5l_wake_reclaim(struct r5l_log *log, sector_t space); | ||
801 | extern void r5c_handle_cached_data_endio(struct r5conf *conf, | ||
802 | struct stripe_head *sh, int disks, struct bio_list *return_bi); | ||
803 | extern int r5c_cache_data(struct r5l_log *log, struct stripe_head *sh, | ||
804 | struct stripe_head_state *s); | ||
805 | extern void r5c_make_stripe_write_out(struct stripe_head *sh); | ||
806 | extern void r5c_flush_cache(struct r5conf *conf, int num); | ||
807 | extern void r5c_check_stripe_cache_usage(struct r5conf *conf); | ||
808 | extern void r5c_check_cached_full_stripe(struct r5conf *conf); | ||
809 | extern struct md_sysfs_entry r5c_journal_mode; | ||
810 | extern void r5c_update_on_rdev_error(struct mddev *mddev); | ||
811 | extern bool r5c_big_stripe_cached(struct r5conf *conf, sector_t sect); | ||
812 | #endif | 782 | #endif |