Prepare v2024.10
[platform/kernel/u-boot.git] / fs / ubifs / lprops.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * This file is part of UBIFS.
4  *
5  * Copyright (C) 2006-2008 Nokia Corporation.
6  *
7  * Authors: Adrian Hunter
8  *          Artem Bityutskiy (Битюцкий Артём)
9  */
10
11 /*
12  * This file implements the functions that access LEB properties and their
13  * categories. LEBs are categorized based on the needs of UBIFS, and the
14  * categories are stored as either heaps or lists to provide a fast way of
15  * finding a LEB in a particular category. For example, UBIFS may need to find
16  * an empty LEB for the journal, or a very dirty LEB for garbage collection.
17  */
18
19 #ifdef __UBOOT__
20 #include <log.h>
21 #include <malloc.h>
22 #include <linux/err.h>
23 #endif
24 #include "ubifs.h"
25
26 /**
27  * get_heap_comp_val - get the LEB properties value for heap comparisons.
28  * @lprops: LEB properties
29  * @cat: LEB category
30  */
31 static int get_heap_comp_val(struct ubifs_lprops *lprops, int cat)
32 {
33         switch (cat) {
34         case LPROPS_FREE:
35                 return lprops->free;
36         case LPROPS_DIRTY_IDX:
37                 return lprops->free + lprops->dirty;
38         default:
39                 return lprops->dirty;
40         }
41 }
42
43 /**
44  * move_up_lpt_heap - move a new heap entry up as far as possible.
45  * @c: UBIFS file-system description object
46  * @heap: LEB category heap
47  * @lprops: LEB properties to move
48  * @cat: LEB category
49  *
50  * New entries to a heap are added at the bottom and then moved up until the
51  * parent's value is greater.  In the case of LPT's category heaps, the value
52  * is either the amount of free space or the amount of dirty space, depending
53  * on the category.
54  */
55 static void move_up_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
56                              struct ubifs_lprops *lprops, int cat)
57 {
58         int val1, val2, hpos;
59
60         hpos = lprops->hpos;
61         if (!hpos)
62                 return; /* Already top of the heap */
63         val1 = get_heap_comp_val(lprops, cat);
64         /* Compare to parent and, if greater, move up the heap */
65         do {
66                 int ppos = (hpos - 1) / 2;
67
68                 val2 = get_heap_comp_val(heap->arr[ppos], cat);
69                 if (val2 >= val1)
70                         return;
71                 /* Greater than parent so move up */
72                 heap->arr[ppos]->hpos = hpos;
73                 heap->arr[hpos] = heap->arr[ppos];
74                 heap->arr[ppos] = lprops;
75                 lprops->hpos = ppos;
76                 hpos = ppos;
77         } while (hpos);
78 }
79
80 /**
81  * adjust_lpt_heap - move a changed heap entry up or down the heap.
82  * @c: UBIFS file-system description object
83  * @heap: LEB category heap
84  * @lprops: LEB properties to move
85  * @hpos: heap position of @lprops
86  * @cat: LEB category
87  *
88  * Changed entries in a heap are moved up or down until the parent's value is
89  * greater.  In the case of LPT's category heaps, the value is either the amount
90  * of free space or the amount of dirty space, depending on the category.
91  */
92 static void adjust_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
93                             struct ubifs_lprops *lprops, int hpos, int cat)
94 {
95         int val1, val2, val3, cpos;
96
97         val1 = get_heap_comp_val(lprops, cat);
98         /* Compare to parent and, if greater than parent, move up the heap */
99         if (hpos) {
100                 int ppos = (hpos - 1) / 2;
101
102                 val2 = get_heap_comp_val(heap->arr[ppos], cat);
103                 if (val1 > val2) {
104                         /* Greater than parent so move up */
105                         while (1) {
106                                 heap->arr[ppos]->hpos = hpos;
107                                 heap->arr[hpos] = heap->arr[ppos];
108                                 heap->arr[ppos] = lprops;
109                                 lprops->hpos = ppos;
110                                 hpos = ppos;
111                                 if (!hpos)
112                                         return;
113                                 ppos = (hpos - 1) / 2;
114                                 val2 = get_heap_comp_val(heap->arr[ppos], cat);
115                                 if (val1 <= val2)
116                                         return;
117                                 /* Still greater than parent so keep going */
118                         }
119                 }
120         }
121
122         /* Not greater than parent, so compare to children */
123         while (1) {
124                 /* Compare to left child */
125                 cpos = hpos * 2 + 1;
126                 if (cpos >= heap->cnt)
127                         return;
128                 val2 = get_heap_comp_val(heap->arr[cpos], cat);
129                 if (val1 < val2) {
130                         /* Less than left child, so promote biggest child */
131                         if (cpos + 1 < heap->cnt) {
132                                 val3 = get_heap_comp_val(heap->arr[cpos + 1],
133                                                          cat);
134                                 if (val3 > val2)
135                                         cpos += 1; /* Right child is bigger */
136                         }
137                         heap->arr[cpos]->hpos = hpos;
138                         heap->arr[hpos] = heap->arr[cpos];
139                         heap->arr[cpos] = lprops;
140                         lprops->hpos = cpos;
141                         hpos = cpos;
142                         continue;
143                 }
144                 /* Compare to right child */
145                 cpos += 1;
146                 if (cpos >= heap->cnt)
147                         return;
148                 val3 = get_heap_comp_val(heap->arr[cpos], cat);
149                 if (val1 < val3) {
150                         /* Less than right child, so promote right child */
151                         heap->arr[cpos]->hpos = hpos;
152                         heap->arr[hpos] = heap->arr[cpos];
153                         heap->arr[cpos] = lprops;
154                         lprops->hpos = cpos;
155                         hpos = cpos;
156                         continue;
157                 }
158                 return;
159         }
160 }
161
162 /**
163  * add_to_lpt_heap - add LEB properties to a LEB category heap.
164  * @c: UBIFS file-system description object
165  * @lprops: LEB properties to add
166  * @cat: LEB category
167  *
168  * This function returns %1 if @lprops is added to the heap for LEB category
169  * @cat, otherwise %0 is returned because the heap is full.
170  */
171 static int add_to_lpt_heap(struct ubifs_info *c, struct ubifs_lprops *lprops,
172                            int cat)
173 {
174         struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
175
176         if (heap->cnt >= heap->max_cnt) {
177                 const int b = LPT_HEAP_SZ / 2 - 1;
178                 int cpos, val1, val2;
179
180                 /* Compare to some other LEB on the bottom of heap */
181                 /* Pick a position kind of randomly */
182                 cpos = (((size_t)lprops >> 4) & b) + b;
183                 ubifs_assert(cpos >= b);
184                 ubifs_assert(cpos < LPT_HEAP_SZ);
185                 ubifs_assert(cpos < heap->cnt);
186
187                 val1 = get_heap_comp_val(lprops, cat);
188                 val2 = get_heap_comp_val(heap->arr[cpos], cat);
189                 if (val1 > val2) {
190                         struct ubifs_lprops *lp;
191
192                         lp = heap->arr[cpos];
193                         lp->flags &= ~LPROPS_CAT_MASK;
194                         lp->flags |= LPROPS_UNCAT;
195                         list_add(&lp->list, &c->uncat_list);
196                         lprops->hpos = cpos;
197                         heap->arr[cpos] = lprops;
198                         move_up_lpt_heap(c, heap, lprops, cat);
199                         dbg_check_heap(c, heap, cat, lprops->hpos);
200                         return 1; /* Added to heap */
201                 }
202                 dbg_check_heap(c, heap, cat, -1);
203                 return 0; /* Not added to heap */
204         } else {
205                 lprops->hpos = heap->cnt++;
206                 heap->arr[lprops->hpos] = lprops;
207                 move_up_lpt_heap(c, heap, lprops, cat);
208                 dbg_check_heap(c, heap, cat, lprops->hpos);
209                 return 1; /* Added to heap */
210         }
211 }
212
213 /**
214  * remove_from_lpt_heap - remove LEB properties from a LEB category heap.
215  * @c: UBIFS file-system description object
216  * @lprops: LEB properties to remove
217  * @cat: LEB category
218  */
219 static void remove_from_lpt_heap(struct ubifs_info *c,
220                                  struct ubifs_lprops *lprops, int cat)
221 {
222         struct ubifs_lpt_heap *heap;
223         int hpos = lprops->hpos;
224
225         heap = &c->lpt_heap[cat - 1];
226         ubifs_assert(hpos >= 0 && hpos < heap->cnt);
227         ubifs_assert(heap->arr[hpos] == lprops);
228         heap->cnt -= 1;
229         if (hpos < heap->cnt) {
230                 heap->arr[hpos] = heap->arr[heap->cnt];
231                 heap->arr[hpos]->hpos = hpos;
232                 adjust_lpt_heap(c, heap, heap->arr[hpos], hpos, cat);
233         }
234         dbg_check_heap(c, heap, cat, -1);
235 }
236
237 /**
238  * lpt_heap_replace - replace lprops in a category heap.
239  * @c: UBIFS file-system description object
240  * @old_lprops: LEB properties to replace
241  * @new_lprops: LEB properties with which to replace
242  * @cat: LEB category
243  *
244  * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
245  * and the lprops that the pnode contains.  When that happens, references in
246  * the category heaps to those lprops must be updated to point to the new
247  * lprops.  This function does that.
248  */
249 static void lpt_heap_replace(struct ubifs_info *c,
250                              struct ubifs_lprops *old_lprops,
251                              struct ubifs_lprops *new_lprops, int cat)
252 {
253         struct ubifs_lpt_heap *heap;
254         int hpos = new_lprops->hpos;
255
256         heap = &c->lpt_heap[cat - 1];
257         heap->arr[hpos] = new_lprops;
258 }
259
260 /**
261  * ubifs_add_to_cat - add LEB properties to a category list or heap.
262  * @c: UBIFS file-system description object
263  * @lprops: LEB properties to add
264  * @cat: LEB category to which to add
265  *
266  * LEB properties are categorized to enable fast find operations.
267  */
268 void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
269                       int cat)
270 {
271         switch (cat) {
272         case LPROPS_DIRTY:
273         case LPROPS_DIRTY_IDX:
274         case LPROPS_FREE:
275                 if (add_to_lpt_heap(c, lprops, cat))
276                         break;
277                 /* No more room on heap so make it un-categorized */
278                 cat = LPROPS_UNCAT;
279                 /* Fall through */
280         case LPROPS_UNCAT:
281                 list_add(&lprops->list, &c->uncat_list);
282                 break;
283         case LPROPS_EMPTY:
284                 list_add(&lprops->list, &c->empty_list);
285                 break;
286         case LPROPS_FREEABLE:
287                 list_add(&lprops->list, &c->freeable_list);
288                 c->freeable_cnt += 1;
289                 break;
290         case LPROPS_FRDI_IDX:
291                 list_add(&lprops->list, &c->frdi_idx_list);
292                 break;
293         default:
294                 ubifs_assert(0);
295         }
296
297         lprops->flags &= ~LPROPS_CAT_MASK;
298         lprops->flags |= cat;
299         c->in_a_category_cnt += 1;
300         ubifs_assert(c->in_a_category_cnt <= c->main_lebs);
301 }
302
303 /**
304  * ubifs_remove_from_cat - remove LEB properties from a category list or heap.
305  * @c: UBIFS file-system description object
306  * @lprops: LEB properties to remove
307  * @cat: LEB category from which to remove
308  *
309  * LEB properties are categorized to enable fast find operations.
310  */
311 static void ubifs_remove_from_cat(struct ubifs_info *c,
312                                   struct ubifs_lprops *lprops, int cat)
313 {
314         switch (cat) {
315         case LPROPS_DIRTY:
316         case LPROPS_DIRTY_IDX:
317         case LPROPS_FREE:
318                 remove_from_lpt_heap(c, lprops, cat);
319                 break;
320         case LPROPS_FREEABLE:
321                 c->freeable_cnt -= 1;
322                 ubifs_assert(c->freeable_cnt >= 0);
323                 /* Fall through */
324         case LPROPS_UNCAT:
325         case LPROPS_EMPTY:
326         case LPROPS_FRDI_IDX:
327                 ubifs_assert(!list_empty(&lprops->list));
328                 list_del(&lprops->list);
329                 break;
330         default:
331                 ubifs_assert(0);
332         }
333
334         c->in_a_category_cnt -= 1;
335         ubifs_assert(c->in_a_category_cnt >= 0);
336 }
337
338 /**
339  * ubifs_replace_cat - replace lprops in a category list or heap.
340  * @c: UBIFS file-system description object
341  * @old_lprops: LEB properties to replace
342  * @new_lprops: LEB properties with which to replace
343  *
344  * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
345  * and the lprops that the pnode contains. When that happens, references in
346  * category lists and heaps must be replaced. This function does that.
347  */
348 void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
349                        struct ubifs_lprops *new_lprops)
350 {
351         int cat;
352
353         cat = new_lprops->flags & LPROPS_CAT_MASK;
354         switch (cat) {
355         case LPROPS_DIRTY:
356         case LPROPS_DIRTY_IDX:
357         case LPROPS_FREE:
358                 lpt_heap_replace(c, old_lprops, new_lprops, cat);
359                 break;
360         case LPROPS_UNCAT:
361         case LPROPS_EMPTY:
362         case LPROPS_FREEABLE:
363         case LPROPS_FRDI_IDX:
364                 list_replace(&old_lprops->list, &new_lprops->list);
365                 break;
366         default:
367                 ubifs_assert(0);
368         }
369 }
370
371 /**
372  * ubifs_ensure_cat - ensure LEB properties are categorized.
373  * @c: UBIFS file-system description object
374  * @lprops: LEB properties
375  *
376  * A LEB may have fallen off of the bottom of a heap, and ended up as
377  * un-categorized even though it has enough space for us now. If that is the
378  * case this function will put the LEB back onto a heap.
379  */
380 void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops)
381 {
382         int cat = lprops->flags & LPROPS_CAT_MASK;
383
384         if (cat != LPROPS_UNCAT)
385                 return;
386         cat = ubifs_categorize_lprops(c, lprops);
387         if (cat == LPROPS_UNCAT)
388                 return;
389         ubifs_remove_from_cat(c, lprops, LPROPS_UNCAT);
390         ubifs_add_to_cat(c, lprops, cat);
391 }
392
393 /**
394  * ubifs_categorize_lprops - categorize LEB properties.
395  * @c: UBIFS file-system description object
396  * @lprops: LEB properties to categorize
397  *
398  * LEB properties are categorized to enable fast find operations. This function
399  * returns the LEB category to which the LEB properties belong. Note however
400  * that if the LEB category is stored as a heap and the heap is full, the
401  * LEB properties may have their category changed to %LPROPS_UNCAT.
402  */
403 int ubifs_categorize_lprops(const struct ubifs_info *c,
404                             const struct ubifs_lprops *lprops)
405 {
406         if (lprops->flags & LPROPS_TAKEN)
407                 return LPROPS_UNCAT;
408
409         if (lprops->free == c->leb_size) {
410                 ubifs_assert(!(lprops->flags & LPROPS_INDEX));
411                 return LPROPS_EMPTY;
412         }
413
414         if (lprops->free + lprops->dirty == c->leb_size) {
415                 if (lprops->flags & LPROPS_INDEX)
416                         return LPROPS_FRDI_IDX;
417                 else
418                         return LPROPS_FREEABLE;
419         }
420
421         if (lprops->flags & LPROPS_INDEX) {
422                 if (lprops->dirty + lprops->free >= c->min_idx_node_sz)
423                         return LPROPS_DIRTY_IDX;
424         } else {
425                 if (lprops->dirty >= c->dead_wm &&
426                     lprops->dirty > lprops->free)
427                         return LPROPS_DIRTY;
428                 if (lprops->free > 0)
429                         return LPROPS_FREE;
430         }
431
432         return LPROPS_UNCAT;
433 }
434
435 /**
436  * change_category - change LEB properties category.
437  * @c: UBIFS file-system description object
438  * @lprops: LEB properties to re-categorize
439  *
440  * LEB properties are categorized to enable fast find operations. When the LEB
441  * properties change they must be re-categorized.
442  */
443 static void change_category(struct ubifs_info *c, struct ubifs_lprops *lprops)
444 {
445         int old_cat = lprops->flags & LPROPS_CAT_MASK;
446         int new_cat = ubifs_categorize_lprops(c, lprops);
447
448         if (old_cat == new_cat) {
449                 struct ubifs_lpt_heap *heap;
450
451                 /* lprops on a heap now must be moved up or down */
452                 if (new_cat < 1 || new_cat > LPROPS_HEAP_CNT)
453                         return; /* Not on a heap */
454                 heap = &c->lpt_heap[new_cat - 1];
455                 adjust_lpt_heap(c, heap, lprops, lprops->hpos, new_cat);
456         } else {
457                 ubifs_remove_from_cat(c, lprops, old_cat);
458                 ubifs_add_to_cat(c, lprops, new_cat);
459         }
460 }
461
462 /**
463  * ubifs_calc_dark - calculate LEB dark space size.
464  * @c: the UBIFS file-system description object
465  * @spc: amount of free and dirty space in the LEB
466  *
467  * This function calculates and returns amount of dark space in an LEB which
468  * has @spc bytes of free and dirty space.
469  *
470  * UBIFS is trying to account the space which might not be usable, and this
471  * space is called "dark space". For example, if an LEB has only %512 free
472  * bytes, it is dark space, because it cannot fit a large data node.
473  */
474 int ubifs_calc_dark(const struct ubifs_info *c, int spc)
475 {
476         ubifs_assert(!(spc & 7));
477
478         if (spc < c->dark_wm)
479                 return spc;
480
481         /*
482          * If we have slightly more space then the dark space watermark, we can
483          * anyway safely assume it we'll be able to write a node of the
484          * smallest size there.
485          */
486         if (spc - c->dark_wm < MIN_WRITE_SZ)
487                 return spc - MIN_WRITE_SZ;
488
489         return c->dark_wm;
490 }
491
492 /**
493  * is_lprops_dirty - determine if LEB properties are dirty.
494  * @c: the UBIFS file-system description object
495  * @lprops: LEB properties to test
496  */
497 static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
498 {
499         struct ubifs_pnode *pnode;
500         int pos;
501
502         pos = (lprops->lnum - c->main_first) & (UBIFS_LPT_FANOUT - 1);
503         pnode = (struct ubifs_pnode *)container_of(lprops - pos,
504                                                    struct ubifs_pnode,
505                                                    lprops[0]);
506         return !test_bit(COW_CNODE, &pnode->flags) &&
507                test_bit(DIRTY_CNODE, &pnode->flags);
508 }
509
510 /**
511  * ubifs_change_lp - change LEB properties.
512  * @c: the UBIFS file-system description object
513  * @lp: LEB properties to change
514  * @free: new free space amount
515  * @dirty: new dirty space amount
516  * @flags: new flags
517  * @idx_gc_cnt: change to the count of @idx_gc list
518  *
519  * This function changes LEB properties (@free, @dirty or @flag). However, the
520  * property which has the %LPROPS_NC value is not changed. Returns a pointer to
521  * the updated LEB properties on success and a negative error code on failure.
522  *
523  * Note, the LEB properties may have had to be copied (due to COW) and
524  * consequently the pointer returned may not be the same as the pointer
525  * passed.
526  */
527 const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
528                                            const struct ubifs_lprops *lp,
529                                            int free, int dirty, int flags,
530                                            int idx_gc_cnt)
531 {
532         /*
533          * This is the only function that is allowed to change lprops, so we
534          * discard the "const" qualifier.
535          */
536         struct ubifs_lprops *lprops = (struct ubifs_lprops *)lp;
537
538         dbg_lp("LEB %d, free %d, dirty %d, flags %d",
539                lprops->lnum, free, dirty, flags);
540
541         ubifs_assert(mutex_is_locked(&c->lp_mutex));
542         ubifs_assert(c->lst.empty_lebs >= 0 &&
543                      c->lst.empty_lebs <= c->main_lebs);
544         ubifs_assert(c->freeable_cnt >= 0);
545         ubifs_assert(c->freeable_cnt <= c->main_lebs);
546         ubifs_assert(c->lst.taken_empty_lebs >= 0);
547         ubifs_assert(c->lst.taken_empty_lebs <= c->lst.empty_lebs);
548         ubifs_assert(!(c->lst.total_free & 7) && !(c->lst.total_dirty & 7));
549         ubifs_assert(!(c->lst.total_dead & 7) && !(c->lst.total_dark & 7));
550         ubifs_assert(!(c->lst.total_used & 7));
551         ubifs_assert(free == LPROPS_NC || free >= 0);
552         ubifs_assert(dirty == LPROPS_NC || dirty >= 0);
553
554         if (!is_lprops_dirty(c, lprops)) {
555                 lprops = ubifs_lpt_lookup_dirty(c, lprops->lnum);
556                 if (IS_ERR(lprops))
557                         return lprops;
558         } else
559                 ubifs_assert(lprops == ubifs_lpt_lookup_dirty(c, lprops->lnum));
560
561         ubifs_assert(!(lprops->free & 7) && !(lprops->dirty & 7));
562
563         spin_lock(&c->space_lock);
564         if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
565                 c->lst.taken_empty_lebs -= 1;
566
567         if (!(lprops->flags & LPROPS_INDEX)) {
568                 int old_spc;
569
570                 old_spc = lprops->free + lprops->dirty;
571                 if (old_spc < c->dead_wm)
572                         c->lst.total_dead -= old_spc;
573                 else
574                         c->lst.total_dark -= ubifs_calc_dark(c, old_spc);
575
576                 c->lst.total_used -= c->leb_size - old_spc;
577         }
578
579         if (free != LPROPS_NC) {
580                 free = ALIGN(free, 8);
581                 c->lst.total_free += free - lprops->free;
582
583                 /* Increase or decrease empty LEBs counter if needed */
584                 if (free == c->leb_size) {
585                         if (lprops->free != c->leb_size)
586                                 c->lst.empty_lebs += 1;
587                 } else if (lprops->free == c->leb_size)
588                         c->lst.empty_lebs -= 1;
589                 lprops->free = free;
590         }
591
592         if (dirty != LPROPS_NC) {
593                 dirty = ALIGN(dirty, 8);
594                 c->lst.total_dirty += dirty - lprops->dirty;
595                 lprops->dirty = dirty;
596         }
597
598         if (flags != LPROPS_NC) {
599                 /* Take care about indexing LEBs counter if needed */
600                 if ((lprops->flags & LPROPS_INDEX)) {
601                         if (!(flags & LPROPS_INDEX))
602                                 c->lst.idx_lebs -= 1;
603                 } else if (flags & LPROPS_INDEX)
604                         c->lst.idx_lebs += 1;
605                 lprops->flags = flags;
606         }
607
608         if (!(lprops->flags & LPROPS_INDEX)) {
609                 int new_spc;
610
611                 new_spc = lprops->free + lprops->dirty;
612                 if (new_spc < c->dead_wm)
613                         c->lst.total_dead += new_spc;
614                 else
615                         c->lst.total_dark += ubifs_calc_dark(c, new_spc);
616
617                 c->lst.total_used += c->leb_size - new_spc;
618         }
619
620         if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
621                 c->lst.taken_empty_lebs += 1;
622
623         change_category(c, lprops);
624         c->idx_gc_cnt += idx_gc_cnt;
625         spin_unlock(&c->space_lock);
626         return lprops;
627 }
628
629 /**
630  * ubifs_get_lp_stats - get lprops statistics.
631  * @c: UBIFS file-system description object
632  * @st: return statistics
633  */
634 void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst)
635 {
636         spin_lock(&c->space_lock);
637         memcpy(lst, &c->lst, sizeof(struct ubifs_lp_stats));
638         spin_unlock(&c->space_lock);
639 }
640
641 /**
642  * ubifs_change_one_lp - change LEB properties.
643  * @c: the UBIFS file-system description object
644  * @lnum: LEB to change properties for
645  * @free: amount of free space
646  * @dirty: amount of dirty space
647  * @flags_set: flags to set
648  * @flags_clean: flags to clean
649  * @idx_gc_cnt: change to the count of idx_gc list
650  *
651  * This function changes properties of LEB @lnum. It is a helper wrapper over
652  * 'ubifs_change_lp()' which hides lprops get/release. The arguments are the
653  * same as in case of 'ubifs_change_lp()'. Returns zero in case of success and
654  * a negative error code in case of failure.
655  */
656 int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
657                         int flags_set, int flags_clean, int idx_gc_cnt)
658 {
659         int err = 0, flags;
660         const struct ubifs_lprops *lp;
661
662         ubifs_get_lprops(c);
663
664         lp = ubifs_lpt_lookup_dirty(c, lnum);
665         if (IS_ERR(lp)) {
666                 err = PTR_ERR(lp);
667                 goto out;
668         }
669
670         flags = (lp->flags | flags_set) & ~flags_clean;
671         lp = ubifs_change_lp(c, lp, free, dirty, flags, idx_gc_cnt);
672         if (IS_ERR(lp))
673                 err = PTR_ERR(lp);
674
675 out:
676         ubifs_release_lprops(c);
677         if (err)
678                 ubifs_err(c, "cannot change properties of LEB %d, error %d",
679                           lnum, err);
680         return err;
681 }
682
683 /**
684  * ubifs_update_one_lp - update LEB properties.
685  * @c: the UBIFS file-system description object
686  * @lnum: LEB to change properties for
687  * @free: amount of free space
688  * @dirty: amount of dirty space to add
689  * @flags_set: flags to set
690  * @flags_clean: flags to clean
691  *
692  * This function is the same as 'ubifs_change_one_lp()' but @dirty is added to
693  * current dirty space, not substitutes it.
694  */
695 int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
696                         int flags_set, int flags_clean)
697 {
698         int err = 0, flags;
699         const struct ubifs_lprops *lp;
700
701         ubifs_get_lprops(c);
702
703         lp = ubifs_lpt_lookup_dirty(c, lnum);
704         if (IS_ERR(lp)) {
705                 err = PTR_ERR(lp);
706                 goto out;
707         }
708
709         flags = (lp->flags | flags_set) & ~flags_clean;
710         lp = ubifs_change_lp(c, lp, free, lp->dirty + dirty, flags, 0);
711         if (IS_ERR(lp))
712                 err = PTR_ERR(lp);
713
714 out:
715         ubifs_release_lprops(c);
716         if (err)
717                 ubifs_err(c, "cannot update properties of LEB %d, error %d",
718                           lnum, err);
719         return err;
720 }
721
722 /**
723  * ubifs_read_one_lp - read LEB properties.
724  * @c: the UBIFS file-system description object
725  * @lnum: LEB to read properties for
726  * @lp: where to store read properties
727  *
728  * This helper function reads properties of a LEB @lnum and stores them in @lp.
729  * Returns zero in case of success and a negative error code in case of
730  * failure.
731  */
732 int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp)
733 {
734         int err = 0;
735         const struct ubifs_lprops *lpp;
736
737         ubifs_get_lprops(c);
738
739         lpp = ubifs_lpt_lookup(c, lnum);
740         if (IS_ERR(lpp)) {
741                 err = PTR_ERR(lpp);
742                 ubifs_err(c, "cannot read properties of LEB %d, error %d",
743                           lnum, err);
744                 goto out;
745         }
746
747         memcpy(lp, lpp, sizeof(struct ubifs_lprops));
748
749 out:
750         ubifs_release_lprops(c);
751         return err;
752 }
753
754 /**
755  * ubifs_fast_find_free - try to find a LEB with free space quickly.
756  * @c: the UBIFS file-system description object
757  *
758  * This function returns LEB properties for a LEB with free space or %NULL if
759  * the function is unable to find a LEB quickly.
760  */
761 const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c)
762 {
763         struct ubifs_lprops *lprops;
764         struct ubifs_lpt_heap *heap;
765
766         ubifs_assert(mutex_is_locked(&c->lp_mutex));
767
768         heap = &c->lpt_heap[LPROPS_FREE - 1];
769         if (heap->cnt == 0)
770                 return NULL;
771
772         lprops = heap->arr[0];
773         ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
774         ubifs_assert(!(lprops->flags & LPROPS_INDEX));
775         return lprops;
776 }
777
778 /**
779  * ubifs_fast_find_empty - try to find an empty LEB quickly.
780  * @c: the UBIFS file-system description object
781  *
782  * This function returns LEB properties for an empty LEB or %NULL if the
783  * function is unable to find an empty LEB quickly.
784  */
785 const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c)
786 {
787         struct ubifs_lprops *lprops;
788
789         ubifs_assert(mutex_is_locked(&c->lp_mutex));
790
791         if (list_empty(&c->empty_list))
792                 return NULL;
793
794         lprops = list_entry(c->empty_list.next, struct ubifs_lprops, list);
795         ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
796         ubifs_assert(!(lprops->flags & LPROPS_INDEX));
797         ubifs_assert(lprops->free == c->leb_size);
798         return lprops;
799 }
800
801 /**
802  * ubifs_fast_find_freeable - try to find a freeable LEB quickly.
803  * @c: the UBIFS file-system description object
804  *
805  * This function returns LEB properties for a freeable LEB or %NULL if the
806  * function is unable to find a freeable LEB quickly.
807  */
808 const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c)
809 {
810         struct ubifs_lprops *lprops;
811
812         ubifs_assert(mutex_is_locked(&c->lp_mutex));
813
814         if (list_empty(&c->freeable_list))
815                 return NULL;
816
817         lprops = list_entry(c->freeable_list.next, struct ubifs_lprops, list);
818         ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
819         ubifs_assert(!(lprops->flags & LPROPS_INDEX));
820         ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
821         ubifs_assert(c->freeable_cnt > 0);
822         return lprops;
823 }
824
825 /**
826  * ubifs_fast_find_frdi_idx - try to find a freeable index LEB quickly.
827  * @c: the UBIFS file-system description object
828  *
829  * This function returns LEB properties for a freeable index LEB or %NULL if the
830  * function is unable to find a freeable index LEB quickly.
831  */
832 const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c)
833 {
834         struct ubifs_lprops *lprops;
835
836         ubifs_assert(mutex_is_locked(&c->lp_mutex));
837
838         if (list_empty(&c->frdi_idx_list))
839                 return NULL;
840
841         lprops = list_entry(c->frdi_idx_list.next, struct ubifs_lprops, list);
842         ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
843         ubifs_assert((lprops->flags & LPROPS_INDEX));
844         ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
845         return lprops;
846 }
847
848 /*
849  * Everything below is related to debugging.
850  */
851
852 /**
853  * dbg_check_cats - check category heaps and lists.
854  * @c: UBIFS file-system description object
855  *
856  * This function returns %0 on success and a negative error code on failure.
857  */
858 int dbg_check_cats(struct ubifs_info *c)
859 {
860         struct ubifs_lprops *lprops;
861         struct list_head *pos;
862         int i, cat;
863
864         if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
865                 return 0;
866
867         list_for_each_entry(lprops, &c->empty_list, list) {
868                 if (lprops->free != c->leb_size) {
869                         ubifs_err(c, "non-empty LEB %d on empty list (free %d dirty %d flags %d)",
870                                   lprops->lnum, lprops->free, lprops->dirty,
871                                   lprops->flags);
872                         return -EINVAL;
873                 }
874                 if (lprops->flags & LPROPS_TAKEN) {
875                         ubifs_err(c, "taken LEB %d on empty list (free %d dirty %d flags %d)",
876                                   lprops->lnum, lprops->free, lprops->dirty,
877                                   lprops->flags);
878                         return -EINVAL;
879                 }
880         }
881
882         i = 0;
883         list_for_each_entry(lprops, &c->freeable_list, list) {
884                 if (lprops->free + lprops->dirty != c->leb_size) {
885                         ubifs_err(c, "non-freeable LEB %d on freeable list (free %d dirty %d flags %d)",
886                                   lprops->lnum, lprops->free, lprops->dirty,
887                                   lprops->flags);
888                         return -EINVAL;
889                 }
890                 if (lprops->flags & LPROPS_TAKEN) {
891                         ubifs_err(c, "taken LEB %d on freeable list (free %d dirty %d flags %d)",
892                                   lprops->lnum, lprops->free, lprops->dirty,
893                                   lprops->flags);
894                         return -EINVAL;
895                 }
896                 i += 1;
897         }
898         if (i != c->freeable_cnt) {
899                 ubifs_err(c, "freeable list count %d expected %d", i,
900                           c->freeable_cnt);
901                 return -EINVAL;
902         }
903
904         i = 0;
905         list_for_each(pos, &c->idx_gc)
906                 i += 1;
907         if (i != c->idx_gc_cnt) {
908                 ubifs_err(c, "idx_gc list count %d expected %d", i,
909                           c->idx_gc_cnt);
910                 return -EINVAL;
911         }
912
913         list_for_each_entry(lprops, &c->frdi_idx_list, list) {
914                 if (lprops->free + lprops->dirty != c->leb_size) {
915                         ubifs_err(c, "non-freeable LEB %d on frdi_idx list (free %d dirty %d flags %d)",
916                                   lprops->lnum, lprops->free, lprops->dirty,
917                                   lprops->flags);
918                         return -EINVAL;
919                 }
920                 if (lprops->flags & LPROPS_TAKEN) {
921                         ubifs_err(c, "taken LEB %d on frdi_idx list (free %d dirty %d flags %d)",
922                                   lprops->lnum, lprops->free, lprops->dirty,
923                                   lprops->flags);
924                         return -EINVAL;
925                 }
926                 if (!(lprops->flags & LPROPS_INDEX)) {
927                         ubifs_err(c, "non-index LEB %d on frdi_idx list (free %d dirty %d flags %d)",
928                                   lprops->lnum, lprops->free, lprops->dirty,
929                                   lprops->flags);
930                         return -EINVAL;
931                 }
932         }
933
934         for (cat = 1; cat <= LPROPS_HEAP_CNT; cat++) {
935                 struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
936
937                 for (i = 0; i < heap->cnt; i++) {
938                         lprops = heap->arr[i];
939                         if (!lprops) {
940                                 ubifs_err(c, "null ptr in LPT heap cat %d", cat);
941                                 return -EINVAL;
942                         }
943                         if (lprops->hpos != i) {
944                                 ubifs_err(c, "bad ptr in LPT heap cat %d", cat);
945                                 return -EINVAL;
946                         }
947                         if (lprops->flags & LPROPS_TAKEN) {
948                                 ubifs_err(c, "taken LEB in LPT heap cat %d", cat);
949                                 return -EINVAL;
950                         }
951                 }
952         }
953
954         return 0;
955 }
956
957 void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
958                     int add_pos)
959 {
960         int i = 0, j, err = 0;
961
962         if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
963                 return;
964
965         for (i = 0; i < heap->cnt; i++) {
966                 struct ubifs_lprops *lprops = heap->arr[i];
967                 struct ubifs_lprops *lp;
968
969                 if (i != add_pos)
970                         if ((lprops->flags & LPROPS_CAT_MASK) != cat) {
971                                 err = 1;
972                                 goto out;
973                         }
974                 if (lprops->hpos != i) {
975                         err = 2;
976                         goto out;
977                 }
978                 lp = ubifs_lpt_lookup(c, lprops->lnum);
979                 if (IS_ERR(lp)) {
980                         err = 3;
981                         goto out;
982                 }
983                 if (lprops != lp) {
984                         ubifs_err(c, "lprops %zx lp %zx lprops->lnum %d lp->lnum %d",
985                                   (size_t)lprops, (size_t)lp, lprops->lnum,
986                                   lp->lnum);
987                         err = 4;
988                         goto out;
989                 }
990                 for (j = 0; j < i; j++) {
991                         lp = heap->arr[j];
992                         if (lp == lprops) {
993                                 err = 5;
994                                 goto out;
995                         }
996                         if (lp->lnum == lprops->lnum) {
997                                 err = 6;
998                                 goto out;
999                         }
1000                 }
1001         }
1002 out:
1003         if (err) {
1004                 ubifs_err(c, "failed cat %d hpos %d err %d", cat, i, err);
1005                 dump_stack();
1006                 ubifs_dump_heap(c, heap, cat);
1007         }
1008 }
1009
1010 /**
1011  * scan_check_cb - scan callback.
1012  * @c: the UBIFS file-system description object
1013  * @lp: LEB properties to scan
1014  * @in_tree: whether the LEB properties are in main memory
1015  * @lst: lprops statistics to update
1016  *
1017  * This function returns a code that indicates whether the scan should continue
1018  * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
1019  * in main memory (%LPT_SCAN_ADD), or whether the scan should stop
1020  * (%LPT_SCAN_STOP).
1021  */
1022 static int scan_check_cb(struct ubifs_info *c,
1023                          const struct ubifs_lprops *lp, int in_tree,
1024                          struct ubifs_lp_stats *lst)
1025 {
1026         struct ubifs_scan_leb *sleb;
1027         struct ubifs_scan_node *snod;
1028         int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
1029         void *buf = NULL;
1030
1031         cat = lp->flags & LPROPS_CAT_MASK;
1032         if (cat != LPROPS_UNCAT) {
1033                 cat = ubifs_categorize_lprops(c, lp);
1034                 if (cat != (lp->flags & LPROPS_CAT_MASK)) {
1035                         ubifs_err(c, "bad LEB category %d expected %d",
1036                                   (lp->flags & LPROPS_CAT_MASK), cat);
1037                         return -EINVAL;
1038                 }
1039         }
1040
1041         /* Check lp is on its category list (if it has one) */
1042         if (in_tree) {
1043                 struct list_head *list = NULL;
1044
1045                 switch (cat) {
1046                 case LPROPS_EMPTY:
1047                         list = &c->empty_list;
1048                         break;
1049                 case LPROPS_FREEABLE:
1050                         list = &c->freeable_list;
1051                         break;
1052                 case LPROPS_FRDI_IDX:
1053                         list = &c->frdi_idx_list;
1054                         break;
1055                 case LPROPS_UNCAT:
1056                         list = &c->uncat_list;
1057                         break;
1058                 }
1059                 if (list) {
1060                         struct ubifs_lprops *lprops;
1061                         int found = 0;
1062
1063                         list_for_each_entry(lprops, list, list) {
1064                                 if (lprops == lp) {
1065                                         found = 1;
1066                                         break;
1067                                 }
1068                         }
1069                         if (!found) {
1070                                 ubifs_err(c, "bad LPT list (category %d)", cat);
1071                                 return -EINVAL;
1072                         }
1073                 }
1074         }
1075
1076         /* Check lp is on its category heap (if it has one) */
1077         if (in_tree && cat > 0 && cat <= LPROPS_HEAP_CNT) {
1078                 struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
1079
1080                 if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) ||
1081                     lp != heap->arr[lp->hpos]) {
1082                         ubifs_err(c, "bad LPT heap (category %d)", cat);
1083                         return -EINVAL;
1084                 }
1085         }
1086
1087         buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
1088         if (!buf)
1089                 return -ENOMEM;
1090
1091         /*
1092          * After an unclean unmount, empty and freeable LEBs
1093          * may contain garbage - do not scan them.
1094          */
1095         if (lp->free == c->leb_size) {
1096                 lst->empty_lebs += 1;
1097                 lst->total_free += c->leb_size;
1098                 lst->total_dark += ubifs_calc_dark(c, c->leb_size);
1099                 return LPT_SCAN_CONTINUE;
1100         }
1101         if (lp->free + lp->dirty == c->leb_size &&
1102             !(lp->flags & LPROPS_INDEX)) {
1103                 lst->total_free  += lp->free;
1104                 lst->total_dirty += lp->dirty;
1105                 lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
1106                 return LPT_SCAN_CONTINUE;
1107         }
1108
1109         sleb = ubifs_scan(c, lnum, 0, buf, 0);
1110         if (IS_ERR(sleb)) {
1111                 ret = PTR_ERR(sleb);
1112                 if (ret == -EUCLEAN) {
1113                         ubifs_dump_lprops(c);
1114                         ubifs_dump_budg(c, &c->bi);
1115                 }
1116                 goto out;
1117         }
1118
1119         is_idx = -1;
1120         list_for_each_entry(snod, &sleb->nodes, list) {
1121                 int found, level = 0;
1122
1123                 cond_resched();
1124
1125                 if (is_idx == -1)
1126                         is_idx = (snod->type == UBIFS_IDX_NODE) ? 1 : 0;
1127
1128                 if (is_idx && snod->type != UBIFS_IDX_NODE) {
1129                         ubifs_err(c, "indexing node in data LEB %d:%d",
1130                                   lnum, snod->offs);
1131                         goto out_destroy;
1132                 }
1133
1134                 if (snod->type == UBIFS_IDX_NODE) {
1135                         struct ubifs_idx_node *idx = snod->node;
1136
1137                         key_read(c, ubifs_idx_key(c, idx), &snod->key);
1138                         level = le16_to_cpu(idx->level);
1139                 }
1140
1141                 found = ubifs_tnc_has_node(c, &snod->key, level, lnum,
1142                                            snod->offs, is_idx);
1143                 if (found) {
1144                         if (found < 0)
1145                                 goto out_destroy;
1146                         used += ALIGN(snod->len, 8);
1147                 }
1148         }
1149
1150         free = c->leb_size - sleb->endpt;
1151         dirty = sleb->endpt - used;
1152
1153         if (free > c->leb_size || free < 0 || dirty > c->leb_size ||
1154             dirty < 0) {
1155                 ubifs_err(c, "bad calculated accounting for LEB %d: free %d, dirty %d",
1156                           lnum, free, dirty);
1157                 goto out_destroy;
1158         }
1159
1160         if (lp->free + lp->dirty == c->leb_size &&
1161             free + dirty == c->leb_size)
1162                 if ((is_idx && !(lp->flags & LPROPS_INDEX)) ||
1163                     (!is_idx && free == c->leb_size) ||
1164                     lp->free == c->leb_size) {
1165                         /*
1166                          * Empty or freeable LEBs could contain index
1167                          * nodes from an uncompleted commit due to an
1168                          * unclean unmount. Or they could be empty for
1169                          * the same reason. Or it may simply not have been
1170                          * unmapped.
1171                          */
1172                         free = lp->free;
1173                         dirty = lp->dirty;
1174                         is_idx = 0;
1175                     }
1176
1177         if (is_idx && lp->free + lp->dirty == free + dirty &&
1178             lnum != c->ihead_lnum) {
1179                 /*
1180                  * After an unclean unmount, an index LEB could have a different
1181                  * amount of free space than the value recorded by lprops. That
1182                  * is because the in-the-gaps method may use free space or
1183                  * create free space (as a side-effect of using ubi_leb_change
1184                  * and not writing the whole LEB). The incorrect free space
1185                  * value is not a problem because the index is only ever
1186                  * allocated empty LEBs, so there will never be an attempt to
1187                  * write to the free space at the end of an index LEB - except
1188                  * by the in-the-gaps method for which it is not a problem.
1189                  */
1190                 free = lp->free;
1191                 dirty = lp->dirty;
1192         }
1193
1194         if (lp->free != free || lp->dirty != dirty)
1195                 goto out_print;
1196
1197         if (is_idx && !(lp->flags & LPROPS_INDEX)) {
1198                 if (free == c->leb_size)
1199                         /* Free but not unmapped LEB, it's fine */
1200                         is_idx = 0;
1201                 else {
1202                         ubifs_err(c, "indexing node without indexing flag");
1203                         goto out_print;
1204                 }
1205         }
1206
1207         if (!is_idx && (lp->flags & LPROPS_INDEX)) {
1208                 ubifs_err(c, "data node with indexing flag");
1209                 goto out_print;
1210         }
1211
1212         if (free == c->leb_size)
1213                 lst->empty_lebs += 1;
1214
1215         if (is_idx)
1216                 lst->idx_lebs += 1;
1217
1218         if (!(lp->flags & LPROPS_INDEX))
1219                 lst->total_used += c->leb_size - free - dirty;
1220         lst->total_free += free;
1221         lst->total_dirty += dirty;
1222
1223         if (!(lp->flags & LPROPS_INDEX)) {
1224                 int spc = free + dirty;
1225
1226                 if (spc < c->dead_wm)
1227                         lst->total_dead += spc;
1228                 else
1229                         lst->total_dark += ubifs_calc_dark(c, spc);
1230         }
1231
1232         ubifs_scan_destroy(sleb);
1233         vfree(buf);
1234         return LPT_SCAN_CONTINUE;
1235
1236 out_print:
1237         ubifs_err(c, "bad accounting of LEB %d: free %d, dirty %d flags %#x, should be free %d, dirty %d",
1238                   lnum, lp->free, lp->dirty, lp->flags, free, dirty);
1239         ubifs_dump_leb(c, lnum);
1240 out_destroy:
1241         ubifs_scan_destroy(sleb);
1242         ret = -EINVAL;
1243 out:
1244         vfree(buf);
1245         return ret;
1246 }
1247
1248 /**
1249  * dbg_check_lprops - check all LEB properties.
1250  * @c: UBIFS file-system description object
1251  *
1252  * This function checks all LEB properties and makes sure they are all correct.
1253  * It returns zero if everything is fine, %-EINVAL if there is an inconsistency
1254  * and other negative error codes in case of other errors. This function is
1255  * called while the file system is locked (because of commit start), so no
1256  * additional locking is required. Note that locking the LPT mutex would cause
1257  * a circular lock dependency with the TNC mutex.
1258  */
1259 int dbg_check_lprops(struct ubifs_info *c)
1260 {
1261         int i, err;
1262         struct ubifs_lp_stats lst;
1263
1264         if (!dbg_is_chk_lprops(c))
1265                 return 0;
1266
1267         /*
1268          * As we are going to scan the media, the write buffers have to be
1269          * synchronized.
1270          */
1271         for (i = 0; i < c->jhead_cnt; i++) {
1272                 err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
1273                 if (err)
1274                         return err;
1275         }
1276
1277         memset(&lst, 0, sizeof(struct ubifs_lp_stats));
1278         err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
1279                                     (ubifs_lpt_scan_callback)scan_check_cb,
1280                                     &lst);
1281         if (err && err != -ENOSPC)
1282                 goto out;
1283
1284         if (lst.empty_lebs != c->lst.empty_lebs ||
1285             lst.idx_lebs != c->lst.idx_lebs ||
1286             lst.total_free != c->lst.total_free ||
1287             lst.total_dirty != c->lst.total_dirty ||
1288             lst.total_used != c->lst.total_used) {
1289                 ubifs_err(c, "bad overall accounting");
1290                 ubifs_err(c, "calculated: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
1291                           lst.empty_lebs, lst.idx_lebs, lst.total_free,
1292                           lst.total_dirty, lst.total_used);
1293                 ubifs_err(c, "read from lprops: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
1294                           c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free,
1295                           c->lst.total_dirty, c->lst.total_used);
1296                 err = -EINVAL;
1297                 goto out;
1298         }
1299
1300         if (lst.total_dead != c->lst.total_dead ||
1301             lst.total_dark != c->lst.total_dark) {
1302                 ubifs_err(c, "bad dead/dark space accounting");
1303                 ubifs_err(c, "calculated: total_dead %lld, total_dark %lld",
1304                           lst.total_dead, lst.total_dark);
1305                 ubifs_err(c, "read from lprops: total_dead %lld, total_dark %lld",
1306                           c->lst.total_dead, c->lst.total_dark);
1307                 err = -EINVAL;
1308                 goto out;
1309         }
1310
1311         err = dbg_check_cats(c);
1312 out:
1313         return err;
1314 }