18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * This file is part of UBIFS.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Authors: Adrian Hunter
88c2ecf20Sopenharmony_ci *          Artem Bityutskiy (Битюцкий Артём)
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/*
128c2ecf20Sopenharmony_ci * This file implements the functions that access LEB properties and their
138c2ecf20Sopenharmony_ci * categories. LEBs are categorized based on the needs of UBIFS, and the
148c2ecf20Sopenharmony_ci * categories are stored as either heaps or lists to provide a fast way of
158c2ecf20Sopenharmony_ci * finding a LEB in a particular category. For example, UBIFS may need to find
168c2ecf20Sopenharmony_ci * an empty LEB for the journal, or a very dirty LEB for garbage collection.
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "ubifs.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/**
228c2ecf20Sopenharmony_ci * get_heap_comp_val - get the LEB properties value for heap comparisons.
238c2ecf20Sopenharmony_ci * @lprops: LEB properties
248c2ecf20Sopenharmony_ci * @cat: LEB category
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_cistatic int get_heap_comp_val(struct ubifs_lprops *lprops, int cat)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	switch (cat) {
298c2ecf20Sopenharmony_ci	case LPROPS_FREE:
308c2ecf20Sopenharmony_ci		return lprops->free;
318c2ecf20Sopenharmony_ci	case LPROPS_DIRTY_IDX:
328c2ecf20Sopenharmony_ci		return lprops->free + lprops->dirty;
338c2ecf20Sopenharmony_ci	default:
348c2ecf20Sopenharmony_ci		return lprops->dirty;
358c2ecf20Sopenharmony_ci	}
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/**
398c2ecf20Sopenharmony_ci * move_up_lpt_heap - move a new heap entry up as far as possible.
408c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
418c2ecf20Sopenharmony_ci * @heap: LEB category heap
428c2ecf20Sopenharmony_ci * @lprops: LEB properties to move
438c2ecf20Sopenharmony_ci * @cat: LEB category
448c2ecf20Sopenharmony_ci *
458c2ecf20Sopenharmony_ci * New entries to a heap are added at the bottom and then moved up until the
468c2ecf20Sopenharmony_ci * parent's value is greater.  In the case of LPT's category heaps, the value
478c2ecf20Sopenharmony_ci * is either the amount of free space or the amount of dirty space, depending
488c2ecf20Sopenharmony_ci * on the category.
498c2ecf20Sopenharmony_ci */
508c2ecf20Sopenharmony_cistatic void move_up_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
518c2ecf20Sopenharmony_ci			     struct ubifs_lprops *lprops, int cat)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	int val1, val2, hpos;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	hpos = lprops->hpos;
568c2ecf20Sopenharmony_ci	if (!hpos)
578c2ecf20Sopenharmony_ci		return; /* Already top of the heap */
588c2ecf20Sopenharmony_ci	val1 = get_heap_comp_val(lprops, cat);
598c2ecf20Sopenharmony_ci	/* Compare to parent and, if greater, move up the heap */
608c2ecf20Sopenharmony_ci	do {
618c2ecf20Sopenharmony_ci		int ppos = (hpos - 1) / 2;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci		val2 = get_heap_comp_val(heap->arr[ppos], cat);
648c2ecf20Sopenharmony_ci		if (val2 >= val1)
658c2ecf20Sopenharmony_ci			return;
668c2ecf20Sopenharmony_ci		/* Greater than parent so move up */
678c2ecf20Sopenharmony_ci		heap->arr[ppos]->hpos = hpos;
688c2ecf20Sopenharmony_ci		heap->arr[hpos] = heap->arr[ppos];
698c2ecf20Sopenharmony_ci		heap->arr[ppos] = lprops;
708c2ecf20Sopenharmony_ci		lprops->hpos = ppos;
718c2ecf20Sopenharmony_ci		hpos = ppos;
728c2ecf20Sopenharmony_ci	} while (hpos);
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/**
768c2ecf20Sopenharmony_ci * adjust_lpt_heap - move a changed heap entry up or down the heap.
778c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
788c2ecf20Sopenharmony_ci * @heap: LEB category heap
798c2ecf20Sopenharmony_ci * @lprops: LEB properties to move
808c2ecf20Sopenharmony_ci * @hpos: heap position of @lprops
818c2ecf20Sopenharmony_ci * @cat: LEB category
828c2ecf20Sopenharmony_ci *
838c2ecf20Sopenharmony_ci * Changed entries in a heap are moved up or down until the parent's value is
848c2ecf20Sopenharmony_ci * greater.  In the case of LPT's category heaps, the value is either the amount
858c2ecf20Sopenharmony_ci * of free space or the amount of dirty space, depending on the category.
868c2ecf20Sopenharmony_ci */
878c2ecf20Sopenharmony_cistatic void adjust_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
888c2ecf20Sopenharmony_ci			    struct ubifs_lprops *lprops, int hpos, int cat)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	int val1, val2, val3, cpos;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	val1 = get_heap_comp_val(lprops, cat);
938c2ecf20Sopenharmony_ci	/* Compare to parent and, if greater than parent, move up the heap */
948c2ecf20Sopenharmony_ci	if (hpos) {
958c2ecf20Sopenharmony_ci		int ppos = (hpos - 1) / 2;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci		val2 = get_heap_comp_val(heap->arr[ppos], cat);
988c2ecf20Sopenharmony_ci		if (val1 > val2) {
998c2ecf20Sopenharmony_ci			/* Greater than parent so move up */
1008c2ecf20Sopenharmony_ci			while (1) {
1018c2ecf20Sopenharmony_ci				heap->arr[ppos]->hpos = hpos;
1028c2ecf20Sopenharmony_ci				heap->arr[hpos] = heap->arr[ppos];
1038c2ecf20Sopenharmony_ci				heap->arr[ppos] = lprops;
1048c2ecf20Sopenharmony_ci				lprops->hpos = ppos;
1058c2ecf20Sopenharmony_ci				hpos = ppos;
1068c2ecf20Sopenharmony_ci				if (!hpos)
1078c2ecf20Sopenharmony_ci					return;
1088c2ecf20Sopenharmony_ci				ppos = (hpos - 1) / 2;
1098c2ecf20Sopenharmony_ci				val2 = get_heap_comp_val(heap->arr[ppos], cat);
1108c2ecf20Sopenharmony_ci				if (val1 <= val2)
1118c2ecf20Sopenharmony_ci					return;
1128c2ecf20Sopenharmony_ci				/* Still greater than parent so keep going */
1138c2ecf20Sopenharmony_ci			}
1148c2ecf20Sopenharmony_ci		}
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/* Not greater than parent, so compare to children */
1188c2ecf20Sopenharmony_ci	while (1) {
1198c2ecf20Sopenharmony_ci		/* Compare to left child */
1208c2ecf20Sopenharmony_ci		cpos = hpos * 2 + 1;
1218c2ecf20Sopenharmony_ci		if (cpos >= heap->cnt)
1228c2ecf20Sopenharmony_ci			return;
1238c2ecf20Sopenharmony_ci		val2 = get_heap_comp_val(heap->arr[cpos], cat);
1248c2ecf20Sopenharmony_ci		if (val1 < val2) {
1258c2ecf20Sopenharmony_ci			/* Less than left child, so promote biggest child */
1268c2ecf20Sopenharmony_ci			if (cpos + 1 < heap->cnt) {
1278c2ecf20Sopenharmony_ci				val3 = get_heap_comp_val(heap->arr[cpos + 1],
1288c2ecf20Sopenharmony_ci							 cat);
1298c2ecf20Sopenharmony_ci				if (val3 > val2)
1308c2ecf20Sopenharmony_ci					cpos += 1; /* Right child is bigger */
1318c2ecf20Sopenharmony_ci			}
1328c2ecf20Sopenharmony_ci			heap->arr[cpos]->hpos = hpos;
1338c2ecf20Sopenharmony_ci			heap->arr[hpos] = heap->arr[cpos];
1348c2ecf20Sopenharmony_ci			heap->arr[cpos] = lprops;
1358c2ecf20Sopenharmony_ci			lprops->hpos = cpos;
1368c2ecf20Sopenharmony_ci			hpos = cpos;
1378c2ecf20Sopenharmony_ci			continue;
1388c2ecf20Sopenharmony_ci		}
1398c2ecf20Sopenharmony_ci		/* Compare to right child */
1408c2ecf20Sopenharmony_ci		cpos += 1;
1418c2ecf20Sopenharmony_ci		if (cpos >= heap->cnt)
1428c2ecf20Sopenharmony_ci			return;
1438c2ecf20Sopenharmony_ci		val3 = get_heap_comp_val(heap->arr[cpos], cat);
1448c2ecf20Sopenharmony_ci		if (val1 < val3) {
1458c2ecf20Sopenharmony_ci			/* Less than right child, so promote right child */
1468c2ecf20Sopenharmony_ci			heap->arr[cpos]->hpos = hpos;
1478c2ecf20Sopenharmony_ci			heap->arr[hpos] = heap->arr[cpos];
1488c2ecf20Sopenharmony_ci			heap->arr[cpos] = lprops;
1498c2ecf20Sopenharmony_ci			lprops->hpos = cpos;
1508c2ecf20Sopenharmony_ci			hpos = cpos;
1518c2ecf20Sopenharmony_ci			continue;
1528c2ecf20Sopenharmony_ci		}
1538c2ecf20Sopenharmony_ci		return;
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci/**
1588c2ecf20Sopenharmony_ci * add_to_lpt_heap - add LEB properties to a LEB category heap.
1598c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
1608c2ecf20Sopenharmony_ci * @lprops: LEB properties to add
1618c2ecf20Sopenharmony_ci * @cat: LEB category
1628c2ecf20Sopenharmony_ci *
1638c2ecf20Sopenharmony_ci * This function returns %1 if @lprops is added to the heap for LEB category
1648c2ecf20Sopenharmony_ci * @cat, otherwise %0 is returned because the heap is full.
1658c2ecf20Sopenharmony_ci */
1668c2ecf20Sopenharmony_cistatic int add_to_lpt_heap(struct ubifs_info *c, struct ubifs_lprops *lprops,
1678c2ecf20Sopenharmony_ci			   int cat)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (heap->cnt >= heap->max_cnt) {
1728c2ecf20Sopenharmony_ci		const int b = LPT_HEAP_SZ / 2 - 1;
1738c2ecf20Sopenharmony_ci		int cpos, val1, val2;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci		/* Compare to some other LEB on the bottom of heap */
1768c2ecf20Sopenharmony_ci		/* Pick a position kind of randomly */
1778c2ecf20Sopenharmony_ci		cpos = (((size_t)lprops >> 4) & b) + b;
1788c2ecf20Sopenharmony_ci		ubifs_assert(c, cpos >= b);
1798c2ecf20Sopenharmony_ci		ubifs_assert(c, cpos < LPT_HEAP_SZ);
1808c2ecf20Sopenharmony_ci		ubifs_assert(c, cpos < heap->cnt);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		val1 = get_heap_comp_val(lprops, cat);
1838c2ecf20Sopenharmony_ci		val2 = get_heap_comp_val(heap->arr[cpos], cat);
1848c2ecf20Sopenharmony_ci		if (val1 > val2) {
1858c2ecf20Sopenharmony_ci			struct ubifs_lprops *lp;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci			lp = heap->arr[cpos];
1888c2ecf20Sopenharmony_ci			lp->flags &= ~LPROPS_CAT_MASK;
1898c2ecf20Sopenharmony_ci			lp->flags |= LPROPS_UNCAT;
1908c2ecf20Sopenharmony_ci			list_add(&lp->list, &c->uncat_list);
1918c2ecf20Sopenharmony_ci			lprops->hpos = cpos;
1928c2ecf20Sopenharmony_ci			heap->arr[cpos] = lprops;
1938c2ecf20Sopenharmony_ci			move_up_lpt_heap(c, heap, lprops, cat);
1948c2ecf20Sopenharmony_ci			dbg_check_heap(c, heap, cat, lprops->hpos);
1958c2ecf20Sopenharmony_ci			return 1; /* Added to heap */
1968c2ecf20Sopenharmony_ci		}
1978c2ecf20Sopenharmony_ci		dbg_check_heap(c, heap, cat, -1);
1988c2ecf20Sopenharmony_ci		return 0; /* Not added to heap */
1998c2ecf20Sopenharmony_ci	} else {
2008c2ecf20Sopenharmony_ci		lprops->hpos = heap->cnt++;
2018c2ecf20Sopenharmony_ci		heap->arr[lprops->hpos] = lprops;
2028c2ecf20Sopenharmony_ci		move_up_lpt_heap(c, heap, lprops, cat);
2038c2ecf20Sopenharmony_ci		dbg_check_heap(c, heap, cat, lprops->hpos);
2048c2ecf20Sopenharmony_ci		return 1; /* Added to heap */
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci/**
2098c2ecf20Sopenharmony_ci * remove_from_lpt_heap - remove LEB properties from a LEB category heap.
2108c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
2118c2ecf20Sopenharmony_ci * @lprops: LEB properties to remove
2128c2ecf20Sopenharmony_ci * @cat: LEB category
2138c2ecf20Sopenharmony_ci */
2148c2ecf20Sopenharmony_cistatic void remove_from_lpt_heap(struct ubifs_info *c,
2158c2ecf20Sopenharmony_ci				 struct ubifs_lprops *lprops, int cat)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	struct ubifs_lpt_heap *heap;
2188c2ecf20Sopenharmony_ci	int hpos = lprops->hpos;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	heap = &c->lpt_heap[cat - 1];
2218c2ecf20Sopenharmony_ci	ubifs_assert(c, hpos >= 0 && hpos < heap->cnt);
2228c2ecf20Sopenharmony_ci	ubifs_assert(c, heap->arr[hpos] == lprops);
2238c2ecf20Sopenharmony_ci	heap->cnt -= 1;
2248c2ecf20Sopenharmony_ci	if (hpos < heap->cnt) {
2258c2ecf20Sopenharmony_ci		heap->arr[hpos] = heap->arr[heap->cnt];
2268c2ecf20Sopenharmony_ci		heap->arr[hpos]->hpos = hpos;
2278c2ecf20Sopenharmony_ci		adjust_lpt_heap(c, heap, heap->arr[hpos], hpos, cat);
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci	dbg_check_heap(c, heap, cat, -1);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci/**
2338c2ecf20Sopenharmony_ci * lpt_heap_replace - replace lprops in a category heap.
2348c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
2358c2ecf20Sopenharmony_ci * @new_lprops: LEB properties with which to replace
2368c2ecf20Sopenharmony_ci * @cat: LEB category
2378c2ecf20Sopenharmony_ci *
2388c2ecf20Sopenharmony_ci * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
2398c2ecf20Sopenharmony_ci * and the lprops that the pnode contains.  When that happens, references in
2408c2ecf20Sopenharmony_ci * the category heaps to those lprops must be updated to point to the new
2418c2ecf20Sopenharmony_ci * lprops.  This function does that.
2428c2ecf20Sopenharmony_ci */
2438c2ecf20Sopenharmony_cistatic void lpt_heap_replace(struct ubifs_info *c,
2448c2ecf20Sopenharmony_ci			     struct ubifs_lprops *new_lprops, int cat)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct ubifs_lpt_heap *heap;
2478c2ecf20Sopenharmony_ci	int hpos = new_lprops->hpos;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	heap = &c->lpt_heap[cat - 1];
2508c2ecf20Sopenharmony_ci	heap->arr[hpos] = new_lprops;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci/**
2548c2ecf20Sopenharmony_ci * ubifs_add_to_cat - add LEB properties to a category list or heap.
2558c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
2568c2ecf20Sopenharmony_ci * @lprops: LEB properties to add
2578c2ecf20Sopenharmony_ci * @cat: LEB category to which to add
2588c2ecf20Sopenharmony_ci *
2598c2ecf20Sopenharmony_ci * LEB properties are categorized to enable fast find operations.
2608c2ecf20Sopenharmony_ci */
2618c2ecf20Sopenharmony_civoid ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
2628c2ecf20Sopenharmony_ci		      int cat)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	switch (cat) {
2658c2ecf20Sopenharmony_ci	case LPROPS_DIRTY:
2668c2ecf20Sopenharmony_ci	case LPROPS_DIRTY_IDX:
2678c2ecf20Sopenharmony_ci	case LPROPS_FREE:
2688c2ecf20Sopenharmony_ci		if (add_to_lpt_heap(c, lprops, cat))
2698c2ecf20Sopenharmony_ci			break;
2708c2ecf20Sopenharmony_ci		/* No more room on heap so make it un-categorized */
2718c2ecf20Sopenharmony_ci		cat = LPROPS_UNCAT;
2728c2ecf20Sopenharmony_ci		fallthrough;
2738c2ecf20Sopenharmony_ci	case LPROPS_UNCAT:
2748c2ecf20Sopenharmony_ci		list_add(&lprops->list, &c->uncat_list);
2758c2ecf20Sopenharmony_ci		break;
2768c2ecf20Sopenharmony_ci	case LPROPS_EMPTY:
2778c2ecf20Sopenharmony_ci		list_add(&lprops->list, &c->empty_list);
2788c2ecf20Sopenharmony_ci		break;
2798c2ecf20Sopenharmony_ci	case LPROPS_FREEABLE:
2808c2ecf20Sopenharmony_ci		list_add(&lprops->list, &c->freeable_list);
2818c2ecf20Sopenharmony_ci		c->freeable_cnt += 1;
2828c2ecf20Sopenharmony_ci		break;
2838c2ecf20Sopenharmony_ci	case LPROPS_FRDI_IDX:
2848c2ecf20Sopenharmony_ci		list_add(&lprops->list, &c->frdi_idx_list);
2858c2ecf20Sopenharmony_ci		break;
2868c2ecf20Sopenharmony_ci	default:
2878c2ecf20Sopenharmony_ci		ubifs_assert(c, 0);
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	lprops->flags &= ~LPROPS_CAT_MASK;
2918c2ecf20Sopenharmony_ci	lprops->flags |= cat;
2928c2ecf20Sopenharmony_ci	c->in_a_category_cnt += 1;
2938c2ecf20Sopenharmony_ci	ubifs_assert(c, c->in_a_category_cnt <= c->main_lebs);
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci/**
2978c2ecf20Sopenharmony_ci * ubifs_remove_from_cat - remove LEB properties from a category list or heap.
2988c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
2998c2ecf20Sopenharmony_ci * @lprops: LEB properties to remove
3008c2ecf20Sopenharmony_ci * @cat: LEB category from which to remove
3018c2ecf20Sopenharmony_ci *
3028c2ecf20Sopenharmony_ci * LEB properties are categorized to enable fast find operations.
3038c2ecf20Sopenharmony_ci */
3048c2ecf20Sopenharmony_cistatic void ubifs_remove_from_cat(struct ubifs_info *c,
3058c2ecf20Sopenharmony_ci				  struct ubifs_lprops *lprops, int cat)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	switch (cat) {
3088c2ecf20Sopenharmony_ci	case LPROPS_DIRTY:
3098c2ecf20Sopenharmony_ci	case LPROPS_DIRTY_IDX:
3108c2ecf20Sopenharmony_ci	case LPROPS_FREE:
3118c2ecf20Sopenharmony_ci		remove_from_lpt_heap(c, lprops, cat);
3128c2ecf20Sopenharmony_ci		break;
3138c2ecf20Sopenharmony_ci	case LPROPS_FREEABLE:
3148c2ecf20Sopenharmony_ci		c->freeable_cnt -= 1;
3158c2ecf20Sopenharmony_ci		ubifs_assert(c, c->freeable_cnt >= 0);
3168c2ecf20Sopenharmony_ci		fallthrough;
3178c2ecf20Sopenharmony_ci	case LPROPS_UNCAT:
3188c2ecf20Sopenharmony_ci	case LPROPS_EMPTY:
3198c2ecf20Sopenharmony_ci	case LPROPS_FRDI_IDX:
3208c2ecf20Sopenharmony_ci		ubifs_assert(c, !list_empty(&lprops->list));
3218c2ecf20Sopenharmony_ci		list_del(&lprops->list);
3228c2ecf20Sopenharmony_ci		break;
3238c2ecf20Sopenharmony_ci	default:
3248c2ecf20Sopenharmony_ci		ubifs_assert(c, 0);
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	c->in_a_category_cnt -= 1;
3288c2ecf20Sopenharmony_ci	ubifs_assert(c, c->in_a_category_cnt >= 0);
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci/**
3328c2ecf20Sopenharmony_ci * ubifs_replace_cat - replace lprops in a category list or heap.
3338c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
3348c2ecf20Sopenharmony_ci * @old_lprops: LEB properties to replace
3358c2ecf20Sopenharmony_ci * @new_lprops: LEB properties with which to replace
3368c2ecf20Sopenharmony_ci *
3378c2ecf20Sopenharmony_ci * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
3388c2ecf20Sopenharmony_ci * and the lprops that the pnode contains. When that happens, references in
3398c2ecf20Sopenharmony_ci * category lists and heaps must be replaced. This function does that.
3408c2ecf20Sopenharmony_ci */
3418c2ecf20Sopenharmony_civoid ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
3428c2ecf20Sopenharmony_ci		       struct ubifs_lprops *new_lprops)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	int cat;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	cat = new_lprops->flags & LPROPS_CAT_MASK;
3478c2ecf20Sopenharmony_ci	switch (cat) {
3488c2ecf20Sopenharmony_ci	case LPROPS_DIRTY:
3498c2ecf20Sopenharmony_ci	case LPROPS_DIRTY_IDX:
3508c2ecf20Sopenharmony_ci	case LPROPS_FREE:
3518c2ecf20Sopenharmony_ci		lpt_heap_replace(c, new_lprops, cat);
3528c2ecf20Sopenharmony_ci		break;
3538c2ecf20Sopenharmony_ci	case LPROPS_UNCAT:
3548c2ecf20Sopenharmony_ci	case LPROPS_EMPTY:
3558c2ecf20Sopenharmony_ci	case LPROPS_FREEABLE:
3568c2ecf20Sopenharmony_ci	case LPROPS_FRDI_IDX:
3578c2ecf20Sopenharmony_ci		list_replace(&old_lprops->list, &new_lprops->list);
3588c2ecf20Sopenharmony_ci		break;
3598c2ecf20Sopenharmony_ci	default:
3608c2ecf20Sopenharmony_ci		ubifs_assert(c, 0);
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci/**
3658c2ecf20Sopenharmony_ci * ubifs_ensure_cat - ensure LEB properties are categorized.
3668c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
3678c2ecf20Sopenharmony_ci * @lprops: LEB properties
3688c2ecf20Sopenharmony_ci *
3698c2ecf20Sopenharmony_ci * A LEB may have fallen off of the bottom of a heap, and ended up as
3708c2ecf20Sopenharmony_ci * un-categorized even though it has enough space for us now. If that is the
3718c2ecf20Sopenharmony_ci * case this function will put the LEB back onto a heap.
3728c2ecf20Sopenharmony_ci */
3738c2ecf20Sopenharmony_civoid ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	int cat = lprops->flags & LPROPS_CAT_MASK;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	if (cat != LPROPS_UNCAT)
3788c2ecf20Sopenharmony_ci		return;
3798c2ecf20Sopenharmony_ci	cat = ubifs_categorize_lprops(c, lprops);
3808c2ecf20Sopenharmony_ci	if (cat == LPROPS_UNCAT)
3818c2ecf20Sopenharmony_ci		return;
3828c2ecf20Sopenharmony_ci	ubifs_remove_from_cat(c, lprops, LPROPS_UNCAT);
3838c2ecf20Sopenharmony_ci	ubifs_add_to_cat(c, lprops, cat);
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci/**
3878c2ecf20Sopenharmony_ci * ubifs_categorize_lprops - categorize LEB properties.
3888c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
3898c2ecf20Sopenharmony_ci * @lprops: LEB properties to categorize
3908c2ecf20Sopenharmony_ci *
3918c2ecf20Sopenharmony_ci * LEB properties are categorized to enable fast find operations. This function
3928c2ecf20Sopenharmony_ci * returns the LEB category to which the LEB properties belong. Note however
3938c2ecf20Sopenharmony_ci * that if the LEB category is stored as a heap and the heap is full, the
3948c2ecf20Sopenharmony_ci * LEB properties may have their category changed to %LPROPS_UNCAT.
3958c2ecf20Sopenharmony_ci */
3968c2ecf20Sopenharmony_ciint ubifs_categorize_lprops(const struct ubifs_info *c,
3978c2ecf20Sopenharmony_ci			    const struct ubifs_lprops *lprops)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	if (lprops->flags & LPROPS_TAKEN)
4008c2ecf20Sopenharmony_ci		return LPROPS_UNCAT;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	if (lprops->free == c->leb_size) {
4038c2ecf20Sopenharmony_ci		ubifs_assert(c, !(lprops->flags & LPROPS_INDEX));
4048c2ecf20Sopenharmony_ci		return LPROPS_EMPTY;
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	if (lprops->free + lprops->dirty == c->leb_size) {
4088c2ecf20Sopenharmony_ci		if (lprops->flags & LPROPS_INDEX)
4098c2ecf20Sopenharmony_ci			return LPROPS_FRDI_IDX;
4108c2ecf20Sopenharmony_ci		else
4118c2ecf20Sopenharmony_ci			return LPROPS_FREEABLE;
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	if (lprops->flags & LPROPS_INDEX) {
4158c2ecf20Sopenharmony_ci		if (lprops->dirty + lprops->free >= c->min_idx_node_sz)
4168c2ecf20Sopenharmony_ci			return LPROPS_DIRTY_IDX;
4178c2ecf20Sopenharmony_ci	} else {
4188c2ecf20Sopenharmony_ci		if (lprops->dirty >= c->dead_wm &&
4198c2ecf20Sopenharmony_ci		    lprops->dirty > lprops->free)
4208c2ecf20Sopenharmony_ci			return LPROPS_DIRTY;
4218c2ecf20Sopenharmony_ci		if (lprops->free > 0)
4228c2ecf20Sopenharmony_ci			return LPROPS_FREE;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	return LPROPS_UNCAT;
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci/**
4298c2ecf20Sopenharmony_ci * change_category - change LEB properties category.
4308c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
4318c2ecf20Sopenharmony_ci * @lprops: LEB properties to re-categorize
4328c2ecf20Sopenharmony_ci *
4338c2ecf20Sopenharmony_ci * LEB properties are categorized to enable fast find operations. When the LEB
4348c2ecf20Sopenharmony_ci * properties change they must be re-categorized.
4358c2ecf20Sopenharmony_ci */
4368c2ecf20Sopenharmony_cistatic void change_category(struct ubifs_info *c, struct ubifs_lprops *lprops)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	int old_cat = lprops->flags & LPROPS_CAT_MASK;
4398c2ecf20Sopenharmony_ci	int new_cat = ubifs_categorize_lprops(c, lprops);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	if (old_cat == new_cat) {
4428c2ecf20Sopenharmony_ci		struct ubifs_lpt_heap *heap;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci		/* lprops on a heap now must be moved up or down */
4458c2ecf20Sopenharmony_ci		if (new_cat < 1 || new_cat > LPROPS_HEAP_CNT)
4468c2ecf20Sopenharmony_ci			return; /* Not on a heap */
4478c2ecf20Sopenharmony_ci		heap = &c->lpt_heap[new_cat - 1];
4488c2ecf20Sopenharmony_ci		adjust_lpt_heap(c, heap, lprops, lprops->hpos, new_cat);
4498c2ecf20Sopenharmony_ci	} else {
4508c2ecf20Sopenharmony_ci		ubifs_remove_from_cat(c, lprops, old_cat);
4518c2ecf20Sopenharmony_ci		ubifs_add_to_cat(c, lprops, new_cat);
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci/**
4568c2ecf20Sopenharmony_ci * ubifs_calc_dark - calculate LEB dark space size.
4578c2ecf20Sopenharmony_ci * @c: the UBIFS file-system description object
4588c2ecf20Sopenharmony_ci * @spc: amount of free and dirty space in the LEB
4598c2ecf20Sopenharmony_ci *
4608c2ecf20Sopenharmony_ci * This function calculates and returns amount of dark space in an LEB which
4618c2ecf20Sopenharmony_ci * has @spc bytes of free and dirty space.
4628c2ecf20Sopenharmony_ci *
4638c2ecf20Sopenharmony_ci * UBIFS is trying to account the space which might not be usable, and this
4648c2ecf20Sopenharmony_ci * space is called "dark space". For example, if an LEB has only %512 free
4658c2ecf20Sopenharmony_ci * bytes, it is dark space, because it cannot fit a large data node.
4668c2ecf20Sopenharmony_ci */
4678c2ecf20Sopenharmony_ciint ubifs_calc_dark(const struct ubifs_info *c, int spc)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	ubifs_assert(c, !(spc & 7));
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	if (spc < c->dark_wm)
4728c2ecf20Sopenharmony_ci		return spc;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	/*
4758c2ecf20Sopenharmony_ci	 * If we have slightly more space then the dark space watermark, we can
4768c2ecf20Sopenharmony_ci	 * anyway safely assume it we'll be able to write a node of the
4778c2ecf20Sopenharmony_ci	 * smallest size there.
4788c2ecf20Sopenharmony_ci	 */
4798c2ecf20Sopenharmony_ci	if (spc - c->dark_wm < MIN_WRITE_SZ)
4808c2ecf20Sopenharmony_ci		return spc - MIN_WRITE_SZ;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	return c->dark_wm;
4838c2ecf20Sopenharmony_ci}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci/**
4868c2ecf20Sopenharmony_ci * is_lprops_dirty - determine if LEB properties are dirty.
4878c2ecf20Sopenharmony_ci * @c: the UBIFS file-system description object
4888c2ecf20Sopenharmony_ci * @lprops: LEB properties to test
4898c2ecf20Sopenharmony_ci */
4908c2ecf20Sopenharmony_cistatic int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	struct ubifs_pnode *pnode;
4938c2ecf20Sopenharmony_ci	int pos;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	pos = (lprops->lnum - c->main_first) & (UBIFS_LPT_FANOUT - 1);
4968c2ecf20Sopenharmony_ci	pnode = (struct ubifs_pnode *)container_of(lprops - pos,
4978c2ecf20Sopenharmony_ci						   struct ubifs_pnode,
4988c2ecf20Sopenharmony_ci						   lprops[0]);
4998c2ecf20Sopenharmony_ci	return !test_bit(COW_CNODE, &pnode->flags) &&
5008c2ecf20Sopenharmony_ci	       test_bit(DIRTY_CNODE, &pnode->flags);
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci/**
5048c2ecf20Sopenharmony_ci * ubifs_change_lp - change LEB properties.
5058c2ecf20Sopenharmony_ci * @c: the UBIFS file-system description object
5068c2ecf20Sopenharmony_ci * @lp: LEB properties to change
5078c2ecf20Sopenharmony_ci * @free: new free space amount
5088c2ecf20Sopenharmony_ci * @dirty: new dirty space amount
5098c2ecf20Sopenharmony_ci * @flags: new flags
5108c2ecf20Sopenharmony_ci * @idx_gc_cnt: change to the count of @idx_gc list
5118c2ecf20Sopenharmony_ci *
5128c2ecf20Sopenharmony_ci * This function changes LEB properties (@free, @dirty or @flag). However, the
5138c2ecf20Sopenharmony_ci * property which has the %LPROPS_NC value is not changed. Returns a pointer to
5148c2ecf20Sopenharmony_ci * the updated LEB properties on success and a negative error code on failure.
5158c2ecf20Sopenharmony_ci *
5168c2ecf20Sopenharmony_ci * Note, the LEB properties may have had to be copied (due to COW) and
5178c2ecf20Sopenharmony_ci * consequently the pointer returned may not be the same as the pointer
5188c2ecf20Sopenharmony_ci * passed.
5198c2ecf20Sopenharmony_ci */
5208c2ecf20Sopenharmony_ciconst struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
5218c2ecf20Sopenharmony_ci					   const struct ubifs_lprops *lp,
5228c2ecf20Sopenharmony_ci					   int free, int dirty, int flags,
5238c2ecf20Sopenharmony_ci					   int idx_gc_cnt)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	/*
5268c2ecf20Sopenharmony_ci	 * This is the only function that is allowed to change lprops, so we
5278c2ecf20Sopenharmony_ci	 * discard the "const" qualifier.
5288c2ecf20Sopenharmony_ci	 */
5298c2ecf20Sopenharmony_ci	struct ubifs_lprops *lprops = (struct ubifs_lprops *)lp;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	dbg_lp("LEB %d, free %d, dirty %d, flags %d",
5328c2ecf20Sopenharmony_ci	       lprops->lnum, free, dirty, flags);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	ubifs_assert(c, mutex_is_locked(&c->lp_mutex));
5358c2ecf20Sopenharmony_ci	ubifs_assert(c, c->lst.empty_lebs >= 0 &&
5368c2ecf20Sopenharmony_ci		     c->lst.empty_lebs <= c->main_lebs);
5378c2ecf20Sopenharmony_ci	ubifs_assert(c, c->freeable_cnt >= 0);
5388c2ecf20Sopenharmony_ci	ubifs_assert(c, c->freeable_cnt <= c->main_lebs);
5398c2ecf20Sopenharmony_ci	ubifs_assert(c, c->lst.taken_empty_lebs >= 0);
5408c2ecf20Sopenharmony_ci	ubifs_assert(c, c->lst.taken_empty_lebs <= c->lst.empty_lebs);
5418c2ecf20Sopenharmony_ci	ubifs_assert(c, !(c->lst.total_free & 7) && !(c->lst.total_dirty & 7));
5428c2ecf20Sopenharmony_ci	ubifs_assert(c, !(c->lst.total_dead & 7) && !(c->lst.total_dark & 7));
5438c2ecf20Sopenharmony_ci	ubifs_assert(c, !(c->lst.total_used & 7));
5448c2ecf20Sopenharmony_ci	ubifs_assert(c, free == LPROPS_NC || free >= 0);
5458c2ecf20Sopenharmony_ci	ubifs_assert(c, dirty == LPROPS_NC || dirty >= 0);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	if (!is_lprops_dirty(c, lprops)) {
5488c2ecf20Sopenharmony_ci		lprops = ubifs_lpt_lookup_dirty(c, lprops->lnum);
5498c2ecf20Sopenharmony_ci		if (IS_ERR(lprops))
5508c2ecf20Sopenharmony_ci			return lprops;
5518c2ecf20Sopenharmony_ci	} else
5528c2ecf20Sopenharmony_ci		ubifs_assert(c, lprops == ubifs_lpt_lookup_dirty(c, lprops->lnum));
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	ubifs_assert(c, !(lprops->free & 7) && !(lprops->dirty & 7));
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	spin_lock(&c->space_lock);
5578c2ecf20Sopenharmony_ci	if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
5588c2ecf20Sopenharmony_ci		c->lst.taken_empty_lebs -= 1;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	if (!(lprops->flags & LPROPS_INDEX)) {
5618c2ecf20Sopenharmony_ci		int old_spc;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci		old_spc = lprops->free + lprops->dirty;
5648c2ecf20Sopenharmony_ci		if (old_spc < c->dead_wm)
5658c2ecf20Sopenharmony_ci			c->lst.total_dead -= old_spc;
5668c2ecf20Sopenharmony_ci		else
5678c2ecf20Sopenharmony_ci			c->lst.total_dark -= ubifs_calc_dark(c, old_spc);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci		c->lst.total_used -= c->leb_size - old_spc;
5708c2ecf20Sopenharmony_ci	}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	if (free != LPROPS_NC) {
5738c2ecf20Sopenharmony_ci		free = ALIGN(free, 8);
5748c2ecf20Sopenharmony_ci		c->lst.total_free += free - lprops->free;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci		/* Increase or decrease empty LEBs counter if needed */
5778c2ecf20Sopenharmony_ci		if (free == c->leb_size) {
5788c2ecf20Sopenharmony_ci			if (lprops->free != c->leb_size)
5798c2ecf20Sopenharmony_ci				c->lst.empty_lebs += 1;
5808c2ecf20Sopenharmony_ci		} else if (lprops->free == c->leb_size)
5818c2ecf20Sopenharmony_ci			c->lst.empty_lebs -= 1;
5828c2ecf20Sopenharmony_ci		lprops->free = free;
5838c2ecf20Sopenharmony_ci	}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	if (dirty != LPROPS_NC) {
5868c2ecf20Sopenharmony_ci		dirty = ALIGN(dirty, 8);
5878c2ecf20Sopenharmony_ci		c->lst.total_dirty += dirty - lprops->dirty;
5888c2ecf20Sopenharmony_ci		lprops->dirty = dirty;
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	if (flags != LPROPS_NC) {
5928c2ecf20Sopenharmony_ci		/* Take care about indexing LEBs counter if needed */
5938c2ecf20Sopenharmony_ci		if ((lprops->flags & LPROPS_INDEX)) {
5948c2ecf20Sopenharmony_ci			if (!(flags & LPROPS_INDEX))
5958c2ecf20Sopenharmony_ci				c->lst.idx_lebs -= 1;
5968c2ecf20Sopenharmony_ci		} else if (flags & LPROPS_INDEX)
5978c2ecf20Sopenharmony_ci			c->lst.idx_lebs += 1;
5988c2ecf20Sopenharmony_ci		lprops->flags = flags;
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	if (!(lprops->flags & LPROPS_INDEX)) {
6028c2ecf20Sopenharmony_ci		int new_spc;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci		new_spc = lprops->free + lprops->dirty;
6058c2ecf20Sopenharmony_ci		if (new_spc < c->dead_wm)
6068c2ecf20Sopenharmony_ci			c->lst.total_dead += new_spc;
6078c2ecf20Sopenharmony_ci		else
6088c2ecf20Sopenharmony_ci			c->lst.total_dark += ubifs_calc_dark(c, new_spc);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci		c->lst.total_used += c->leb_size - new_spc;
6118c2ecf20Sopenharmony_ci	}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
6148c2ecf20Sopenharmony_ci		c->lst.taken_empty_lebs += 1;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	change_category(c, lprops);
6178c2ecf20Sopenharmony_ci	c->idx_gc_cnt += idx_gc_cnt;
6188c2ecf20Sopenharmony_ci	spin_unlock(&c->space_lock);
6198c2ecf20Sopenharmony_ci	return lprops;
6208c2ecf20Sopenharmony_ci}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci/**
6238c2ecf20Sopenharmony_ci * ubifs_get_lp_stats - get lprops statistics.
6248c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
6258c2ecf20Sopenharmony_ci * @lst: return statistics
6268c2ecf20Sopenharmony_ci */
6278c2ecf20Sopenharmony_civoid ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst)
6288c2ecf20Sopenharmony_ci{
6298c2ecf20Sopenharmony_ci	spin_lock(&c->space_lock);
6308c2ecf20Sopenharmony_ci	memcpy(lst, &c->lst, sizeof(struct ubifs_lp_stats));
6318c2ecf20Sopenharmony_ci	spin_unlock(&c->space_lock);
6328c2ecf20Sopenharmony_ci}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci/**
6358c2ecf20Sopenharmony_ci * ubifs_change_one_lp - change LEB properties.
6368c2ecf20Sopenharmony_ci * @c: the UBIFS file-system description object
6378c2ecf20Sopenharmony_ci * @lnum: LEB to change properties for
6388c2ecf20Sopenharmony_ci * @free: amount of free space
6398c2ecf20Sopenharmony_ci * @dirty: amount of dirty space
6408c2ecf20Sopenharmony_ci * @flags_set: flags to set
6418c2ecf20Sopenharmony_ci * @flags_clean: flags to clean
6428c2ecf20Sopenharmony_ci * @idx_gc_cnt: change to the count of idx_gc list
6438c2ecf20Sopenharmony_ci *
6448c2ecf20Sopenharmony_ci * This function changes properties of LEB @lnum. It is a helper wrapper over
6458c2ecf20Sopenharmony_ci * 'ubifs_change_lp()' which hides lprops get/release. The arguments are the
6468c2ecf20Sopenharmony_ci * same as in case of 'ubifs_change_lp()'. Returns zero in case of success and
6478c2ecf20Sopenharmony_ci * a negative error code in case of failure.
6488c2ecf20Sopenharmony_ci */
6498c2ecf20Sopenharmony_ciint ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
6508c2ecf20Sopenharmony_ci			int flags_set, int flags_clean, int idx_gc_cnt)
6518c2ecf20Sopenharmony_ci{
6528c2ecf20Sopenharmony_ci	int err = 0, flags;
6538c2ecf20Sopenharmony_ci	const struct ubifs_lprops *lp;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	ubifs_get_lprops(c);
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	lp = ubifs_lpt_lookup_dirty(c, lnum);
6588c2ecf20Sopenharmony_ci	if (IS_ERR(lp)) {
6598c2ecf20Sopenharmony_ci		err = PTR_ERR(lp);
6608c2ecf20Sopenharmony_ci		goto out;
6618c2ecf20Sopenharmony_ci	}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	flags = (lp->flags | flags_set) & ~flags_clean;
6648c2ecf20Sopenharmony_ci	lp = ubifs_change_lp(c, lp, free, dirty, flags, idx_gc_cnt);
6658c2ecf20Sopenharmony_ci	if (IS_ERR(lp))
6668c2ecf20Sopenharmony_ci		err = PTR_ERR(lp);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ciout:
6698c2ecf20Sopenharmony_ci	ubifs_release_lprops(c);
6708c2ecf20Sopenharmony_ci	if (err)
6718c2ecf20Sopenharmony_ci		ubifs_err(c, "cannot change properties of LEB %d, error %d",
6728c2ecf20Sopenharmony_ci			  lnum, err);
6738c2ecf20Sopenharmony_ci	return err;
6748c2ecf20Sopenharmony_ci}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci/**
6778c2ecf20Sopenharmony_ci * ubifs_update_one_lp - update LEB properties.
6788c2ecf20Sopenharmony_ci * @c: the UBIFS file-system description object
6798c2ecf20Sopenharmony_ci * @lnum: LEB to change properties for
6808c2ecf20Sopenharmony_ci * @free: amount of free space
6818c2ecf20Sopenharmony_ci * @dirty: amount of dirty space to add
6828c2ecf20Sopenharmony_ci * @flags_set: flags to set
6838c2ecf20Sopenharmony_ci * @flags_clean: flags to clean
6848c2ecf20Sopenharmony_ci *
6858c2ecf20Sopenharmony_ci * This function is the same as 'ubifs_change_one_lp()' but @dirty is added to
6868c2ecf20Sopenharmony_ci * current dirty space, not substitutes it.
6878c2ecf20Sopenharmony_ci */
6888c2ecf20Sopenharmony_ciint ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
6898c2ecf20Sopenharmony_ci			int flags_set, int flags_clean)
6908c2ecf20Sopenharmony_ci{
6918c2ecf20Sopenharmony_ci	int err = 0, flags;
6928c2ecf20Sopenharmony_ci	const struct ubifs_lprops *lp;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	ubifs_get_lprops(c);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	lp = ubifs_lpt_lookup_dirty(c, lnum);
6978c2ecf20Sopenharmony_ci	if (IS_ERR(lp)) {
6988c2ecf20Sopenharmony_ci		err = PTR_ERR(lp);
6998c2ecf20Sopenharmony_ci		goto out;
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	flags = (lp->flags | flags_set) & ~flags_clean;
7038c2ecf20Sopenharmony_ci	lp = ubifs_change_lp(c, lp, free, lp->dirty + dirty, flags, 0);
7048c2ecf20Sopenharmony_ci	if (IS_ERR(lp))
7058c2ecf20Sopenharmony_ci		err = PTR_ERR(lp);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ciout:
7088c2ecf20Sopenharmony_ci	ubifs_release_lprops(c);
7098c2ecf20Sopenharmony_ci	if (err)
7108c2ecf20Sopenharmony_ci		ubifs_err(c, "cannot update properties of LEB %d, error %d",
7118c2ecf20Sopenharmony_ci			  lnum, err);
7128c2ecf20Sopenharmony_ci	return err;
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci/**
7168c2ecf20Sopenharmony_ci * ubifs_read_one_lp - read LEB properties.
7178c2ecf20Sopenharmony_ci * @c: the UBIFS file-system description object
7188c2ecf20Sopenharmony_ci * @lnum: LEB to read properties for
7198c2ecf20Sopenharmony_ci * @lp: where to store read properties
7208c2ecf20Sopenharmony_ci *
7218c2ecf20Sopenharmony_ci * This helper function reads properties of a LEB @lnum and stores them in @lp.
7228c2ecf20Sopenharmony_ci * Returns zero in case of success and a negative error code in case of
7238c2ecf20Sopenharmony_ci * failure.
7248c2ecf20Sopenharmony_ci */
7258c2ecf20Sopenharmony_ciint ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp)
7268c2ecf20Sopenharmony_ci{
7278c2ecf20Sopenharmony_ci	int err = 0;
7288c2ecf20Sopenharmony_ci	const struct ubifs_lprops *lpp;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	ubifs_get_lprops(c);
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	lpp = ubifs_lpt_lookup(c, lnum);
7338c2ecf20Sopenharmony_ci	if (IS_ERR(lpp)) {
7348c2ecf20Sopenharmony_ci		err = PTR_ERR(lpp);
7358c2ecf20Sopenharmony_ci		ubifs_err(c, "cannot read properties of LEB %d, error %d",
7368c2ecf20Sopenharmony_ci			  lnum, err);
7378c2ecf20Sopenharmony_ci		goto out;
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	memcpy(lp, lpp, sizeof(struct ubifs_lprops));
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ciout:
7438c2ecf20Sopenharmony_ci	ubifs_release_lprops(c);
7448c2ecf20Sopenharmony_ci	return err;
7458c2ecf20Sopenharmony_ci}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci/**
7488c2ecf20Sopenharmony_ci * ubifs_fast_find_free - try to find a LEB with free space quickly.
7498c2ecf20Sopenharmony_ci * @c: the UBIFS file-system description object
7508c2ecf20Sopenharmony_ci *
7518c2ecf20Sopenharmony_ci * This function returns LEB properties for a LEB with free space or %NULL if
7528c2ecf20Sopenharmony_ci * the function is unable to find a LEB quickly.
7538c2ecf20Sopenharmony_ci */
7548c2ecf20Sopenharmony_ciconst struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	struct ubifs_lprops *lprops;
7578c2ecf20Sopenharmony_ci	struct ubifs_lpt_heap *heap;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	ubifs_assert(c, mutex_is_locked(&c->lp_mutex));
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	heap = &c->lpt_heap[LPROPS_FREE - 1];
7628c2ecf20Sopenharmony_ci	if (heap->cnt == 0)
7638c2ecf20Sopenharmony_ci		return NULL;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	lprops = heap->arr[0];
7668c2ecf20Sopenharmony_ci	ubifs_assert(c, !(lprops->flags & LPROPS_TAKEN));
7678c2ecf20Sopenharmony_ci	ubifs_assert(c, !(lprops->flags & LPROPS_INDEX));
7688c2ecf20Sopenharmony_ci	return lprops;
7698c2ecf20Sopenharmony_ci}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci/**
7728c2ecf20Sopenharmony_ci * ubifs_fast_find_empty - try to find an empty LEB quickly.
7738c2ecf20Sopenharmony_ci * @c: the UBIFS file-system description object
7748c2ecf20Sopenharmony_ci *
7758c2ecf20Sopenharmony_ci * This function returns LEB properties for an empty LEB or %NULL if the
7768c2ecf20Sopenharmony_ci * function is unable to find an empty LEB quickly.
7778c2ecf20Sopenharmony_ci */
7788c2ecf20Sopenharmony_ciconst struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c)
7798c2ecf20Sopenharmony_ci{
7808c2ecf20Sopenharmony_ci	struct ubifs_lprops *lprops;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	ubifs_assert(c, mutex_is_locked(&c->lp_mutex));
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	if (list_empty(&c->empty_list))
7858c2ecf20Sopenharmony_ci		return NULL;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	lprops = list_entry(c->empty_list.next, struct ubifs_lprops, list);
7888c2ecf20Sopenharmony_ci	ubifs_assert(c, !(lprops->flags & LPROPS_TAKEN));
7898c2ecf20Sopenharmony_ci	ubifs_assert(c, !(lprops->flags & LPROPS_INDEX));
7908c2ecf20Sopenharmony_ci	ubifs_assert(c, lprops->free == c->leb_size);
7918c2ecf20Sopenharmony_ci	return lprops;
7928c2ecf20Sopenharmony_ci}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci/**
7958c2ecf20Sopenharmony_ci * ubifs_fast_find_freeable - try to find a freeable LEB quickly.
7968c2ecf20Sopenharmony_ci * @c: the UBIFS file-system description object
7978c2ecf20Sopenharmony_ci *
7988c2ecf20Sopenharmony_ci * This function returns LEB properties for a freeable LEB or %NULL if the
7998c2ecf20Sopenharmony_ci * function is unable to find a freeable LEB quickly.
8008c2ecf20Sopenharmony_ci */
8018c2ecf20Sopenharmony_ciconst struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	struct ubifs_lprops *lprops;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	ubifs_assert(c, mutex_is_locked(&c->lp_mutex));
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	if (list_empty(&c->freeable_list))
8088c2ecf20Sopenharmony_ci		return NULL;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	lprops = list_entry(c->freeable_list.next, struct ubifs_lprops, list);
8118c2ecf20Sopenharmony_ci	ubifs_assert(c, !(lprops->flags & LPROPS_TAKEN));
8128c2ecf20Sopenharmony_ci	ubifs_assert(c, !(lprops->flags & LPROPS_INDEX));
8138c2ecf20Sopenharmony_ci	ubifs_assert(c, lprops->free + lprops->dirty == c->leb_size);
8148c2ecf20Sopenharmony_ci	ubifs_assert(c, c->freeable_cnt > 0);
8158c2ecf20Sopenharmony_ci	return lprops;
8168c2ecf20Sopenharmony_ci}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci/**
8198c2ecf20Sopenharmony_ci * ubifs_fast_find_frdi_idx - try to find a freeable index LEB quickly.
8208c2ecf20Sopenharmony_ci * @c: the UBIFS file-system description object
8218c2ecf20Sopenharmony_ci *
8228c2ecf20Sopenharmony_ci * This function returns LEB properties for a freeable index LEB or %NULL if the
8238c2ecf20Sopenharmony_ci * function is unable to find a freeable index LEB quickly.
8248c2ecf20Sopenharmony_ci */
8258c2ecf20Sopenharmony_ciconst struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c)
8268c2ecf20Sopenharmony_ci{
8278c2ecf20Sopenharmony_ci	struct ubifs_lprops *lprops;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	ubifs_assert(c, mutex_is_locked(&c->lp_mutex));
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	if (list_empty(&c->frdi_idx_list))
8328c2ecf20Sopenharmony_ci		return NULL;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	lprops = list_entry(c->frdi_idx_list.next, struct ubifs_lprops, list);
8358c2ecf20Sopenharmony_ci	ubifs_assert(c, !(lprops->flags & LPROPS_TAKEN));
8368c2ecf20Sopenharmony_ci	ubifs_assert(c, (lprops->flags & LPROPS_INDEX));
8378c2ecf20Sopenharmony_ci	ubifs_assert(c, lprops->free + lprops->dirty == c->leb_size);
8388c2ecf20Sopenharmony_ci	return lprops;
8398c2ecf20Sopenharmony_ci}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci/*
8428c2ecf20Sopenharmony_ci * Everything below is related to debugging.
8438c2ecf20Sopenharmony_ci */
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci/**
8468c2ecf20Sopenharmony_ci * dbg_check_cats - check category heaps and lists.
8478c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
8488c2ecf20Sopenharmony_ci *
8498c2ecf20Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
8508c2ecf20Sopenharmony_ci */
8518c2ecf20Sopenharmony_ciint dbg_check_cats(struct ubifs_info *c)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	struct ubifs_lprops *lprops;
8548c2ecf20Sopenharmony_ci	struct list_head *pos;
8558c2ecf20Sopenharmony_ci	int i, cat;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
8588c2ecf20Sopenharmony_ci		return 0;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	list_for_each_entry(lprops, &c->empty_list, list) {
8618c2ecf20Sopenharmony_ci		if (lprops->free != c->leb_size) {
8628c2ecf20Sopenharmony_ci			ubifs_err(c, "non-empty LEB %d on empty list (free %d dirty %d flags %d)",
8638c2ecf20Sopenharmony_ci				  lprops->lnum, lprops->free, lprops->dirty,
8648c2ecf20Sopenharmony_ci				  lprops->flags);
8658c2ecf20Sopenharmony_ci			return -EINVAL;
8668c2ecf20Sopenharmony_ci		}
8678c2ecf20Sopenharmony_ci		if (lprops->flags & LPROPS_TAKEN) {
8688c2ecf20Sopenharmony_ci			ubifs_err(c, "taken LEB %d on empty list (free %d dirty %d flags %d)",
8698c2ecf20Sopenharmony_ci				  lprops->lnum, lprops->free, lprops->dirty,
8708c2ecf20Sopenharmony_ci				  lprops->flags);
8718c2ecf20Sopenharmony_ci			return -EINVAL;
8728c2ecf20Sopenharmony_ci		}
8738c2ecf20Sopenharmony_ci	}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	i = 0;
8768c2ecf20Sopenharmony_ci	list_for_each_entry(lprops, &c->freeable_list, list) {
8778c2ecf20Sopenharmony_ci		if (lprops->free + lprops->dirty != c->leb_size) {
8788c2ecf20Sopenharmony_ci			ubifs_err(c, "non-freeable LEB %d on freeable list (free %d dirty %d flags %d)",
8798c2ecf20Sopenharmony_ci				  lprops->lnum, lprops->free, lprops->dirty,
8808c2ecf20Sopenharmony_ci				  lprops->flags);
8818c2ecf20Sopenharmony_ci			return -EINVAL;
8828c2ecf20Sopenharmony_ci		}
8838c2ecf20Sopenharmony_ci		if (lprops->flags & LPROPS_TAKEN) {
8848c2ecf20Sopenharmony_ci			ubifs_err(c, "taken LEB %d on freeable list (free %d dirty %d flags %d)",
8858c2ecf20Sopenharmony_ci				  lprops->lnum, lprops->free, lprops->dirty,
8868c2ecf20Sopenharmony_ci				  lprops->flags);
8878c2ecf20Sopenharmony_ci			return -EINVAL;
8888c2ecf20Sopenharmony_ci		}
8898c2ecf20Sopenharmony_ci		i += 1;
8908c2ecf20Sopenharmony_ci	}
8918c2ecf20Sopenharmony_ci	if (i != c->freeable_cnt) {
8928c2ecf20Sopenharmony_ci		ubifs_err(c, "freeable list count %d expected %d", i,
8938c2ecf20Sopenharmony_ci			  c->freeable_cnt);
8948c2ecf20Sopenharmony_ci		return -EINVAL;
8958c2ecf20Sopenharmony_ci	}
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	i = 0;
8988c2ecf20Sopenharmony_ci	list_for_each(pos, &c->idx_gc)
8998c2ecf20Sopenharmony_ci		i += 1;
9008c2ecf20Sopenharmony_ci	if (i != c->idx_gc_cnt) {
9018c2ecf20Sopenharmony_ci		ubifs_err(c, "idx_gc list count %d expected %d", i,
9028c2ecf20Sopenharmony_ci			  c->idx_gc_cnt);
9038c2ecf20Sopenharmony_ci		return -EINVAL;
9048c2ecf20Sopenharmony_ci	}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	list_for_each_entry(lprops, &c->frdi_idx_list, list) {
9078c2ecf20Sopenharmony_ci		if (lprops->free + lprops->dirty != c->leb_size) {
9088c2ecf20Sopenharmony_ci			ubifs_err(c, "non-freeable LEB %d on frdi_idx list (free %d dirty %d flags %d)",
9098c2ecf20Sopenharmony_ci				  lprops->lnum, lprops->free, lprops->dirty,
9108c2ecf20Sopenharmony_ci				  lprops->flags);
9118c2ecf20Sopenharmony_ci			return -EINVAL;
9128c2ecf20Sopenharmony_ci		}
9138c2ecf20Sopenharmony_ci		if (lprops->flags & LPROPS_TAKEN) {
9148c2ecf20Sopenharmony_ci			ubifs_err(c, "taken LEB %d on frdi_idx list (free %d dirty %d flags %d)",
9158c2ecf20Sopenharmony_ci				  lprops->lnum, lprops->free, lprops->dirty,
9168c2ecf20Sopenharmony_ci				  lprops->flags);
9178c2ecf20Sopenharmony_ci			return -EINVAL;
9188c2ecf20Sopenharmony_ci		}
9198c2ecf20Sopenharmony_ci		if (!(lprops->flags & LPROPS_INDEX)) {
9208c2ecf20Sopenharmony_ci			ubifs_err(c, "non-index LEB %d on frdi_idx list (free %d dirty %d flags %d)",
9218c2ecf20Sopenharmony_ci				  lprops->lnum, lprops->free, lprops->dirty,
9228c2ecf20Sopenharmony_ci				  lprops->flags);
9238c2ecf20Sopenharmony_ci			return -EINVAL;
9248c2ecf20Sopenharmony_ci		}
9258c2ecf20Sopenharmony_ci	}
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	for (cat = 1; cat <= LPROPS_HEAP_CNT; cat++) {
9288c2ecf20Sopenharmony_ci		struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci		for (i = 0; i < heap->cnt; i++) {
9318c2ecf20Sopenharmony_ci			lprops = heap->arr[i];
9328c2ecf20Sopenharmony_ci			if (!lprops) {
9338c2ecf20Sopenharmony_ci				ubifs_err(c, "null ptr in LPT heap cat %d", cat);
9348c2ecf20Sopenharmony_ci				return -EINVAL;
9358c2ecf20Sopenharmony_ci			}
9368c2ecf20Sopenharmony_ci			if (lprops->hpos != i) {
9378c2ecf20Sopenharmony_ci				ubifs_err(c, "bad ptr in LPT heap cat %d", cat);
9388c2ecf20Sopenharmony_ci				return -EINVAL;
9398c2ecf20Sopenharmony_ci			}
9408c2ecf20Sopenharmony_ci			if (lprops->flags & LPROPS_TAKEN) {
9418c2ecf20Sopenharmony_ci				ubifs_err(c, "taken LEB in LPT heap cat %d", cat);
9428c2ecf20Sopenharmony_ci				return -EINVAL;
9438c2ecf20Sopenharmony_ci			}
9448c2ecf20Sopenharmony_ci		}
9458c2ecf20Sopenharmony_ci	}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	return 0;
9488c2ecf20Sopenharmony_ci}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_civoid dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
9518c2ecf20Sopenharmony_ci		    int add_pos)
9528c2ecf20Sopenharmony_ci{
9538c2ecf20Sopenharmony_ci	int i = 0, j, err = 0;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
9568c2ecf20Sopenharmony_ci		return;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	for (i = 0; i < heap->cnt; i++) {
9598c2ecf20Sopenharmony_ci		struct ubifs_lprops *lprops = heap->arr[i];
9608c2ecf20Sopenharmony_ci		struct ubifs_lprops *lp;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci		if (i != add_pos)
9638c2ecf20Sopenharmony_ci			if ((lprops->flags & LPROPS_CAT_MASK) != cat) {
9648c2ecf20Sopenharmony_ci				err = 1;
9658c2ecf20Sopenharmony_ci				goto out;
9668c2ecf20Sopenharmony_ci			}
9678c2ecf20Sopenharmony_ci		if (lprops->hpos != i) {
9688c2ecf20Sopenharmony_ci			err = 2;
9698c2ecf20Sopenharmony_ci			goto out;
9708c2ecf20Sopenharmony_ci		}
9718c2ecf20Sopenharmony_ci		lp = ubifs_lpt_lookup(c, lprops->lnum);
9728c2ecf20Sopenharmony_ci		if (IS_ERR(lp)) {
9738c2ecf20Sopenharmony_ci			err = 3;
9748c2ecf20Sopenharmony_ci			goto out;
9758c2ecf20Sopenharmony_ci		}
9768c2ecf20Sopenharmony_ci		if (lprops != lp) {
9778c2ecf20Sopenharmony_ci			ubifs_err(c, "lprops %zx lp %zx lprops->lnum %d lp->lnum %d",
9788c2ecf20Sopenharmony_ci				  (size_t)lprops, (size_t)lp, lprops->lnum,
9798c2ecf20Sopenharmony_ci				  lp->lnum);
9808c2ecf20Sopenharmony_ci			err = 4;
9818c2ecf20Sopenharmony_ci			goto out;
9828c2ecf20Sopenharmony_ci		}
9838c2ecf20Sopenharmony_ci		for (j = 0; j < i; j++) {
9848c2ecf20Sopenharmony_ci			lp = heap->arr[j];
9858c2ecf20Sopenharmony_ci			if (lp == lprops) {
9868c2ecf20Sopenharmony_ci				err = 5;
9878c2ecf20Sopenharmony_ci				goto out;
9888c2ecf20Sopenharmony_ci			}
9898c2ecf20Sopenharmony_ci			if (lp->lnum == lprops->lnum) {
9908c2ecf20Sopenharmony_ci				err = 6;
9918c2ecf20Sopenharmony_ci				goto out;
9928c2ecf20Sopenharmony_ci			}
9938c2ecf20Sopenharmony_ci		}
9948c2ecf20Sopenharmony_ci	}
9958c2ecf20Sopenharmony_ciout:
9968c2ecf20Sopenharmony_ci	if (err) {
9978c2ecf20Sopenharmony_ci		ubifs_err(c, "failed cat %d hpos %d err %d", cat, i, err);
9988c2ecf20Sopenharmony_ci		dump_stack();
9998c2ecf20Sopenharmony_ci		ubifs_dump_heap(c, heap, cat);
10008c2ecf20Sopenharmony_ci	}
10018c2ecf20Sopenharmony_ci}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci/**
10048c2ecf20Sopenharmony_ci * scan_check_cb - scan callback.
10058c2ecf20Sopenharmony_ci * @c: the UBIFS file-system description object
10068c2ecf20Sopenharmony_ci * @lp: LEB properties to scan
10078c2ecf20Sopenharmony_ci * @in_tree: whether the LEB properties are in main memory
10088c2ecf20Sopenharmony_ci * @lst: lprops statistics to update
10098c2ecf20Sopenharmony_ci *
10108c2ecf20Sopenharmony_ci * This function returns a code that indicates whether the scan should continue
10118c2ecf20Sopenharmony_ci * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
10128c2ecf20Sopenharmony_ci * in main memory (%LPT_SCAN_ADD), or whether the scan should stop
10138c2ecf20Sopenharmony_ci * (%LPT_SCAN_STOP).
10148c2ecf20Sopenharmony_ci */
10158c2ecf20Sopenharmony_cistatic int scan_check_cb(struct ubifs_info *c,
10168c2ecf20Sopenharmony_ci			 const struct ubifs_lprops *lp, int in_tree,
10178c2ecf20Sopenharmony_ci			 struct ubifs_lp_stats *lst)
10188c2ecf20Sopenharmony_ci{
10198c2ecf20Sopenharmony_ci	struct ubifs_scan_leb *sleb;
10208c2ecf20Sopenharmony_ci	struct ubifs_scan_node *snod;
10218c2ecf20Sopenharmony_ci	int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
10228c2ecf20Sopenharmony_ci	void *buf = NULL;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	cat = lp->flags & LPROPS_CAT_MASK;
10258c2ecf20Sopenharmony_ci	if (cat != LPROPS_UNCAT) {
10268c2ecf20Sopenharmony_ci		cat = ubifs_categorize_lprops(c, lp);
10278c2ecf20Sopenharmony_ci		if (cat != (lp->flags & LPROPS_CAT_MASK)) {
10288c2ecf20Sopenharmony_ci			ubifs_err(c, "bad LEB category %d expected %d",
10298c2ecf20Sopenharmony_ci				  (lp->flags & LPROPS_CAT_MASK), cat);
10308c2ecf20Sopenharmony_ci			return -EINVAL;
10318c2ecf20Sopenharmony_ci		}
10328c2ecf20Sopenharmony_ci	}
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	/* Check lp is on its category list (if it has one) */
10358c2ecf20Sopenharmony_ci	if (in_tree) {
10368c2ecf20Sopenharmony_ci		struct list_head *list = NULL;
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci		switch (cat) {
10398c2ecf20Sopenharmony_ci		case LPROPS_EMPTY:
10408c2ecf20Sopenharmony_ci			list = &c->empty_list;
10418c2ecf20Sopenharmony_ci			break;
10428c2ecf20Sopenharmony_ci		case LPROPS_FREEABLE:
10438c2ecf20Sopenharmony_ci			list = &c->freeable_list;
10448c2ecf20Sopenharmony_ci			break;
10458c2ecf20Sopenharmony_ci		case LPROPS_FRDI_IDX:
10468c2ecf20Sopenharmony_ci			list = &c->frdi_idx_list;
10478c2ecf20Sopenharmony_ci			break;
10488c2ecf20Sopenharmony_ci		case LPROPS_UNCAT:
10498c2ecf20Sopenharmony_ci			list = &c->uncat_list;
10508c2ecf20Sopenharmony_ci			break;
10518c2ecf20Sopenharmony_ci		}
10528c2ecf20Sopenharmony_ci		if (list) {
10538c2ecf20Sopenharmony_ci			struct ubifs_lprops *lprops;
10548c2ecf20Sopenharmony_ci			int found = 0;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci			list_for_each_entry(lprops, list, list) {
10578c2ecf20Sopenharmony_ci				if (lprops == lp) {
10588c2ecf20Sopenharmony_ci					found = 1;
10598c2ecf20Sopenharmony_ci					break;
10608c2ecf20Sopenharmony_ci				}
10618c2ecf20Sopenharmony_ci			}
10628c2ecf20Sopenharmony_ci			if (!found) {
10638c2ecf20Sopenharmony_ci				ubifs_err(c, "bad LPT list (category %d)", cat);
10648c2ecf20Sopenharmony_ci				return -EINVAL;
10658c2ecf20Sopenharmony_ci			}
10668c2ecf20Sopenharmony_ci		}
10678c2ecf20Sopenharmony_ci	}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	/* Check lp is on its category heap (if it has one) */
10708c2ecf20Sopenharmony_ci	if (in_tree && cat > 0 && cat <= LPROPS_HEAP_CNT) {
10718c2ecf20Sopenharmony_ci		struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci		if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) ||
10748c2ecf20Sopenharmony_ci		    lp != heap->arr[lp->hpos]) {
10758c2ecf20Sopenharmony_ci			ubifs_err(c, "bad LPT heap (category %d)", cat);
10768c2ecf20Sopenharmony_ci			return -EINVAL;
10778c2ecf20Sopenharmony_ci		}
10788c2ecf20Sopenharmony_ci	}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	/*
10818c2ecf20Sopenharmony_ci	 * After an unclean unmount, empty and freeable LEBs
10828c2ecf20Sopenharmony_ci	 * may contain garbage - do not scan them.
10838c2ecf20Sopenharmony_ci	 */
10848c2ecf20Sopenharmony_ci	if (lp->free == c->leb_size) {
10858c2ecf20Sopenharmony_ci		lst->empty_lebs += 1;
10868c2ecf20Sopenharmony_ci		lst->total_free += c->leb_size;
10878c2ecf20Sopenharmony_ci		lst->total_dark += ubifs_calc_dark(c, c->leb_size);
10888c2ecf20Sopenharmony_ci		return LPT_SCAN_CONTINUE;
10898c2ecf20Sopenharmony_ci	}
10908c2ecf20Sopenharmony_ci	if (lp->free + lp->dirty == c->leb_size &&
10918c2ecf20Sopenharmony_ci	    !(lp->flags & LPROPS_INDEX)) {
10928c2ecf20Sopenharmony_ci		lst->total_free  += lp->free;
10938c2ecf20Sopenharmony_ci		lst->total_dirty += lp->dirty;
10948c2ecf20Sopenharmony_ci		lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
10958c2ecf20Sopenharmony_ci		return LPT_SCAN_CONTINUE;
10968c2ecf20Sopenharmony_ci	}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	buf = __vmalloc(c->leb_size, GFP_NOFS);
10998c2ecf20Sopenharmony_ci	if (!buf)
11008c2ecf20Sopenharmony_ci		return -ENOMEM;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	sleb = ubifs_scan(c, lnum, 0, buf, 0);
11038c2ecf20Sopenharmony_ci	if (IS_ERR(sleb)) {
11048c2ecf20Sopenharmony_ci		ret = PTR_ERR(sleb);
11058c2ecf20Sopenharmony_ci		if (ret == -EUCLEAN) {
11068c2ecf20Sopenharmony_ci			ubifs_dump_lprops(c);
11078c2ecf20Sopenharmony_ci			ubifs_dump_budg(c, &c->bi);
11088c2ecf20Sopenharmony_ci		}
11098c2ecf20Sopenharmony_ci		goto out;
11108c2ecf20Sopenharmony_ci	}
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	is_idx = -1;
11138c2ecf20Sopenharmony_ci	list_for_each_entry(snod, &sleb->nodes, list) {
11148c2ecf20Sopenharmony_ci		int found, level = 0;
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci		cond_resched();
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci		if (is_idx == -1)
11198c2ecf20Sopenharmony_ci			is_idx = (snod->type == UBIFS_IDX_NODE) ? 1 : 0;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci		if (is_idx && snod->type != UBIFS_IDX_NODE) {
11228c2ecf20Sopenharmony_ci			ubifs_err(c, "indexing node in data LEB %d:%d",
11238c2ecf20Sopenharmony_ci				  lnum, snod->offs);
11248c2ecf20Sopenharmony_ci			goto out_destroy;
11258c2ecf20Sopenharmony_ci		}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci		if (snod->type == UBIFS_IDX_NODE) {
11288c2ecf20Sopenharmony_ci			struct ubifs_idx_node *idx = snod->node;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci			key_read(c, ubifs_idx_key(c, idx), &snod->key);
11318c2ecf20Sopenharmony_ci			level = le16_to_cpu(idx->level);
11328c2ecf20Sopenharmony_ci		}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci		found = ubifs_tnc_has_node(c, &snod->key, level, lnum,
11358c2ecf20Sopenharmony_ci					   snod->offs, is_idx);
11368c2ecf20Sopenharmony_ci		if (found) {
11378c2ecf20Sopenharmony_ci			if (found < 0)
11388c2ecf20Sopenharmony_ci				goto out_destroy;
11398c2ecf20Sopenharmony_ci			used += ALIGN(snod->len, 8);
11408c2ecf20Sopenharmony_ci		}
11418c2ecf20Sopenharmony_ci	}
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	free = c->leb_size - sleb->endpt;
11448c2ecf20Sopenharmony_ci	dirty = sleb->endpt - used;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	if (free > c->leb_size || free < 0 || dirty > c->leb_size ||
11478c2ecf20Sopenharmony_ci	    dirty < 0) {
11488c2ecf20Sopenharmony_ci		ubifs_err(c, "bad calculated accounting for LEB %d: free %d, dirty %d",
11498c2ecf20Sopenharmony_ci			  lnum, free, dirty);
11508c2ecf20Sopenharmony_ci		goto out_destroy;
11518c2ecf20Sopenharmony_ci	}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	if (lp->free + lp->dirty == c->leb_size &&
11548c2ecf20Sopenharmony_ci	    free + dirty == c->leb_size)
11558c2ecf20Sopenharmony_ci		if ((is_idx && !(lp->flags & LPROPS_INDEX)) ||
11568c2ecf20Sopenharmony_ci		    (!is_idx && free == c->leb_size) ||
11578c2ecf20Sopenharmony_ci		    lp->free == c->leb_size) {
11588c2ecf20Sopenharmony_ci			/*
11598c2ecf20Sopenharmony_ci			 * Empty or freeable LEBs could contain index
11608c2ecf20Sopenharmony_ci			 * nodes from an uncompleted commit due to an
11618c2ecf20Sopenharmony_ci			 * unclean unmount. Or they could be empty for
11628c2ecf20Sopenharmony_ci			 * the same reason. Or it may simply not have been
11638c2ecf20Sopenharmony_ci			 * unmapped.
11648c2ecf20Sopenharmony_ci			 */
11658c2ecf20Sopenharmony_ci			free = lp->free;
11668c2ecf20Sopenharmony_ci			dirty = lp->dirty;
11678c2ecf20Sopenharmony_ci			is_idx = 0;
11688c2ecf20Sopenharmony_ci		    }
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	if (is_idx && lp->free + lp->dirty == free + dirty &&
11718c2ecf20Sopenharmony_ci	    lnum != c->ihead_lnum) {
11728c2ecf20Sopenharmony_ci		/*
11738c2ecf20Sopenharmony_ci		 * After an unclean unmount, an index LEB could have a different
11748c2ecf20Sopenharmony_ci		 * amount of free space than the value recorded by lprops. That
11758c2ecf20Sopenharmony_ci		 * is because the in-the-gaps method may use free space or
11768c2ecf20Sopenharmony_ci		 * create free space (as a side-effect of using ubi_leb_change
11778c2ecf20Sopenharmony_ci		 * and not writing the whole LEB). The incorrect free space
11788c2ecf20Sopenharmony_ci		 * value is not a problem because the index is only ever
11798c2ecf20Sopenharmony_ci		 * allocated empty LEBs, so there will never be an attempt to
11808c2ecf20Sopenharmony_ci		 * write to the free space at the end of an index LEB - except
11818c2ecf20Sopenharmony_ci		 * by the in-the-gaps method for which it is not a problem.
11828c2ecf20Sopenharmony_ci		 */
11838c2ecf20Sopenharmony_ci		free = lp->free;
11848c2ecf20Sopenharmony_ci		dirty = lp->dirty;
11858c2ecf20Sopenharmony_ci	}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	if (lp->free != free || lp->dirty != dirty)
11888c2ecf20Sopenharmony_ci		goto out_print;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	if (is_idx && !(lp->flags & LPROPS_INDEX)) {
11918c2ecf20Sopenharmony_ci		if (free == c->leb_size)
11928c2ecf20Sopenharmony_ci			/* Free but not unmapped LEB, it's fine */
11938c2ecf20Sopenharmony_ci			is_idx = 0;
11948c2ecf20Sopenharmony_ci		else {
11958c2ecf20Sopenharmony_ci			ubifs_err(c, "indexing node without indexing flag");
11968c2ecf20Sopenharmony_ci			goto out_print;
11978c2ecf20Sopenharmony_ci		}
11988c2ecf20Sopenharmony_ci	}
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	if (!is_idx && (lp->flags & LPROPS_INDEX)) {
12018c2ecf20Sopenharmony_ci		ubifs_err(c, "data node with indexing flag");
12028c2ecf20Sopenharmony_ci		goto out_print;
12038c2ecf20Sopenharmony_ci	}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	if (free == c->leb_size)
12068c2ecf20Sopenharmony_ci		lst->empty_lebs += 1;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	if (is_idx)
12098c2ecf20Sopenharmony_ci		lst->idx_lebs += 1;
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	if (!(lp->flags & LPROPS_INDEX))
12128c2ecf20Sopenharmony_ci		lst->total_used += c->leb_size - free - dirty;
12138c2ecf20Sopenharmony_ci	lst->total_free += free;
12148c2ecf20Sopenharmony_ci	lst->total_dirty += dirty;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	if (!(lp->flags & LPROPS_INDEX)) {
12178c2ecf20Sopenharmony_ci		int spc = free + dirty;
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci		if (spc < c->dead_wm)
12208c2ecf20Sopenharmony_ci			lst->total_dead += spc;
12218c2ecf20Sopenharmony_ci		else
12228c2ecf20Sopenharmony_ci			lst->total_dark += ubifs_calc_dark(c, spc);
12238c2ecf20Sopenharmony_ci	}
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	ubifs_scan_destroy(sleb);
12268c2ecf20Sopenharmony_ci	vfree(buf);
12278c2ecf20Sopenharmony_ci	return LPT_SCAN_CONTINUE;
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ciout_print:
12308c2ecf20Sopenharmony_ci	ubifs_err(c, "bad accounting of LEB %d: free %d, dirty %d flags %#x, should be free %d, dirty %d",
12318c2ecf20Sopenharmony_ci		  lnum, lp->free, lp->dirty, lp->flags, free, dirty);
12328c2ecf20Sopenharmony_ci	ubifs_dump_leb(c, lnum);
12338c2ecf20Sopenharmony_ciout_destroy:
12348c2ecf20Sopenharmony_ci	ubifs_scan_destroy(sleb);
12358c2ecf20Sopenharmony_ci	ret = -EINVAL;
12368c2ecf20Sopenharmony_ciout:
12378c2ecf20Sopenharmony_ci	vfree(buf);
12388c2ecf20Sopenharmony_ci	return ret;
12398c2ecf20Sopenharmony_ci}
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci/**
12428c2ecf20Sopenharmony_ci * dbg_check_lprops - check all LEB properties.
12438c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
12448c2ecf20Sopenharmony_ci *
12458c2ecf20Sopenharmony_ci * This function checks all LEB properties and makes sure they are all correct.
12468c2ecf20Sopenharmony_ci * It returns zero if everything is fine, %-EINVAL if there is an inconsistency
12478c2ecf20Sopenharmony_ci * and other negative error codes in case of other errors. This function is
12488c2ecf20Sopenharmony_ci * called while the file system is locked (because of commit start), so no
12498c2ecf20Sopenharmony_ci * additional locking is required. Note that locking the LPT mutex would cause
12508c2ecf20Sopenharmony_ci * a circular lock dependency with the TNC mutex.
12518c2ecf20Sopenharmony_ci */
12528c2ecf20Sopenharmony_ciint dbg_check_lprops(struct ubifs_info *c)
12538c2ecf20Sopenharmony_ci{
12548c2ecf20Sopenharmony_ci	int i, err;
12558c2ecf20Sopenharmony_ci	struct ubifs_lp_stats lst;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	if (!dbg_is_chk_lprops(c))
12588c2ecf20Sopenharmony_ci		return 0;
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	/*
12618c2ecf20Sopenharmony_ci	 * As we are going to scan the media, the write buffers have to be
12628c2ecf20Sopenharmony_ci	 * synchronized.
12638c2ecf20Sopenharmony_ci	 */
12648c2ecf20Sopenharmony_ci	for (i = 0; i < c->jhead_cnt; i++) {
12658c2ecf20Sopenharmony_ci		err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
12668c2ecf20Sopenharmony_ci		if (err)
12678c2ecf20Sopenharmony_ci			return err;
12688c2ecf20Sopenharmony_ci	}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	memset(&lst, 0, sizeof(struct ubifs_lp_stats));
12718c2ecf20Sopenharmony_ci	err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
12728c2ecf20Sopenharmony_ci				    (ubifs_lpt_scan_callback)scan_check_cb,
12738c2ecf20Sopenharmony_ci				    &lst);
12748c2ecf20Sopenharmony_ci	if (err && err != -ENOSPC)
12758c2ecf20Sopenharmony_ci		goto out;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	if (lst.empty_lebs != c->lst.empty_lebs ||
12788c2ecf20Sopenharmony_ci	    lst.idx_lebs != c->lst.idx_lebs ||
12798c2ecf20Sopenharmony_ci	    lst.total_free != c->lst.total_free ||
12808c2ecf20Sopenharmony_ci	    lst.total_dirty != c->lst.total_dirty ||
12818c2ecf20Sopenharmony_ci	    lst.total_used != c->lst.total_used) {
12828c2ecf20Sopenharmony_ci		ubifs_err(c, "bad overall accounting");
12838c2ecf20Sopenharmony_ci		ubifs_err(c, "calculated: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
12848c2ecf20Sopenharmony_ci			  lst.empty_lebs, lst.idx_lebs, lst.total_free,
12858c2ecf20Sopenharmony_ci			  lst.total_dirty, lst.total_used);
12868c2ecf20Sopenharmony_ci		ubifs_err(c, "read from lprops: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
12878c2ecf20Sopenharmony_ci			  c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free,
12888c2ecf20Sopenharmony_ci			  c->lst.total_dirty, c->lst.total_used);
12898c2ecf20Sopenharmony_ci		err = -EINVAL;
12908c2ecf20Sopenharmony_ci		goto out;
12918c2ecf20Sopenharmony_ci	}
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	if (lst.total_dead != c->lst.total_dead ||
12948c2ecf20Sopenharmony_ci	    lst.total_dark != c->lst.total_dark) {
12958c2ecf20Sopenharmony_ci		ubifs_err(c, "bad dead/dark space accounting");
12968c2ecf20Sopenharmony_ci		ubifs_err(c, "calculated: total_dead %lld, total_dark %lld",
12978c2ecf20Sopenharmony_ci			  lst.total_dead, lst.total_dark);
12988c2ecf20Sopenharmony_ci		ubifs_err(c, "read from lprops: total_dead %lld, total_dark %lld",
12998c2ecf20Sopenharmony_ci			  c->lst.total_dead, c->lst.total_dark);
13008c2ecf20Sopenharmony_ci		err = -EINVAL;
13018c2ecf20Sopenharmony_ci		goto out;
13028c2ecf20Sopenharmony_ci	}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	err = dbg_check_cats(c);
13058c2ecf20Sopenharmony_ciout:
13068c2ecf20Sopenharmony_ci	return err;
13078c2ecf20Sopenharmony_ci}
1308