.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2016 CNEX Labs |
---|
3 | 4 | * Initial release: Javier Gonzalez <javier@cnexlabs.com> |
---|
.. | .. |
---|
16 | 17 | */ |
---|
17 | 18 | |
---|
18 | 19 | #include "pblk.h" |
---|
| 20 | +#include "pblk-trace.h" |
---|
19 | 21 | #include <linux/delay.h> |
---|
| 22 | + |
---|
20 | 23 | |
---|
21 | 24 | static void pblk_gc_free_gc_rq(struct pblk_gc_rq *gc_rq) |
---|
22 | 25 | { |
---|
.. | .. |
---|
56 | 59 | wake_up_process(gc->gc_writer_ts); |
---|
57 | 60 | } |
---|
58 | 61 | |
---|
59 | | -static void pblk_put_line_back(struct pblk *pblk, struct pblk_line *line) |
---|
| 62 | +void pblk_put_line_back(struct pblk *pblk, struct pblk_line *line) |
---|
60 | 63 | { |
---|
61 | 64 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; |
---|
62 | 65 | struct list_head *move_list; |
---|
63 | 66 | |
---|
| 67 | + spin_lock(&l_mg->gc_lock); |
---|
64 | 68 | spin_lock(&line->lock); |
---|
65 | 69 | WARN_ON(line->state != PBLK_LINESTATE_GC); |
---|
66 | 70 | line->state = PBLK_LINESTATE_CLOSED; |
---|
| 71 | + trace_pblk_line_state(pblk_disk_name(pblk), line->id, |
---|
| 72 | + line->state); |
---|
| 73 | + |
---|
| 74 | + /* We need to reset gc_group in order to ensure that |
---|
| 75 | + * pblk_line_gc_list will return proper move_list |
---|
| 76 | + * since right now current line is not on any of the |
---|
| 77 | + * gc lists. |
---|
| 78 | + */ |
---|
| 79 | + line->gc_group = PBLK_LINEGC_NONE; |
---|
67 | 80 | move_list = pblk_line_gc_list(pblk, line); |
---|
68 | 81 | spin_unlock(&line->lock); |
---|
69 | | - |
---|
70 | | - if (move_list) { |
---|
71 | | - spin_lock(&l_mg->gc_lock); |
---|
72 | | - list_add_tail(&line->list, move_list); |
---|
73 | | - spin_unlock(&l_mg->gc_lock); |
---|
74 | | - } |
---|
| 82 | + list_add_tail(&line->list, move_list); |
---|
| 83 | + spin_unlock(&l_mg->gc_lock); |
---|
75 | 84 | } |
---|
76 | 85 | |
---|
77 | 86 | static void pblk_gc_line_ws(struct work_struct *work) |
---|
.. | .. |
---|
79 | 88 | struct pblk_line_ws *gc_rq_ws = container_of(work, |
---|
80 | 89 | struct pblk_line_ws, ws); |
---|
81 | 90 | struct pblk *pblk = gc_rq_ws->pblk; |
---|
82 | | - struct nvm_tgt_dev *dev = pblk->dev; |
---|
83 | | - struct nvm_geo *geo = &dev->geo; |
---|
84 | 91 | struct pblk_gc *gc = &pblk->gc; |
---|
85 | 92 | struct pblk_line *line = gc_rq_ws->line; |
---|
86 | 93 | struct pblk_gc_rq *gc_rq = gc_rq_ws->priv; |
---|
.. | .. |
---|
88 | 95 | |
---|
89 | 96 | up(&gc->gc_sem); |
---|
90 | 97 | |
---|
91 | | - gc_rq->data = vmalloc(array_size(gc_rq->nr_secs, geo->csecs)); |
---|
92 | | - if (!gc_rq->data) { |
---|
93 | | - pblk_err(pblk, "could not GC line:%d (%d/%d)\n", |
---|
94 | | - line->id, *line->vsc, gc_rq->nr_secs); |
---|
95 | | - goto out; |
---|
96 | | - } |
---|
97 | | - |
---|
98 | 98 | /* Read from GC victim block */ |
---|
99 | 99 | ret = pblk_submit_read_gc(pblk, gc_rq); |
---|
100 | 100 | if (ret) { |
---|
101 | | - pblk_err(pblk, "failed GC read in line:%d (err:%d)\n", |
---|
102 | | - line->id, ret); |
---|
| 101 | + line->w_err_gc->has_gc_err = 1; |
---|
103 | 102 | goto out; |
---|
104 | 103 | } |
---|
105 | 104 | |
---|
.. | .. |
---|
133 | 132 | struct pblk_line *line) |
---|
134 | 133 | { |
---|
135 | 134 | struct line_emeta *emeta_buf; |
---|
136 | | - struct pblk_line_mgmt *l_mg = &pblk->l_mg; |
---|
137 | 135 | struct pblk_line_meta *lm = &pblk->lm; |
---|
138 | 136 | unsigned int lba_list_size = lm->emeta_len[2]; |
---|
139 | 137 | __le64 *lba_list; |
---|
140 | 138 | int ret; |
---|
141 | 139 | |
---|
142 | | - emeta_buf = pblk_malloc(lm->emeta_len[0], |
---|
143 | | - l_mg->emeta_alloc_type, GFP_KERNEL); |
---|
| 140 | + emeta_buf = kvmalloc(lm->emeta_len[0], GFP_KERNEL); |
---|
144 | 141 | if (!emeta_buf) |
---|
145 | 142 | return NULL; |
---|
146 | 143 | |
---|
147 | | - ret = pblk_line_read_emeta(pblk, line, emeta_buf); |
---|
| 144 | + ret = pblk_line_emeta_read(pblk, line, emeta_buf); |
---|
148 | 145 | if (ret) { |
---|
149 | 146 | pblk_err(pblk, "line %d read emeta failed (%d)\n", |
---|
150 | 147 | line->id, ret); |
---|
151 | | - pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); |
---|
| 148 | + kvfree(emeta_buf); |
---|
152 | 149 | return NULL; |
---|
153 | 150 | } |
---|
154 | 151 | |
---|
.. | .. |
---|
162 | 159 | if (ret) { |
---|
163 | 160 | pblk_err(pblk, "inconsistent emeta (line %d)\n", |
---|
164 | 161 | line->id); |
---|
165 | | - pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); |
---|
| 162 | + kvfree(emeta_buf); |
---|
166 | 163 | return NULL; |
---|
167 | 164 | } |
---|
168 | 165 | |
---|
169 | | - lba_list = pblk_malloc(lba_list_size, |
---|
170 | | - l_mg->emeta_alloc_type, GFP_KERNEL); |
---|
| 166 | + lba_list = kvmalloc(lba_list_size, GFP_KERNEL); |
---|
| 167 | + |
---|
171 | 168 | if (lba_list) |
---|
172 | 169 | memcpy(lba_list, emeta_to_lbas(pblk, emeta_buf), lba_list_size); |
---|
173 | 170 | |
---|
174 | | - pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); |
---|
| 171 | + kvfree(emeta_buf); |
---|
175 | 172 | |
---|
176 | 173 | return lba_list; |
---|
177 | 174 | } |
---|
.. | .. |
---|
182 | 179 | ws); |
---|
183 | 180 | struct pblk *pblk = line_ws->pblk; |
---|
184 | 181 | struct pblk_line *line = line_ws->line; |
---|
185 | | - struct pblk_line_mgmt *l_mg = &pblk->l_mg; |
---|
186 | 182 | struct pblk_line_meta *lm = &pblk->lm; |
---|
| 183 | + struct nvm_tgt_dev *dev = pblk->dev; |
---|
| 184 | + struct nvm_geo *geo = &dev->geo; |
---|
187 | 185 | struct pblk_gc *gc = &pblk->gc; |
---|
188 | 186 | struct pblk_line_ws *gc_rq_ws; |
---|
189 | 187 | struct pblk_gc_rq *gc_rq; |
---|
.. | .. |
---|
242 | 240 | gc_rq->nr_secs = nr_secs; |
---|
243 | 241 | gc_rq->line = line; |
---|
244 | 242 | |
---|
| 243 | + gc_rq->data = vmalloc(array_size(gc_rq->nr_secs, geo->csecs)); |
---|
| 244 | + if (!gc_rq->data) |
---|
| 245 | + goto fail_free_gc_rq; |
---|
| 246 | + |
---|
245 | 247 | gc_rq_ws = kmalloc(sizeof(struct pblk_line_ws), GFP_KERNEL); |
---|
246 | 248 | if (!gc_rq_ws) |
---|
247 | | - goto fail_free_gc_rq; |
---|
| 249 | + goto fail_free_gc_data; |
---|
248 | 250 | |
---|
249 | 251 | gc_rq_ws->pblk = pblk; |
---|
250 | 252 | gc_rq_ws->line = line; |
---|
.. | .. |
---|
267 | 269 | goto next_rq; |
---|
268 | 270 | |
---|
269 | 271 | out: |
---|
270 | | - pblk_mfree(lba_list, l_mg->emeta_alloc_type); |
---|
| 272 | + kvfree(lba_list); |
---|
271 | 273 | kfree(line_ws); |
---|
272 | 274 | kfree(invalid_bitmap); |
---|
273 | 275 | |
---|
.. | .. |
---|
276 | 278 | |
---|
277 | 279 | return; |
---|
278 | 280 | |
---|
| 281 | +fail_free_gc_data: |
---|
| 282 | + vfree(gc_rq->data); |
---|
279 | 283 | fail_free_gc_rq: |
---|
280 | 284 | kfree(gc_rq); |
---|
281 | 285 | fail_free_lba_list: |
---|
282 | | - pblk_mfree(lba_list, l_mg->emeta_alloc_type); |
---|
| 286 | + kvfree(lba_list); |
---|
283 | 287 | fail_free_invalid_bitmap: |
---|
284 | 288 | kfree(invalid_bitmap); |
---|
285 | 289 | fail_free_ws: |
---|
286 | 290 | kfree(line_ws); |
---|
287 | 291 | |
---|
| 292 | + /* Line goes back to closed state, so we cannot release additional |
---|
| 293 | + * reference for line, since we do that only when we want to do |
---|
| 294 | + * gc to free line state transition. |
---|
| 295 | + */ |
---|
288 | 296 | pblk_put_line_back(pblk, line); |
---|
289 | | - kref_put(&line->ref, pblk_line_put); |
---|
290 | 297 | atomic_dec(&gc->read_inflight_gc); |
---|
291 | 298 | |
---|
292 | 299 | pblk_err(pblk, "failed to GC line %d\n", line->id); |
---|
.. | .. |
---|
350 | 357 | |
---|
351 | 358 | pblk_gc_kick(pblk); |
---|
352 | 359 | |
---|
353 | | - if (pblk_gc_line(pblk, line)) |
---|
| 360 | + if (pblk_gc_line(pblk, line)) { |
---|
354 | 361 | pblk_err(pblk, "failed to GC line %d\n", line->id); |
---|
| 362 | + /* rollback */ |
---|
| 363 | + spin_lock(&gc->r_lock); |
---|
| 364 | + list_add_tail(&line->list, &gc->r_list); |
---|
| 365 | + spin_unlock(&gc->r_lock); |
---|
| 366 | + } |
---|
355 | 367 | |
---|
356 | 368 | return 0; |
---|
357 | 369 | } |
---|
.. | .. |
---|
360 | 372 | struct list_head *group_list) |
---|
361 | 373 | { |
---|
362 | 374 | struct pblk_line *line, *victim; |
---|
363 | | - int line_vsc, victim_vsc; |
---|
| 375 | + unsigned int line_vsc = ~0x0L, victim_vsc = ~0x0L; |
---|
364 | 376 | |
---|
365 | 377 | victim = list_first_entry(group_list, struct pblk_line, list); |
---|
| 378 | + |
---|
366 | 379 | list_for_each_entry(line, group_list, list) { |
---|
367 | | - line_vsc = le32_to_cpu(*line->vsc); |
---|
368 | | - victim_vsc = le32_to_cpu(*victim->vsc); |
---|
369 | | - if (line_vsc < victim_vsc) |
---|
| 380 | + if (!atomic_read(&line->sec_to_update)) |
---|
| 381 | + line_vsc = le32_to_cpu(*line->vsc); |
---|
| 382 | + if (line_vsc < victim_vsc) { |
---|
370 | 383 | victim = line; |
---|
| 384 | + victim_vsc = le32_to_cpu(*victim->vsc); |
---|
| 385 | + } |
---|
371 | 386 | } |
---|
| 387 | + |
---|
| 388 | + if (victim_vsc == ~0x0) |
---|
| 389 | + return NULL; |
---|
372 | 390 | |
---|
373 | 391 | return victim; |
---|
374 | 392 | } |
---|
.. | .. |
---|
405 | 423 | spin_lock(&line->lock); |
---|
406 | 424 | WARN_ON(line->state != PBLK_LINESTATE_CLOSED); |
---|
407 | 425 | line->state = PBLK_LINESTATE_GC; |
---|
| 426 | + trace_pblk_line_state(pblk_disk_name(pblk), line->id, |
---|
| 427 | + line->state); |
---|
408 | 428 | spin_unlock(&line->lock); |
---|
409 | 429 | |
---|
410 | 430 | list_del(&line->list); |
---|
.. | .. |
---|
441 | 461 | |
---|
442 | 462 | do { |
---|
443 | 463 | spin_lock(&l_mg->gc_lock); |
---|
444 | | - if (list_empty(group_list)) { |
---|
| 464 | + |
---|
| 465 | + line = pblk_gc_get_victim_line(pblk, group_list); |
---|
| 466 | + if (!line) { |
---|
445 | 467 | spin_unlock(&l_mg->gc_lock); |
---|
446 | 468 | break; |
---|
447 | 469 | } |
---|
448 | 470 | |
---|
449 | | - line = pblk_gc_get_victim_line(pblk, group_list); |
---|
450 | | - |
---|
451 | 471 | spin_lock(&line->lock); |
---|
452 | 472 | WARN_ON(line->state != PBLK_LINESTATE_CLOSED); |
---|
453 | 473 | line->state = PBLK_LINESTATE_GC; |
---|
| 474 | + trace_pblk_line_state(pblk_disk_name(pblk), line->id, |
---|
| 475 | + line->state); |
---|
454 | 476 | spin_unlock(&line->lock); |
---|
455 | 477 | |
---|
456 | 478 | list_del(&line->list); |
---|