Commit b4cdc426 authored by Javier González's avatar Javier González Committed by Jens Axboe

lightnvm: pblk: prevent stall due to wb threshold

In order to respect mw_cuinits, pblk's write buffer maintains a
backpointer to protect data not yet persisted; when writing to the write
buffer, this backpointer defines a threshold that pblk's rate-limiter
enforces.

On small PU configurations, the following scenarios might take place: (i)
the threshold is larger than the write buffer and (ii) the threshold is
smaller than the write buffer, but larger than the maximun allowed
split bio - 256KB at this moment (Note that writes are not always
split - we only do this when we the size of the buffer is smaller
than the buffer). In both cases, pblk's rate-limiter prevents the I/O to
be written to the buffer, thus stalling.

This patch fixes the original backpointer implementation by considering
the threshold both on buffer creation and on the rate-limiters path,
when bio_split is triggered (case (ii) above).

Fixes: 766c8ceb ("lightnvm: pblk: guarantee that backpointer is respected on writer stall")
Signed-off-by: default avatarJavier González <javier@javigon.com>
Reviewed-by: default avatarHans Holmberg <hans.holmberg@cnexlabs.com>
Signed-off-by: default avatarMatias Bjørling <mb@lightnvm.io>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent aa8759d8
...@@ -45,10 +45,23 @@ void pblk_rb_free(struct pblk_rb *rb) ...@@ -45,10 +45,23 @@ void pblk_rb_free(struct pblk_rb *rb)
/* /*
* pblk_rb_calculate_size -- calculate the size of the write buffer * pblk_rb_calculate_size -- calculate the size of the write buffer
*/ */
static unsigned int pblk_rb_calculate_size(unsigned int nr_entries) static unsigned int pblk_rb_calculate_size(unsigned int nr_entries,
unsigned int threshold)
{ {
/* Alloc a write buffer that can at least fit 128 entries */ unsigned int thr_sz = 1 << (get_count_order(threshold + NVM_MAX_VLBA));
return (1 << max(get_count_order(nr_entries), 7)); unsigned int max_sz = max(thr_sz, nr_entries);
unsigned int max_io;
/* Alloc a write buffer that can (i) fit at least two split bios
* (considering max I/O size NVM_MAX_VLBA, and (ii) guarantee that the
* threshold will be respected
*/
max_io = (1 << max((int)(get_count_order(max_sz)),
(int)(get_count_order(NVM_MAX_VLBA << 1))));
if ((threshold + NVM_MAX_VLBA) >= max_io)
max_io <<= 1;
return max_io;
} }
/* /*
...@@ -67,12 +80,12 @@ int pblk_rb_init(struct pblk_rb *rb, unsigned int size, unsigned int threshold, ...@@ -67,12 +80,12 @@ int pblk_rb_init(struct pblk_rb *rb, unsigned int size, unsigned int threshold,
unsigned int alloc_order, order, iter; unsigned int alloc_order, order, iter;
unsigned int nr_entries; unsigned int nr_entries;
nr_entries = pblk_rb_calculate_size(size); nr_entries = pblk_rb_calculate_size(size, threshold);
entries = vzalloc(array_size(nr_entries, sizeof(struct pblk_rb_entry))); entries = vzalloc(array_size(nr_entries, sizeof(struct pblk_rb_entry)));
if (!entries) if (!entries)
return -ENOMEM; return -ENOMEM;
power_size = get_count_order(size); power_size = get_count_order(nr_entries);
power_seg_sz = get_count_order(seg_size); power_seg_sz = get_count_order(seg_size);
down_write(&pblk_rb_lock); down_write(&pblk_rb_lock);
...@@ -149,7 +162,7 @@ int pblk_rb_init(struct pblk_rb *rb, unsigned int size, unsigned int threshold, ...@@ -149,7 +162,7 @@ int pblk_rb_init(struct pblk_rb *rb, unsigned int size, unsigned int threshold,
* Initialize rate-limiter, which controls access to the write buffer * Initialize rate-limiter, which controls access to the write buffer
* by user and GC I/O * by user and GC I/O
*/ */
pblk_rl_init(&pblk->rl, rb->nr_entries); pblk_rl_init(&pblk->rl, rb->nr_entries, threshold);
return 0; return 0;
} }
......
...@@ -207,7 +207,7 @@ void pblk_rl_free(struct pblk_rl *rl) ...@@ -207,7 +207,7 @@ void pblk_rl_free(struct pblk_rl *rl)
del_timer(&rl->u_timer); del_timer(&rl->u_timer);
} }
void pblk_rl_init(struct pblk_rl *rl, int budget) void pblk_rl_init(struct pblk_rl *rl, int budget, int threshold)
{ {
struct pblk *pblk = container_of(rl, struct pblk, rl); struct pblk *pblk = container_of(rl, struct pblk, rl);
struct nvm_tgt_dev *dev = pblk->dev; struct nvm_tgt_dev *dev = pblk->dev;
...@@ -217,7 +217,6 @@ void pblk_rl_init(struct pblk_rl *rl, int budget) ...@@ -217,7 +217,6 @@ void pblk_rl_init(struct pblk_rl *rl, int budget)
int sec_meta, blk_meta; int sec_meta, blk_meta;
unsigned int rb_windows; unsigned int rb_windows;
/* Consider sectors used for metadata */ /* Consider sectors used for metadata */
sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines; sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines;
blk_meta = DIV_ROUND_UP(sec_meta, geo->clba); blk_meta = DIV_ROUND_UP(sec_meta, geo->clba);
...@@ -234,7 +233,7 @@ void pblk_rl_init(struct pblk_rl *rl, int budget) ...@@ -234,7 +233,7 @@ void pblk_rl_init(struct pblk_rl *rl, int budget)
/* To start with, all buffer is available to user I/O writers */ /* To start with, all buffer is available to user I/O writers */
rl->rb_budget = budget; rl->rb_budget = budget;
rl->rb_user_max = budget; rl->rb_user_max = budget;
rl->rb_max_io = budget >> 1; rl->rb_max_io = threshold ? (budget - threshold) : (budget - 1);
rl->rb_gc_max = 0; rl->rb_gc_max = 0;
rl->rb_state = PBLK_RL_HIGH; rl->rb_state = PBLK_RL_HIGH;
......
...@@ -924,7 +924,7 @@ int pblk_gc_sysfs_force(struct pblk *pblk, int force); ...@@ -924,7 +924,7 @@ int pblk_gc_sysfs_force(struct pblk *pblk, int force);
/* /*
* pblk rate limiter * pblk rate limiter
*/ */
void pblk_rl_init(struct pblk_rl *rl, int budget); void pblk_rl_init(struct pblk_rl *rl, int budget, int threshold);
void pblk_rl_free(struct pblk_rl *rl); void pblk_rl_free(struct pblk_rl *rl);
void pblk_rl_update_rates(struct pblk_rl *rl); void pblk_rl_update_rates(struct pblk_rl *rl);
int pblk_rl_high_thrs(struct pblk_rl *rl); int pblk_rl_high_thrs(struct pblk_rl *rl);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment