Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+19 −6
Original line number Original line Diff line number Diff line
@@ -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,
	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,
	 * 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;
}
}
+2 −3
Original line number Original line Diff line number Diff line
@@ -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)
	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)
	/* 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;


+1 −1
Original line number Original line Diff line number Diff line
@@ -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);