xref: /openbmc/linux/fs/ubifs/lprops.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
12b27bdccSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21e51764aSArtem Bityutskiy /*
31e51764aSArtem Bityutskiy  * This file is part of UBIFS.
41e51764aSArtem Bityutskiy  *
51e51764aSArtem Bityutskiy  * Copyright (C) 2006-2008 Nokia Corporation.
61e51764aSArtem Bityutskiy  *
71e51764aSArtem Bityutskiy  * Authors: Adrian Hunter
81e51764aSArtem Bityutskiy  *          Artem Bityutskiy (Битюцкий Артём)
91e51764aSArtem Bityutskiy  */
101e51764aSArtem Bityutskiy 
111e51764aSArtem Bityutskiy /*
121e51764aSArtem Bityutskiy  * This file implements the functions that access LEB properties and their
131e51764aSArtem Bityutskiy  * categories. LEBs are categorized based on the needs of UBIFS, and the
141e51764aSArtem Bityutskiy  * categories are stored as either heaps or lists to provide a fast way of
151e51764aSArtem Bityutskiy  * finding a LEB in a particular category. For example, UBIFS may need to find
161e51764aSArtem Bityutskiy  * an empty LEB for the journal, or a very dirty LEB for garbage collection.
171e51764aSArtem Bityutskiy  */
181e51764aSArtem Bityutskiy 
191e51764aSArtem Bityutskiy #include "ubifs.h"
201e51764aSArtem Bityutskiy 
211e51764aSArtem Bityutskiy /**
221e51764aSArtem Bityutskiy  * get_heap_comp_val - get the LEB properties value for heap comparisons.
231e51764aSArtem Bityutskiy  * @lprops: LEB properties
241e51764aSArtem Bityutskiy  * @cat: LEB category
251e51764aSArtem Bityutskiy  */
get_heap_comp_val(struct ubifs_lprops * lprops,int cat)261e51764aSArtem Bityutskiy static int get_heap_comp_val(struct ubifs_lprops *lprops, int cat)
271e51764aSArtem Bityutskiy {
281e51764aSArtem Bityutskiy 	switch (cat) {
291e51764aSArtem Bityutskiy 	case LPROPS_FREE:
301e51764aSArtem Bityutskiy 		return lprops->free;
311e51764aSArtem Bityutskiy 	case LPROPS_DIRTY_IDX:
321e51764aSArtem Bityutskiy 		return lprops->free + lprops->dirty;
331e51764aSArtem Bityutskiy 	default:
341e51764aSArtem Bityutskiy 		return lprops->dirty;
351e51764aSArtem Bityutskiy 	}
361e51764aSArtem Bityutskiy }
371e51764aSArtem Bityutskiy 
381e51764aSArtem Bityutskiy /**
391e51764aSArtem Bityutskiy  * move_up_lpt_heap - move a new heap entry up as far as possible.
401e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
411e51764aSArtem Bityutskiy  * @heap: LEB category heap
421e51764aSArtem Bityutskiy  * @lprops: LEB properties to move
431e51764aSArtem Bityutskiy  * @cat: LEB category
441e51764aSArtem Bityutskiy  *
451e51764aSArtem Bityutskiy  * New entries to a heap are added at the bottom and then moved up until the
461e51764aSArtem Bityutskiy  * parent's value is greater.  In the case of LPT's category heaps, the value
471e51764aSArtem Bityutskiy  * is either the amount of free space or the amount of dirty space, depending
481e51764aSArtem Bityutskiy  * on the category.
491e51764aSArtem Bityutskiy  */
move_up_lpt_heap(struct ubifs_info * c,struct ubifs_lpt_heap * heap,struct ubifs_lprops * lprops,int cat)501e51764aSArtem Bityutskiy static void move_up_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
511e51764aSArtem Bityutskiy 			     struct ubifs_lprops *lprops, int cat)
521e51764aSArtem Bityutskiy {
531e51764aSArtem Bityutskiy 	int val1, val2, hpos;
541e51764aSArtem Bityutskiy 
551e51764aSArtem Bityutskiy 	hpos = lprops->hpos;
561e51764aSArtem Bityutskiy 	if (!hpos)
571e51764aSArtem Bityutskiy 		return; /* Already top of the heap */
581e51764aSArtem Bityutskiy 	val1 = get_heap_comp_val(lprops, cat);
591e51764aSArtem Bityutskiy 	/* Compare to parent and, if greater, move up the heap */
601e51764aSArtem Bityutskiy 	do {
611e51764aSArtem Bityutskiy 		int ppos = (hpos - 1) / 2;
621e51764aSArtem Bityutskiy 
631e51764aSArtem Bityutskiy 		val2 = get_heap_comp_val(heap->arr[ppos], cat);
641e51764aSArtem Bityutskiy 		if (val2 >= val1)
651e51764aSArtem Bityutskiy 			return;
661e51764aSArtem Bityutskiy 		/* Greater than parent so move up */
671e51764aSArtem Bityutskiy 		heap->arr[ppos]->hpos = hpos;
681e51764aSArtem Bityutskiy 		heap->arr[hpos] = heap->arr[ppos];
691e51764aSArtem Bityutskiy 		heap->arr[ppos] = lprops;
701e51764aSArtem Bityutskiy 		lprops->hpos = ppos;
711e51764aSArtem Bityutskiy 		hpos = ppos;
721e51764aSArtem Bityutskiy 	} while (hpos);
731e51764aSArtem Bityutskiy }
741e51764aSArtem Bityutskiy 
751e51764aSArtem Bityutskiy /**
761e51764aSArtem Bityutskiy  * adjust_lpt_heap - move a changed heap entry up or down the heap.
771e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
781e51764aSArtem Bityutskiy  * @heap: LEB category heap
791e51764aSArtem Bityutskiy  * @lprops: LEB properties to move
801e51764aSArtem Bityutskiy  * @hpos: heap position of @lprops
811e51764aSArtem Bityutskiy  * @cat: LEB category
821e51764aSArtem Bityutskiy  *
831e51764aSArtem Bityutskiy  * Changed entries in a heap are moved up or down until the parent's value is
841e51764aSArtem Bityutskiy  * greater.  In the case of LPT's category heaps, the value is either the amount
851e51764aSArtem Bityutskiy  * of free space or the amount of dirty space, depending on the category.
861e51764aSArtem Bityutskiy  */
adjust_lpt_heap(struct ubifs_info * c,struct ubifs_lpt_heap * heap,struct ubifs_lprops * lprops,int hpos,int cat)871e51764aSArtem Bityutskiy static void adjust_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
881e51764aSArtem Bityutskiy 			    struct ubifs_lprops *lprops, int hpos, int cat)
891e51764aSArtem Bityutskiy {
901e51764aSArtem Bityutskiy 	int val1, val2, val3, cpos;
911e51764aSArtem Bityutskiy 
921e51764aSArtem Bityutskiy 	val1 = get_heap_comp_val(lprops, cat);
931e51764aSArtem Bityutskiy 	/* Compare to parent and, if greater than parent, move up the heap */
941e51764aSArtem Bityutskiy 	if (hpos) {
951e51764aSArtem Bityutskiy 		int ppos = (hpos - 1) / 2;
961e51764aSArtem Bityutskiy 
971e51764aSArtem Bityutskiy 		val2 = get_heap_comp_val(heap->arr[ppos], cat);
981e51764aSArtem Bityutskiy 		if (val1 > val2) {
991e51764aSArtem Bityutskiy 			/* Greater than parent so move up */
1001e51764aSArtem Bityutskiy 			while (1) {
1011e51764aSArtem Bityutskiy 				heap->arr[ppos]->hpos = hpos;
1021e51764aSArtem Bityutskiy 				heap->arr[hpos] = heap->arr[ppos];
1031e51764aSArtem Bityutskiy 				heap->arr[ppos] = lprops;
1041e51764aSArtem Bityutskiy 				lprops->hpos = ppos;
1051e51764aSArtem Bityutskiy 				hpos = ppos;
1061e51764aSArtem Bityutskiy 				if (!hpos)
1071e51764aSArtem Bityutskiy 					return;
1081e51764aSArtem Bityutskiy 				ppos = (hpos - 1) / 2;
1091e51764aSArtem Bityutskiy 				val2 = get_heap_comp_val(heap->arr[ppos], cat);
1101e51764aSArtem Bityutskiy 				if (val1 <= val2)
1111e51764aSArtem Bityutskiy 					return;
1121e51764aSArtem Bityutskiy 				/* Still greater than parent so keep going */
1131e51764aSArtem Bityutskiy 			}
1141e51764aSArtem Bityutskiy 		}
1151e51764aSArtem Bityutskiy 	}
116948cfb21SArtem Bityutskiy 
1171e51764aSArtem Bityutskiy 	/* Not greater than parent, so compare to children */
1181e51764aSArtem Bityutskiy 	while (1) {
1191e51764aSArtem Bityutskiy 		/* Compare to left child */
1201e51764aSArtem Bityutskiy 		cpos = hpos * 2 + 1;
1211e51764aSArtem Bityutskiy 		if (cpos >= heap->cnt)
1221e51764aSArtem Bityutskiy 			return;
1231e51764aSArtem Bityutskiy 		val2 = get_heap_comp_val(heap->arr[cpos], cat);
1241e51764aSArtem Bityutskiy 		if (val1 < val2) {
1251e51764aSArtem Bityutskiy 			/* Less than left child, so promote biggest child */
1261e51764aSArtem Bityutskiy 			if (cpos + 1 < heap->cnt) {
1271e51764aSArtem Bityutskiy 				val3 = get_heap_comp_val(heap->arr[cpos + 1],
1281e51764aSArtem Bityutskiy 							 cat);
1291e51764aSArtem Bityutskiy 				if (val3 > val2)
1301e51764aSArtem Bityutskiy 					cpos += 1; /* Right child is bigger */
1311e51764aSArtem Bityutskiy 			}
1321e51764aSArtem Bityutskiy 			heap->arr[cpos]->hpos = hpos;
1331e51764aSArtem Bityutskiy 			heap->arr[hpos] = heap->arr[cpos];
1341e51764aSArtem Bityutskiy 			heap->arr[cpos] = lprops;
1351e51764aSArtem Bityutskiy 			lprops->hpos = cpos;
1361e51764aSArtem Bityutskiy 			hpos = cpos;
1371e51764aSArtem Bityutskiy 			continue;
1381e51764aSArtem Bityutskiy 		}
1391e51764aSArtem Bityutskiy 		/* Compare to right child */
1401e51764aSArtem Bityutskiy 		cpos += 1;
1411e51764aSArtem Bityutskiy 		if (cpos >= heap->cnt)
1421e51764aSArtem Bityutskiy 			return;
1431e51764aSArtem Bityutskiy 		val3 = get_heap_comp_val(heap->arr[cpos], cat);
1441e51764aSArtem Bityutskiy 		if (val1 < val3) {
1451e51764aSArtem Bityutskiy 			/* Less than right child, so promote right child */
1461e51764aSArtem Bityutskiy 			heap->arr[cpos]->hpos = hpos;
1471e51764aSArtem Bityutskiy 			heap->arr[hpos] = heap->arr[cpos];
1481e51764aSArtem Bityutskiy 			heap->arr[cpos] = lprops;
1491e51764aSArtem Bityutskiy 			lprops->hpos = cpos;
1501e51764aSArtem Bityutskiy 			hpos = cpos;
1511e51764aSArtem Bityutskiy 			continue;
1521e51764aSArtem Bityutskiy 		}
1531e51764aSArtem Bityutskiy 		return;
1541e51764aSArtem Bityutskiy 	}
1551e51764aSArtem Bityutskiy }
1561e51764aSArtem Bityutskiy 
1571e51764aSArtem Bityutskiy /**
1581e51764aSArtem Bityutskiy  * add_to_lpt_heap - add LEB properties to a LEB category heap.
1591e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
1601e51764aSArtem Bityutskiy  * @lprops: LEB properties to add
1611e51764aSArtem Bityutskiy  * @cat: LEB category
1621e51764aSArtem Bityutskiy  *
1631e51764aSArtem Bityutskiy  * This function returns %1 if @lprops is added to the heap for LEB category
1641e51764aSArtem Bityutskiy  * @cat, otherwise %0 is returned because the heap is full.
1651e51764aSArtem Bityutskiy  */
add_to_lpt_heap(struct ubifs_info * c,struct ubifs_lprops * lprops,int cat)1661e51764aSArtem Bityutskiy static int add_to_lpt_heap(struct ubifs_info *c, struct ubifs_lprops *lprops,
1671e51764aSArtem Bityutskiy 			   int cat)
1681e51764aSArtem Bityutskiy {
1691e51764aSArtem Bityutskiy 	struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
1701e51764aSArtem Bityutskiy 
1711e51764aSArtem Bityutskiy 	if (heap->cnt >= heap->max_cnt) {
1721e51764aSArtem Bityutskiy 		const int b = LPT_HEAP_SZ / 2 - 1;
1731e51764aSArtem Bityutskiy 		int cpos, val1, val2;
1741e51764aSArtem Bityutskiy 
1751e51764aSArtem Bityutskiy 		/* Compare to some other LEB on the bottom of heap */
1761e51764aSArtem Bityutskiy 		/* Pick a position kind of randomly */
1771e51764aSArtem Bityutskiy 		cpos = (((size_t)lprops >> 4) & b) + b;
1786eb61d58SRichard Weinberger 		ubifs_assert(c, cpos >= b);
1796eb61d58SRichard Weinberger 		ubifs_assert(c, cpos < LPT_HEAP_SZ);
1806eb61d58SRichard Weinberger 		ubifs_assert(c, cpos < heap->cnt);
1811e51764aSArtem Bityutskiy 
1821e51764aSArtem Bityutskiy 		val1 = get_heap_comp_val(lprops, cat);
1831e51764aSArtem Bityutskiy 		val2 = get_heap_comp_val(heap->arr[cpos], cat);
1841e51764aSArtem Bityutskiy 		if (val1 > val2) {
1851e51764aSArtem Bityutskiy 			struct ubifs_lprops *lp;
1861e51764aSArtem Bityutskiy 
1871e51764aSArtem Bityutskiy 			lp = heap->arr[cpos];
1881e51764aSArtem Bityutskiy 			lp->flags &= ~LPROPS_CAT_MASK;
1891e51764aSArtem Bityutskiy 			lp->flags |= LPROPS_UNCAT;
1901e51764aSArtem Bityutskiy 			list_add(&lp->list, &c->uncat_list);
1911e51764aSArtem Bityutskiy 			lprops->hpos = cpos;
1921e51764aSArtem Bityutskiy 			heap->arr[cpos] = lprops;
1931e51764aSArtem Bityutskiy 			move_up_lpt_heap(c, heap, lprops, cat);
1941e51764aSArtem Bityutskiy 			dbg_check_heap(c, heap, cat, lprops->hpos);
1951e51764aSArtem Bityutskiy 			return 1; /* Added to heap */
1961e51764aSArtem Bityutskiy 		}
1971e51764aSArtem Bityutskiy 		dbg_check_heap(c, heap, cat, -1);
1981e51764aSArtem Bityutskiy 		return 0; /* Not added to heap */
1991e51764aSArtem Bityutskiy 	} else {
2001e51764aSArtem Bityutskiy 		lprops->hpos = heap->cnt++;
2011e51764aSArtem Bityutskiy 		heap->arr[lprops->hpos] = lprops;
2021e51764aSArtem Bityutskiy 		move_up_lpt_heap(c, heap, lprops, cat);
2031e51764aSArtem Bityutskiy 		dbg_check_heap(c, heap, cat, lprops->hpos);
2041e51764aSArtem Bityutskiy 		return 1; /* Added to heap */
2051e51764aSArtem Bityutskiy 	}
2061e51764aSArtem Bityutskiy }
2071e51764aSArtem Bityutskiy 
2081e51764aSArtem Bityutskiy /**
2091e51764aSArtem Bityutskiy  * remove_from_lpt_heap - remove LEB properties from a LEB category heap.
2101e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
2111e51764aSArtem Bityutskiy  * @lprops: LEB properties to remove
2121e51764aSArtem Bityutskiy  * @cat: LEB category
2131e51764aSArtem Bityutskiy  */
remove_from_lpt_heap(struct ubifs_info * c,struct ubifs_lprops * lprops,int cat)2141e51764aSArtem Bityutskiy static void remove_from_lpt_heap(struct ubifs_info *c,
2151e51764aSArtem Bityutskiy 				 struct ubifs_lprops *lprops, int cat)
2161e51764aSArtem Bityutskiy {
2171e51764aSArtem Bityutskiy 	struct ubifs_lpt_heap *heap;
2181e51764aSArtem Bityutskiy 	int hpos = lprops->hpos;
2191e51764aSArtem Bityutskiy 
2201e51764aSArtem Bityutskiy 	heap = &c->lpt_heap[cat - 1];
2216eb61d58SRichard Weinberger 	ubifs_assert(c, hpos >= 0 && hpos < heap->cnt);
2226eb61d58SRichard Weinberger 	ubifs_assert(c, heap->arr[hpos] == lprops);
2231e51764aSArtem Bityutskiy 	heap->cnt -= 1;
2241e51764aSArtem Bityutskiy 	if (hpos < heap->cnt) {
2251e51764aSArtem Bityutskiy 		heap->arr[hpos] = heap->arr[heap->cnt];
2261e51764aSArtem Bityutskiy 		heap->arr[hpos]->hpos = hpos;
2271e51764aSArtem Bityutskiy 		adjust_lpt_heap(c, heap, heap->arr[hpos], hpos, cat);
2281e51764aSArtem Bityutskiy 	}
2291e51764aSArtem Bityutskiy 	dbg_check_heap(c, heap, cat, -1);
2301e51764aSArtem Bityutskiy }
2311e51764aSArtem Bityutskiy 
2321e51764aSArtem Bityutskiy /**
2331e51764aSArtem Bityutskiy  * lpt_heap_replace - replace lprops in a category heap.
2341e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
2351e51764aSArtem Bityutskiy  * @new_lprops: LEB properties with which to replace
2361e51764aSArtem Bityutskiy  * @cat: LEB category
2371e51764aSArtem Bityutskiy  *
2381e51764aSArtem Bityutskiy  * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
2391e51764aSArtem Bityutskiy  * and the lprops that the pnode contains.  When that happens, references in
2401e51764aSArtem Bityutskiy  * the category heaps to those lprops must be updated to point to the new
2411e51764aSArtem Bityutskiy  * lprops.  This function does that.
2421e51764aSArtem Bityutskiy  */
lpt_heap_replace(struct ubifs_info * c,struct ubifs_lprops * new_lprops,int cat)2431e51764aSArtem Bityutskiy static void lpt_heap_replace(struct ubifs_info *c,
2441e51764aSArtem Bityutskiy 			     struct ubifs_lprops *new_lprops, int cat)
2451e51764aSArtem Bityutskiy {
2461e51764aSArtem Bityutskiy 	struct ubifs_lpt_heap *heap;
2471e51764aSArtem Bityutskiy 	int hpos = new_lprops->hpos;
2481e51764aSArtem Bityutskiy 
2491e51764aSArtem Bityutskiy 	heap = &c->lpt_heap[cat - 1];
2501e51764aSArtem Bityutskiy 	heap->arr[hpos] = new_lprops;
2511e51764aSArtem Bityutskiy }
2521e51764aSArtem Bityutskiy 
2531e51764aSArtem Bityutskiy /**
2541e51764aSArtem Bityutskiy  * ubifs_add_to_cat - add LEB properties to a category list or heap.
2551e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
2561e51764aSArtem Bityutskiy  * @lprops: LEB properties to add
2571e51764aSArtem Bityutskiy  * @cat: LEB category to which to add
2581e51764aSArtem Bityutskiy  *
2591e51764aSArtem Bityutskiy  * LEB properties are categorized to enable fast find operations.
2601e51764aSArtem Bityutskiy  */
ubifs_add_to_cat(struct ubifs_info * c,struct ubifs_lprops * lprops,int cat)2611e51764aSArtem Bityutskiy void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
2621e51764aSArtem Bityutskiy 		      int cat)
2631e51764aSArtem Bityutskiy {
2641e51764aSArtem Bityutskiy 	switch (cat) {
2651e51764aSArtem Bityutskiy 	case LPROPS_DIRTY:
2661e51764aSArtem Bityutskiy 	case LPROPS_DIRTY_IDX:
2671e51764aSArtem Bityutskiy 	case LPROPS_FREE:
2681e51764aSArtem Bityutskiy 		if (add_to_lpt_heap(c, lprops, cat))
2691e51764aSArtem Bityutskiy 			break;
270055da1b7SArtem Bityutskiy 		/* No more room on heap so make it un-categorized */
2711e51764aSArtem Bityutskiy 		cat = LPROPS_UNCAT;
272*df561f66SGustavo A. R. Silva 		fallthrough;
2731e51764aSArtem Bityutskiy 	case LPROPS_UNCAT:
2741e51764aSArtem Bityutskiy 		list_add(&lprops->list, &c->uncat_list);
2751e51764aSArtem Bityutskiy 		break;
2761e51764aSArtem Bityutskiy 	case LPROPS_EMPTY:
2771e51764aSArtem Bityutskiy 		list_add(&lprops->list, &c->empty_list);
2781e51764aSArtem Bityutskiy 		break;
2791e51764aSArtem Bityutskiy 	case LPROPS_FREEABLE:
2801e51764aSArtem Bityutskiy 		list_add(&lprops->list, &c->freeable_list);
2811e51764aSArtem Bityutskiy 		c->freeable_cnt += 1;
2821e51764aSArtem Bityutskiy 		break;
2831e51764aSArtem Bityutskiy 	case LPROPS_FRDI_IDX:
2841e51764aSArtem Bityutskiy 		list_add(&lprops->list, &c->frdi_idx_list);
2851e51764aSArtem Bityutskiy 		break;
2861e51764aSArtem Bityutskiy 	default:
2876eb61d58SRichard Weinberger 		ubifs_assert(c, 0);
2881e51764aSArtem Bityutskiy 	}
28998a1eebdSArtem Bityutskiy 
2901e51764aSArtem Bityutskiy 	lprops->flags &= ~LPROPS_CAT_MASK;
2911e51764aSArtem Bityutskiy 	lprops->flags |= cat;
29298a1eebdSArtem Bityutskiy 	c->in_a_category_cnt += 1;
2936eb61d58SRichard Weinberger 	ubifs_assert(c, c->in_a_category_cnt <= c->main_lebs);
2941e51764aSArtem Bityutskiy }
2951e51764aSArtem Bityutskiy 
2961e51764aSArtem Bityutskiy /**
2971e51764aSArtem Bityutskiy  * ubifs_remove_from_cat - remove LEB properties from a category list or heap.
2981e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
2991e51764aSArtem Bityutskiy  * @lprops: LEB properties to remove
3001e51764aSArtem Bityutskiy  * @cat: LEB category from which to remove
3011e51764aSArtem Bityutskiy  *
3021e51764aSArtem Bityutskiy  * LEB properties are categorized to enable fast find operations.
3031e51764aSArtem Bityutskiy  */
ubifs_remove_from_cat(struct ubifs_info * c,struct ubifs_lprops * lprops,int cat)3041e51764aSArtem Bityutskiy static void ubifs_remove_from_cat(struct ubifs_info *c,
3051e51764aSArtem Bityutskiy 				  struct ubifs_lprops *lprops, int cat)
3061e51764aSArtem Bityutskiy {
3071e51764aSArtem Bityutskiy 	switch (cat) {
3081e51764aSArtem Bityutskiy 	case LPROPS_DIRTY:
3091e51764aSArtem Bityutskiy 	case LPROPS_DIRTY_IDX:
3101e51764aSArtem Bityutskiy 	case LPROPS_FREE:
3111e51764aSArtem Bityutskiy 		remove_from_lpt_heap(c, lprops, cat);
3121e51764aSArtem Bityutskiy 		break;
3131e51764aSArtem Bityutskiy 	case LPROPS_FREEABLE:
3141e51764aSArtem Bityutskiy 		c->freeable_cnt -= 1;
3156eb61d58SRichard Weinberger 		ubifs_assert(c, c->freeable_cnt >= 0);
316*df561f66SGustavo A. R. Silva 		fallthrough;
3171e51764aSArtem Bityutskiy 	case LPROPS_UNCAT:
3181e51764aSArtem Bityutskiy 	case LPROPS_EMPTY:
3191e51764aSArtem Bityutskiy 	case LPROPS_FRDI_IDX:
3206eb61d58SRichard Weinberger 		ubifs_assert(c, !list_empty(&lprops->list));
3211e51764aSArtem Bityutskiy 		list_del(&lprops->list);
3221e51764aSArtem Bityutskiy 		break;
3231e51764aSArtem Bityutskiy 	default:
3246eb61d58SRichard Weinberger 		ubifs_assert(c, 0);
3251e51764aSArtem Bityutskiy 	}
32698a1eebdSArtem Bityutskiy 
32798a1eebdSArtem Bityutskiy 	c->in_a_category_cnt -= 1;
3286eb61d58SRichard Weinberger 	ubifs_assert(c, c->in_a_category_cnt >= 0);
3291e51764aSArtem Bityutskiy }
3301e51764aSArtem Bityutskiy 
3311e51764aSArtem Bityutskiy /**
3321e51764aSArtem Bityutskiy  * ubifs_replace_cat - replace lprops in a category list or heap.
3331e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
3341e51764aSArtem Bityutskiy  * @old_lprops: LEB properties to replace
3351e51764aSArtem Bityutskiy  * @new_lprops: LEB properties with which to replace
3361e51764aSArtem Bityutskiy  *
3371e51764aSArtem Bityutskiy  * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
3381e51764aSArtem Bityutskiy  * and the lprops that the pnode contains. When that happens, references in
3391e51764aSArtem Bityutskiy  * category lists and heaps must be replaced. This function does that.
3401e51764aSArtem Bityutskiy  */
ubifs_replace_cat(struct ubifs_info * c,struct ubifs_lprops * old_lprops,struct ubifs_lprops * new_lprops)3411e51764aSArtem Bityutskiy void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
3421e51764aSArtem Bityutskiy 		       struct ubifs_lprops *new_lprops)
3431e51764aSArtem Bityutskiy {
3441e51764aSArtem Bityutskiy 	int cat;
3451e51764aSArtem Bityutskiy 
3461e51764aSArtem Bityutskiy 	cat = new_lprops->flags & LPROPS_CAT_MASK;
3471e51764aSArtem Bityutskiy 	switch (cat) {
3481e51764aSArtem Bityutskiy 	case LPROPS_DIRTY:
3491e51764aSArtem Bityutskiy 	case LPROPS_DIRTY_IDX:
3501e51764aSArtem Bityutskiy 	case LPROPS_FREE:
3514fb1cd82SJiang Biao 		lpt_heap_replace(c, new_lprops, cat);
3521e51764aSArtem Bityutskiy 		break;
3531e51764aSArtem Bityutskiy 	case LPROPS_UNCAT:
3541e51764aSArtem Bityutskiy 	case LPROPS_EMPTY:
3551e51764aSArtem Bityutskiy 	case LPROPS_FREEABLE:
3561e51764aSArtem Bityutskiy 	case LPROPS_FRDI_IDX:
3571e51764aSArtem Bityutskiy 		list_replace(&old_lprops->list, &new_lprops->list);
3581e51764aSArtem Bityutskiy 		break;
3591e51764aSArtem Bityutskiy 	default:
3606eb61d58SRichard Weinberger 		ubifs_assert(c, 0);
3611e51764aSArtem Bityutskiy 	}
3621e51764aSArtem Bityutskiy }
3631e51764aSArtem Bityutskiy 
3641e51764aSArtem Bityutskiy /**
3651e51764aSArtem Bityutskiy  * ubifs_ensure_cat - ensure LEB properties are categorized.
3661e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
3671e51764aSArtem Bityutskiy  * @lprops: LEB properties
3681e51764aSArtem Bityutskiy  *
3691e51764aSArtem Bityutskiy  * A LEB may have fallen off of the bottom of a heap, and ended up as
370055da1b7SArtem Bityutskiy  * un-categorized even though it has enough space for us now. If that is the
371055da1b7SArtem Bityutskiy  * case this function will put the LEB back onto a heap.
3721e51764aSArtem Bityutskiy  */
ubifs_ensure_cat(struct ubifs_info * c,struct ubifs_lprops * lprops)3731e51764aSArtem Bityutskiy void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops)
3741e51764aSArtem Bityutskiy {
3751e51764aSArtem Bityutskiy 	int cat = lprops->flags & LPROPS_CAT_MASK;
3761e51764aSArtem Bityutskiy 
3771e51764aSArtem Bityutskiy 	if (cat != LPROPS_UNCAT)
3781e51764aSArtem Bityutskiy 		return;
3791e51764aSArtem Bityutskiy 	cat = ubifs_categorize_lprops(c, lprops);
3801e51764aSArtem Bityutskiy 	if (cat == LPROPS_UNCAT)
3811e51764aSArtem Bityutskiy 		return;
3821e51764aSArtem Bityutskiy 	ubifs_remove_from_cat(c, lprops, LPROPS_UNCAT);
3831e51764aSArtem Bityutskiy 	ubifs_add_to_cat(c, lprops, cat);
3841e51764aSArtem Bityutskiy }
3851e51764aSArtem Bityutskiy 
3861e51764aSArtem Bityutskiy /**
3871e51764aSArtem Bityutskiy  * ubifs_categorize_lprops - categorize LEB properties.
3881e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
3891e51764aSArtem Bityutskiy  * @lprops: LEB properties to categorize
3901e51764aSArtem Bityutskiy  *
3911e51764aSArtem Bityutskiy  * LEB properties are categorized to enable fast find operations. This function
3921e51764aSArtem Bityutskiy  * returns the LEB category to which the LEB properties belong. Note however
3931e51764aSArtem Bityutskiy  * that if the LEB category is stored as a heap and the heap is full, the
3941e51764aSArtem Bityutskiy  * LEB properties may have their category changed to %LPROPS_UNCAT.
3951e51764aSArtem Bityutskiy  */
ubifs_categorize_lprops(const struct ubifs_info * c,const struct ubifs_lprops * lprops)3961e51764aSArtem Bityutskiy int ubifs_categorize_lprops(const struct ubifs_info *c,
3971e51764aSArtem Bityutskiy 			    const struct ubifs_lprops *lprops)
3981e51764aSArtem Bityutskiy {
3991e51764aSArtem Bityutskiy 	if (lprops->flags & LPROPS_TAKEN)
4001e51764aSArtem Bityutskiy 		return LPROPS_UNCAT;
4011e51764aSArtem Bityutskiy 
4021e51764aSArtem Bityutskiy 	if (lprops->free == c->leb_size) {
4036eb61d58SRichard Weinberger 		ubifs_assert(c, !(lprops->flags & LPROPS_INDEX));
4041e51764aSArtem Bityutskiy 		return LPROPS_EMPTY;
4051e51764aSArtem Bityutskiy 	}
4061e51764aSArtem Bityutskiy 
4071e51764aSArtem Bityutskiy 	if (lprops->free + lprops->dirty == c->leb_size) {
4081e51764aSArtem Bityutskiy 		if (lprops->flags & LPROPS_INDEX)
4091e51764aSArtem Bityutskiy 			return LPROPS_FRDI_IDX;
4101e51764aSArtem Bityutskiy 		else
4111e51764aSArtem Bityutskiy 			return LPROPS_FREEABLE;
4121e51764aSArtem Bityutskiy 	}
4131e51764aSArtem Bityutskiy 
4141e51764aSArtem Bityutskiy 	if (lprops->flags & LPROPS_INDEX) {
4151e51764aSArtem Bityutskiy 		if (lprops->dirty + lprops->free >= c->min_idx_node_sz)
4161e51764aSArtem Bityutskiy 			return LPROPS_DIRTY_IDX;
4171e51764aSArtem Bityutskiy 	} else {
4181e51764aSArtem Bityutskiy 		if (lprops->dirty >= c->dead_wm &&
4191e51764aSArtem Bityutskiy 		    lprops->dirty > lprops->free)
4201e51764aSArtem Bityutskiy 			return LPROPS_DIRTY;
4211e51764aSArtem Bityutskiy 		if (lprops->free > 0)
4221e51764aSArtem Bityutskiy 			return LPROPS_FREE;
4231e51764aSArtem Bityutskiy 	}
4241e51764aSArtem Bityutskiy 
4251e51764aSArtem Bityutskiy 	return LPROPS_UNCAT;
4261e51764aSArtem Bityutskiy }
4271e51764aSArtem Bityutskiy 
4281e51764aSArtem Bityutskiy /**
4291e51764aSArtem Bityutskiy  * change_category - change LEB properties category.
4301e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
431055da1b7SArtem Bityutskiy  * @lprops: LEB properties to re-categorize
4321e51764aSArtem Bityutskiy  *
4331e51764aSArtem Bityutskiy  * LEB properties are categorized to enable fast find operations. When the LEB
434055da1b7SArtem Bityutskiy  * properties change they must be re-categorized.
4351e51764aSArtem Bityutskiy  */
change_category(struct ubifs_info * c,struct ubifs_lprops * lprops)4361e51764aSArtem Bityutskiy static void change_category(struct ubifs_info *c, struct ubifs_lprops *lprops)
4371e51764aSArtem Bityutskiy {
4381e51764aSArtem Bityutskiy 	int old_cat = lprops->flags & LPROPS_CAT_MASK;
4391e51764aSArtem Bityutskiy 	int new_cat = ubifs_categorize_lprops(c, lprops);
4401e51764aSArtem Bityutskiy 
4411e51764aSArtem Bityutskiy 	if (old_cat == new_cat) {
442273946a5SDan Carpenter 		struct ubifs_lpt_heap *heap;
4431e51764aSArtem Bityutskiy 
4441e51764aSArtem Bityutskiy 		/* lprops on a heap now must be moved up or down */
4451e51764aSArtem Bityutskiy 		if (new_cat < 1 || new_cat > LPROPS_HEAP_CNT)
4461e51764aSArtem Bityutskiy 			return; /* Not on a heap */
4471e51764aSArtem Bityutskiy 		heap = &c->lpt_heap[new_cat - 1];
4481e51764aSArtem Bityutskiy 		adjust_lpt_heap(c, heap, lprops, lprops->hpos, new_cat);
4491e51764aSArtem Bityutskiy 	} else {
4501e51764aSArtem Bityutskiy 		ubifs_remove_from_cat(c, lprops, old_cat);
4511e51764aSArtem Bityutskiy 		ubifs_add_to_cat(c, lprops, new_cat);
4521e51764aSArtem Bityutskiy 	}
4531e51764aSArtem Bityutskiy }
4541e51764aSArtem Bityutskiy 
4551e51764aSArtem Bityutskiy /**
456be9e62a7SArtem Bityutskiy  * ubifs_calc_dark - calculate LEB dark space size.
4571e51764aSArtem Bityutskiy  * @c: the UBIFS file-system description object
4581e51764aSArtem Bityutskiy  * @spc: amount of free and dirty space in the LEB
4591e51764aSArtem Bityutskiy  *
460be9e62a7SArtem Bityutskiy  * This function calculates and returns amount of dark space in an LEB which
461be9e62a7SArtem Bityutskiy  * has @spc bytes of free and dirty space.
4621e51764aSArtem Bityutskiy  *
463be9e62a7SArtem Bityutskiy  * UBIFS is trying to account the space which might not be usable, and this
464be9e62a7SArtem Bityutskiy  * space is called "dark space". For example, if an LEB has only %512 free
465be9e62a7SArtem Bityutskiy  * bytes, it is dark space, because it cannot fit a large data node.
4661e51764aSArtem Bityutskiy  */
ubifs_calc_dark(const struct ubifs_info * c,int spc)467be9e62a7SArtem Bityutskiy int ubifs_calc_dark(const struct ubifs_info *c, int spc)
4681e51764aSArtem Bityutskiy {
4696eb61d58SRichard Weinberger 	ubifs_assert(c, !(spc & 7));
4701e51764aSArtem Bityutskiy 
4711e51764aSArtem Bityutskiy 	if (spc < c->dark_wm)
4721e51764aSArtem Bityutskiy 		return spc;
4731e51764aSArtem Bityutskiy 
4741e51764aSArtem Bityutskiy 	/*
4751e51764aSArtem Bityutskiy 	 * If we have slightly more space then the dark space watermark, we can
4761e51764aSArtem Bityutskiy 	 * anyway safely assume it we'll be able to write a node of the
4771e51764aSArtem Bityutskiy 	 * smallest size there.
4781e51764aSArtem Bityutskiy 	 */
4791e51764aSArtem Bityutskiy 	if (spc - c->dark_wm < MIN_WRITE_SZ)
4801e51764aSArtem Bityutskiy 		return spc - MIN_WRITE_SZ;
4811e51764aSArtem Bityutskiy 
4821e51764aSArtem Bityutskiy 	return c->dark_wm;
4831e51764aSArtem Bityutskiy }
4841e51764aSArtem Bityutskiy 
4851e51764aSArtem Bityutskiy /**
4861e51764aSArtem Bityutskiy  * is_lprops_dirty - determine if LEB properties are dirty.
4871e51764aSArtem Bityutskiy  * @c: the UBIFS file-system description object
4881e51764aSArtem Bityutskiy  * @lprops: LEB properties to test
4891e51764aSArtem Bityutskiy  */
is_lprops_dirty(struct ubifs_info * c,struct ubifs_lprops * lprops)4901e51764aSArtem Bityutskiy static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
4911e51764aSArtem Bityutskiy {
4921e51764aSArtem Bityutskiy 	struct ubifs_pnode *pnode;
4931e51764aSArtem Bityutskiy 	int pos;
4941e51764aSArtem Bityutskiy 
4951e51764aSArtem Bityutskiy 	pos = (lprops->lnum - c->main_first) & (UBIFS_LPT_FANOUT - 1);
4961e51764aSArtem Bityutskiy 	pnode = (struct ubifs_pnode *)container_of(lprops - pos,
4971e51764aSArtem Bityutskiy 						   struct ubifs_pnode,
4981e51764aSArtem Bityutskiy 						   lprops[0]);
49937662447SArtem Bityutskiy 	return !test_bit(COW_CNODE, &pnode->flags) &&
5001e51764aSArtem Bityutskiy 	       test_bit(DIRTY_CNODE, &pnode->flags);
5011e51764aSArtem Bityutskiy }
5021e51764aSArtem Bityutskiy 
5031e51764aSArtem Bityutskiy /**
5041e51764aSArtem Bityutskiy  * ubifs_change_lp - change LEB properties.
5051e51764aSArtem Bityutskiy  * @c: the UBIFS file-system description object
5061e51764aSArtem Bityutskiy  * @lp: LEB properties to change
5071e51764aSArtem Bityutskiy  * @free: new free space amount
5081e51764aSArtem Bityutskiy  * @dirty: new dirty space amount
5091e51764aSArtem Bityutskiy  * @flags: new flags
510055da1b7SArtem Bityutskiy  * @idx_gc_cnt: change to the count of @idx_gc list
5111e51764aSArtem Bityutskiy  *
512d3cf502bSArtem Bityutskiy  * This function changes LEB properties (@free, @dirty or @flag). However, the
513d3cf502bSArtem Bityutskiy  * property which has the %LPROPS_NC value is not changed. Returns a pointer to
514d3cf502bSArtem Bityutskiy  * the updated LEB properties on success and a negative error code on failure.
5151e51764aSArtem Bityutskiy  *
516d3cf502bSArtem Bityutskiy  * Note, the LEB properties may have had to be copied (due to COW) and
517d3cf502bSArtem Bityutskiy  * consequently the pointer returned may not be the same as the pointer
518d3cf502bSArtem Bityutskiy  * passed.
5191e51764aSArtem Bityutskiy  */
ubifs_change_lp(struct ubifs_info * c,const struct ubifs_lprops * lp,int free,int dirty,int flags,int idx_gc_cnt)5201e51764aSArtem Bityutskiy const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
5211e51764aSArtem Bityutskiy 					   const struct ubifs_lprops *lp,
5221e51764aSArtem Bityutskiy 					   int free, int dirty, int flags,
5231e51764aSArtem Bityutskiy 					   int idx_gc_cnt)
5241e51764aSArtem Bityutskiy {
5251e51764aSArtem Bityutskiy 	/*
5261e51764aSArtem Bityutskiy 	 * This is the only function that is allowed to change lprops, so we
527055da1b7SArtem Bityutskiy 	 * discard the "const" qualifier.
5281e51764aSArtem Bityutskiy 	 */
5291e51764aSArtem Bityutskiy 	struct ubifs_lprops *lprops = (struct ubifs_lprops *)lp;
5301e51764aSArtem Bityutskiy 
5311e51764aSArtem Bityutskiy 	dbg_lp("LEB %d, free %d, dirty %d, flags %d",
5321e51764aSArtem Bityutskiy 	       lprops->lnum, free, dirty, flags);
5331e51764aSArtem Bityutskiy 
5346eb61d58SRichard Weinberger 	ubifs_assert(c, mutex_is_locked(&c->lp_mutex));
5356eb61d58SRichard Weinberger 	ubifs_assert(c, c->lst.empty_lebs >= 0 &&
5361e51764aSArtem Bityutskiy 		     c->lst.empty_lebs <= c->main_lebs);
5376eb61d58SRichard Weinberger 	ubifs_assert(c, c->freeable_cnt >= 0);
5386eb61d58SRichard Weinberger 	ubifs_assert(c, c->freeable_cnt <= c->main_lebs);
5396eb61d58SRichard Weinberger 	ubifs_assert(c, c->lst.taken_empty_lebs >= 0);
5406eb61d58SRichard Weinberger 	ubifs_assert(c, c->lst.taken_empty_lebs <= c->lst.empty_lebs);
5416eb61d58SRichard Weinberger 	ubifs_assert(c, !(c->lst.total_free & 7) && !(c->lst.total_dirty & 7));
5426eb61d58SRichard Weinberger 	ubifs_assert(c, !(c->lst.total_dead & 7) && !(c->lst.total_dark & 7));
5436eb61d58SRichard Weinberger 	ubifs_assert(c, !(c->lst.total_used & 7));
5446eb61d58SRichard Weinberger 	ubifs_assert(c, free == LPROPS_NC || free >= 0);
5456eb61d58SRichard Weinberger 	ubifs_assert(c, dirty == LPROPS_NC || dirty >= 0);
5461e51764aSArtem Bityutskiy 
5471e51764aSArtem Bityutskiy 	if (!is_lprops_dirty(c, lprops)) {
5481e51764aSArtem Bityutskiy 		lprops = ubifs_lpt_lookup_dirty(c, lprops->lnum);
5491e51764aSArtem Bityutskiy 		if (IS_ERR(lprops))
5501e51764aSArtem Bityutskiy 			return lprops;
5511e51764aSArtem Bityutskiy 	} else
5526eb61d58SRichard Weinberger 		ubifs_assert(c, lprops == ubifs_lpt_lookup_dirty(c, lprops->lnum));
5531e51764aSArtem Bityutskiy 
5546eb61d58SRichard Weinberger 	ubifs_assert(c, !(lprops->free & 7) && !(lprops->dirty & 7));
5551e51764aSArtem Bityutskiy 
5561e51764aSArtem Bityutskiy 	spin_lock(&c->space_lock);
5571e51764aSArtem Bityutskiy 	if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
5581e51764aSArtem Bityutskiy 		c->lst.taken_empty_lebs -= 1;
5591e51764aSArtem Bityutskiy 
5601e51764aSArtem Bityutskiy 	if (!(lprops->flags & LPROPS_INDEX)) {
5611e51764aSArtem Bityutskiy 		int old_spc;
5621e51764aSArtem Bityutskiy 
5631e51764aSArtem Bityutskiy 		old_spc = lprops->free + lprops->dirty;
5641e51764aSArtem Bityutskiy 		if (old_spc < c->dead_wm)
5651e51764aSArtem Bityutskiy 			c->lst.total_dead -= old_spc;
5661e51764aSArtem Bityutskiy 		else
567be9e62a7SArtem Bityutskiy 			c->lst.total_dark -= ubifs_calc_dark(c, old_spc);
5681e51764aSArtem Bityutskiy 
5691e51764aSArtem Bityutskiy 		c->lst.total_used -= c->leb_size - old_spc;
5701e51764aSArtem Bityutskiy 	}
5711e51764aSArtem Bityutskiy 
5721e51764aSArtem Bityutskiy 	if (free != LPROPS_NC) {
5731e51764aSArtem Bityutskiy 		free = ALIGN(free, 8);
5741e51764aSArtem Bityutskiy 		c->lst.total_free += free - lprops->free;
5751e51764aSArtem Bityutskiy 
5761e51764aSArtem Bityutskiy 		/* Increase or decrease empty LEBs counter if needed */
5771e51764aSArtem Bityutskiy 		if (free == c->leb_size) {
5781e51764aSArtem Bityutskiy 			if (lprops->free != c->leb_size)
5791e51764aSArtem Bityutskiy 				c->lst.empty_lebs += 1;
5801e51764aSArtem Bityutskiy 		} else if (lprops->free == c->leb_size)
5811e51764aSArtem Bityutskiy 			c->lst.empty_lebs -= 1;
5821e51764aSArtem Bityutskiy 		lprops->free = free;
5831e51764aSArtem Bityutskiy 	}
5841e51764aSArtem Bityutskiy 
5851e51764aSArtem Bityutskiy 	if (dirty != LPROPS_NC) {
5861e51764aSArtem Bityutskiy 		dirty = ALIGN(dirty, 8);
5871e51764aSArtem Bityutskiy 		c->lst.total_dirty += dirty - lprops->dirty;
5881e51764aSArtem Bityutskiy 		lprops->dirty = dirty;
5891e51764aSArtem Bityutskiy 	}
5901e51764aSArtem Bityutskiy 
5911e51764aSArtem Bityutskiy 	if (flags != LPROPS_NC) {
5921e51764aSArtem Bityutskiy 		/* Take care about indexing LEBs counter if needed */
5931e51764aSArtem Bityutskiy 		if ((lprops->flags & LPROPS_INDEX)) {
5941e51764aSArtem Bityutskiy 			if (!(flags & LPROPS_INDEX))
5951e51764aSArtem Bityutskiy 				c->lst.idx_lebs -= 1;
5961e51764aSArtem Bityutskiy 		} else if (flags & LPROPS_INDEX)
5971e51764aSArtem Bityutskiy 			c->lst.idx_lebs += 1;
5981e51764aSArtem Bityutskiy 		lprops->flags = flags;
5991e51764aSArtem Bityutskiy 	}
6001e51764aSArtem Bityutskiy 
6011e51764aSArtem Bityutskiy 	if (!(lprops->flags & LPROPS_INDEX)) {
6021e51764aSArtem Bityutskiy 		int new_spc;
6031e51764aSArtem Bityutskiy 
6041e51764aSArtem Bityutskiy 		new_spc = lprops->free + lprops->dirty;
6051e51764aSArtem Bityutskiy 		if (new_spc < c->dead_wm)
6061e51764aSArtem Bityutskiy 			c->lst.total_dead += new_spc;
6071e51764aSArtem Bityutskiy 		else
608be9e62a7SArtem Bityutskiy 			c->lst.total_dark += ubifs_calc_dark(c, new_spc);
6091e51764aSArtem Bityutskiy 
6101e51764aSArtem Bityutskiy 		c->lst.total_used += c->leb_size - new_spc;
6111e51764aSArtem Bityutskiy 	}
6121e51764aSArtem Bityutskiy 
6131e51764aSArtem Bityutskiy 	if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
6141e51764aSArtem Bityutskiy 		c->lst.taken_empty_lebs += 1;
6151e51764aSArtem Bityutskiy 
6161e51764aSArtem Bityutskiy 	change_category(c, lprops);
6171e51764aSArtem Bityutskiy 	c->idx_gc_cnt += idx_gc_cnt;
6181e51764aSArtem Bityutskiy 	spin_unlock(&c->space_lock);
6191e51764aSArtem Bityutskiy 	return lprops;
6201e51764aSArtem Bityutskiy }
6211e51764aSArtem Bityutskiy 
6221e51764aSArtem Bityutskiy /**
6231e51764aSArtem Bityutskiy  * ubifs_get_lp_stats - get lprops statistics.
6241e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
625ec037dfcSJulia Lawall  * @lst: return statistics
6261e51764aSArtem Bityutskiy  */
ubifs_get_lp_stats(struct ubifs_info * c,struct ubifs_lp_stats * lst)62784abf972SArtem Bityutskiy void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst)
6281e51764aSArtem Bityutskiy {
6291e51764aSArtem Bityutskiy 	spin_lock(&c->space_lock);
63084abf972SArtem Bityutskiy 	memcpy(lst, &c->lst, sizeof(struct ubifs_lp_stats));
6311e51764aSArtem Bityutskiy 	spin_unlock(&c->space_lock);
6321e51764aSArtem Bityutskiy }
6331e51764aSArtem Bityutskiy 
6341e51764aSArtem Bityutskiy /**
6351e51764aSArtem Bityutskiy  * ubifs_change_one_lp - change LEB properties.
6361e51764aSArtem Bityutskiy  * @c: the UBIFS file-system description object
6371e51764aSArtem Bityutskiy  * @lnum: LEB to change properties for
6381e51764aSArtem Bityutskiy  * @free: amount of free space
6391e51764aSArtem Bityutskiy  * @dirty: amount of dirty space
6401e51764aSArtem Bityutskiy  * @flags_set: flags to set
6411e51764aSArtem Bityutskiy  * @flags_clean: flags to clean
6421e51764aSArtem Bityutskiy  * @idx_gc_cnt: change to the count of idx_gc list
6431e51764aSArtem Bityutskiy  *
6441e51764aSArtem Bityutskiy  * This function changes properties of LEB @lnum. It is a helper wrapper over
6451e51764aSArtem Bityutskiy  * 'ubifs_change_lp()' which hides lprops get/release. The arguments are the
6461e51764aSArtem Bityutskiy  * same as in case of 'ubifs_change_lp()'. Returns zero in case of success and
6471e51764aSArtem Bityutskiy  * a negative error code in case of failure.
6481e51764aSArtem Bityutskiy  */
ubifs_change_one_lp(struct ubifs_info * c,int lnum,int free,int dirty,int flags_set,int flags_clean,int idx_gc_cnt)6491e51764aSArtem Bityutskiy int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
6501e51764aSArtem Bityutskiy 			int flags_set, int flags_clean, int idx_gc_cnt)
6511e51764aSArtem Bityutskiy {
6521e51764aSArtem Bityutskiy 	int err = 0, flags;
6531e51764aSArtem Bityutskiy 	const struct ubifs_lprops *lp;
6541e51764aSArtem Bityutskiy 
6551e51764aSArtem Bityutskiy 	ubifs_get_lprops(c);
6561e51764aSArtem Bityutskiy 
6571e51764aSArtem Bityutskiy 	lp = ubifs_lpt_lookup_dirty(c, lnum);
6581e51764aSArtem Bityutskiy 	if (IS_ERR(lp)) {
6591e51764aSArtem Bityutskiy 		err = PTR_ERR(lp);
6601e51764aSArtem Bityutskiy 		goto out;
6611e51764aSArtem Bityutskiy 	}
6621e51764aSArtem Bityutskiy 
6631e51764aSArtem Bityutskiy 	flags = (lp->flags | flags_set) & ~flags_clean;
6641e51764aSArtem Bityutskiy 	lp = ubifs_change_lp(c, lp, free, dirty, flags, idx_gc_cnt);
6651e51764aSArtem Bityutskiy 	if (IS_ERR(lp))
6661e51764aSArtem Bityutskiy 		err = PTR_ERR(lp);
6671e51764aSArtem Bityutskiy 
6681e51764aSArtem Bityutskiy out:
6691e51764aSArtem Bityutskiy 	ubifs_release_lprops(c);
670e4d9b6cbSArtem Bityutskiy 	if (err)
671235c362bSSheng Yong 		ubifs_err(c, "cannot change properties of LEB %d, error %d",
672e4d9b6cbSArtem Bityutskiy 			  lnum, err);
6731e51764aSArtem Bityutskiy 	return err;
6741e51764aSArtem Bityutskiy }
6751e51764aSArtem Bityutskiy 
6761e51764aSArtem Bityutskiy /**
6771e51764aSArtem Bityutskiy  * ubifs_update_one_lp - update LEB properties.
6781e51764aSArtem Bityutskiy  * @c: the UBIFS file-system description object
6791e51764aSArtem Bityutskiy  * @lnum: LEB to change properties for
6801e51764aSArtem Bityutskiy  * @free: amount of free space
6811e51764aSArtem Bityutskiy  * @dirty: amount of dirty space to add
6821e51764aSArtem Bityutskiy  * @flags_set: flags to set
6831e51764aSArtem Bityutskiy  * @flags_clean: flags to clean
6841e51764aSArtem Bityutskiy  *
6851e51764aSArtem Bityutskiy  * This function is the same as 'ubifs_change_one_lp()' but @dirty is added to
6861e51764aSArtem Bityutskiy  * current dirty space, not substitutes it.
6871e51764aSArtem Bityutskiy  */
ubifs_update_one_lp(struct ubifs_info * c,int lnum,int free,int dirty,int flags_set,int flags_clean)6881e51764aSArtem Bityutskiy int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
6891e51764aSArtem Bityutskiy 			int flags_set, int flags_clean)
6901e51764aSArtem Bityutskiy {
6911e51764aSArtem Bityutskiy 	int err = 0, flags;
6921e51764aSArtem Bityutskiy 	const struct ubifs_lprops *lp;
6931e51764aSArtem Bityutskiy 
6941e51764aSArtem Bityutskiy 	ubifs_get_lprops(c);
6951e51764aSArtem Bityutskiy 
6961e51764aSArtem Bityutskiy 	lp = ubifs_lpt_lookup_dirty(c, lnum);
6971e51764aSArtem Bityutskiy 	if (IS_ERR(lp)) {
6981e51764aSArtem Bityutskiy 		err = PTR_ERR(lp);
6991e51764aSArtem Bityutskiy 		goto out;
7001e51764aSArtem Bityutskiy 	}
7011e51764aSArtem Bityutskiy 
7021e51764aSArtem Bityutskiy 	flags = (lp->flags | flags_set) & ~flags_clean;
7031e51764aSArtem Bityutskiy 	lp = ubifs_change_lp(c, lp, free, lp->dirty + dirty, flags, 0);
7041e51764aSArtem Bityutskiy 	if (IS_ERR(lp))
7051e51764aSArtem Bityutskiy 		err = PTR_ERR(lp);
7061e51764aSArtem Bityutskiy 
7071e51764aSArtem Bityutskiy out:
7081e51764aSArtem Bityutskiy 	ubifs_release_lprops(c);
709e4d9b6cbSArtem Bityutskiy 	if (err)
710235c362bSSheng Yong 		ubifs_err(c, "cannot update properties of LEB %d, error %d",
711e4d9b6cbSArtem Bityutskiy 			  lnum, err);
7121e51764aSArtem Bityutskiy 	return err;
7131e51764aSArtem Bityutskiy }
7141e51764aSArtem Bityutskiy 
7151e51764aSArtem Bityutskiy /**
7161e51764aSArtem Bityutskiy  * ubifs_read_one_lp - read LEB properties.
7171e51764aSArtem Bityutskiy  * @c: the UBIFS file-system description object
7181e51764aSArtem Bityutskiy  * @lnum: LEB to read properties for
7191e51764aSArtem Bityutskiy  * @lp: where to store read properties
7201e51764aSArtem Bityutskiy  *
7211e51764aSArtem Bityutskiy  * This helper function reads properties of a LEB @lnum and stores them in @lp.
7221e51764aSArtem Bityutskiy  * Returns zero in case of success and a negative error code in case of
7231e51764aSArtem Bityutskiy  * failure.
7241e51764aSArtem Bityutskiy  */
ubifs_read_one_lp(struct ubifs_info * c,int lnum,struct ubifs_lprops * lp)7251e51764aSArtem Bityutskiy int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp)
7261e51764aSArtem Bityutskiy {
7271e51764aSArtem Bityutskiy 	int err = 0;
7281e51764aSArtem Bityutskiy 	const struct ubifs_lprops *lpp;
7291e51764aSArtem Bityutskiy 
7301e51764aSArtem Bityutskiy 	ubifs_get_lprops(c);
7311e51764aSArtem Bityutskiy 
7321e51764aSArtem Bityutskiy 	lpp = ubifs_lpt_lookup(c, lnum);
7331e51764aSArtem Bityutskiy 	if (IS_ERR(lpp)) {
7341e51764aSArtem Bityutskiy 		err = PTR_ERR(lpp);
735235c362bSSheng Yong 		ubifs_err(c, "cannot read properties of LEB %d, error %d",
736e4d9b6cbSArtem Bityutskiy 			  lnum, err);
7371e51764aSArtem Bityutskiy 		goto out;
7381e51764aSArtem Bityutskiy 	}
7391e51764aSArtem Bityutskiy 
7401e51764aSArtem Bityutskiy 	memcpy(lp, lpp, sizeof(struct ubifs_lprops));
7411e51764aSArtem Bityutskiy 
7421e51764aSArtem Bityutskiy out:
7431e51764aSArtem Bityutskiy 	ubifs_release_lprops(c);
7441e51764aSArtem Bityutskiy 	return err;
7451e51764aSArtem Bityutskiy }
7461e51764aSArtem Bityutskiy 
7471e51764aSArtem Bityutskiy /**
7481e51764aSArtem Bityutskiy  * ubifs_fast_find_free - try to find a LEB with free space quickly.
7491e51764aSArtem Bityutskiy  * @c: the UBIFS file-system description object
7501e51764aSArtem Bityutskiy  *
7511e51764aSArtem Bityutskiy  * This function returns LEB properties for a LEB with free space or %NULL if
7521e51764aSArtem Bityutskiy  * the function is unable to find a LEB quickly.
7531e51764aSArtem Bityutskiy  */
ubifs_fast_find_free(struct ubifs_info * c)7541e51764aSArtem Bityutskiy const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c)
7551e51764aSArtem Bityutskiy {
7561e51764aSArtem Bityutskiy 	struct ubifs_lprops *lprops;
7571e51764aSArtem Bityutskiy 	struct ubifs_lpt_heap *heap;
7581e51764aSArtem Bityutskiy 
7596eb61d58SRichard Weinberger 	ubifs_assert(c, mutex_is_locked(&c->lp_mutex));
7601e51764aSArtem Bityutskiy 
7611e51764aSArtem Bityutskiy 	heap = &c->lpt_heap[LPROPS_FREE - 1];
7621e51764aSArtem Bityutskiy 	if (heap->cnt == 0)
7631e51764aSArtem Bityutskiy 		return NULL;
7641e51764aSArtem Bityutskiy 
7651e51764aSArtem Bityutskiy 	lprops = heap->arr[0];
7666eb61d58SRichard Weinberger 	ubifs_assert(c, !(lprops->flags & LPROPS_TAKEN));
7676eb61d58SRichard Weinberger 	ubifs_assert(c, !(lprops->flags & LPROPS_INDEX));
7681e51764aSArtem Bityutskiy 	return lprops;
7691e51764aSArtem Bityutskiy }
7701e51764aSArtem Bityutskiy 
7711e51764aSArtem Bityutskiy /**
7721e51764aSArtem Bityutskiy  * ubifs_fast_find_empty - try to find an empty LEB quickly.
7731e51764aSArtem Bityutskiy  * @c: the UBIFS file-system description object
7741e51764aSArtem Bityutskiy  *
7751e51764aSArtem Bityutskiy  * This function returns LEB properties for an empty LEB or %NULL if the
7761e51764aSArtem Bityutskiy  * function is unable to find an empty LEB quickly.
7771e51764aSArtem Bityutskiy  */
ubifs_fast_find_empty(struct ubifs_info * c)7781e51764aSArtem Bityutskiy const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c)
7791e51764aSArtem Bityutskiy {
7801e51764aSArtem Bityutskiy 	struct ubifs_lprops *lprops;
7811e51764aSArtem Bityutskiy 
7826eb61d58SRichard Weinberger 	ubifs_assert(c, mutex_is_locked(&c->lp_mutex));
7831e51764aSArtem Bityutskiy 
7841e51764aSArtem Bityutskiy 	if (list_empty(&c->empty_list))
7851e51764aSArtem Bityutskiy 		return NULL;
7861e51764aSArtem Bityutskiy 
7871e51764aSArtem Bityutskiy 	lprops = list_entry(c->empty_list.next, struct ubifs_lprops, list);
7886eb61d58SRichard Weinberger 	ubifs_assert(c, !(lprops->flags & LPROPS_TAKEN));
7896eb61d58SRichard Weinberger 	ubifs_assert(c, !(lprops->flags & LPROPS_INDEX));
7906eb61d58SRichard Weinberger 	ubifs_assert(c, lprops->free == c->leb_size);
7911e51764aSArtem Bityutskiy 	return lprops;
7921e51764aSArtem Bityutskiy }
7931e51764aSArtem Bityutskiy 
7941e51764aSArtem Bityutskiy /**
7951e51764aSArtem Bityutskiy  * ubifs_fast_find_freeable - try to find a freeable LEB quickly.
7961e51764aSArtem Bityutskiy  * @c: the UBIFS file-system description object
7971e51764aSArtem Bityutskiy  *
7981e51764aSArtem Bityutskiy  * This function returns LEB properties for a freeable LEB or %NULL if the
7991e51764aSArtem Bityutskiy  * function is unable to find a freeable LEB quickly.
8001e51764aSArtem Bityutskiy  */
ubifs_fast_find_freeable(struct ubifs_info * c)8011e51764aSArtem Bityutskiy const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c)
8021e51764aSArtem Bityutskiy {
8031e51764aSArtem Bityutskiy 	struct ubifs_lprops *lprops;
8041e51764aSArtem Bityutskiy 
8056eb61d58SRichard Weinberger 	ubifs_assert(c, mutex_is_locked(&c->lp_mutex));
8061e51764aSArtem Bityutskiy 
8071e51764aSArtem Bityutskiy 	if (list_empty(&c->freeable_list))
8081e51764aSArtem Bityutskiy 		return NULL;
8091e51764aSArtem Bityutskiy 
8101e51764aSArtem Bityutskiy 	lprops = list_entry(c->freeable_list.next, struct ubifs_lprops, list);
8116eb61d58SRichard Weinberger 	ubifs_assert(c, !(lprops->flags & LPROPS_TAKEN));
8126eb61d58SRichard Weinberger 	ubifs_assert(c, !(lprops->flags & LPROPS_INDEX));
8136eb61d58SRichard Weinberger 	ubifs_assert(c, lprops->free + lprops->dirty == c->leb_size);
8146eb61d58SRichard Weinberger 	ubifs_assert(c, c->freeable_cnt > 0);
8151e51764aSArtem Bityutskiy 	return lprops;
8161e51764aSArtem Bityutskiy }
8171e51764aSArtem Bityutskiy 
8181e51764aSArtem Bityutskiy /**
8191e51764aSArtem Bityutskiy  * ubifs_fast_find_frdi_idx - try to find a freeable index LEB quickly.
8201e51764aSArtem Bityutskiy  * @c: the UBIFS file-system description object
8211e51764aSArtem Bityutskiy  *
8221e51764aSArtem Bityutskiy  * This function returns LEB properties for a freeable index LEB or %NULL if the
8231e51764aSArtem Bityutskiy  * function is unable to find a freeable index LEB quickly.
8241e51764aSArtem Bityutskiy  */
ubifs_fast_find_frdi_idx(struct ubifs_info * c)8251e51764aSArtem Bityutskiy const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c)
8261e51764aSArtem Bityutskiy {
8271e51764aSArtem Bityutskiy 	struct ubifs_lprops *lprops;
8281e51764aSArtem Bityutskiy 
8296eb61d58SRichard Weinberger 	ubifs_assert(c, mutex_is_locked(&c->lp_mutex));
8301e51764aSArtem Bityutskiy 
8311e51764aSArtem Bityutskiy 	if (list_empty(&c->frdi_idx_list))
8321e51764aSArtem Bityutskiy 		return NULL;
8331e51764aSArtem Bityutskiy 
8341e51764aSArtem Bityutskiy 	lprops = list_entry(c->frdi_idx_list.next, struct ubifs_lprops, list);
8356eb61d58SRichard Weinberger 	ubifs_assert(c, !(lprops->flags & LPROPS_TAKEN));
8366eb61d58SRichard Weinberger 	ubifs_assert(c, (lprops->flags & LPROPS_INDEX));
8376eb61d58SRichard Weinberger 	ubifs_assert(c, lprops->free + lprops->dirty == c->leb_size);
8381e51764aSArtem Bityutskiy 	return lprops;
8391e51764aSArtem Bityutskiy }
8401e51764aSArtem Bityutskiy 
841f70b7e52SArtem Bityutskiy /*
842f70b7e52SArtem Bityutskiy  * Everything below is related to debugging.
843f70b7e52SArtem Bityutskiy  */
8441e51764aSArtem Bityutskiy 
8451e51764aSArtem Bityutskiy /**
8461e51764aSArtem Bityutskiy  * dbg_check_cats - check category heaps and lists.
8471e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
8481e51764aSArtem Bityutskiy  *
8491e51764aSArtem Bityutskiy  * This function returns %0 on success and a negative error code on failure.
8501e51764aSArtem Bityutskiy  */
dbg_check_cats(struct ubifs_info * c)8511e51764aSArtem Bityutskiy int dbg_check_cats(struct ubifs_info *c)
8521e51764aSArtem Bityutskiy {
8531e51764aSArtem Bityutskiy 	struct ubifs_lprops *lprops;
8541e51764aSArtem Bityutskiy 	struct list_head *pos;
8551e51764aSArtem Bityutskiy 	int i, cat;
8561e51764aSArtem Bityutskiy 
8572b1844a8SArtem Bityutskiy 	if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
8581e51764aSArtem Bityutskiy 		return 0;
8591e51764aSArtem Bityutskiy 
8601e51764aSArtem Bityutskiy 	list_for_each_entry(lprops, &c->empty_list, list) {
8611e51764aSArtem Bityutskiy 		if (lprops->free != c->leb_size) {
862235c362bSSheng Yong 			ubifs_err(c, "non-empty LEB %d on empty list (free %d dirty %d flags %d)",
86379fda517SArtem Bityutskiy 				  lprops->lnum, lprops->free, lprops->dirty,
86479fda517SArtem Bityutskiy 				  lprops->flags);
8651e51764aSArtem Bityutskiy 			return -EINVAL;
8661e51764aSArtem Bityutskiy 		}
8671e51764aSArtem Bityutskiy 		if (lprops->flags & LPROPS_TAKEN) {
868235c362bSSheng Yong 			ubifs_err(c, "taken LEB %d on empty list (free %d dirty %d flags %d)",
86979fda517SArtem Bityutskiy 				  lprops->lnum, lprops->free, lprops->dirty,
87079fda517SArtem Bityutskiy 				  lprops->flags);
8711e51764aSArtem Bityutskiy 			return -EINVAL;
8721e51764aSArtem Bityutskiy 		}
8731e51764aSArtem Bityutskiy 	}
8741e51764aSArtem Bityutskiy 
8751e51764aSArtem Bityutskiy 	i = 0;
8761e51764aSArtem Bityutskiy 	list_for_each_entry(lprops, &c->freeable_list, list) {
8771e51764aSArtem Bityutskiy 		if (lprops->free + lprops->dirty != c->leb_size) {
878235c362bSSheng Yong 			ubifs_err(c, "non-freeable LEB %d on freeable list (free %d dirty %d flags %d)",
87979fda517SArtem Bityutskiy 				  lprops->lnum, lprops->free, lprops->dirty,
88079fda517SArtem Bityutskiy 				  lprops->flags);
8811e51764aSArtem Bityutskiy 			return -EINVAL;
8821e51764aSArtem Bityutskiy 		}
8831e51764aSArtem Bityutskiy 		if (lprops->flags & LPROPS_TAKEN) {
884235c362bSSheng Yong 			ubifs_err(c, "taken LEB %d on freeable list (free %d dirty %d flags %d)",
88579fda517SArtem Bityutskiy 				  lprops->lnum, lprops->free, lprops->dirty,
88679fda517SArtem Bityutskiy 				  lprops->flags);
8871e51764aSArtem Bityutskiy 			return -EINVAL;
8881e51764aSArtem Bityutskiy 		}
8891e51764aSArtem Bityutskiy 		i += 1;
8901e51764aSArtem Bityutskiy 	}
8911e51764aSArtem Bityutskiy 	if (i != c->freeable_cnt) {
892235c362bSSheng Yong 		ubifs_err(c, "freeable list count %d expected %d", i,
8931e51764aSArtem Bityutskiy 			  c->freeable_cnt);
8941e51764aSArtem Bityutskiy 		return -EINVAL;
8951e51764aSArtem Bityutskiy 	}
8961e51764aSArtem Bityutskiy 
8971e51764aSArtem Bityutskiy 	i = 0;
8981e51764aSArtem Bityutskiy 	list_for_each(pos, &c->idx_gc)
8991e51764aSArtem Bityutskiy 		i += 1;
9001e51764aSArtem Bityutskiy 	if (i != c->idx_gc_cnt) {
901235c362bSSheng Yong 		ubifs_err(c, "idx_gc list count %d expected %d", i,
9021e51764aSArtem Bityutskiy 			  c->idx_gc_cnt);
9031e51764aSArtem Bityutskiy 		return -EINVAL;
9041e51764aSArtem Bityutskiy 	}
9051e51764aSArtem Bityutskiy 
9061e51764aSArtem Bityutskiy 	list_for_each_entry(lprops, &c->frdi_idx_list, list) {
9071e51764aSArtem Bityutskiy 		if (lprops->free + lprops->dirty != c->leb_size) {
908235c362bSSheng Yong 			ubifs_err(c, "non-freeable LEB %d on frdi_idx list (free %d dirty %d flags %d)",
90979fda517SArtem Bityutskiy 				  lprops->lnum, lprops->free, lprops->dirty,
91079fda517SArtem Bityutskiy 				  lprops->flags);
9111e51764aSArtem Bityutskiy 			return -EINVAL;
9121e51764aSArtem Bityutskiy 		}
9131e51764aSArtem Bityutskiy 		if (lprops->flags & LPROPS_TAKEN) {
914235c362bSSheng Yong 			ubifs_err(c, "taken LEB %d on frdi_idx list (free %d dirty %d flags %d)",
91579fda517SArtem Bityutskiy 				  lprops->lnum, lprops->free, lprops->dirty,
91679fda517SArtem Bityutskiy 				  lprops->flags);
9171e51764aSArtem Bityutskiy 			return -EINVAL;
9181e51764aSArtem Bityutskiy 		}
9191e51764aSArtem Bityutskiy 		if (!(lprops->flags & LPROPS_INDEX)) {
920235c362bSSheng Yong 			ubifs_err(c, "non-index LEB %d on frdi_idx list (free %d dirty %d flags %d)",
92179fda517SArtem Bityutskiy 				  lprops->lnum, lprops->free, lprops->dirty,
92279fda517SArtem Bityutskiy 				  lprops->flags);
9231e51764aSArtem Bityutskiy 			return -EINVAL;
9241e51764aSArtem Bityutskiy 		}
9251e51764aSArtem Bityutskiy 	}
9261e51764aSArtem Bityutskiy 
9271e51764aSArtem Bityutskiy 	for (cat = 1; cat <= LPROPS_HEAP_CNT; cat++) {
9281e51764aSArtem Bityutskiy 		struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
9291e51764aSArtem Bityutskiy 
9301e51764aSArtem Bityutskiy 		for (i = 0; i < heap->cnt; i++) {
9311e51764aSArtem Bityutskiy 			lprops = heap->arr[i];
9321e51764aSArtem Bityutskiy 			if (!lprops) {
933235c362bSSheng Yong 				ubifs_err(c, "null ptr in LPT heap cat %d", cat);
9341e51764aSArtem Bityutskiy 				return -EINVAL;
9351e51764aSArtem Bityutskiy 			}
9361e51764aSArtem Bityutskiy 			if (lprops->hpos != i) {
937235c362bSSheng Yong 				ubifs_err(c, "bad ptr in LPT heap cat %d", cat);
9381e51764aSArtem Bityutskiy 				return -EINVAL;
9391e51764aSArtem Bityutskiy 			}
9401e51764aSArtem Bityutskiy 			if (lprops->flags & LPROPS_TAKEN) {
941235c362bSSheng Yong 				ubifs_err(c, "taken LEB in LPT heap cat %d", cat);
9421e51764aSArtem Bityutskiy 				return -EINVAL;
9431e51764aSArtem Bityutskiy 			}
9441e51764aSArtem Bityutskiy 		}
9451e51764aSArtem Bityutskiy 	}
9461e51764aSArtem Bityutskiy 
9471e51764aSArtem Bityutskiy 	return 0;
9481e51764aSArtem Bityutskiy }
9491e51764aSArtem Bityutskiy 
dbg_check_heap(struct ubifs_info * c,struct ubifs_lpt_heap * heap,int cat,int add_pos)9501e51764aSArtem Bityutskiy void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
9511e51764aSArtem Bityutskiy 		    int add_pos)
9521e51764aSArtem Bityutskiy {
9531e51764aSArtem Bityutskiy 	int i = 0, j, err = 0;
9541e51764aSArtem Bityutskiy 
9552b1844a8SArtem Bityutskiy 	if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
9561e51764aSArtem Bityutskiy 		return;
9571e51764aSArtem Bityutskiy 
9581e51764aSArtem Bityutskiy 	for (i = 0; i < heap->cnt; i++) {
9591e51764aSArtem Bityutskiy 		struct ubifs_lprops *lprops = heap->arr[i];
9601e51764aSArtem Bityutskiy 		struct ubifs_lprops *lp;
9611e51764aSArtem Bityutskiy 
9621e51764aSArtem Bityutskiy 		if (i != add_pos)
9631e51764aSArtem Bityutskiy 			if ((lprops->flags & LPROPS_CAT_MASK) != cat) {
9641e51764aSArtem Bityutskiy 				err = 1;
9651e51764aSArtem Bityutskiy 				goto out;
9661e51764aSArtem Bityutskiy 			}
9671e51764aSArtem Bityutskiy 		if (lprops->hpos != i) {
9681e51764aSArtem Bityutskiy 			err = 2;
9691e51764aSArtem Bityutskiy 			goto out;
9701e51764aSArtem Bityutskiy 		}
9711e51764aSArtem Bityutskiy 		lp = ubifs_lpt_lookup(c, lprops->lnum);
9721e51764aSArtem Bityutskiy 		if (IS_ERR(lp)) {
9731e51764aSArtem Bityutskiy 			err = 3;
9741e51764aSArtem Bityutskiy 			goto out;
9751e51764aSArtem Bityutskiy 		}
9761e51764aSArtem Bityutskiy 		if (lprops != lp) {
977235c362bSSheng Yong 			ubifs_err(c, "lprops %zx lp %zx lprops->lnum %d lp->lnum %d",
9781e51764aSArtem Bityutskiy 				  (size_t)lprops, (size_t)lp, lprops->lnum,
9791e51764aSArtem Bityutskiy 				  lp->lnum);
9801e51764aSArtem Bityutskiy 			err = 4;
9811e51764aSArtem Bityutskiy 			goto out;
9821e51764aSArtem Bityutskiy 		}
9831e51764aSArtem Bityutskiy 		for (j = 0; j < i; j++) {
9841e51764aSArtem Bityutskiy 			lp = heap->arr[j];
9851e51764aSArtem Bityutskiy 			if (lp == lprops) {
9861e51764aSArtem Bityutskiy 				err = 5;
9871e51764aSArtem Bityutskiy 				goto out;
9881e51764aSArtem Bityutskiy 			}
9891e51764aSArtem Bityutskiy 			if (lp->lnum == lprops->lnum) {
9901e51764aSArtem Bityutskiy 				err = 6;
9911e51764aSArtem Bityutskiy 				goto out;
9921e51764aSArtem Bityutskiy 			}
9931e51764aSArtem Bityutskiy 		}
9941e51764aSArtem Bityutskiy 	}
9951e51764aSArtem Bityutskiy out:
9961e51764aSArtem Bityutskiy 	if (err) {
997235c362bSSheng Yong 		ubifs_err(c, "failed cat %d hpos %d err %d", cat, i, err);
9987c46d0aeSArtem Bityutskiy 		dump_stack();
999edf6be24SArtem Bityutskiy 		ubifs_dump_heap(c, heap, cat);
10001e51764aSArtem Bityutskiy 	}
10011e51764aSArtem Bityutskiy }
10021e51764aSArtem Bityutskiy 
10031e51764aSArtem Bityutskiy /**
10041e51764aSArtem Bityutskiy  * scan_check_cb - scan callback.
10051e51764aSArtem Bityutskiy  * @c: the UBIFS file-system description object
10061e51764aSArtem Bityutskiy  * @lp: LEB properties to scan
10071e51764aSArtem Bityutskiy  * @in_tree: whether the LEB properties are in main memory
100834bdc3e2SArtem Bityutskiy  * @lst: lprops statistics to update
10091e51764aSArtem Bityutskiy  *
10101e51764aSArtem Bityutskiy  * This function returns a code that indicates whether the scan should continue
10111e51764aSArtem Bityutskiy  * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
10121e51764aSArtem Bityutskiy  * in main memory (%LPT_SCAN_ADD), or whether the scan should stop
10131e51764aSArtem Bityutskiy  * (%LPT_SCAN_STOP).
10141e51764aSArtem Bityutskiy  */
scan_check_cb(struct ubifs_info * c,const struct ubifs_lprops * lp,int in_tree,struct ubifs_lp_stats * lst)10151e51764aSArtem Bityutskiy static int scan_check_cb(struct ubifs_info *c,
10161e51764aSArtem Bityutskiy 			 const struct ubifs_lprops *lp, int in_tree,
101734bdc3e2SArtem Bityutskiy 			 struct ubifs_lp_stats *lst)
10181e51764aSArtem Bityutskiy {
10191e51764aSArtem Bityutskiy 	struct ubifs_scan_leb *sleb;
10201e51764aSArtem Bityutskiy 	struct ubifs_scan_node *snod;
1021cd5f7485SArtem Bityutskiy 	int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
1022cd5f7485SArtem Bityutskiy 	void *buf = NULL;
10231e51764aSArtem Bityutskiy 
10241e51764aSArtem Bityutskiy 	cat = lp->flags & LPROPS_CAT_MASK;
10251e51764aSArtem Bityutskiy 	if (cat != LPROPS_UNCAT) {
10261e51764aSArtem Bityutskiy 		cat = ubifs_categorize_lprops(c, lp);
10271e51764aSArtem Bityutskiy 		if (cat != (lp->flags & LPROPS_CAT_MASK)) {
1028235c362bSSheng Yong 			ubifs_err(c, "bad LEB category %d expected %d",
10291e51764aSArtem Bityutskiy 				  (lp->flags & LPROPS_CAT_MASK), cat);
1030dcc50c8eSArtem Bityutskiy 			return -EINVAL;
10311e51764aSArtem Bityutskiy 		}
10321e51764aSArtem Bityutskiy 	}
10331e51764aSArtem Bityutskiy 
10341e51764aSArtem Bityutskiy 	/* Check lp is on its category list (if it has one) */
10351e51764aSArtem Bityutskiy 	if (in_tree) {
10361e51764aSArtem Bityutskiy 		struct list_head *list = NULL;
10371e51764aSArtem Bityutskiy 
10381e51764aSArtem Bityutskiy 		switch (cat) {
10391e51764aSArtem Bityutskiy 		case LPROPS_EMPTY:
10401e51764aSArtem Bityutskiy 			list = &c->empty_list;
10411e51764aSArtem Bityutskiy 			break;
10421e51764aSArtem Bityutskiy 		case LPROPS_FREEABLE:
10431e51764aSArtem Bityutskiy 			list = &c->freeable_list;
10441e51764aSArtem Bityutskiy 			break;
10451e51764aSArtem Bityutskiy 		case LPROPS_FRDI_IDX:
10461e51764aSArtem Bityutskiy 			list = &c->frdi_idx_list;
10471e51764aSArtem Bityutskiy 			break;
10481e51764aSArtem Bityutskiy 		case LPROPS_UNCAT:
10491e51764aSArtem Bityutskiy 			list = &c->uncat_list;
10501e51764aSArtem Bityutskiy 			break;
10511e51764aSArtem Bityutskiy 		}
10521e51764aSArtem Bityutskiy 		if (list) {
10531e51764aSArtem Bityutskiy 			struct ubifs_lprops *lprops;
10541e51764aSArtem Bityutskiy 			int found = 0;
10551e51764aSArtem Bityutskiy 
10561e51764aSArtem Bityutskiy 			list_for_each_entry(lprops, list, list) {
10571e51764aSArtem Bityutskiy 				if (lprops == lp) {
10581e51764aSArtem Bityutskiy 					found = 1;
10591e51764aSArtem Bityutskiy 					break;
10601e51764aSArtem Bityutskiy 				}
10611e51764aSArtem Bityutskiy 			}
10621e51764aSArtem Bityutskiy 			if (!found) {
1063235c362bSSheng Yong 				ubifs_err(c, "bad LPT list (category %d)", cat);
1064dcc50c8eSArtem Bityutskiy 				return -EINVAL;
10651e51764aSArtem Bityutskiy 			}
10661e51764aSArtem Bityutskiy 		}
10671e51764aSArtem Bityutskiy 	}
10681e51764aSArtem Bityutskiy 
10691e51764aSArtem Bityutskiy 	/* Check lp is on its category heap (if it has one) */
10701e51764aSArtem Bityutskiy 	if (in_tree && cat > 0 && cat <= LPROPS_HEAP_CNT) {
10711e51764aSArtem Bityutskiy 		struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
10721e51764aSArtem Bityutskiy 
10731e51764aSArtem Bityutskiy 		if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) ||
10741e51764aSArtem Bityutskiy 		    lp != heap->arr[lp->hpos]) {
1075235c362bSSheng Yong 			ubifs_err(c, "bad LPT heap (category %d)", cat);
1076dcc50c8eSArtem Bityutskiy 			return -EINVAL;
10771e51764aSArtem Bityutskiy 		}
10781e51764aSArtem Bityutskiy 	}
10791e51764aSArtem Bityutskiy 
10801e51764aSArtem Bityutskiy 	/*
10811e51764aSArtem Bityutskiy 	 * After an unclean unmount, empty and freeable LEBs
10828ca5175bSArtem Bityutskiy 	 * may contain garbage - do not scan them.
10831e51764aSArtem Bityutskiy 	 */
10841e51764aSArtem Bityutskiy 	if (lp->free == c->leb_size) {
10851e51764aSArtem Bityutskiy 		lst->empty_lebs += 1;
10861e51764aSArtem Bityutskiy 		lst->total_free += c->leb_size;
1087be9e62a7SArtem Bityutskiy 		lst->total_dark += ubifs_calc_dark(c, c->leb_size);
10888ca5175bSArtem Bityutskiy 		return LPT_SCAN_CONTINUE;
10891e51764aSArtem Bityutskiy 	}
10901e51764aSArtem Bityutskiy 	if (lp->free + lp->dirty == c->leb_size &&
10911e51764aSArtem Bityutskiy 	    !(lp->flags & LPROPS_INDEX)) {
10921e51764aSArtem Bityutskiy 		lst->total_free  += lp->free;
10931e51764aSArtem Bityutskiy 		lst->total_dirty += lp->dirty;
1094be9e62a7SArtem Bityutskiy 		lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
10958ca5175bSArtem Bityutskiy 		return LPT_SCAN_CONTINUE;
10961e51764aSArtem Bityutskiy 	}
10978ca5175bSArtem Bityutskiy 
109888dca4caSChristoph Hellwig 	buf = __vmalloc(c->leb_size, GFP_NOFS);
1099eef19816SRichard Weinberger 	if (!buf)
1100eef19816SRichard Weinberger 		return -ENOMEM;
1101eef19816SRichard Weinberger 
11028ca5175bSArtem Bityutskiy 	sleb = ubifs_scan(c, lnum, 0, buf, 0);
11038ca5175bSArtem Bityutskiy 	if (IS_ERR(sleb)) {
1104dcc50c8eSArtem Bityutskiy 		ret = PTR_ERR(sleb);
110512346037SArtem Bityutskiy 		if (ret == -EUCLEAN) {
1106edf6be24SArtem Bityutskiy 			ubifs_dump_lprops(c);
1107edf6be24SArtem Bityutskiy 			ubifs_dump_budg(c, &c->bi);
110812346037SArtem Bityutskiy 		}
1109dcc50c8eSArtem Bityutskiy 		goto out;
11101e51764aSArtem Bityutskiy 	}
11111e51764aSArtem Bityutskiy 
11121e51764aSArtem Bityutskiy 	is_idx = -1;
11131e51764aSArtem Bityutskiy 	list_for_each_entry(snod, &sleb->nodes, list) {
11141e51764aSArtem Bityutskiy 		int found, level = 0;
11151e51764aSArtem Bityutskiy 
11161e51764aSArtem Bityutskiy 		cond_resched();
11171e51764aSArtem Bityutskiy 
11181e51764aSArtem Bityutskiy 		if (is_idx == -1)
11191e51764aSArtem Bityutskiy 			is_idx = (snod->type == UBIFS_IDX_NODE) ? 1 : 0;
11201e51764aSArtem Bityutskiy 
11211e51764aSArtem Bityutskiy 		if (is_idx && snod->type != UBIFS_IDX_NODE) {
1122235c362bSSheng Yong 			ubifs_err(c, "indexing node in data LEB %d:%d",
11231e51764aSArtem Bityutskiy 				  lnum, snod->offs);
11241e51764aSArtem Bityutskiy 			goto out_destroy;
11251e51764aSArtem Bityutskiy 		}
11261e51764aSArtem Bityutskiy 
11271e51764aSArtem Bityutskiy 		if (snod->type == UBIFS_IDX_NODE) {
11281e51764aSArtem Bityutskiy 			struct ubifs_idx_node *idx = snod->node;
11291e51764aSArtem Bityutskiy 
11301e51764aSArtem Bityutskiy 			key_read(c, ubifs_idx_key(c, idx), &snod->key);
11311e51764aSArtem Bityutskiy 			level = le16_to_cpu(idx->level);
11321e51764aSArtem Bityutskiy 		}
11331e51764aSArtem Bityutskiy 
11341e51764aSArtem Bityutskiy 		found = ubifs_tnc_has_node(c, &snod->key, level, lnum,
11351e51764aSArtem Bityutskiy 					   snod->offs, is_idx);
11361e51764aSArtem Bityutskiy 		if (found) {
11371e51764aSArtem Bityutskiy 			if (found < 0)
11381e51764aSArtem Bityutskiy 				goto out_destroy;
11391e51764aSArtem Bityutskiy 			used += ALIGN(snod->len, 8);
11401e51764aSArtem Bityutskiy 		}
11411e51764aSArtem Bityutskiy 	}
11421e51764aSArtem Bityutskiy 
11431e51764aSArtem Bityutskiy 	free = c->leb_size - sleb->endpt;
11441e51764aSArtem Bityutskiy 	dirty = sleb->endpt - used;
11451e51764aSArtem Bityutskiy 
11461e51764aSArtem Bityutskiy 	if (free > c->leb_size || free < 0 || dirty > c->leb_size ||
11471e51764aSArtem Bityutskiy 	    dirty < 0) {
1148235c362bSSheng Yong 		ubifs_err(c, "bad calculated accounting for LEB %d: free %d, dirty %d",
114979fda517SArtem Bityutskiy 			  lnum, free, dirty);
11501e51764aSArtem Bityutskiy 		goto out_destroy;
11511e51764aSArtem Bityutskiy 	}
11521e51764aSArtem Bityutskiy 
11531e51764aSArtem Bityutskiy 	if (lp->free + lp->dirty == c->leb_size &&
11541e51764aSArtem Bityutskiy 	    free + dirty == c->leb_size)
11551e51764aSArtem Bityutskiy 		if ((is_idx && !(lp->flags & LPROPS_INDEX)) ||
11561e51764aSArtem Bityutskiy 		    (!is_idx && free == c->leb_size) ||
11571e51764aSArtem Bityutskiy 		    lp->free == c->leb_size) {
11581e51764aSArtem Bityutskiy 			/*
11591e51764aSArtem Bityutskiy 			 * Empty or freeable LEBs could contain index
11601e51764aSArtem Bityutskiy 			 * nodes from an uncompleted commit due to an
11611e51764aSArtem Bityutskiy 			 * unclean unmount. Or they could be empty for
11621e51764aSArtem Bityutskiy 			 * the same reason. Or it may simply not have been
11631e51764aSArtem Bityutskiy 			 * unmapped.
11641e51764aSArtem Bityutskiy 			 */
11651e51764aSArtem Bityutskiy 			free = lp->free;
11661e51764aSArtem Bityutskiy 			dirty = lp->dirty;
11671e51764aSArtem Bityutskiy 			is_idx = 0;
11681e51764aSArtem Bityutskiy 		    }
11691e51764aSArtem Bityutskiy 
11701e51764aSArtem Bityutskiy 	if (is_idx && lp->free + lp->dirty == free + dirty &&
11711e51764aSArtem Bityutskiy 	    lnum != c->ihead_lnum) {
11721e51764aSArtem Bityutskiy 		/*
11731e51764aSArtem Bityutskiy 		 * After an unclean unmount, an index LEB could have a different
11741e51764aSArtem Bityutskiy 		 * amount of free space than the value recorded by lprops. That
11751e51764aSArtem Bityutskiy 		 * is because the in-the-gaps method may use free space or
11761e51764aSArtem Bityutskiy 		 * create free space (as a side-effect of using ubi_leb_change
11771e51764aSArtem Bityutskiy 		 * and not writing the whole LEB). The incorrect free space
11781e51764aSArtem Bityutskiy 		 * value is not a problem because the index is only ever
11791e51764aSArtem Bityutskiy 		 * allocated empty LEBs, so there will never be an attempt to
11801e51764aSArtem Bityutskiy 		 * write to the free space at the end of an index LEB - except
11811e51764aSArtem Bityutskiy 		 * by the in-the-gaps method for which it is not a problem.
11821e51764aSArtem Bityutskiy 		 */
11831e51764aSArtem Bityutskiy 		free = lp->free;
11841e51764aSArtem Bityutskiy 		dirty = lp->dirty;
11851e51764aSArtem Bityutskiy 	}
11861e51764aSArtem Bityutskiy 
11871e51764aSArtem Bityutskiy 	if (lp->free != free || lp->dirty != dirty)
11881e51764aSArtem Bityutskiy 		goto out_print;
11891e51764aSArtem Bityutskiy 
11901e51764aSArtem Bityutskiy 	if (is_idx && !(lp->flags & LPROPS_INDEX)) {
11911e51764aSArtem Bityutskiy 		if (free == c->leb_size)
11921e51764aSArtem Bityutskiy 			/* Free but not unmapped LEB, it's fine */
11931e51764aSArtem Bityutskiy 			is_idx = 0;
11941e51764aSArtem Bityutskiy 		else {
1195235c362bSSheng Yong 			ubifs_err(c, "indexing node without indexing flag");
11961e51764aSArtem Bityutskiy 			goto out_print;
11971e51764aSArtem Bityutskiy 		}
11981e51764aSArtem Bityutskiy 	}
11991e51764aSArtem Bityutskiy 
12001e51764aSArtem Bityutskiy 	if (!is_idx && (lp->flags & LPROPS_INDEX)) {
1201235c362bSSheng Yong 		ubifs_err(c, "data node with indexing flag");
12021e51764aSArtem Bityutskiy 		goto out_print;
12031e51764aSArtem Bityutskiy 	}
12041e51764aSArtem Bityutskiy 
12051e51764aSArtem Bityutskiy 	if (free == c->leb_size)
12061e51764aSArtem Bityutskiy 		lst->empty_lebs += 1;
12071e51764aSArtem Bityutskiy 
12081e51764aSArtem Bityutskiy 	if (is_idx)
12091e51764aSArtem Bityutskiy 		lst->idx_lebs += 1;
12101e51764aSArtem Bityutskiy 
12111e51764aSArtem Bityutskiy 	if (!(lp->flags & LPROPS_INDEX))
12121e51764aSArtem Bityutskiy 		lst->total_used += c->leb_size - free - dirty;
12131e51764aSArtem Bityutskiy 	lst->total_free += free;
12141e51764aSArtem Bityutskiy 	lst->total_dirty += dirty;
12151e51764aSArtem Bityutskiy 
12161e51764aSArtem Bityutskiy 	if (!(lp->flags & LPROPS_INDEX)) {
12171e51764aSArtem Bityutskiy 		int spc = free + dirty;
12181e51764aSArtem Bityutskiy 
12191e51764aSArtem Bityutskiy 		if (spc < c->dead_wm)
12201e51764aSArtem Bityutskiy 			lst->total_dead += spc;
12211e51764aSArtem Bityutskiy 		else
1222be9e62a7SArtem Bityutskiy 			lst->total_dark += ubifs_calc_dark(c, spc);
12231e51764aSArtem Bityutskiy 	}
12241e51764aSArtem Bityutskiy 
12251e51764aSArtem Bityutskiy 	ubifs_scan_destroy(sleb);
1226cd5f7485SArtem Bityutskiy 	vfree(buf);
1227dcc50c8eSArtem Bityutskiy 	return LPT_SCAN_CONTINUE;
12281e51764aSArtem Bityutskiy 
12291e51764aSArtem Bityutskiy out_print:
1230235c362bSSheng Yong 	ubifs_err(c, "bad accounting of LEB %d: free %d, dirty %d flags %#x, should be free %d, dirty %d",
12311e51764aSArtem Bityutskiy 		  lnum, lp->free, lp->dirty, lp->flags, free, dirty);
1232edf6be24SArtem Bityutskiy 	ubifs_dump_leb(c, lnum);
12331e51764aSArtem Bityutskiy out_destroy:
12341e51764aSArtem Bityutskiy 	ubifs_scan_destroy(sleb);
1235dcc50c8eSArtem Bityutskiy 	ret = -EINVAL;
12361e51764aSArtem Bityutskiy out:
1237cd5f7485SArtem Bityutskiy 	vfree(buf);
1238dcc50c8eSArtem Bityutskiy 	return ret;
12391e51764aSArtem Bityutskiy }
12401e51764aSArtem Bityutskiy 
12411e51764aSArtem Bityutskiy /**
12421e51764aSArtem Bityutskiy  * dbg_check_lprops - check all LEB properties.
12431e51764aSArtem Bityutskiy  * @c: UBIFS file-system description object
12441e51764aSArtem Bityutskiy  *
12451e51764aSArtem Bityutskiy  * This function checks all LEB properties and makes sure they are all correct.
12461e51764aSArtem Bityutskiy  * It returns zero if everything is fine, %-EINVAL if there is an inconsistency
12471e51764aSArtem Bityutskiy  * and other negative error codes in case of other errors. This function is
12481e51764aSArtem Bityutskiy  * called while the file system is locked (because of commit start), so no
12491e51764aSArtem Bityutskiy  * additional locking is required. Note that locking the LPT mutex would cause
12501e51764aSArtem Bityutskiy  * a circular lock dependency with the TNC mutex.
12511e51764aSArtem Bityutskiy  */
dbg_check_lprops(struct ubifs_info * c)12521e51764aSArtem Bityutskiy int dbg_check_lprops(struct ubifs_info *c)
12531e51764aSArtem Bityutskiy {
12541e51764aSArtem Bityutskiy 	int i, err;
125534bdc3e2SArtem Bityutskiy 	struct ubifs_lp_stats lst;
12561e51764aSArtem Bityutskiy 
12572b1844a8SArtem Bityutskiy 	if (!dbg_is_chk_lprops(c))
12581e51764aSArtem Bityutskiy 		return 0;
12591e51764aSArtem Bityutskiy 
12601e51764aSArtem Bityutskiy 	/*
12611e51764aSArtem Bityutskiy 	 * As we are going to scan the media, the write buffers have to be
12621e51764aSArtem Bityutskiy 	 * synchronized.
12631e51764aSArtem Bityutskiy 	 */
12641e51764aSArtem Bityutskiy 	for (i = 0; i < c->jhead_cnt; i++) {
12651e51764aSArtem Bityutskiy 		err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
12661e51764aSArtem Bityutskiy 		if (err)
12671e51764aSArtem Bityutskiy 			return err;
12681e51764aSArtem Bityutskiy 	}
12691e51764aSArtem Bityutskiy 
127034bdc3e2SArtem Bityutskiy 	memset(&lst, 0, sizeof(struct ubifs_lp_stats));
12711e51764aSArtem Bityutskiy 	err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
12721e51764aSArtem Bityutskiy 				    (ubifs_lpt_scan_callback)scan_check_cb,
127334bdc3e2SArtem Bityutskiy 				    &lst);
12741e51764aSArtem Bityutskiy 	if (err && err != -ENOSPC)
12751e51764aSArtem Bityutskiy 		goto out;
12761e51764aSArtem Bityutskiy 
127734bdc3e2SArtem Bityutskiy 	if (lst.empty_lebs != c->lst.empty_lebs ||
127834bdc3e2SArtem Bityutskiy 	    lst.idx_lebs != c->lst.idx_lebs ||
127934bdc3e2SArtem Bityutskiy 	    lst.total_free != c->lst.total_free ||
128034bdc3e2SArtem Bityutskiy 	    lst.total_dirty != c->lst.total_dirty ||
128134bdc3e2SArtem Bityutskiy 	    lst.total_used != c->lst.total_used) {
1282235c362bSSheng Yong 		ubifs_err(c, "bad overall accounting");
1283235c362bSSheng Yong 		ubifs_err(c, "calculated: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
128434bdc3e2SArtem Bityutskiy 			  lst.empty_lebs, lst.idx_lebs, lst.total_free,
128534bdc3e2SArtem Bityutskiy 			  lst.total_dirty, lst.total_used);
1286235c362bSSheng Yong 		ubifs_err(c, "read from lprops: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
12871e51764aSArtem Bityutskiy 			  c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free,
12881e51764aSArtem Bityutskiy 			  c->lst.total_dirty, c->lst.total_used);
12891e51764aSArtem Bityutskiy 		err = -EINVAL;
12901e51764aSArtem Bityutskiy 		goto out;
12911e51764aSArtem Bityutskiy 	}
12921e51764aSArtem Bityutskiy 
129334bdc3e2SArtem Bityutskiy 	if (lst.total_dead != c->lst.total_dead ||
129434bdc3e2SArtem Bityutskiy 	    lst.total_dark != c->lst.total_dark) {
1295235c362bSSheng Yong 		ubifs_err(c, "bad dead/dark space accounting");
1296235c362bSSheng Yong 		ubifs_err(c, "calculated: total_dead %lld, total_dark %lld",
129734bdc3e2SArtem Bityutskiy 			  lst.total_dead, lst.total_dark);
1298235c362bSSheng Yong 		ubifs_err(c, "read from lprops: total_dead %lld, total_dark %lld",
12991e51764aSArtem Bityutskiy 			  c->lst.total_dead, c->lst.total_dark);
13001e51764aSArtem Bityutskiy 		err = -EINVAL;
13011e51764aSArtem Bityutskiy 		goto out;
13021e51764aSArtem Bityutskiy 	}
13031e51764aSArtem Bityutskiy 
13041e51764aSArtem Bityutskiy 	err = dbg_check_cats(c);
13051e51764aSArtem Bityutskiy out:
13061e51764aSArtem Bityutskiy 	return err;
13071e51764aSArtem Bityutskiy }
1308