Skip to content

Commit 766c8ce

Browse files
javigonaxboe
authored andcommitted
lightnvm: pblk: guarantee that backpointer is respected on writer stall
pblk's write buffer must guarantee that it respects the device's constrains for reads (i.e., mw_cunits). This is done by maintaining a backpointer that updates the L2P table as entries wrap up, making them point to the media instead of pointing to the write buffer. This mechanism can race in case that the write thread stalls, as the write pointer will protect the last written entry, thus disregarding the read constrains. This patch adds an extra check on wrap up, making sure that the threshold is respected at all times, preventing new entries to overwrite committed data, also in case of write thread stall. Reported-by: Heiner Litz <hlitz@ucsc.edu> Signed-off-by: Javier González <javier@cnexlabs.com> Reviewed-by: Heiner Litz <hlitz@ucsc.edu> Signed-off-by: Matias Bjørling <mb@lightnvm.io> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 8a57fc3 commit 766c8ce

File tree

3 files changed

+17
-5
lines changed

3 files changed

+17
-5
lines changed

drivers/lightnvm/pblk-init.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,9 @@ static int pblk_rwb_init(struct pblk *pblk)
193193
struct nvm_tgt_dev *dev = pblk->dev;
194194
struct nvm_geo *geo = &dev->geo;
195195
unsigned long buffer_size;
196-
int pgs_in_buffer;
196+
int pgs_in_buffer, threshold;
197197

198+
threshold = geo->mw_cunits * geo->all_luns;
198199
pgs_in_buffer = (max(geo->mw_cunits, geo->ws_opt) + geo->ws_opt)
199200
* geo->all_luns;
200201

@@ -203,7 +204,7 @@ static int pblk_rwb_init(struct pblk *pblk)
203204
else
204205
buffer_size = pgs_in_buffer;
205206

206-
return pblk_rb_init(&pblk->rwb, buffer_size, geo->csecs);
207+
return pblk_rb_init(&pblk->rwb, buffer_size, threshold, geo->csecs);
207208
}
208209

209210
/* Minimum pages needed within a lun */

drivers/lightnvm/pblk-rb.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ static unsigned int pblk_rb_calculate_size(unsigned int nr_entries)
5656
* allocated and their size must be a power of two
5757
* (Documentation/core-api/circular-buffers.rst)
5858
*/
59-
int pblk_rb_init(struct pblk_rb *rb, unsigned int size, unsigned int seg_size)
59+
int pblk_rb_init(struct pblk_rb *rb, unsigned int size, unsigned int threshold,
60+
unsigned int seg_size)
6061
{
6162
struct pblk *pblk = container_of(rb, struct pblk, rwb);
6263
struct pblk_rb_entry *entries;
@@ -79,6 +80,7 @@ int pblk_rb_init(struct pblk_rb *rb, unsigned int size, unsigned int seg_size)
7980
rb->seg_size = (1 << power_seg_sz);
8081
rb->nr_entries = (1 << power_size);
8182
rb->mem = rb->subm = rb->sync = rb->l2p_update = 0;
83+
rb->back_thres = threshold;
8284
rb->flush_point = EMPTY_ENTRY;
8385

8486
spin_lock_init(&rb->w_lock);
@@ -404,11 +406,14 @@ static int __pblk_rb_may_write(struct pblk_rb *rb, unsigned int nr_entries,
404406
{
405407
unsigned int mem;
406408
unsigned int sync;
409+
unsigned int threshold;
407410

408411
sync = READ_ONCE(rb->sync);
409412
mem = READ_ONCE(rb->mem);
410413

411-
if (pblk_rb_ring_space(rb, mem, sync, rb->nr_entries) < nr_entries)
414+
threshold = nr_entries + rb->back_thres;
415+
416+
if (pblk_rb_ring_space(rb, mem, sync, rb->nr_entries) < threshold)
412417
return 0;
413418

414419
if (pblk_rb_update_l2p(rb, nr_entries, mem, sync))

drivers/lightnvm/pblk.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ struct pblk_rb {
203203
* will be 4KB
204204
*/
205205

206+
unsigned int back_thres; /* Threshold that shall be maintained by
207+
* the backpointer in order to respect
208+
* geo->mw_cunits on a per chunk basis
209+
*/
210+
206211
struct list_head pages; /* List of data pages */
207212

208213
spinlock_t w_lock; /* Write lock */
@@ -734,7 +739,8 @@ struct pblk_line_ws {
734739
/*
735740
* pblk ring buffer operations
736741
*/
737-
int pblk_rb_init(struct pblk_rb *rb, unsigned int size, unsigned int seg_sz);
742+
int pblk_rb_init(struct pblk_rb *rb, unsigned int size, unsigned int threshold,
743+
unsigned int seg_sz);
738744
int pblk_rb_may_write_user(struct pblk_rb *rb, struct bio *bio,
739745
unsigned int nr_entries, unsigned int *pos);
740746
int pblk_rb_may_write_gc(struct pblk_rb *rb, unsigned int nr_entries,

0 commit comments

Comments
 (0)