diff options
| author | Zhihao Cheng <chengzhihao1@huawei.com> | 2024-11-11 16:36:59 +0800 | 
|---|---|---|
| committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2024-11-11 10:32:45 +0100 | 
| commit | 5278ea32ae168fe182a122e516ab4fa644df6469 (patch) | |
| tree | 2e6bdb61140884c5fb9881cdd02d19505df101c6 /ubifs-utils | |
| parent | 5fb520b07182de04eea6373e95b580a88dca3037 (diff) | |
ubifs-utils: Adapt lpt subsystem in libubifs
Adapt lpt subsystem(lpt.c,lprops.c,lpt_commit.c) in libubifs, compared
with linux kernel implementations:
 1. Remove debug related functions(eg. dbg_chk_lpt_sz, dbg_chk_pnode),
    some of debug functions are not needed by fsck, because fsck will
    check fs in another way.
 2. Remove some functions(eg. ubifs_create_dflt_lpt) which won't be used
    in fsck/mkfs.
 3. Adapt do_calc_lpt_geom() to mkfs/fsck situations.
 4. Adapt calc_dflt_lpt_geom to support the mkfs tool, and export it.
 5. Adapt ubifs_create_lpt() according to create_lpt(mkfs), make sure that
    the height of created lpt is right.
Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'ubifs-utils')
| -rw-r--r-- | ubifs-utils/libubifs/lprops.c | 484 | ||||
| -rw-r--r-- | ubifs-utils/libubifs/lpt.c | 381 | ||||
| -rw-r--r-- | ubifs-utils/libubifs/lpt_commit.c | 235 | 
3 files changed, 136 insertions, 964 deletions
| diff --git a/ubifs-utils/libubifs/lprops.c b/ubifs-utils/libubifs/lprops.c index 6d6cd85..84cdb35 100644 --- a/ubifs-utils/libubifs/lprops.c +++ b/ubifs-utils/libubifs/lprops.c @@ -16,7 +16,13 @@   * an empty LEB for the journal, or a very dirty LEB for garbage collection.   */ +#include "linux_err.h" +#include "bitops.h" +#include "kmem.h"  #include "ubifs.h" +#include "defs.h" +#include "debug.h" +#include "misc.h"  /**   * get_heap_comp_val - get the LEB properties value for heap comparisons. @@ -47,7 +53,8 @@ static int get_heap_comp_val(struct ubifs_lprops *lprops, int cat)   * is either the amount of free space or the amount of dirty space, depending   * on the category.   */ -static void move_up_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, +static void move_up_lpt_heap(__unused struct ubifs_info *c, +			     struct ubifs_lpt_heap *heap,  			     struct ubifs_lprops *lprops, int cat)  {  	int val1, val2, hpos; @@ -84,7 +91,8 @@ static void move_up_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,   * greater.  In the case of LPT's category heaps, the value is either the amount   * of free space or the amount of dirty space, depending on the category.   */ -static void adjust_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, +static void adjust_lpt_heap(__unused struct ubifs_info *c, +			    struct ubifs_lpt_heap *heap,  			    struct ubifs_lprops *lprops, int hpos, int cat)  {  	int val1, val2, val3, cpos; @@ -191,16 +199,13 @@ static int add_to_lpt_heap(struct ubifs_info *c, struct ubifs_lprops *lprops,  			lprops->hpos = cpos;  			heap->arr[cpos] = lprops;  			move_up_lpt_heap(c, heap, lprops, cat); -			dbg_check_heap(c, heap, cat, lprops->hpos);  			return 1; /* Added to heap */  		} -		dbg_check_heap(c, heap, cat, -1);  		return 0; /* Not added to heap */  	} else {  		lprops->hpos = heap->cnt++;  		heap->arr[lprops->hpos] = lprops;  		move_up_lpt_heap(c, heap, lprops, cat); -		dbg_check_heap(c, heap, cat, lprops->hpos);  		return 1; /* Added to heap */  	}  } @@ -226,7 +231,6 @@ static void remove_from_lpt_heap(struct ubifs_info *c,  		heap->arr[hpos]->hpos = hpos;  		adjust_lpt_heap(c, heap, heap->arr[hpos], hpos, cat);  	} -	dbg_check_heap(c, heap, cat, -1);  }  /** @@ -837,471 +841,3 @@ const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c)  	ubifs_assert(c, lprops->free + lprops->dirty == c->leb_size);  	return lprops;  } - -/* - * Everything below is related to debugging. - */ - -/** - * dbg_check_cats - check category heaps and lists. - * @c: UBIFS file-system description object - * - * This function returns %0 on success and a negative error code on failure. - */ -int dbg_check_cats(struct ubifs_info *c) -{ -	struct ubifs_lprops *lprops; -	struct list_head *pos; -	int i, cat; - -	if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c)) -		return 0; - -	list_for_each_entry(lprops, &c->empty_list, list) { -		if (lprops->free != c->leb_size) { -			ubifs_err(c, "non-empty LEB %d on empty list (free %d dirty %d flags %d)", -				  lprops->lnum, lprops->free, lprops->dirty, -				  lprops->flags); -			return -EINVAL; -		} -		if (lprops->flags & LPROPS_TAKEN) { -			ubifs_err(c, "taken LEB %d on empty list (free %d dirty %d flags %d)", -				  lprops->lnum, lprops->free, lprops->dirty, -				  lprops->flags); -			return -EINVAL; -		} -	} - -	i = 0; -	list_for_each_entry(lprops, &c->freeable_list, list) { -		if (lprops->free + lprops->dirty != c->leb_size) { -			ubifs_err(c, "non-freeable LEB %d on freeable list (free %d dirty %d flags %d)", -				  lprops->lnum, lprops->free, lprops->dirty, -				  lprops->flags); -			return -EINVAL; -		} -		if (lprops->flags & LPROPS_TAKEN) { -			ubifs_err(c, "taken LEB %d on freeable list (free %d dirty %d flags %d)", -				  lprops->lnum, lprops->free, lprops->dirty, -				  lprops->flags); -			return -EINVAL; -		} -		i += 1; -	} -	if (i != c->freeable_cnt) { -		ubifs_err(c, "freeable list count %d expected %d", i, -			  c->freeable_cnt); -		return -EINVAL; -	} - -	i = 0; -	list_for_each(pos, &c->idx_gc) -		i += 1; -	if (i != c->idx_gc_cnt) { -		ubifs_err(c, "idx_gc list count %d expected %d", i, -			  c->idx_gc_cnt); -		return -EINVAL; -	} - -	list_for_each_entry(lprops, &c->frdi_idx_list, list) { -		if (lprops->free + lprops->dirty != c->leb_size) { -			ubifs_err(c, "non-freeable LEB %d on frdi_idx list (free %d dirty %d flags %d)", -				  lprops->lnum, lprops->free, lprops->dirty, -				  lprops->flags); -			return -EINVAL; -		} -		if (lprops->flags & LPROPS_TAKEN) { -			ubifs_err(c, "taken LEB %d on frdi_idx list (free %d dirty %d flags %d)", -				  lprops->lnum, lprops->free, lprops->dirty, -				  lprops->flags); -			return -EINVAL; -		} -		if (!(lprops->flags & LPROPS_INDEX)) { -			ubifs_err(c, "non-index LEB %d on frdi_idx list (free %d dirty %d flags %d)", -				  lprops->lnum, lprops->free, lprops->dirty, -				  lprops->flags); -			return -EINVAL; -		} -	} - -	for (cat = 1; cat <= LPROPS_HEAP_CNT; cat++) { -		struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1]; - -		for (i = 0; i < heap->cnt; i++) { -			lprops = heap->arr[i]; -			if (!lprops) { -				ubifs_err(c, "null ptr in LPT heap cat %d", cat); -				return -EINVAL; -			} -			if (lprops->hpos != i) { -				ubifs_err(c, "bad ptr in LPT heap cat %d", cat); -				return -EINVAL; -			} -			if (lprops->flags & LPROPS_TAKEN) { -				ubifs_err(c, "taken LEB in LPT heap cat %d", cat); -				return -EINVAL; -			} -		} -	} - -	return 0; -} - -void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat, -		    int add_pos) -{ -	int i = 0, j, err = 0; - -	if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c)) -		return; - -	for (i = 0; i < heap->cnt; i++) { -		struct ubifs_lprops *lprops = heap->arr[i]; -		struct ubifs_lprops *lp; - -		if (i != add_pos) -			if ((lprops->flags & LPROPS_CAT_MASK) != cat) { -				err = 1; -				goto out; -			} -		if (lprops->hpos != i) { -			err = 2; -			goto out; -		} -		lp = ubifs_lpt_lookup(c, lprops->lnum); -		if (IS_ERR(lp)) { -			err = 3; -			goto out; -		} -		if (lprops != lp) { -			ubifs_err(c, "lprops %zx lp %zx lprops->lnum %d lp->lnum %d", -				  (size_t)lprops, (size_t)lp, lprops->lnum, -				  lp->lnum); -			err = 4; -			goto out; -		} -		for (j = 0; j < i; j++) { -			lp = heap->arr[j]; -			if (lp == lprops) { -				err = 5; -				goto out; -			} -			if (lp->lnum == lprops->lnum) { -				err = 6; -				goto out; -			} -		} -	} -out: -	if (err) { -		ubifs_err(c, "failed cat %d hpos %d err %d", cat, i, err); -		dump_stack(); -		ubifs_dump_heap(c, heap, cat); -	} -} - -/** - * scan_check_cb - scan callback. - * @c: the UBIFS file-system description object - * @lp: LEB properties to scan - * @in_tree: whether the LEB properties are in main memory - * @lst: lprops statistics to update - * - * This function returns a code that indicates whether the scan should continue - * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree - * in main memory (%LPT_SCAN_ADD), or whether the scan should stop - * (%LPT_SCAN_STOP). - */ -static int scan_check_cb(struct ubifs_info *c, -			 const struct ubifs_lprops *lp, int in_tree, -			 struct ubifs_lp_stats *lst) -{ -	struct ubifs_scan_leb *sleb; -	struct ubifs_scan_node *snod; -	int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret; -	void *buf = NULL; - -	cat = lp->flags & LPROPS_CAT_MASK; -	if (cat != LPROPS_UNCAT) { -		cat = ubifs_categorize_lprops(c, lp); -		if (cat != (lp->flags & LPROPS_CAT_MASK)) { -			ubifs_err(c, "bad LEB category %d expected %d", -				  (lp->flags & LPROPS_CAT_MASK), cat); -			return -EINVAL; -		} -	} - -	/* Check lp is on its category list (if it has one) */ -	if (in_tree) { -		struct list_head *list = NULL; - -		switch (cat) { -		case LPROPS_EMPTY: -			list = &c->empty_list; -			break; -		case LPROPS_FREEABLE: -			list = &c->freeable_list; -			break; -		case LPROPS_FRDI_IDX: -			list = &c->frdi_idx_list; -			break; -		case LPROPS_UNCAT: -			list = &c->uncat_list; -			break; -		} -		if (list) { -			struct ubifs_lprops *lprops; -			int found = 0; - -			list_for_each_entry(lprops, list, list) { -				if (lprops == lp) { -					found = 1; -					break; -				} -			} -			if (!found) { -				ubifs_err(c, "bad LPT list (category %d)", cat); -				return -EINVAL; -			} -		} -	} - -	/* Check lp is on its category heap (if it has one) */ -	if (in_tree && cat > 0 && cat <= LPROPS_HEAP_CNT) { -		struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1]; - -		if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) || -		    lp != heap->arr[lp->hpos]) { -			ubifs_err(c, "bad LPT heap (category %d)", cat); -			return -EINVAL; -		} -	} - -	/* -	 * After an unclean unmount, empty and freeable LEBs -	 * may contain garbage - do not scan them. -	 */ -	if (lp->free == c->leb_size) { -		lst->empty_lebs += 1; -		lst->total_free += c->leb_size; -		lst->total_dark += ubifs_calc_dark(c, c->leb_size); -		return LPT_SCAN_CONTINUE; -	} -	if (lp->free + lp->dirty == c->leb_size && -	    !(lp->flags & LPROPS_INDEX)) { -		lst->total_free  += lp->free; -		lst->total_dirty += lp->dirty; -		lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size); -		return LPT_SCAN_CONTINUE; -	} - -	buf = __vmalloc(c->leb_size, GFP_NOFS); -	if (!buf) -		return -ENOMEM; - -	sleb = ubifs_scan(c, lnum, 0, buf, 0); -	if (IS_ERR(sleb)) { -		ret = PTR_ERR(sleb); -		if (ret == -EUCLEAN) { -			ubifs_dump_lprops(c); -			ubifs_dump_budg(c, &c->bi); -		} -		goto out; -	} - -	is_idx = -1; -	list_for_each_entry(snod, &sleb->nodes, list) { -		int found, level = 0; - -		cond_resched(); - -		if (is_idx == -1) -			is_idx = (snod->type == UBIFS_IDX_NODE) ? 1 : 0; - -		if (is_idx && snod->type != UBIFS_IDX_NODE) { -			ubifs_err(c, "indexing node in data LEB %d:%d", -				  lnum, snod->offs); -			goto out_destroy; -		} - -		if (snod->type == UBIFS_IDX_NODE) { -			struct ubifs_idx_node *idx = snod->node; - -			key_read(c, ubifs_idx_key(c, idx), &snod->key); -			level = le16_to_cpu(idx->level); -		} - -		found = ubifs_tnc_has_node(c, &snod->key, level, lnum, -					   snod->offs, is_idx); -		if (found) { -			if (found < 0) -				goto out_destroy; -			used += ALIGN(snod->len, 8); -		} -	} - -	free = c->leb_size - sleb->endpt; -	dirty = sleb->endpt - used; - -	if (free > c->leb_size || free < 0 || dirty > c->leb_size || -	    dirty < 0) { -		ubifs_err(c, "bad calculated accounting for LEB %d: free %d, dirty %d", -			  lnum, free, dirty); -		goto out_destroy; -	} - -	if (lp->free + lp->dirty == c->leb_size && -	    free + dirty == c->leb_size) -		if ((is_idx && !(lp->flags & LPROPS_INDEX)) || -		    (!is_idx && free == c->leb_size) || -		    lp->free == c->leb_size) { -			/* -			 * Empty or freeable LEBs could contain index -			 * nodes from an uncompleted commit due to an -			 * unclean unmount. Or they could be empty for -			 * the same reason. Or it may simply not have been -			 * unmapped. -			 */ -			free = lp->free; -			dirty = lp->dirty; -			is_idx = 0; -		    } - -	if (is_idx && lp->free + lp->dirty == free + dirty && -	    lnum != c->ihead_lnum) { -		/* -		 * After an unclean unmount, an index LEB could have a different -		 * amount of free space than the value recorded by lprops. That -		 * is because the in-the-gaps method may use free space or -		 * create free space (as a side-effect of using ubi_leb_change -		 * and not writing the whole LEB). The incorrect free space -		 * value is not a problem because the index is only ever -		 * allocated empty LEBs, so there will never be an attempt to -		 * write to the free space at the end of an index LEB - except -		 * by the in-the-gaps method for which it is not a problem. -		 */ -		free = lp->free; -		dirty = lp->dirty; -	} - -	if (lp->free != free || lp->dirty != dirty) -		goto out_print; - -	if (is_idx && !(lp->flags & LPROPS_INDEX)) { -		if (free == c->leb_size) -			/* Free but not unmapped LEB, it's fine */ -			is_idx = 0; -		else { -			ubifs_err(c, "indexing node without indexing flag"); -			goto out_print; -		} -	} - -	if (!is_idx && (lp->flags & LPROPS_INDEX)) { -		ubifs_err(c, "data node with indexing flag"); -		goto out_print; -	} - -	if (free == c->leb_size) -		lst->empty_lebs += 1; - -	if (is_idx) -		lst->idx_lebs += 1; - -	if (!(lp->flags & LPROPS_INDEX)) -		lst->total_used += c->leb_size - free - dirty; -	lst->total_free += free; -	lst->total_dirty += dirty; - -	if (!(lp->flags & LPROPS_INDEX)) { -		int spc = free + dirty; - -		if (spc < c->dead_wm) -			lst->total_dead += spc; -		else -			lst->total_dark += ubifs_calc_dark(c, spc); -	} - -	ubifs_scan_destroy(sleb); -	vfree(buf); -	return LPT_SCAN_CONTINUE; - -out_print: -	ubifs_err(c, "bad accounting of LEB %d: free %d, dirty %d flags %#x, should be free %d, dirty %d", -		  lnum, lp->free, lp->dirty, lp->flags, free, dirty); -	ubifs_dump_leb(c, lnum); -out_destroy: -	ubifs_scan_destroy(sleb); -	ret = -EINVAL; -out: -	vfree(buf); -	return ret; -} - -/** - * dbg_check_lprops - check all LEB properties. - * @c: UBIFS file-system description object - * - * This function checks all LEB properties and makes sure they are all correct. - * It returns zero if everything is fine, %-EINVAL if there is an inconsistency - * and other negative error codes in case of other errors. This function is - * called while the file system is locked (because of commit start), so no - * additional locking is required. Note that locking the LPT mutex would cause - * a circular lock dependency with the TNC mutex. - */ -int dbg_check_lprops(struct ubifs_info *c) -{ -	int i, err; -	struct ubifs_lp_stats lst; - -	if (!dbg_is_chk_lprops(c)) -		return 0; - -	/* -	 * As we are going to scan the media, the write buffers have to be -	 * synchronized. -	 */ -	for (i = 0; i < c->jhead_cnt; i++) { -		err = ubifs_wbuf_sync(&c->jheads[i].wbuf); -		if (err) -			return err; -	} - -	memset(&lst, 0, sizeof(struct ubifs_lp_stats)); -	err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1, -				    (ubifs_lpt_scan_callback)scan_check_cb, -				    &lst); -	if (err && err != -ENOSPC) -		goto out; - -	if (lst.empty_lebs != c->lst.empty_lebs || -	    lst.idx_lebs != c->lst.idx_lebs || -	    lst.total_free != c->lst.total_free || -	    lst.total_dirty != c->lst.total_dirty || -	    lst.total_used != c->lst.total_used) { -		ubifs_err(c, "bad overall accounting"); -		ubifs_err(c, "calculated: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld", -			  lst.empty_lebs, lst.idx_lebs, lst.total_free, -			  lst.total_dirty, lst.total_used); -		ubifs_err(c, "read from lprops: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld", -			  c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free, -			  c->lst.total_dirty, c->lst.total_used); -		err = -EINVAL; -		goto out; -	} - -	if (lst.total_dead != c->lst.total_dead || -	    lst.total_dark != c->lst.total_dark) { -		ubifs_err(c, "bad dead/dark space accounting"); -		ubifs_err(c, "calculated: total_dead %lld, total_dark %lld", -			  lst.total_dead, lst.total_dark); -		ubifs_err(c, "read from lprops: total_dead %lld, total_dark %lld", -			  c->lst.total_dead, c->lst.total_dark); -		err = -EINVAL; -		goto out; -	} - -	err = dbg_check_cats(c); -out: -	return err; -} diff --git a/ubifs-utils/libubifs/lpt.c b/ubifs-utils/libubifs/lpt.c index 1889170..92b3fec 100644 --- a/ubifs-utils/libubifs/lpt.c +++ b/ubifs-utils/libubifs/lpt.c @@ -31,10 +31,13 @@   * mounted.   */ +#include "linux_err.h" +#include "bitops.h" +#include "kmem.h" +#include "crc16.h"  #include "ubifs.h" -#include <linux/crc16.h> -#include <linux/math64.h> -#include <linux/slab.h> +#include "defs.h" +#include "debug.h"  /**   * do_calc_lpt_geom - calculate sizes for the LPT area. @@ -48,8 +51,20 @@ static void do_calc_lpt_geom(struct ubifs_info *c)  	int i, n, bits, per_leb_wastage, max_pnode_cnt;  	long long sz, tot_wastage; -	n = c->main_lebs + c->max_leb_cnt - c->leb_cnt; -	max_pnode_cnt = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT); +	if (c->program_type != MKFS_PROGRAM_TYPE) { +		n = c->main_lebs + c->max_leb_cnt - c->leb_cnt; +		max_pnode_cnt = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT); +	} else { +		/* +		 * Different from linux kernel. +		 * +		 * We change it, because 'c->leb_cnt' is not initialized in +		 * mkfs.ubifs when do_calc_lpt_geom() is invoked, 'c->main_lebs' +		 * is calculated by 'c->max_leb_cnt', so the 'c->lpt_hght' +		 * should be calculated by 'c->main_lebs'. +		 */ +		max_pnode_cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT); +	}  	c->lpt_hght = 1;  	n = UBIFS_LPT_FANOUT; @@ -148,7 +163,7 @@ int ubifs_calc_lpt_geom(struct ubifs_info *c)  }  /** - * calc_dflt_lpt_geom - calculate default LPT geometry. + * ubifs_calc_dflt_lpt_geom - calculate default LPT geometry.   * @c: the UBIFS file-system description object   * @main_lebs: number of main area LEBs is passed and returned here   * @big_lpt: whether the LPT area is "big" is returned here @@ -159,8 +174,7 @@ int ubifs_calc_lpt_geom(struct ubifs_info *c)   *   * This function returns %0 on success and a negative error code on failure.   */ -static int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, -			      int *big_lpt) +int ubifs_calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt)  {  	int i, lebs_needed;  	long long sz; @@ -275,7 +289,7 @@ uint32_t ubifs_unpack_bits(const struct ubifs_info *c, uint8_t **addr, int *pos,  	const int k = 32 - nrbits;  	uint8_t *p = *addr;  	int b = *pos; -	uint32_t val; +	uint32_t val = 0;  	const int bytes = (nrbits + b + 7) >> 3;  	ubifs_assert(c, nrbits > 0); @@ -638,8 +652,13 @@ int ubifs_create_lpt(struct ubifs_info *c, struct ubifs_lprops *lps, int lp_cnt,  	lnum = c->lpt_first;  	p = buf;  	len = 0; -	/* Number of leaf nodes (pnodes) */ -	cnt = c->pnode_cnt; +	/* +	 * Different from linux kernel. The number of leaf nodes (pnodes) should +	 * be calculated by the number of current main LEBs. The 'c->pnode_cnt' +	 * may not be equal to 'DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT)' in +	 * mkfs when 'c->leb_cnt != c->max_leb_cnt' is true. +	 */ +	cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT);  	/*  	 * To calculate the internal node branches, we keep information about @@ -655,8 +674,19 @@ int ubifs_create_lpt(struct ubifs_info *c, struct ubifs_lprops *lps, int lp_cnt,  		if (len + c->pnode_sz > c->leb_size) {  			alen = ALIGN(len, c->min_io_size);  			set_ltab(c, lnum, c->leb_size - alen, alen - len); -			memset(p, 0xff, alen - len); -			err = ubifs_leb_change(c, lnum++, buf, alen); +			/* +			 * Different from linux kernel. +			 * The mkfs may partially write data into a certain LEB +			 * of file image, the left unwritten area in the LEB +			 * should be filled with '0xFF'. +			 */ +			if (c->libubi) { +				memset(p, 0xff, alen - len); +				err = ubifs_leb_change(c, lnum++, buf, alen); +			} else { +				memset(p, 0xff, c->leb_size - len); +				err = ubifs_leb_change(c, lnum++, buf, c->leb_size); +			}  			if (err)  				goto out;  			p = buf; @@ -691,27 +721,45 @@ int ubifs_create_lpt(struct ubifs_info *c, struct ubifs_lprops *lps, int lp_cnt,  		pnode->num += 1;  	} -	row = 0; -	for (i = UBIFS_LPT_FANOUT; cnt > i; i <<= UBIFS_LPT_FANOUT_SHIFT) -		row += 1; +	/* +	 * Different from linux kernel. The 'c->lpt_hght' is calculated by the +	 * 'c->max_leb_cnt', according to the implementation of function +	 * ubifs_pnode_lookup(), there are at least 'c->lpt_hght' cnodes should +	 * be created, otherwise the LPT looking up could be failed after +	 * mouting. +	 */ +	row = c->lpt_hght - 1;  	/* Add all nnodes, one level at a time */  	while (1) {  		/* Number of internal nodes (nnodes) at next level */  		cnt = DIV_ROUND_UP(cnt, UBIFS_LPT_FANOUT); +		if (cnt == 0) +			cnt = 1;  		for (i = 0; i < cnt; i++) {  			if (len + c->nnode_sz > c->leb_size) {  				alen = ALIGN(len, c->min_io_size);  				set_ltab(c, lnum, c->leb_size - alen,  					    alen - len); -				memset(p, 0xff, alen - len); -				err = ubifs_leb_change(c, lnum++, buf, alen); +				/* +				 * Different from linux kernel. +				 * The mkfs may partially write data into a certain LEB +				 * of file image, the left unwritten area in the LEB +				 * should be filled with '0xFF'. +				 */ +				if (c->libubi) { +					memset(p, 0xff, alen - len); +					err = ubifs_leb_change(c, lnum++, buf, alen); +				} else { +					memset(p, 0xff, c->leb_size - len); +					err = ubifs_leb_change(c, lnum++, buf, c->leb_size); +				}  				if (err)  					goto out;  				p = buf;  				len = 0;  			}  			/* Only 1 nnode at this level, so it is the root */ -			if (cnt == 1) { +			if (row == 0) {  				c->lpt_lnum = lnum;  				c->lpt_offs = len;  			} @@ -736,8 +784,8 @@ int ubifs_create_lpt(struct ubifs_info *c, struct ubifs_lprops *lps, int lp_cnt,  			p += c->nnode_sz;  			len += c->nnode_sz;  		} -		/* Only 1 nnode at this level, so it is the root */ -		if (cnt == 1) +		/* Row zero  is the top row */ +		if (row == 0)  			break;  		/* Update the information about the level below */  		bcnt = cnt; @@ -750,8 +798,19 @@ int ubifs_create_lpt(struct ubifs_info *c, struct ubifs_lprops *lps, int lp_cnt,  		if (len + c->lsave_sz > c->leb_size) {  			alen = ALIGN(len, c->min_io_size);  			set_ltab(c, lnum, c->leb_size - alen, alen - len); -			memset(p, 0xff, alen - len); -			err = ubifs_leb_change(c, lnum++, buf, alen); +			/* +			 * Different from linux kernel. +			 * The mkfs may partially write data into a certain LEB +			 * of file image, the left unwritten area in the LEB +			 * should be filled with '0xFF'. +			 */ +			if (c->libubi) { +				memset(p, 0xff, alen - len); +				err = ubifs_leb_change(c, lnum++, buf, alen); +			} else { +				memset(p, 0xff, c->leb_size - len); +				err = ubifs_leb_change(c, lnum++, buf, c->leb_size); +			}  			if (err)  				goto out;  			p = buf; @@ -775,8 +834,19 @@ int ubifs_create_lpt(struct ubifs_info *c, struct ubifs_lprops *lps, int lp_cnt,  	if (len + c->ltab_sz > c->leb_size) {  		alen = ALIGN(len, c->min_io_size);  		set_ltab(c, lnum, c->leb_size - alen, alen - len); -		memset(p, 0xff, alen - len); -		err = ubifs_leb_change(c, lnum++, buf, alen); +		/* +		 * Different from linux kernel. +		 * The mkfs may partially write data into a certain LEB +		 * of file image, the left unwritten area in the LEB +		 * should be filled with '0xFF'. +		 */ +		if (c->libubi) { +			memset(p, 0xff, alen - len); +			err = ubifs_leb_change(c, lnum++, buf, alen); +		} else { +			memset(p, 0xff, c->leb_size - len); +			err = ubifs_leb_change(c, lnum++, buf, c->leb_size); +		}  		if (err)  			goto out;  		p = buf; @@ -795,11 +865,25 @@ int ubifs_create_lpt(struct ubifs_info *c, struct ubifs_lprops *lps, int lp_cnt,  	p += c->ltab_sz;  	/* Write remaining buffer */ -	memset(p, 0xff, alen - len); -	err = ubifs_leb_change(c, lnum, buf, alen); +	/* +	 * Different from linux kernel. +	 * The mkfs may partially write data into a certain LEB +	 * of file image, the left unwritten area in the LEB +	 * should be filled with '0xFF'. +	 */ +	if (c->libubi) { +		memset(p, 0xff, alen - len); +		err = ubifs_leb_change(c, lnum, buf, alen); +	} else { +		memset(p, 0xff, c->leb_size - len); +		err = ubifs_leb_change(c, lnum, buf, c->leb_size); +	}  	if (err)  		goto out; +	if (c->big_lpt && c->lsave) +		memcpy(c->lsave, lsave, c->lsave_cnt * sizeof(int)); +  	err = ubifs_shash_final(c, desc, hash);  	if (err)  		goto out; @@ -837,54 +921,6 @@ out:  }  /** - * ubifs_create_dflt_lpt - create default LPT. - * @c: UBIFS file-system description object - * @main_lebs: number of main area LEBs is passed and returned here - * @lpt_first: LEB number of first LPT LEB - * @lpt_lebs: number of LEBs for LPT is passed and returned here - * @big_lpt: use big LPT model is passed and returned here - * @hash: hash of the LPT is returned here - * - * This function returns %0 on success and a negative error code on failure. - */ -int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, -			  int *lpt_lebs, int *big_lpt, u8 *hash) -{ -	int node_sz, iopos, err = 0; -	struct ubifs_lprops lps[2]; - -	err = calc_dflt_lpt_geom(c, main_lebs, big_lpt); -	if (err) -		return err; -	*lpt_lebs = c->lpt_lebs; - -	/* Needed by 'ubifs_pack_nnode()' and 'set_ltab()' */ -	c->lpt_first = lpt_first; -	/* Needed by 'set_ltab()' */ -	c->lpt_last = lpt_first + c->lpt_lebs - 1; -	/* Needed by 'ubifs_pack_lsave()' */ -	c->main_first = c->leb_cnt - *main_lebs; - -	/* -	 * The first pnode contains the LEB properties for the LEBs that contain -	 * the root inode node and the root index node of the index tree. -	 */ -	node_sz = ALIGN(ubifs_idx_node_sz(c, 1), 8); -	iopos = ALIGN(node_sz, c->min_io_size); -	lps[0].free = c->leb_size - iopos; -	lps[0].dirty = iopos - node_sz; -	lps[0].flags = LPROPS_INDEX; - -	node_sz = UBIFS_INO_NODE_SZ; -	iopos = ALIGN(node_sz, c->min_io_size); -	lps[1].free = c->leb_size - iopos; -	lps[1].dirty = iopos - node_sz; -	lps[1].flags = 0; - -	return ubifs_create_lpt(c, lps, 2, hash); -} - -/**   * update_cats - add LEB properties of a pnode to LEB category lists and heaps.   * @c: UBIFS file-system description object   * @pnode: pnode @@ -2254,198 +2290,3 @@ out:  	kfree(path);  	return err;  } - -/** - * dbg_chk_pnode - check a pnode. - * @c: the UBIFS file-system description object - * @pnode: pnode to check - * @col: pnode column - * - * This function returns %0 on success and a negative error code on failure. - */ -static int dbg_chk_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, -			 int col) -{ -	int i; - -	if (pnode->num != col) { -		ubifs_err(c, "pnode num %d expected %d parent num %d iip %d", -			  pnode->num, col, pnode->parent->num, pnode->iip); -		return -EINVAL; -	} -	for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -		struct ubifs_lprops *lp, *lprops = &pnode->lprops[i]; -		int lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + i + -			   c->main_first; -		int found, cat = lprops->flags & LPROPS_CAT_MASK; -		struct ubifs_lpt_heap *heap; -		struct list_head *list = NULL; - -		if (lnum >= c->leb_cnt) -			continue; -		if (lprops->lnum != lnum) { -			ubifs_err(c, "bad LEB number %d expected %d", -				  lprops->lnum, lnum); -			return -EINVAL; -		} -		if (lprops->flags & LPROPS_TAKEN) { -			if (cat != LPROPS_UNCAT) { -				ubifs_err(c, "LEB %d taken but not uncat %d", -					  lprops->lnum, cat); -				return -EINVAL; -			} -			continue; -		} -		if (lprops->flags & LPROPS_INDEX) { -			switch (cat) { -			case LPROPS_UNCAT: -			case LPROPS_DIRTY_IDX: -			case LPROPS_FRDI_IDX: -				break; -			default: -				ubifs_err(c, "LEB %d index but cat %d", -					  lprops->lnum, cat); -				return -EINVAL; -			} -		} else { -			switch (cat) { -			case LPROPS_UNCAT: -			case LPROPS_DIRTY: -			case LPROPS_FREE: -			case LPROPS_EMPTY: -			case LPROPS_FREEABLE: -				break; -			default: -				ubifs_err(c, "LEB %d not index but cat %d", -					  lprops->lnum, cat); -				return -EINVAL; -			} -		} -		switch (cat) { -		case LPROPS_UNCAT: -			list = &c->uncat_list; -			break; -		case LPROPS_EMPTY: -			list = &c->empty_list; -			break; -		case LPROPS_FREEABLE: -			list = &c->freeable_list; -			break; -		case LPROPS_FRDI_IDX: -			list = &c->frdi_idx_list; -			break; -		} -		found = 0; -		switch (cat) { -		case LPROPS_DIRTY: -		case LPROPS_DIRTY_IDX: -		case LPROPS_FREE: -			heap = &c->lpt_heap[cat - 1]; -			if (lprops->hpos < heap->cnt && -			    heap->arr[lprops->hpos] == lprops) -				found = 1; -			break; -		case LPROPS_UNCAT: -		case LPROPS_EMPTY: -		case LPROPS_FREEABLE: -		case LPROPS_FRDI_IDX: -			list_for_each_entry(lp, list, list) -				if (lprops == lp) { -					found = 1; -					break; -				} -			break; -		} -		if (!found) { -			ubifs_err(c, "LEB %d cat %d not found in cat heap/list", -				  lprops->lnum, cat); -			return -EINVAL; -		} -		switch (cat) { -		case LPROPS_EMPTY: -			if (lprops->free != c->leb_size) { -				ubifs_err(c, "LEB %d cat %d free %d dirty %d", -					  lprops->lnum, cat, lprops->free, -					  lprops->dirty); -				return -EINVAL; -			} -			break; -		case LPROPS_FREEABLE: -		case LPROPS_FRDI_IDX: -			if (lprops->free + lprops->dirty != c->leb_size) { -				ubifs_err(c, "LEB %d cat %d free %d dirty %d", -					  lprops->lnum, cat, lprops->free, -					  lprops->dirty); -				return -EINVAL; -			} -			break; -		} -	} -	return 0; -} - -/** - * dbg_check_lpt_nodes - check nnodes and pnodes. - * @c: the UBIFS file-system description object - * @cnode: next cnode (nnode or pnode) to check - * @row: row of cnode (root is zero) - * @col: column of cnode (leftmost is zero) - * - * This function returns %0 on success and a negative error code on failure. - */ -int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode, -			int row, int col) -{ -	struct ubifs_nnode *nnode, *nn; -	struct ubifs_cnode *cn; -	int num, iip = 0, err; - -	if (!dbg_is_chk_lprops(c)) -		return 0; - -	while (cnode) { -		ubifs_assert(c, row >= 0); -		nnode = cnode->parent; -		if (cnode->level) { -			/* cnode is a nnode */ -			num = calc_nnode_num(row, col); -			if (cnode->num != num) { -				ubifs_err(c, "nnode num %d expected %d parent num %d iip %d", -					  cnode->num, num, -					  (nnode ? nnode->num : 0), cnode->iip); -				return -EINVAL; -			} -			nn = (struct ubifs_nnode *)cnode; -			while (iip < UBIFS_LPT_FANOUT) { -				cn = nn->nbranch[iip].cnode; -				if (cn) { -					/* Go down */ -					row += 1; -					col <<= UBIFS_LPT_FANOUT_SHIFT; -					col += iip; -					iip = 0; -					cnode = cn; -					break; -				} -				/* Go right */ -				iip += 1; -			} -			if (iip < UBIFS_LPT_FANOUT) -				continue; -		} else { -			struct ubifs_pnode *pnode; - -			/* cnode is a pnode */ -			pnode = (struct ubifs_pnode *)cnode; -			err = dbg_chk_pnode(c, pnode, col); -			if (err) -				return err; -		} -		/* Go up and to the right */ -		row -= 1; -		col >>= UBIFS_LPT_FANOUT_SHIFT; -		iip = cnode->iip + 1; -		cnode = (struct ubifs_cnode *)nnode; -	} -	return 0; -} diff --git a/ubifs-utils/libubifs/lpt_commit.c b/ubifs-utils/libubifs/lpt_commit.c index c4d0793..b00f75f 100644 --- a/ubifs-utils/libubifs/lpt_commit.c +++ b/ubifs-utils/libubifs/lpt_commit.c @@ -13,10 +13,14 @@   * subsystem.   */ -#include <linux/crc16.h> -#include <linux/slab.h> -#include <linux/random.h> +#include "linux_err.h" +#include "bitops.h" +#include "kmem.h" +#include "crc16.h"  #include "ubifs.h" +#include "defs.h" +#include "debug.h" +#include "misc.h"  static int dbg_populate_lsave(struct ubifs_info *c); @@ -1030,7 +1034,8 @@ static int get_lpt_node_len(const struct ubifs_info *c, int node_type)   * @buf: buffer   * @len: length of buffer   */ -static int get_pad_len(const struct ubifs_info *c, uint8_t *buf, int len) +static int get_pad_len(const struct ubifs_info *c, __unused uint8_t *buf, +		       int len)  {  	int offs, pad_len; @@ -1593,9 +1598,6 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)  	int ret;  	void *buf, *p; -	if (!dbg_is_chk_lprops(c)) -		return 0; -  	buf = p = __vmalloc(c->leb_size, GFP_NOFS);  	if (!buf) {  		ubifs_err(c, "cannot allocate memory for ltab checking"); @@ -1646,190 +1648,12 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)  		len -= node_len;  	} -	err = 0;  out:  	vfree(buf);  	return err;  }  /** - * dbg_check_ltab - check the free and dirty space in the ltab. - * @c: the UBIFS file-system description object - * - * This function returns %0 on success and a negative error code on failure. - */ -int dbg_check_ltab(struct ubifs_info *c) -{ -	int lnum, err, i, cnt; - -	if (!dbg_is_chk_lprops(c)) -		return 0; - -	/* Bring the entire tree into memory */ -	cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT); -	for (i = 0; i < cnt; i++) { -		struct ubifs_pnode *pnode; - -		pnode = ubifs_pnode_lookup(c, i); -		if (IS_ERR(pnode)) -			return PTR_ERR(pnode); -		cond_resched(); -	} - -	/* Check nodes */ -	err = dbg_check_lpt_nodes(c, (struct ubifs_cnode *)c->nroot, 0, 0); -	if (err) -		return err; - -	/* Check each LEB */ -	for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) { -		err = dbg_check_ltab_lnum(c, lnum); -		if (err) { -			ubifs_err(c, "failed at LEB %d", lnum); -			return err; -		} -	} - -	dbg_lp("succeeded"); -	return 0; -} - -/** - * dbg_chk_lpt_free_spc - check LPT free space is enough to write entire LPT. - * @c: the UBIFS file-system description object - * - * This function returns %0 on success and a negative error code on failure. - */ -int dbg_chk_lpt_free_spc(struct ubifs_info *c) -{ -	long long free = 0; -	int i; - -	if (!dbg_is_chk_lprops(c)) -		return 0; - -	for (i = 0; i < c->lpt_lebs; i++) { -		if (c->ltab[i].tgc || c->ltab[i].cmt) -			continue; -		if (i + c->lpt_first == c->nhead_lnum) -			free += c->leb_size - c->nhead_offs; -		else if (c->ltab[i].free == c->leb_size) -			free += c->leb_size; -	} -	if (free < c->lpt_sz) { -		ubifs_err(c, "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; -	} -	return 0; -} - -/** - * dbg_chk_lpt_sz - check LPT does not write more than LPT size. - * @c: the UBIFS file-system description object - * @action: what to do - * @len: length written - * - * This function returns %0 on success and a negative error code on failure. - * The @action argument may be one of: - *   o %0 - LPT debugging checking starts, initialize debugging variables; - *   o %1 - wrote an LPT node, increase LPT size by @len bytes; - *   o %2 - switched to a different LEB and wasted @len bytes; - *   o %3 - check that we've written the right number of bytes. - *   o %4 - wasted @len bytes; - */ -int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len) -{ -	struct ubifs_debug_info *d = c->dbg; -	long long chk_lpt_sz, lpt_sz; -	int err = 0; - -	if (!dbg_is_chk_lprops(c)) -		return 0; - -	switch (action) { -	case 0: -		d->chk_lpt_sz = 0; -		d->chk_lpt_sz2 = 0; -		d->chk_lpt_lebs = 0; -		d->chk_lpt_wastage = 0; -		if (c->dirty_pn_cnt > c->pnode_cnt) { -			ubifs_err(c, "dirty pnodes %d exceed max %d", -				  c->dirty_pn_cnt, c->pnode_cnt); -			err = -EINVAL; -		} -		if (c->dirty_nn_cnt > c->nnode_cnt) { -			ubifs_err(c, "dirty nnodes %d exceed max %d", -				  c->dirty_nn_cnt, c->nnode_cnt); -			err = -EINVAL; -		} -		return err; -	case 1: -		d->chk_lpt_sz += len; -		return 0; -	case 2: -		d->chk_lpt_sz += len; -		d->chk_lpt_wastage += len; -		d->chk_lpt_lebs += 1; -		return 0; -	case 3: -		chk_lpt_sz = c->leb_size; -		chk_lpt_sz *= d->chk_lpt_lebs; -		chk_lpt_sz += len - c->nhead_offs; -		if (d->chk_lpt_sz != chk_lpt_sz) { -			ubifs_err(c, "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) { -			ubifs_err(c, "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) { -			ubifs_err(c, "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) { -			ubifs_err(c, "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; -		lpt_sz += (long long)c->nnode_cnt * c->nnode_sz; -		lpt_sz += c->ltab_sz; -		if (c->big_lpt) -			lpt_sz += c->lsave_sz; -		if (d->chk_lpt_sz - d->chk_lpt_wastage > lpt_sz) { -			ubifs_err(c, "LPT chk_lpt_sz %lld + waste %lld exceeds %lld", -				  d->chk_lpt_sz, d->chk_lpt_wastage, lpt_sz); -			err = -EINVAL; -		} -		if (err) { -			ubifs_dump_lpt_info(c); -			ubifs_dump_lpt_lebs(c); -			dump_stack(); -		} -		d->chk_lpt_sz2 = d->chk_lpt_sz; -		d->chk_lpt_sz = 0; -		d->chk_lpt_wastage = 0; -		d->chk_lpt_lebs = 0; -		d->new_nhead_offs = len; -		return err; -	case 4: -		d->chk_lpt_sz += len; -		d->chk_lpt_wastage += len; -		return 0; -	default: -		return -EINVAL; -	} -} - -/**   * dump_lpt_leb - dump an LPT LEB.   * @c: UBIFS file-system description object   * @lnum: LEB number to dump @@ -1844,7 +1668,7 @@ 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, *p; -	pr_err("(pid %d) start dumping LEB %d\n", current->pid, lnum); +	pr_err("(pid %d) start dumping LEB %d\n", getpid(), lnum);  	buf = p = __vmalloc(c->leb_size, GFP_NOFS);  	if (!buf) {  		ubifs_err(c, "cannot allocate memory to dump LPT"); @@ -1930,7 +1754,7 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)  		len -= node_len;  	} -	pr_err("(pid %d) finish dumping LEB %d\n", current->pid, lnum); +	pr_err("(pid %d) finish dumping LEB %d\n", getpid(), lnum);  out:  	vfree(buf);  	return; @@ -1947,10 +1771,10 @@ void ubifs_dump_lpt_lebs(const struct ubifs_info *c)  {  	int i; -	pr_err("(pid %d) start dumping all LPT LEBs\n", current->pid); +	pr_err("(pid %d) start dumping all LPT LEBs\n", getpid());  	for (i = 0; i < c->lpt_lebs; i++)  		dump_lpt_leb(c, i + c->lpt_first); -	pr_err("(pid %d) finish dumping all LPT LEBs\n", current->pid); +	pr_err("(pid %d) finish dumping all LPT LEBs\n", getpid());  }  /** @@ -1962,36 +1786,7 @@ void ubifs_dump_lpt_lebs(const struct ubifs_info *c)   * 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) +static int dbg_populate_lsave(__unused struct ubifs_info *c)  { -	struct ubifs_lprops *lprops; -	struct ubifs_lpt_heap *heap; -	int i; - -	if (!dbg_is_chk_gen(c)) -		return 0; -	if (get_random_u32_below(4)) -		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[get_random_u32_below(c->lsave_cnt)] = lprops->lnum; -	list_for_each_entry(lprops, &c->freeable_list, list) -		c->lsave[get_random_u32_below(c->lsave_cnt)] = lprops->lnum; -	list_for_each_entry(lprops, &c->frdi_idx_list, list) -		c->lsave[get_random_u32_below(c->lsave_cnt)] = lprops->lnum; - -	heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1]; -	for (i = 0; i < heap->cnt; i++) -		c->lsave[get_random_u32_below(c->lsave_cnt)] = heap->arr[i]->lnum; -	heap = &c->lpt_heap[LPROPS_DIRTY - 1]; -	for (i = 0; i < heap->cnt; i++) -		c->lsave[get_random_u32_below(c->lsave_cnt)] = heap->arr[i]->lnum; -	heap = &c->lpt_heap[LPROPS_FREE - 1]; -	for (i = 0; i < heap->cnt; i++) -		c->lsave[get_random_u32_below(c->lsave_cnt)] = heap->arr[i]->lnum; - -	return 1; +	return 0;  } | 
