Skip to content

Commit a85dd7b

Browse files
liu-song-6shligit
authored andcommitted
md/r5cache: flush data only stripes in r5l_recovery_log()
For safer operation, all arrays start in write-through mode, which has been better tested and is more mature. And actually the write-through/write-mode isn't persistent after array restarted, so we always start array in write-through mode. However, if recovery found data-only stripes before the shutdown (from previous write-back mode), it is not safe to start the array in write-through mode, as write-through mode can not handle stripes with data in write-back cache. To solve this problem, we flush all data-only stripes in r5l_recovery_log(). When r5l_recovery_log() returns, the array starts with empty cache in write-through mode. This logic is implemented in r5c_recovery_flush_data_only_stripes(): 1. enable write back cache 2. flush all stripes 3. wake up conf->mddev->thread 4. wait for all stripes get flushed (reuse wait_for_quiescent) 5. disable write back cache The wait in 4 will be waked up in release_inactive_stripe_list() when conf->active_stripes reaches 0. It is safe to wake up mddev->thread here because all the resource required for the thread has been initialized. Signed-off-by: Song Liu <[email protected]> Signed-off-by: Shaohua Li <[email protected]>
1 parent ba02684 commit a85dd7b

File tree

2 files changed

+45
-16
lines changed

2 files changed

+45
-16
lines changed

drivers/md/md.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5291,6 +5291,11 @@ int md_run(struct mddev *mddev)
52915291
if (start_readonly && mddev->ro == 0)
52925292
mddev->ro = 2; /* read-only, but switch on first write */
52935293

5294+
/*
5295+
* NOTE: some pers->run(), for example r5l_recovery_log(), wakes
5296+
* up mddev->thread. It is important to initialize critical
5297+
* resources for mddev->thread BEFORE calling pers->run().
5298+
*/
52945299
err = pers->run(mddev);
52955300
if (err)
52965301
pr_warn("md: pers->run() failed ...\n");

drivers/md/raid5-cache.c

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,7 +2060,7 @@ static int
20602060
r5c_recovery_rewrite_data_only_stripes(struct r5l_log *log,
20612061
struct r5l_recovery_ctx *ctx)
20622062
{
2063-
struct stripe_head *sh, *next;
2063+
struct stripe_head *sh;
20642064
struct mddev *mddev = log->rdev->mddev;
20652065
struct page *page;
20662066
sector_t next_checkpoint = MaxSector;
@@ -2074,7 +2074,7 @@ r5c_recovery_rewrite_data_only_stripes(struct r5l_log *log,
20742074

20752075
WARN_ON(list_empty(&ctx->cached_list));
20762076

2077-
list_for_each_entry_safe(sh, next, &ctx->cached_list, lru) {
2077+
list_for_each_entry(sh, &ctx->cached_list, lru) {
20782078
struct r5l_meta_block *mb;
20792079
int i;
20802080
int offset;
@@ -2124,14 +2124,39 @@ r5c_recovery_rewrite_data_only_stripes(struct r5l_log *log,
21242124
ctx->pos = write_pos;
21252125
ctx->seq += 1;
21262126
next_checkpoint = sh->log_start;
2127-
list_del_init(&sh->lru);
2128-
raid5_release_stripe(sh);
21292127
}
21302128
log->next_checkpoint = next_checkpoint;
21312129
__free_page(page);
21322130
return 0;
21332131
}
21342132

2133+
static void r5c_recovery_flush_data_only_stripes(struct r5l_log *log,
2134+
struct r5l_recovery_ctx *ctx)
2135+
{
2136+
struct mddev *mddev = log->rdev->mddev;
2137+
struct r5conf *conf = mddev->private;
2138+
struct stripe_head *sh, *next;
2139+
2140+
if (ctx->data_only_stripes == 0)
2141+
return;
2142+
2143+
log->r5c_journal_mode = R5C_JOURNAL_MODE_WRITE_BACK;
2144+
2145+
list_for_each_entry_safe(sh, next, &ctx->cached_list, lru) {
2146+
r5c_make_stripe_write_out(sh);
2147+
set_bit(STRIPE_HANDLE, &sh->state);
2148+
list_del_init(&sh->lru);
2149+
raid5_release_stripe(sh);
2150+
}
2151+
2152+
md_wakeup_thread(conf->mddev->thread);
2153+
/* reuse conf->wait_for_quiescent in recovery */
2154+
wait_event(conf->wait_for_quiescent,
2155+
atomic_read(&conf->active_stripes) == 0);
2156+
2157+
log->r5c_journal_mode = R5C_JOURNAL_MODE_WRITE_THROUGH;
2158+
}
2159+
21352160
static int r5l_recovery_log(struct r5l_log *log)
21362161
{
21372162
struct mddev *mddev = log->rdev->mddev;
@@ -2158,32 +2183,31 @@ static int r5l_recovery_log(struct r5l_log *log)
21582183
pos = ctx.pos;
21592184
ctx.seq += 10000;
21602185

2161-
if (ctx.data_only_stripes == 0) {
2162-
log->next_checkpoint = ctx.pos;
2163-
r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq++);
2164-
ctx.pos = r5l_ring_add(log, ctx.pos, BLOCK_SECTORS);
2165-
}
21662186

21672187
if ((ctx.data_only_stripes == 0) && (ctx.data_parity_stripes == 0))
21682188
pr_debug("md/raid:%s: starting from clean shutdown\n",
21692189
mdname(mddev));
2170-
else {
2190+
else
21712191
pr_debug("md/raid:%s: recovering %d data-only stripes and %d data-parity stripes\n",
21722192
mdname(mddev), ctx.data_only_stripes,
21732193
ctx.data_parity_stripes);
21742194

2175-
if (ctx.data_only_stripes > 0)
2176-
if (r5c_recovery_rewrite_data_only_stripes(log, &ctx)) {
2177-
pr_err("md/raid:%s: failed to rewrite stripes to journal\n",
2178-
mdname(mddev));
2179-
return -EIO;
2180-
}
2195+
if (ctx.data_only_stripes == 0) {
2196+
log->next_checkpoint = ctx.pos;
2197+
r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq++);
2198+
ctx.pos = r5l_ring_add(log, ctx.pos, BLOCK_SECTORS);
2199+
} else if (r5c_recovery_rewrite_data_only_stripes(log, &ctx)) {
2200+
pr_err("md/raid:%s: failed to rewrite stripes to journal\n",
2201+
mdname(mddev));
2202+
return -EIO;
21812203
}
21822204

21832205
log->log_start = ctx.pos;
21842206
log->seq = ctx.seq;
21852207
log->last_checkpoint = pos;
21862208
r5l_write_super(log, pos);
2209+
2210+
r5c_recovery_flush_data_only_stripes(log, &ctx);
21872211
return 0;
21882212
}
21892213

0 commit comments

Comments
 (0)