]> git.karo-electronics.de Git - linux-beck.git/commitdiff
md/raid5-cache: adjust the write position of the empty block if no data blocks
authorJackieLiu <liuyun01@kylinos.cn>
Mon, 5 Dec 2016 03:58:53 +0000 (11:58 +0800)
committerShaohua Li <shli@fb.com>
Tue, 6 Dec 2016 01:11:02 +0000 (17:11 -0800)
When recovery is complete, we write an empty block and record his
position first, then make the data-only stripes rewritten done,
the location of the empty block as the last checkpoint position
to write into the super block. And we should update last_checkpoint
to this empty block position.

------------------------------------------------------------------
|  old log       | empty block | data only stripes | invalid log |
------------------------------------------------------------------
^                ^                                 ^
|                |- log->last_checkpoint           |- log->log_start
|                |- log->last_cp_seq               |- log->next_checkpoint
|- log->seq=n    |- log->seq=10+n

At the same time, if there is no data-only stripes, this scene may appear,
| meta1 | meta2 | meta3 |
meta 1 is valid, meta 2 is invalid. meta 3 could be valid. so we should
The solution is we create a new meta in meta2 with its seq == meta1's
seq + 10 and let superblock points to meta2.

Signed-off-by: JackieLiu <liuyun01@kylinos.cn>
Reviewed-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
Reviewed-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Shaohua Li <shli@fb.com>
drivers/md/raid5-cache.c

index c36f86b47252bfc1a048105095fb1046864035cf..5efb876a588d3e441d9d2302be94e7ce0e3fe23d 100644 (file)
@@ -2077,7 +2077,6 @@ r5c_recovery_rewrite_data_only_stripes(struct r5l_log *log,
                return -ENOMEM;
        }
 
-       ctx->seq += 10;
        list_for_each_entry_safe(sh, next, &ctx->cached_list, lru) {
                struct r5l_meta_block *mb;
                int i;
@@ -2137,6 +2136,8 @@ static int r5l_recovery_log(struct r5l_log *log)
        struct mddev *mddev = log->rdev->mddev;
        struct r5l_recovery_ctx ctx;
        int ret;
+       sector_t pos;
+       struct stripe_head *sh;
 
        ctx.pos = log->last_checkpoint;
        ctx.seq = log->last_cp_seq;
@@ -2154,6 +2155,18 @@ static int r5l_recovery_log(struct r5l_log *log)
        if (ret)
                return ret;
 
+       pos = ctx.pos;
+       ctx.seq += 10;
+
+       if (ctx.data_only_stripes == 0) {
+               log->next_checkpoint = ctx.pos;
+               r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq++);
+               ctx.pos = r5l_ring_add(log, ctx.pos, BLOCK_SECTORS);
+       } else {
+               sh = list_last_entry(&ctx.cached_list, struct stripe_head, lru);
+               log->next_checkpoint = sh->log_start;
+       }
+
        if ((ctx.data_only_stripes == 0) && (ctx.data_parity_stripes == 0))
                pr_debug("md/raid:%s: starting from clean shutdown\n",
                         mdname(mddev));
@@ -2171,10 +2184,9 @@ static int r5l_recovery_log(struct r5l_log *log)
        }
 
        log->log_start = ctx.pos;
-       log->next_checkpoint = ctx.pos;
        log->seq = ctx.seq;
-       r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq);
-       r5l_write_super(log, ctx.pos);
+       log->last_checkpoint = pos;
+       r5l_write_super(log, pos);
        return 0;
 }