aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier González <javier@cnexlabs.com>2017-10-13 08:46:07 -0400
committerJens Axboe <axboe@kernel.dk>2017-10-13 10:34:57 -0400
commitb84ae4a8b883b96b95fff0e3979ff2c65bbf96b0 (patch)
tree6f53ea3c0f6d9afd67e3e86354197467a9e495da
parentbd432417681a224d9fa4a9d43be7d4edc82135b2 (diff)
lightnvm: pblk: simplify work_queue mempool
In pblk, we have a mempool to allocate a generic structure that we pass along workqueues. This is heavily used in the GC path in order to have enough inflight reads and fully utilize the GC bandwidth. However, the current GC path copies data to the host memory and puts it back into the write buffer. This requires a vmalloc allocation for the data and a memory copy. Thus, guaranteeing the allocation by using a mempool for the structure in itself does not give us much. Until we implement support for vector copy to avoid moving data through the host, just allocate the workqueue structure using kmalloc. This allows us to have a much smaller mempool. Reported-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Javier González <javier@cnexlabs.com> Signed-off-by: Matias Bjørling <m@bjorling.me> Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--drivers/lightnvm/pblk-core.c13
-rw-r--r--drivers/lightnvm/pblk-gc.c32
-rw-r--r--drivers/lightnvm/pblk-init.c32
-rw-r--r--drivers/lightnvm/pblk-write.c4
-rw-r--r--drivers/lightnvm/pblk.h11
5 files changed, 47 insertions, 45 deletions
diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index f5fbb9a46784..b92532211866 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -33,7 +33,8 @@ static void pblk_mark_bb(struct pblk *pblk, struct pblk_line *line,
33 pr_err("pblk: attempted to erase bb: line:%d, pos:%d\n", 33 pr_err("pblk: attempted to erase bb: line:%d, pos:%d\n",
34 line->id, pos); 34 line->id, pos);
35 35
36 pblk_line_run_ws(pblk, NULL, ppa, pblk_line_mark_bb, pblk->bb_wq); 36 pblk_gen_run_ws(pblk, NULL, ppa, pblk_line_mark_bb,
37 GFP_ATOMIC, pblk->bb_wq);
37} 38}
38 39
39static void __pblk_end_io_erase(struct pblk *pblk, struct nvm_rq *rqd) 40static void __pblk_end_io_erase(struct pblk *pblk, struct nvm_rq *rqd)
@@ -1623,7 +1624,7 @@ void pblk_line_close_ws(struct work_struct *work)
1623 struct pblk_line *line = line_ws->line; 1624 struct pblk_line *line = line_ws->line;
1624 1625
1625 pblk_line_close(pblk, line); 1626 pblk_line_close(pblk, line);
1626 mempool_free(line_ws, pblk->line_ws_pool); 1627 mempool_free(line_ws, pblk->gen_ws_pool);
1627} 1628}
1628 1629
1629void pblk_line_mark_bb(struct work_struct *work) 1630void pblk_line_mark_bb(struct work_struct *work)
@@ -1648,16 +1649,16 @@ void pblk_line_mark_bb(struct work_struct *work)
1648 } 1649 }
1649 1650
1650 kfree(ppa); 1651 kfree(ppa);
1651 mempool_free(line_ws, pblk->line_ws_pool); 1652 mempool_free(line_ws, pblk->gen_ws_pool);
1652} 1653}
1653 1654
1654void pblk_line_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv, 1655void pblk_gen_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv,
1655 void (*work)(struct work_struct *), 1656 void (*work)(struct work_struct *), gfp_t gfp_mask,
1656 struct workqueue_struct *wq) 1657 struct workqueue_struct *wq)
1657{ 1658{
1658 struct pblk_line_ws *line_ws; 1659 struct pblk_line_ws *line_ws;
1659 1660
1660 line_ws = mempool_alloc(pblk->line_ws_pool, GFP_ATOMIC); 1661 line_ws = mempool_alloc(pblk->gen_ws_pool, gfp_mask);
1661 if (!line_ws) 1662 if (!line_ws)
1662 return; 1663 return;
1663 1664
diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c
index 6090d28f7995..f163829ecca8 100644
--- a/drivers/lightnvm/pblk-gc.c
+++ b/drivers/lightnvm/pblk-gc.c
@@ -136,12 +136,12 @@ static void pblk_put_line_back(struct pblk *pblk, struct pblk_line *line)
136 136
137static void pblk_gc_line_ws(struct work_struct *work) 137static void pblk_gc_line_ws(struct work_struct *work)
138{ 138{
139 struct pblk_line_ws *line_rq_ws = container_of(work, 139 struct pblk_line_ws *gc_rq_ws = container_of(work,
140 struct pblk_line_ws, ws); 140 struct pblk_line_ws, ws);
141 struct pblk *pblk = line_rq_ws->pblk; 141 struct pblk *pblk = gc_rq_ws->pblk;
142 struct pblk_gc *gc = &pblk->gc; 142 struct pblk_gc *gc = &pblk->gc;
143 struct pblk_line *line = line_rq_ws->line; 143 struct pblk_line *line = gc_rq_ws->line;
144 struct pblk_gc_rq *gc_rq = line_rq_ws->priv; 144 struct pblk_gc_rq *gc_rq = gc_rq_ws->priv;
145 145
146 up(&gc->gc_sem); 146 up(&gc->gc_sem);
147 147
@@ -151,7 +151,7 @@ static void pblk_gc_line_ws(struct work_struct *work)
151 gc_rq->nr_secs); 151 gc_rq->nr_secs);
152 } 152 }
153 153
154 mempool_free(line_rq_ws, pblk->line_ws_pool); 154 kfree(gc_rq_ws);
155} 155}
156 156
157static void pblk_gc_line_prepare_ws(struct work_struct *work) 157static void pblk_gc_line_prepare_ws(struct work_struct *work)
@@ -164,7 +164,7 @@ static void pblk_gc_line_prepare_ws(struct work_struct *work)
164 struct pblk_line_meta *lm = &pblk->lm; 164 struct pblk_line_meta *lm = &pblk->lm;
165 struct pblk_gc *gc = &pblk->gc; 165 struct pblk_gc *gc = &pblk->gc;
166 struct line_emeta *emeta_buf; 166 struct line_emeta *emeta_buf;
167 struct pblk_line_ws *line_rq_ws; 167 struct pblk_line_ws *gc_rq_ws;
168 struct pblk_gc_rq *gc_rq; 168 struct pblk_gc_rq *gc_rq;
169 __le64 *lba_list; 169 __le64 *lba_list;
170 int sec_left, nr_secs, bit; 170 int sec_left, nr_secs, bit;
@@ -223,19 +223,19 @@ next_rq:
223 gc_rq->nr_secs = nr_secs; 223 gc_rq->nr_secs = nr_secs;
224 gc_rq->line = line; 224 gc_rq->line = line;
225 225
226 line_rq_ws = mempool_alloc(pblk->line_ws_pool, GFP_KERNEL); 226 gc_rq_ws = kmalloc(sizeof(struct pblk_line_ws), GFP_KERNEL);
227 if (!line_rq_ws) 227 if (!gc_rq_ws)
228 goto fail_free_gc_rq; 228 goto fail_free_gc_rq;
229 229
230 line_rq_ws->pblk = pblk; 230 gc_rq_ws->pblk = pblk;
231 line_rq_ws->line = line; 231 gc_rq_ws->line = line;
232 line_rq_ws->priv = gc_rq; 232 gc_rq_ws->priv = gc_rq;
233 233
234 down(&gc->gc_sem); 234 down(&gc->gc_sem);
235 kref_get(&line->ref); 235 kref_get(&line->ref);
236 236
237 INIT_WORK(&line_rq_ws->ws, pblk_gc_line_ws); 237 INIT_WORK(&gc_rq_ws->ws, pblk_gc_line_ws);
238 queue_work(gc->gc_line_reader_wq, &line_rq_ws->ws); 238 queue_work(gc->gc_line_reader_wq, &gc_rq_ws->ws);
239 239
240 sec_left -= nr_secs; 240 sec_left -= nr_secs;
241 if (sec_left > 0) 241 if (sec_left > 0)
@@ -243,7 +243,7 @@ next_rq:
243 243
244out: 244out:
245 pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); 245 pblk_mfree(emeta_buf, l_mg->emeta_alloc_type);
246 mempool_free(line_ws, pblk->line_ws_pool); 246 kfree(line_ws);
247 247
248 kref_put(&line->ref, pblk_line_put); 248 kref_put(&line->ref, pblk_line_put);
249 atomic_dec(&gc->inflight_gc); 249 atomic_dec(&gc->inflight_gc);
@@ -256,7 +256,7 @@ fail_free_emeta:
256 pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); 256 pblk_mfree(emeta_buf, l_mg->emeta_alloc_type);
257 pblk_put_line_back(pblk, line); 257 pblk_put_line_back(pblk, line);
258 kref_put(&line->ref, pblk_line_put); 258 kref_put(&line->ref, pblk_line_put);
259 mempool_free(line_ws, pblk->line_ws_pool); 259 kfree(line_ws);
260 atomic_dec(&gc->inflight_gc); 260 atomic_dec(&gc->inflight_gc);
261 261
262 pr_err("pblk: Failed to GC line %d\n", line->id); 262 pr_err("pblk: Failed to GC line %d\n", line->id);
@@ -269,7 +269,7 @@ static int pblk_gc_line(struct pblk *pblk, struct pblk_line *line)
269 269
270 pr_debug("pblk: line '%d' being reclaimed for GC\n", line->id); 270 pr_debug("pblk: line '%d' being reclaimed for GC\n", line->id);
271 271
272 line_ws = mempool_alloc(pblk->line_ws_pool, GFP_KERNEL); 272 line_ws = kmalloc(sizeof(struct pblk_line_ws), GFP_KERNEL);
273 if (!line_ws) 273 if (!line_ws)
274 return -ENOMEM; 274 return -ENOMEM;
275 275
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index 7b1f29c71338..340552253580 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -20,7 +20,7 @@
20 20
21#include "pblk.h" 21#include "pblk.h"
22 22
23static struct kmem_cache *pblk_blk_ws_cache, *pblk_rec_cache, *pblk_g_rq_cache, 23static struct kmem_cache *pblk_ws_cache, *pblk_rec_cache, *pblk_g_rq_cache,
24 *pblk_w_rq_cache, *pblk_line_meta_cache; 24 *pblk_w_rq_cache, *pblk_line_meta_cache;
25static DECLARE_RWSEM(pblk_lock); 25static DECLARE_RWSEM(pblk_lock);
26struct bio_set *pblk_bio_set; 26struct bio_set *pblk_bio_set;
@@ -184,9 +184,9 @@ static int pblk_init_global_caches(struct pblk *pblk)
184 char cache_name[PBLK_CACHE_NAME_LEN]; 184 char cache_name[PBLK_CACHE_NAME_LEN];
185 185
186 down_write(&pblk_lock); 186 down_write(&pblk_lock);
187 pblk_blk_ws_cache = kmem_cache_create("pblk_blk_ws", 187 pblk_ws_cache = kmem_cache_create("pblk_blk_ws",
188 sizeof(struct pblk_line_ws), 0, 0, NULL); 188 sizeof(struct pblk_line_ws), 0, 0, NULL);
189 if (!pblk_blk_ws_cache) { 189 if (!pblk_ws_cache) {
190 up_write(&pblk_lock); 190 up_write(&pblk_lock);
191 return -ENOMEM; 191 return -ENOMEM;
192 } 192 }
@@ -194,7 +194,7 @@ static int pblk_init_global_caches(struct pblk *pblk)
194 pblk_rec_cache = kmem_cache_create("pblk_rec", 194 pblk_rec_cache = kmem_cache_create("pblk_rec",
195 sizeof(struct pblk_rec_ctx), 0, 0, NULL); 195 sizeof(struct pblk_rec_ctx), 0, 0, NULL);
196 if (!pblk_rec_cache) { 196 if (!pblk_rec_cache) {
197 kmem_cache_destroy(pblk_blk_ws_cache); 197 kmem_cache_destroy(pblk_ws_cache);
198 up_write(&pblk_lock); 198 up_write(&pblk_lock);
199 return -ENOMEM; 199 return -ENOMEM;
200 } 200 }
@@ -202,7 +202,7 @@ static int pblk_init_global_caches(struct pblk *pblk)
202 pblk_g_rq_cache = kmem_cache_create("pblk_g_rq", pblk_g_rq_size, 202 pblk_g_rq_cache = kmem_cache_create("pblk_g_rq", pblk_g_rq_size,
203 0, 0, NULL); 203 0, 0, NULL);
204 if (!pblk_g_rq_cache) { 204 if (!pblk_g_rq_cache) {
205 kmem_cache_destroy(pblk_blk_ws_cache); 205 kmem_cache_destroy(pblk_ws_cache);
206 kmem_cache_destroy(pblk_rec_cache); 206 kmem_cache_destroy(pblk_rec_cache);
207 up_write(&pblk_lock); 207 up_write(&pblk_lock);
208 return -ENOMEM; 208 return -ENOMEM;
@@ -211,7 +211,7 @@ static int pblk_init_global_caches(struct pblk *pblk)
211 pblk_w_rq_cache = kmem_cache_create("pblk_w_rq", pblk_w_rq_size, 211 pblk_w_rq_cache = kmem_cache_create("pblk_w_rq", pblk_w_rq_size,
212 0, 0, NULL); 212 0, 0, NULL);
213 if (!pblk_w_rq_cache) { 213 if (!pblk_w_rq_cache) {
214 kmem_cache_destroy(pblk_blk_ws_cache); 214 kmem_cache_destroy(pblk_ws_cache);
215 kmem_cache_destroy(pblk_rec_cache); 215 kmem_cache_destroy(pblk_rec_cache);
216 kmem_cache_destroy(pblk_g_rq_cache); 216 kmem_cache_destroy(pblk_g_rq_cache);
217 up_write(&pblk_lock); 217 up_write(&pblk_lock);
@@ -223,7 +223,7 @@ static int pblk_init_global_caches(struct pblk *pblk)
223 pblk_line_meta_cache = kmem_cache_create(cache_name, 223 pblk_line_meta_cache = kmem_cache_create(cache_name,
224 pblk->lm.sec_bitmap_len, 0, 0, NULL); 224 pblk->lm.sec_bitmap_len, 0, 0, NULL);
225 if (!pblk_line_meta_cache) { 225 if (!pblk_line_meta_cache) {
226 kmem_cache_destroy(pblk_blk_ws_cache); 226 kmem_cache_destroy(pblk_ws_cache);
227 kmem_cache_destroy(pblk_rec_cache); 227 kmem_cache_destroy(pblk_rec_cache);
228 kmem_cache_destroy(pblk_g_rq_cache); 228 kmem_cache_destroy(pblk_g_rq_cache);
229 kmem_cache_destroy(pblk_w_rq_cache); 229 kmem_cache_destroy(pblk_w_rq_cache);
@@ -246,20 +246,20 @@ static int pblk_core_init(struct pblk *pblk)
246 if (pblk_init_global_caches(pblk)) 246 if (pblk_init_global_caches(pblk))
247 return -ENOMEM; 247 return -ENOMEM;
248 248
249 /* internal bios can be at most the sectors signaled by the device. */ 249 /* Internal bios can be at most the sectors signaled by the device. */
250 pblk->page_bio_pool = mempool_create_page_pool(nvm_max_phys_sects(dev), 250 pblk->page_bio_pool = mempool_create_page_pool(nvm_max_phys_sects(dev),
251 0); 251 0);
252 if (!pblk->page_bio_pool) 252 if (!pblk->page_bio_pool)
253 return -ENOMEM; 253 return -ENOMEM;
254 254
255 pblk->line_ws_pool = mempool_create_slab_pool(PBLK_WS_POOL_SIZE, 255 pblk->gen_ws_pool = mempool_create_slab_pool(PBLK_GEN_WS_POOL_SIZE,
256 pblk_blk_ws_cache); 256 pblk_ws_cache);
257 if (!pblk->line_ws_pool) 257 if (!pblk->gen_ws_pool)
258 goto free_page_bio_pool; 258 goto free_page_bio_pool;
259 259
260 pblk->rec_pool = mempool_create_slab_pool(geo->nr_luns, pblk_rec_cache); 260 pblk->rec_pool = mempool_create_slab_pool(geo->nr_luns, pblk_rec_cache);
261 if (!pblk->rec_pool) 261 if (!pblk->rec_pool)
262 goto free_blk_ws_pool; 262 goto free_gen_ws_pool;
263 263
264 pblk->g_rq_pool = mempool_create_slab_pool(PBLK_READ_REQ_POOL_SIZE, 264 pblk->g_rq_pool = mempool_create_slab_pool(PBLK_READ_REQ_POOL_SIZE,
265 pblk_g_rq_cache); 265 pblk_g_rq_cache);
@@ -308,8 +308,8 @@ free_g_rq_pool:
308 mempool_destroy(pblk->g_rq_pool); 308 mempool_destroy(pblk->g_rq_pool);
309free_rec_pool: 309free_rec_pool:
310 mempool_destroy(pblk->rec_pool); 310 mempool_destroy(pblk->rec_pool);
311free_blk_ws_pool: 311free_gen_ws_pool:
312 mempool_destroy(pblk->line_ws_pool); 312 mempool_destroy(pblk->gen_ws_pool);
313free_page_bio_pool: 313free_page_bio_pool:
314 mempool_destroy(pblk->page_bio_pool); 314 mempool_destroy(pblk->page_bio_pool);
315 return -ENOMEM; 315 return -ENOMEM;
@@ -324,13 +324,13 @@ static void pblk_core_free(struct pblk *pblk)
324 destroy_workqueue(pblk->bb_wq); 324 destroy_workqueue(pblk->bb_wq);
325 325
326 mempool_destroy(pblk->page_bio_pool); 326 mempool_destroy(pblk->page_bio_pool);
327 mempool_destroy(pblk->line_ws_pool); 327 mempool_destroy(pblk->gen_ws_pool);
328 mempool_destroy(pblk->rec_pool); 328 mempool_destroy(pblk->rec_pool);
329 mempool_destroy(pblk->g_rq_pool); 329 mempool_destroy(pblk->g_rq_pool);
330 mempool_destroy(pblk->w_rq_pool); 330 mempool_destroy(pblk->w_rq_pool);
331 mempool_destroy(pblk->line_meta_pool); 331 mempool_destroy(pblk->line_meta_pool);
332 332
333 kmem_cache_destroy(pblk_blk_ws_cache); 333 kmem_cache_destroy(pblk_ws_cache);
334 kmem_cache_destroy(pblk_rec_cache); 334 kmem_cache_destroy(pblk_rec_cache);
335 kmem_cache_destroy(pblk_g_rq_cache); 335 kmem_cache_destroy(pblk_g_rq_cache);
336 kmem_cache_destroy(pblk_w_rq_cache); 336 kmem_cache_destroy(pblk_w_rq_cache);
diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c
index d82ca8bd8390..c73b17bca06b 100644
--- a/drivers/lightnvm/pblk-write.c
+++ b/drivers/lightnvm/pblk-write.c
@@ -198,8 +198,8 @@ static void pblk_end_io_write_meta(struct nvm_rq *rqd)
198 198
199 sync = atomic_add_return(rqd->nr_ppas, &emeta->sync); 199 sync = atomic_add_return(rqd->nr_ppas, &emeta->sync);
200 if (sync == emeta->nr_entries) 200 if (sync == emeta->nr_entries)
201 pblk_line_run_ws(pblk, line, NULL, pblk_line_close_ws, 201 pblk_gen_run_ws(pblk, line, NULL, pblk_line_close_ws,
202 pblk->close_wq); 202 GFP_ATOMIC, pblk->close_wq);
203 203
204 bio_put(rqd->bio); 204 bio_put(rqd->bio);
205 nvm_dev_dma_free(dev->parent, rqd->meta_list, rqd->dma_meta_list); 205 nvm_dev_dma_free(dev->parent, rqd->meta_list, rqd->dma_meta_list);
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index 229f6020ad8a..efaa781abb06 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -40,7 +40,6 @@
40#define PBLK_MAX_REQ_ADDRS (64) 40#define PBLK_MAX_REQ_ADDRS (64)
41#define PBLK_MAX_REQ_ADDRS_PW (6) 41#define PBLK_MAX_REQ_ADDRS_PW (6)
42 42
43#define PBLK_WS_POOL_SIZE (128)
44#define PBLK_META_POOL_SIZE (128) 43#define PBLK_META_POOL_SIZE (128)
45#define PBLK_READ_REQ_POOL_SIZE (1024) 44#define PBLK_READ_REQ_POOL_SIZE (1024)
46 45
@@ -61,6 +60,8 @@
61 60
62#define ERASE 2 /* READ = 0, WRITE = 1 */ 61#define ERASE 2 /* READ = 0, WRITE = 1 */
63 62
63#define PBLK_GEN_WS_POOL_SIZE (2)
64
64enum { 65enum {
65 /* IO Types */ 66 /* IO Types */
66 PBLK_IOTYPE_USER = 1 << 0, 67 PBLK_IOTYPE_USER = 1 << 0,
@@ -621,7 +622,7 @@ struct pblk {
621 struct list_head compl_list; 622 struct list_head compl_list;
622 623
623 mempool_t *page_bio_pool; 624 mempool_t *page_bio_pool;
624 mempool_t *line_ws_pool; 625 mempool_t *gen_ws_pool;
625 mempool_t *rec_pool; 626 mempool_t *rec_pool;
626 mempool_t *g_rq_pool; 627 mempool_t *g_rq_pool;
627 mempool_t *w_rq_pool; 628 mempool_t *w_rq_pool;
@@ -725,9 +726,9 @@ void pblk_line_close_meta_sync(struct pblk *pblk);
725void pblk_line_close_ws(struct work_struct *work); 726void pblk_line_close_ws(struct work_struct *work);
726void pblk_pipeline_stop(struct pblk *pblk); 727void pblk_pipeline_stop(struct pblk *pblk);
727void pblk_line_mark_bb(struct work_struct *work); 728void pblk_line_mark_bb(struct work_struct *work);
728void pblk_line_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv, 729void pblk_gen_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv,
729 void (*work)(struct work_struct *), 730 void (*work)(struct work_struct *), gfp_t gfp_mask,
730 struct workqueue_struct *wq); 731 struct workqueue_struct *wq);
731u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line); 732u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line);
732int pblk_line_read_smeta(struct pblk *pblk, struct pblk_line *line); 733int pblk_line_read_smeta(struct pblk *pblk, struct pblk_line *line);
733int pblk_line_read_emeta(struct pblk *pblk, struct pblk_line *line, 734int pblk_line_read_emeta(struct pblk *pblk, struct pblk_line *line,