diff options
Diffstat (limited to 'fs/ubifs/lpt_commit.c')
| -rw-r--r-- | fs/ubifs/lpt_commit.c | 275 | 
1 files changed, 166 insertions, 109 deletions
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c index 5c90dec5db0..45d4e96a6ba 100644 --- a/fs/ubifs/lpt_commit.c +++ b/fs/ubifs/lpt_commit.c @@ -27,8 +27,11 @@  #include <linux/crc16.h>  #include <linux/slab.h> +#include <linux/random.h>  #include "ubifs.h" +static int dbg_populate_lsave(struct ubifs_info *c); +  /**   * first_dirty_cnode - find first dirty cnode.   * @c: UBIFS file-system description object @@ -110,8 +113,8 @@ static int get_cnodes_to_commit(struct ubifs_info *c)  		return 0;  	cnt += 1;  	while (1) { -		ubifs_assert(!test_bit(COW_ZNODE, &cnode->flags)); -		__set_bit(COW_ZNODE, &cnode->flags); +		ubifs_assert(!test_bit(COW_CNODE, &cnode->flags)); +		__set_bit(COW_CNODE, &cnode->flags);  		cnext = next_dirty_cnode(cnode);  		if (!cnext) {  			cnode->cnext = c->lpt_cnext; @@ -317,11 +320,10 @@ static int layout_cnodes(struct ubifs_info *c)  	return 0;  no_space: -	ubifs_err("LPT out of space"); -	dbg_err("LPT out of space at LEB %d:%d needing %d, done_ltab %d, " -		"done_lsave %d", lnum, offs, len, done_ltab, done_lsave); -	dbg_dump_lpt_info(c); -	dbg_dump_lpt_lebs(c); +	ubifs_err("LPT out of space at LEB %d:%d needing %d, done_ltab %d, done_lsave %d", +		  lnum, offs, len, done_ltab, done_lsave); +	ubifs_dump_lpt_info(c); +	ubifs_dump_lpt_lebs(c);  	dump_stack();  	return err;  } @@ -414,7 +416,7 @@ static int write_cnodes(struct ubifs_info *c)  				alen = ALIGN(wlen, c->min_io_size);  				memset(buf + offs, 0xff, alen - wlen);  				err = ubifs_leb_write(c, lnum, buf + from, from, -						       alen, UBI_SHORTTERM); +						       alen);  				if (err)  					return err;  			} @@ -458,9 +460,9 @@ static int write_cnodes(struct ubifs_info *c)  		 * important.  		 */  		clear_bit(DIRTY_CNODE, &cnode->flags); -		smp_mb__before_clear_bit(); -		clear_bit(COW_ZNODE, &cnode->flags); -		smp_mb__after_clear_bit(); +		smp_mb__before_atomic(); +		clear_bit(COW_CNODE, &cnode->flags); +		smp_mb__after_atomic();  		offs += len;  		dbg_chk_lpt_sz(c, 1, len);  		cnode = cnode->cnext; @@ -472,8 +474,7 @@ static int write_cnodes(struct ubifs_info *c)  			wlen = offs - from;  			alen = ALIGN(wlen, c->min_io_size);  			memset(buf + offs, 0xff, alen - wlen); -			err = ubifs_leb_write(c, lnum, buf + from, from, alen, -					      UBI_SHORTTERM); +			err = ubifs_leb_write(c, lnum, buf + from, from, alen);  			if (err)  				return err;  			dbg_chk_lpt_sz(c, 2, c->leb_size - offs); @@ -499,8 +500,7 @@ static int write_cnodes(struct ubifs_info *c)  			wlen = offs - from;  			alen = ALIGN(wlen, c->min_io_size);  			memset(buf + offs, 0xff, alen - wlen); -			err = ubifs_leb_write(c, lnum, buf + from, from, alen, -					      UBI_SHORTTERM); +			err = ubifs_leb_write(c, lnum, buf + from, from, alen);  			if (err)  				return err;  			dbg_chk_lpt_sz(c, 2, c->leb_size - offs); @@ -524,7 +524,7 @@ static int write_cnodes(struct ubifs_info *c)  	wlen = offs - from;  	alen = ALIGN(wlen, c->min_io_size);  	memset(buf + offs, 0xff, alen - wlen); -	err = ubifs_leb_write(c, lnum, buf + from, from, alen, UBI_SHORTTERM); +	err = ubifs_leb_write(c, lnum, buf + from, from, alen);  	if (err)  		return err; @@ -545,11 +545,10 @@ static int write_cnodes(struct ubifs_info *c)  	return 0;  no_space: -	ubifs_err("LPT out of space mismatch"); -	dbg_err("LPT out of space mismatch at LEB %d:%d needing %d, done_ltab " -		"%d, done_lsave %d", lnum, offs, len, done_ltab, done_lsave); -	dbg_dump_lpt_info(c); -	dbg_dump_lpt_lebs(c); +	ubifs_err("LPT out of space mismatch at LEB %d:%d needing %d, done_ltab %d, done_lsave %d", +		  lnum, offs, len, done_ltab, done_lsave); +	ubifs_dump_lpt_info(c); +	ubifs_dump_lpt_lebs(c);  	dump_stack();  	return err;  } @@ -586,7 +585,7 @@ static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,  			if (nnode->nbranch[iip].lnum)  				break;  		} -       } while (iip >= UBIFS_LPT_FANOUT); +	} while (iip >= UBIFS_LPT_FANOUT);  	/* Go right */  	nnode = ubifs_get_nnode(c, nnode, iip); @@ -815,6 +814,10 @@ static void populate_lsave(struct ubifs_info *c)  		c->lpt_drty_flgs |= LSAVE_DIRTY;  		ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz);  	} + +	if (dbg_populate_lsave(c)) +		return; +  	list_for_each_entry(lprops, &c->empty_list, list) {  		c->lsave[cnt++] = lprops->lnum;  		if (cnt >= c->lsave_cnt) @@ -1150,11 +1153,11 @@ static int lpt_gc_lnum(struct ubifs_info *c, int lnum)  	void *buf = c->lpt_buf;  	dbg_lp("LEB %d", lnum); -	err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size); -	if (err) { -		ubifs_err("cannot read LEB %d, error %d", lnum, err); + +	err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1); +	if (err)  		return err; -	} +  	while (1) {  		if (!is_a_node(c, buf, len)) {  			int pad_len; @@ -1486,7 +1489,9 @@ void ubifs_lpt_free(struct ubifs_info *c, int wr_only)  	kfree(c->lpt_nod_buf);  } -#ifdef CONFIG_UBIFS_FS_DEBUG +/* + * Everything below is related to debugging. + */  /**   * dbg_is_all_ff - determine if a buffer contains only 0xFF bytes. @@ -1628,56 +1633,65 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)  {  	int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len;  	int ret; -	void *buf = c->dbg->buf; +	void *buf, *p; -	if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) +	if (!dbg_is_chk_lprops(c))  		return 0; -	dbg_lp("LEB %d", lnum); -	err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size); -	if (err) { -		dbg_msg("ubi_read failed, LEB %d, error %d", lnum, err); -		return err; +	buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL); +	if (!buf) { +		ubifs_err("cannot allocate memory for ltab checking"); +		return 0;  	} + +	dbg_lp("LEB %d", lnum); + +	err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1); +	if (err) +		goto out; +  	while (1) { -		if (!is_a_node(c, buf, len)) { +		if (!is_a_node(c, p, len)) {  			int i, pad_len; -			pad_len = get_pad_len(c, buf, len); +			pad_len = get_pad_len(c, p, len);  			if (pad_len) { -				buf += pad_len; +				p += pad_len;  				len -= pad_len;  				dirty += pad_len;  				continue;  			} -			if (!dbg_is_all_ff(buf, len)) { -				dbg_msg("invalid empty space in LEB %d at %d", -					lnum, c->leb_size - len); +			if (!dbg_is_all_ff(p, len)) { +				ubifs_err("invalid empty space in LEB %d at %d", +					  lnum, c->leb_size - len);  				err = -EINVAL;  			}  			i = lnum - c->lpt_first;  			if (len != c->ltab[i].free) { -				dbg_msg("invalid free space in LEB %d " -					"(free %d, expected %d)", -					lnum, len, c->ltab[i].free); +				ubifs_err("invalid free space in LEB %d (free %d, expected %d)", +					  lnum, len, c->ltab[i].free);  				err = -EINVAL;  			}  			if (dirty != c->ltab[i].dirty) { -				dbg_msg("invalid dirty space in LEB %d " -					"(dirty %d, expected %d)", -					lnum, dirty, c->ltab[i].dirty); +				ubifs_err("invalid dirty space in LEB %d (dirty %d, expected %d)", +					  lnum, dirty, c->ltab[i].dirty);  				err = -EINVAL;  			} -			return err; +			goto out;  		} -		node_type = get_lpt_node_type(c, buf, &node_num); +		node_type = get_lpt_node_type(c, p, &node_num);  		node_len = get_lpt_node_len(c, node_type);  		ret = dbg_is_node_dirty(c, node_type, lnum, c->leb_size - len);  		if (ret == 1)  			dirty += node_len; -		buf += node_len; +		p += node_len;  		len -= node_len;  	} + +	err = 0; +out: +	vfree(buf); +	return err;  }  /** @@ -1690,7 +1704,7 @@ int dbg_check_ltab(struct ubifs_info *c)  {  	int lnum, err, i, cnt; -	if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) +	if (!dbg_is_chk_lprops(c))  		return 0;  	/* Bring the entire tree into memory */ @@ -1713,7 +1727,7 @@ int dbg_check_ltab(struct ubifs_info *c)  	for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {  		err = dbg_check_ltab_lnum(c, lnum);  		if (err) { -			dbg_err("failed at LEB %d", lnum); +			ubifs_err("failed at LEB %d", lnum);  			return err;  		}  	} @@ -1733,7 +1747,7 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)  	long long free = 0;  	int i; -	if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) +	if (!dbg_is_chk_lprops(c))  		return 0;  	for (i = 0; i < c->lpt_lebs; i++) { @@ -1745,10 +1759,10 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)  			free += c->leb_size;  	}  	if (free < c->lpt_sz) { -		dbg_err("LPT space error: free %lld lpt_sz %lld", -			free, c->lpt_sz); -		dbg_dump_lpt_info(c); -		dbg_dump_lpt_lebs(c); +		ubifs_err("LPT space error: free %lld lpt_sz %lld", +			  free, c->lpt_sz); +		ubifs_dump_lpt_info(c); +		ubifs_dump_lpt_lebs(c);  		dump_stack();  		return -EINVAL;  	} @@ -1775,7 +1789,7 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)  	long long chk_lpt_sz, lpt_sz;  	int err = 0; -	if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) +	if (!dbg_is_chk_lprops(c))  		return 0;  	switch (action) { @@ -1785,13 +1799,13 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)  		d->chk_lpt_lebs = 0;  		d->chk_lpt_wastage = 0;  		if (c->dirty_pn_cnt > c->pnode_cnt) { -			dbg_err("dirty pnodes %d exceed max %d", -				c->dirty_pn_cnt, c->pnode_cnt); +			ubifs_err("dirty pnodes %d exceed max %d", +				  c->dirty_pn_cnt, c->pnode_cnt);  			err = -EINVAL;  		}  		if (c->dirty_nn_cnt > c->nnode_cnt) { -			dbg_err("dirty nnodes %d exceed max %d", -				c->dirty_nn_cnt, c->nnode_cnt); +			ubifs_err("dirty nnodes %d exceed max %d", +				  c->dirty_nn_cnt, c->nnode_cnt);  			err = -EINVAL;  		}  		return err; @@ -1808,23 +1822,23 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)  		chk_lpt_sz *= d->chk_lpt_lebs;  		chk_lpt_sz += len - c->nhead_offs;  		if (d->chk_lpt_sz != chk_lpt_sz) { -			dbg_err("LPT wrote %lld but space used was %lld", -				d->chk_lpt_sz, chk_lpt_sz); +			ubifs_err("LPT wrote %lld but space used was %lld", +				  d->chk_lpt_sz, chk_lpt_sz);  			err = -EINVAL;  		}  		if (d->chk_lpt_sz > c->lpt_sz) { -			dbg_err("LPT wrote %lld but lpt_sz is %lld", -				d->chk_lpt_sz, c->lpt_sz); +			ubifs_err("LPT wrote %lld but lpt_sz is %lld", +				  d->chk_lpt_sz, c->lpt_sz);  			err = -EINVAL;  		}  		if (d->chk_lpt_sz2 && d->chk_lpt_sz != d->chk_lpt_sz2) { -			dbg_err("LPT layout size %lld but wrote %lld", -				d->chk_lpt_sz, d->chk_lpt_sz2); +			ubifs_err("LPT layout size %lld but wrote %lld", +				  d->chk_lpt_sz, d->chk_lpt_sz2);  			err = -EINVAL;  		}  		if (d->chk_lpt_sz2 && d->new_nhead_offs != len) { -			dbg_err("LPT new nhead offs: expected %d was %d", -				d->new_nhead_offs, len); +			ubifs_err("LPT new nhead offs: expected %d was %d", +				  d->new_nhead_offs, len);  			err = -EINVAL;  		}  		lpt_sz = (long long)c->pnode_cnt * c->pnode_sz; @@ -1833,13 +1847,13 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)  		if (c->big_lpt)  			lpt_sz += c->lsave_sz;  		if (d->chk_lpt_sz - d->chk_lpt_wastage > lpt_sz) { -			dbg_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld", -				d->chk_lpt_sz, d->chk_lpt_wastage, lpt_sz); +			ubifs_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld", +				  d->chk_lpt_sz, d->chk_lpt_wastage, lpt_sz);  			err = -EINVAL;  		}  		if (err) { -			dbg_dump_lpt_info(c); -			dbg_dump_lpt_lebs(c); +			ubifs_dump_lpt_info(c); +			ubifs_dump_lpt_lebs(c);  			dump_stack();  		}  		d->chk_lpt_sz2 = d->chk_lpt_sz; @@ -1858,7 +1872,7 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)  }  /** - * dbg_dump_lpt_leb - dump an LPT LEB. + * ubifs_dump_lpt_leb - dump an LPT LEB.   * @c: UBIFS file-system description object   * @lnum: LEB number to dump   * @@ -1870,45 +1884,48 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)  static void dump_lpt_leb(const struct ubifs_info *c, int lnum)  {  	int err, len = c->leb_size, node_type, node_num, node_len, offs; -	void *buf = c->dbg->buf; +	void *buf, *p; -	printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n", -	       current->pid, lnum); -	err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size); -	if (err) { -		ubifs_err("cannot read LEB %d, error %d", lnum, err); +	pr_err("(pid %d) start dumping LEB %d\n", current->pid, lnum); +	buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL); +	if (!buf) { +		ubifs_err("cannot allocate memory to dump LPT");  		return;  	} + +	err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1); +	if (err) +		goto out; +  	while (1) {  		offs = c->leb_size - len; -		if (!is_a_node(c, buf, len)) { +		if (!is_a_node(c, p, len)) {  			int pad_len; -			pad_len = get_pad_len(c, buf, len); +			pad_len = get_pad_len(c, p, len);  			if (pad_len) { -				printk(KERN_DEBUG "LEB %d:%d, pad %d bytes\n", +				pr_err("LEB %d:%d, pad %d bytes\n",  				       lnum, offs, pad_len); -				buf += pad_len; +				p += pad_len;  				len -= pad_len;  				continue;  			}  			if (len) -				printk(KERN_DEBUG "LEB %d:%d, free %d bytes\n", +				pr_err("LEB %d:%d, free %d bytes\n",  				       lnum, offs, len);  			break;  		} -		node_type = get_lpt_node_type(c, buf, &node_num); +		node_type = get_lpt_node_type(c, p, &node_num);  		switch (node_type) {  		case UBIFS_LPT_PNODE:  		{  			node_len = c->pnode_sz;  			if (c->big_lpt) -				printk(KERN_DEBUG "LEB %d:%d, pnode num %d\n", +				pr_err("LEB %d:%d, pnode num %d\n",  				       lnum, offs, node_num);  			else -				printk(KERN_DEBUG "LEB %d:%d, pnode\n", -				       lnum, offs); +				pr_err("LEB %d:%d, pnode\n", lnum, offs);  			break;  		}  		case UBIFS_LPT_NNODE: @@ -1918,60 +1935,100 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)  			node_len = c->nnode_sz;  			if (c->big_lpt) -				printk(KERN_DEBUG "LEB %d:%d, nnode num %d, ", +				pr_err("LEB %d:%d, nnode num %d, ",  				       lnum, offs, node_num);  			else -				printk(KERN_DEBUG "LEB %d:%d, nnode, ", +				pr_err("LEB %d:%d, nnode, ",  				       lnum, offs); -			err = ubifs_unpack_nnode(c, buf, &nnode); +			err = ubifs_unpack_nnode(c, p, &nnode);  			for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -				printk(KERN_CONT "%d:%d", nnode.nbranch[i].lnum, +				pr_cont("%d:%d", nnode.nbranch[i].lnum,  				       nnode.nbranch[i].offs);  				if (i != UBIFS_LPT_FANOUT - 1) -					printk(KERN_CONT ", "); +					pr_cont(", ");  			} -			printk(KERN_CONT "\n"); +			pr_cont("\n");  			break;  		}  		case UBIFS_LPT_LTAB:  			node_len = c->ltab_sz; -			printk(KERN_DEBUG "LEB %d:%d, ltab\n", -			       lnum, offs); +			pr_err("LEB %d:%d, ltab\n", lnum, offs);  			break;  		case UBIFS_LPT_LSAVE:  			node_len = c->lsave_sz; -			printk(KERN_DEBUG "LEB %d:%d, lsave len\n", lnum, offs); +			pr_err("LEB %d:%d, lsave len\n", lnum, offs);  			break;  		default:  			ubifs_err("LPT node type %d not recognized", node_type); -			return; +			goto out;  		} -		buf += node_len; +		p += node_len;  		len -= node_len;  	} -	printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n", -	       current->pid, lnum); +	pr_err("(pid %d) finish dumping LEB %d\n", current->pid, lnum); +out: +	vfree(buf); +	return;  }  /** - * dbg_dump_lpt_lebs - dump LPT lebs. + * ubifs_dump_lpt_lebs - dump LPT lebs.   * @c: UBIFS file-system description object   *   * This function dumps all LPT LEBs. The caller has to make sure the LPT is   * locked.   */ -void dbg_dump_lpt_lebs(const struct ubifs_info *c) +void ubifs_dump_lpt_lebs(const struct ubifs_info *c)  {  	int i; -	printk(KERN_DEBUG "(pid %d) start dumping all LPT LEBs\n", -	       current->pid); +	pr_err("(pid %d) start dumping all LPT LEBs\n", current->pid);  	for (i = 0; i < c->lpt_lebs; i++)  		dump_lpt_leb(c, i + c->lpt_first); -	printk(KERN_DEBUG "(pid %d) finish dumping all LPT LEBs\n", -	       current->pid); +	pr_err("(pid %d) finish dumping all LPT LEBs\n", current->pid);  } -#endif /* CONFIG_UBIFS_FS_DEBUG */ +/** + * dbg_populate_lsave - debugging version of 'populate_lsave()' + * @c: UBIFS file-system description object + * + * This is a debugging version for 'populate_lsave()' which populates lsave + * with random LEBs instead of useful LEBs, which is good for test coverage. + * Returns zero if lsave has not been populated (this debugging feature is + * disabled) an non-zero if lsave has been populated. + */ +static int dbg_populate_lsave(struct ubifs_info *c) +{ +	struct ubifs_lprops *lprops; +	struct ubifs_lpt_heap *heap; +	int i; + +	if (!dbg_is_chk_gen(c)) +		return 0; +	if (prandom_u32() & 3) +		return 0; + +	for (i = 0; i < c->lsave_cnt; i++) +		c->lsave[i] = c->main_first; + +	list_for_each_entry(lprops, &c->empty_list, list) +		c->lsave[prandom_u32() % c->lsave_cnt] = lprops->lnum; +	list_for_each_entry(lprops, &c->freeable_list, list) +		c->lsave[prandom_u32() % c->lsave_cnt] = lprops->lnum; +	list_for_each_entry(lprops, &c->frdi_idx_list, list) +		c->lsave[prandom_u32() % c->lsave_cnt] = lprops->lnum; + +	heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1]; +	for (i = 0; i < heap->cnt; i++) +		c->lsave[prandom_u32() % c->lsave_cnt] = heap->arr[i]->lnum; +	heap = &c->lpt_heap[LPROPS_DIRTY - 1]; +	for (i = 0; i < heap->cnt; i++) +		c->lsave[prandom_u32() % c->lsave_cnt] = heap->arr[i]->lnum; +	heap = &c->lpt_heap[LPROPS_FREE - 1]; +	for (i = 0; i < heap->cnt; i++) +		c->lsave[prandom_u32() % c->lsave_cnt] = heap->arr[i]->lnum; + +	return 1; +}  | 
