lightnvm: pblk: garbage collect lines with failed writes
Write failures should not happen under normal circumstances, so in order to bring the chunk back into a known state as soon as possible, evacuate all the valid data out of the line and let the fw judge if the block can be written to in the next reset cycle. Do this by introducing a new gc list for lines with failed writes, and ensure that the rate limiter allocates a small portion of the write bandwidth to get the job done. The lba list is saved in memory for use during gc as we cannot gurantee that the emeta data is readable if a write error occurred. Signed-off-by: Hans Holmberg <hans.holmberg@cnexlabs.com> Reviewed-by: Javier González <javier@cnexlabs.com> Signed-off-by: Matias Bjørling <mb@lightnvm.io> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:

committed by
Jens Axboe

parent
6a3abf5bee
commit
48b8d20895
@@ -73,6 +73,16 @@ void pblk_rl_user_in(struct pblk_rl *rl, int nr_entries)
|
||||
pblk_rl_kick_u_timer(rl);
|
||||
}
|
||||
|
||||
void pblk_rl_werr_line_in(struct pblk_rl *rl)
|
||||
{
|
||||
atomic_inc(&rl->werr_lines);
|
||||
}
|
||||
|
||||
void pblk_rl_werr_line_out(struct pblk_rl *rl)
|
||||
{
|
||||
atomic_dec(&rl->werr_lines);
|
||||
}
|
||||
|
||||
void pblk_rl_gc_in(struct pblk_rl *rl, int nr_entries)
|
||||
{
|
||||
atomic_add(nr_entries, &rl->rb_gc_cnt);
|
||||
@@ -99,11 +109,21 @@ static void __pblk_rl_update_rates(struct pblk_rl *rl,
|
||||
{
|
||||
struct pblk *pblk = container_of(rl, struct pblk, rl);
|
||||
int max = rl->rb_budget;
|
||||
int werr_gc_needed = atomic_read(&rl->werr_lines);
|
||||
|
||||
if (free_blocks >= rl->high) {
|
||||
rl->rb_user_max = max;
|
||||
rl->rb_gc_max = 0;
|
||||
rl->rb_state = PBLK_RL_HIGH;
|
||||
if (werr_gc_needed) {
|
||||
/* Allocate a small budget for recovering
|
||||
* lines with write errors
|
||||
*/
|
||||
rl->rb_gc_max = 1 << rl->rb_windows_pw;
|
||||
rl->rb_user_max = max - rl->rb_gc_max;
|
||||
rl->rb_state = PBLK_RL_WERR;
|
||||
} else {
|
||||
rl->rb_user_max = max;
|
||||
rl->rb_gc_max = 0;
|
||||
rl->rb_state = PBLK_RL_OFF;
|
||||
}
|
||||
} else if (free_blocks < rl->high) {
|
||||
int shift = rl->high_pw - rl->rb_windows_pw;
|
||||
int user_windows = free_blocks >> shift;
|
||||
@@ -124,7 +144,7 @@ static void __pblk_rl_update_rates(struct pblk_rl *rl,
|
||||
rl->rb_state = PBLK_RL_LOW;
|
||||
}
|
||||
|
||||
if (rl->rb_state == (PBLK_RL_MID | PBLK_RL_LOW))
|
||||
if (rl->rb_state != PBLK_RL_OFF)
|
||||
pblk_gc_should_start(pblk);
|
||||
else
|
||||
pblk_gc_should_stop(pblk);
|
||||
@@ -221,6 +241,7 @@ void pblk_rl_init(struct pblk_rl *rl, int budget)
|
||||
atomic_set(&rl->rb_user_cnt, 0);
|
||||
atomic_set(&rl->rb_gc_cnt, 0);
|
||||
atomic_set(&rl->rb_space, -1);
|
||||
atomic_set(&rl->werr_lines, 0);
|
||||
|
||||
timer_setup(&rl->u_timer, pblk_rl_u_timer, 0);
|
||||
|
||||
|
Reference in New Issue
Block a user