summaryrefslogtreecommitdiffstats
path: root/drivers/lightnvm/pblk-rl.c
diff options
context:
space:
mode:
authorHans Holmberg <hans.holmberg@cnexlabs.com>2018-06-01 10:41:06 -0400
committerJens Axboe <axboe@kernel.dk>2018-06-01 11:02:53 -0400
commit48b8d20895f8a489e1527e9bdc5e372808542fa3 (patch)
tree754ad9c349589759af22adad8286e7fa2b7095bc /drivers/lightnvm/pblk-rl.c
parent6a3abf5beef6ae46381c1fb6976e6f313c40f0c1 (diff)
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>
Diffstat (limited to 'drivers/lightnvm/pblk-rl.c')
-rw-r--r--drivers/lightnvm/pblk-rl.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/drivers/lightnvm/pblk-rl.c b/drivers/lightnvm/pblk-rl.c
index 883a7113b19d..6a0616a6fcaf 100644
--- a/drivers/lightnvm/pblk-rl.c
+++ b/drivers/lightnvm/pblk-rl.c
@@ -73,6 +73,16 @@ void pblk_rl_user_in(struct pblk_rl *rl, int nr_entries)
73 pblk_rl_kick_u_timer(rl); 73 pblk_rl_kick_u_timer(rl);
74} 74}
75 75
76void pblk_rl_werr_line_in(struct pblk_rl *rl)
77{
78 atomic_inc(&rl->werr_lines);
79}
80
81void pblk_rl_werr_line_out(struct pblk_rl *rl)
82{
83 atomic_dec(&rl->werr_lines);
84}
85
76void pblk_rl_gc_in(struct pblk_rl *rl, int nr_entries) 86void pblk_rl_gc_in(struct pblk_rl *rl, int nr_entries)
77{ 87{
78 atomic_add(nr_entries, &rl->rb_gc_cnt); 88 atomic_add(nr_entries, &rl->rb_gc_cnt);
@@ -99,11 +109,21 @@ static void __pblk_rl_update_rates(struct pblk_rl *rl,
99{ 109{
100 struct pblk *pblk = container_of(rl, struct pblk, rl); 110 struct pblk *pblk = container_of(rl, struct pblk, rl);
101 int max = rl->rb_budget; 111 int max = rl->rb_budget;
112 int werr_gc_needed = atomic_read(&rl->werr_lines);
102 113
103 if (free_blocks >= rl->high) { 114 if (free_blocks >= rl->high) {
104 rl->rb_user_max = max; 115 if (werr_gc_needed) {
105 rl->rb_gc_max = 0; 116 /* Allocate a small budget for recovering
106 rl->rb_state = PBLK_RL_HIGH; 117 * lines with write errors
118 */
119 rl->rb_gc_max = 1 << rl->rb_windows_pw;
120 rl->rb_user_max = max - rl->rb_gc_max;
121 rl->rb_state = PBLK_RL_WERR;
122 } else {
123 rl->rb_user_max = max;
124 rl->rb_gc_max = 0;
125 rl->rb_state = PBLK_RL_OFF;
126 }
107 } else if (free_blocks < rl->high) { 127 } else if (free_blocks < rl->high) {
108 int shift = rl->high_pw - rl->rb_windows_pw; 128 int shift = rl->high_pw - rl->rb_windows_pw;
109 int user_windows = free_blocks >> shift; 129 int user_windows = free_blocks >> shift;
@@ -124,7 +144,7 @@ static void __pblk_rl_update_rates(struct pblk_rl *rl,
124 rl->rb_state = PBLK_RL_LOW; 144 rl->rb_state = PBLK_RL_LOW;
125 } 145 }
126 146
127 if (rl->rb_state == (PBLK_RL_MID | PBLK_RL_LOW)) 147 if (rl->rb_state != PBLK_RL_OFF)
128 pblk_gc_should_start(pblk); 148 pblk_gc_should_start(pblk);
129 else 149 else
130 pblk_gc_should_stop(pblk); 150 pblk_gc_should_stop(pblk);
@@ -221,6 +241,7 @@ void pblk_rl_init(struct pblk_rl *rl, int budget)
221 atomic_set(&rl->rb_user_cnt, 0); 241 atomic_set(&rl->rb_user_cnt, 0);
222 atomic_set(&rl->rb_gc_cnt, 0); 242 atomic_set(&rl->rb_gc_cnt, 0);
223 atomic_set(&rl->rb_space, -1); 243 atomic_set(&rl->rb_space, -1);
244 atomic_set(&rl->werr_lines, 0);
224 245
225 timer_setup(&rl->u_timer, pblk_rl_u_timer, 0); 246 timer_setup(&rl->u_timer, pblk_rl_u_timer, 0);
226 247