mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	lightnvm: pblk: set conservative threshold for user writes
In a worst-case scenario (random writes), OP% of sectors in each line will be invalid, and we will then need to move data out of 100/OP% lines to free a single line. So, to prevent the possibility of running out of lines, temporarily block user writes when there is less than 100/OP% free lines. Also ensure that pblk creation does not produce instances with insufficient over provisioning. Insufficient over-provising is not a problem on real hardware, but often an issue when running QEMU simulations (with few lines). 100 lines is enough to create a sane instance with the standard (11%) over provisioning. Signed-off-by: Hans Holmberg <hans.holmberg@cnexlabs.com> Reviewed-by: Javier González <javier@javigon.com> Signed-off-by: Matias Bjørling <mb@lightnvm.io> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
		
							parent
							
								
									525f7bb2c9
								
							
						
					
					
						commit
						3bcebc5bac
					
				
					 3 changed files with 44 additions and 13 deletions
				
			
		|  | @ -635,7 +635,7 @@ static unsigned int calc_emeta_len(struct pblk *pblk) | |||
| 	return (lm->emeta_len[1] + lm->emeta_len[2] + lm->emeta_len[3]); | ||||
| } | ||||
| 
 | ||||
| static void pblk_set_provision(struct pblk *pblk, long nr_free_blks) | ||||
| static int pblk_set_provision(struct pblk *pblk, int nr_free_chks) | ||||
| { | ||||
| 	struct nvm_tgt_dev *dev = pblk->dev; | ||||
| 	struct pblk_line_mgmt *l_mg = &pblk->l_mg; | ||||
|  | @ -643,23 +643,41 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks) | |||
| 	struct nvm_geo *geo = &dev->geo; | ||||
| 	sector_t provisioned; | ||||
| 	int sec_meta, blk_meta; | ||||
| 	int minimum; | ||||
| 
 | ||||
| 	if (geo->op == NVM_TARGET_DEFAULT_OP) | ||||
| 		pblk->op = PBLK_DEFAULT_OP; | ||||
| 	else | ||||
| 		pblk->op = geo->op; | ||||
| 
 | ||||
| 	provisioned = nr_free_blks; | ||||
| 	minimum = pblk_get_min_chks(pblk); | ||||
| 	provisioned = nr_free_chks; | ||||
| 	provisioned *= (100 - pblk->op); | ||||
| 	sector_div(provisioned, 100); | ||||
| 
 | ||||
| 	pblk->op_blks = nr_free_blks - provisioned; | ||||
| 	if ((nr_free_chks - provisioned) < minimum) { | ||||
| 		if (geo->op != NVM_TARGET_DEFAULT_OP) { | ||||
| 			pblk_err(pblk, "OP too small to create a sane instance\n"); | ||||
| 			return -EINTR; | ||||
| 		} | ||||
| 
 | ||||
| 		/* If the user did not specify an OP value, and PBLK_DEFAULT_OP
 | ||||
| 		 * is not enough, calculate and set sane value | ||||
| 		 */ | ||||
| 
 | ||||
| 		provisioned = nr_free_chks - minimum; | ||||
| 		pblk->op =  (100 * minimum) / nr_free_chks; | ||||
| 		pblk_info(pblk, "Default OP insufficient, adjusting OP to %d\n", | ||||
| 				pblk->op); | ||||
| 	} | ||||
| 
 | ||||
| 	pblk->op_blks = nr_free_chks - provisioned; | ||||
| 
 | ||||
| 	/* Internally pblk manages all free blocks, but all calculations based
 | ||||
| 	 * on user capacity consider only provisioned blocks | ||||
| 	 */ | ||||
| 	pblk->rl.total_blocks = nr_free_blks; | ||||
| 	pblk->rl.nr_secs = nr_free_blks * geo->clba; | ||||
| 	pblk->rl.total_blocks = nr_free_chks; | ||||
| 	pblk->rl.nr_secs = nr_free_chks * geo->clba; | ||||
| 
 | ||||
| 	/* Consider sectors used for metadata */ | ||||
| 	sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines; | ||||
|  | @ -667,8 +685,10 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks) | |||
| 
 | ||||
| 	pblk->capacity = (provisioned - blk_meta) * geo->clba; | ||||
| 
 | ||||
| 	atomic_set(&pblk->rl.free_blocks, nr_free_blks); | ||||
| 	atomic_set(&pblk->rl.free_user_blocks, nr_free_blks); | ||||
| 	atomic_set(&pblk->rl.free_blocks, nr_free_chks); | ||||
| 	atomic_set(&pblk->rl.free_user_blocks, nr_free_chks); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int pblk_setup_line_meta_chk(struct pblk *pblk, struct pblk_line *line, | ||||
|  | @ -984,7 +1004,7 @@ static int pblk_lines_init(struct pblk *pblk) | |||
| 	struct pblk_line_mgmt *l_mg = &pblk->l_mg; | ||||
| 	struct pblk_line *line; | ||||
| 	void *chunk_meta; | ||||
| 	long nr_free_chks = 0; | ||||
| 	int nr_free_chks = 0; | ||||
| 	int i, ret; | ||||
| 
 | ||||
| 	ret = pblk_line_meta_init(pblk); | ||||
|  | @ -1031,7 +1051,9 @@ static int pblk_lines_init(struct pblk *pblk) | |||
| 		goto fail_free_lines; | ||||
| 	} | ||||
| 
 | ||||
| 	pblk_set_provision(pblk, nr_free_chks); | ||||
| 	ret = pblk_set_provision(pblk, nr_free_chks); | ||||
| 	if (ret) | ||||
| 		goto fail_free_lines; | ||||
| 
 | ||||
| 	vfree(chunk_meta); | ||||
| 	return 0; | ||||
|  |  | |||
|  | @ -214,11 +214,10 @@ void pblk_rl_init(struct pblk_rl *rl, int budget) | |||
| 	struct nvm_geo *geo = &dev->geo; | ||||
| 	struct pblk_line_mgmt *l_mg = &pblk->l_mg; | ||||
| 	struct pblk_line_meta *lm = &pblk->lm; | ||||
| 	int min_blocks = lm->blk_per_line * PBLK_GC_RSV_LINE; | ||||
| 	int sec_meta, blk_meta; | ||||
| 
 | ||||
| 	unsigned int rb_windows; | ||||
| 
 | ||||
| 
 | ||||
| 	/* Consider sectors used for metadata */ | ||||
| 	sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines; | ||||
| 	blk_meta = DIV_ROUND_UP(sec_meta, geo->clba); | ||||
|  | @ -226,7 +225,7 @@ void pblk_rl_init(struct pblk_rl *rl, int budget) | |||
| 	rl->high = pblk->op_blks - blk_meta - lm->blk_per_line; | ||||
| 	rl->high_pw = get_count_order(rl->high); | ||||
| 
 | ||||
| 	rl->rsv_blocks = min_blocks; | ||||
| 	rl->rsv_blocks = pblk_get_min_chks(pblk); | ||||
| 
 | ||||
| 	/* This will always be a power-of-2 */ | ||||
| 	rb_windows = budget / NVM_MAX_VLBA; | ||||
|  |  | |||
|  | @ -905,7 +905,6 @@ int pblk_recov_check_emeta(struct pblk *pblk, struct line_emeta *emeta); | |||
| #define PBLK_GC_MAX_READERS 8	/* Max number of outstanding GC reader jobs */ | ||||
| #define PBLK_GC_RQ_QD 128	/* Queue depth for inflight GC requests */ | ||||
| #define PBLK_GC_L_QD 4		/* Queue depth for inflight GC lines */ | ||||
| #define PBLK_GC_RSV_LINE 1	/* Reserved lines for GC */ | ||||
| 
 | ||||
| int pblk_gc_init(struct pblk *pblk); | ||||
| void pblk_gc_exit(struct pblk *pblk, bool graceful); | ||||
|  | @ -1370,4 +1369,15 @@ static inline char *pblk_disk_name(struct pblk *pblk) | |||
| 
 | ||||
| 	return disk->disk_name; | ||||
| } | ||||
| 
 | ||||
| static inline unsigned int pblk_get_min_chks(struct pblk *pblk) | ||||
| { | ||||
| 	struct pblk_line_meta *lm = &pblk->lm; | ||||
| 	/* In a worst-case scenario every line will have OP invalid sectors.
 | ||||
| 	 * We will then need a minimum of 1/OP lines to free up a single line | ||||
| 	 */ | ||||
| 
 | ||||
| 	return DIV_ROUND_UP(100, pblk->op) * lm->blk_per_line; | ||||
| 
 | ||||
| } | ||||
| #endif /* PBLK_H_ */ | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Hans Holmberg
						Hans Holmberg