Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lprops.c
Go to the documentation of this file.
1 /*
2  * This file is part of UBIFS.
3  *
4  * Copyright (C) 2006-2008 Nokia Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 as published by
8  * the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 51
17  * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  * Authors: Adrian Hunter
20  * Artem Bityutskiy (Битюцкий Артём)
21  */
22 
23 /*
24  * This file implements the functions that access LEB properties and their
25  * categories. LEBs are categorized based on the needs of UBIFS, and the
26  * categories are stored as either heaps or lists to provide a fast way of
27  * finding a LEB in a particular category. For example, UBIFS may need to find
28  * an empty LEB for the journal, or a very dirty LEB for garbage collection.
29  */
30 
31 #include "ubifs.h"
32 
38 static int get_heap_comp_val(struct ubifs_lprops *lprops, int cat)
39 {
40  switch (cat) {
41  case LPROPS_FREE:
42  return lprops->free;
43  case LPROPS_DIRTY_IDX:
44  return lprops->free + lprops->dirty;
45  default:
46  return lprops->dirty;
47  }
48 }
49 
62 static void move_up_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
63  struct ubifs_lprops *lprops, int cat)
64 {
65  int val1, val2, hpos;
66 
67  hpos = lprops->hpos;
68  if (!hpos)
69  return; /* Already top of the heap */
70  val1 = get_heap_comp_val(lprops, cat);
71  /* Compare to parent and, if greater, move up the heap */
72  do {
73  int ppos = (hpos - 1) / 2;
74 
75  val2 = get_heap_comp_val(heap->arr[ppos], cat);
76  if (val2 >= val1)
77  return;
78  /* Greater than parent so move up */
79  heap->arr[ppos]->hpos = hpos;
80  heap->arr[hpos] = heap->arr[ppos];
81  heap->arr[ppos] = lprops;
82  lprops->hpos = ppos;
83  hpos = ppos;
84  } while (hpos);
85 }
86 
99 static void adjust_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
100  struct ubifs_lprops *lprops, int hpos, int cat)
101 {
102  int val1, val2, val3, cpos;
103 
104  val1 = get_heap_comp_val(lprops, cat);
105  /* Compare to parent and, if greater than parent, move up the heap */
106  if (hpos) {
107  int ppos = (hpos - 1) / 2;
108 
109  val2 = get_heap_comp_val(heap->arr[ppos], cat);
110  if (val1 > val2) {
111  /* Greater than parent so move up */
112  while (1) {
113  heap->arr[ppos]->hpos = hpos;
114  heap->arr[hpos] = heap->arr[ppos];
115  heap->arr[ppos] = lprops;
116  lprops->hpos = ppos;
117  hpos = ppos;
118  if (!hpos)
119  return;
120  ppos = (hpos - 1) / 2;
121  val2 = get_heap_comp_val(heap->arr[ppos], cat);
122  if (val1 <= val2)
123  return;
124  /* Still greater than parent so keep going */
125  }
126  }
127  }
128 
129  /* Not greater than parent, so compare to children */
130  while (1) {
131  /* Compare to left child */
132  cpos = hpos * 2 + 1;
133  if (cpos >= heap->cnt)
134  return;
135  val2 = get_heap_comp_val(heap->arr[cpos], cat);
136  if (val1 < val2) {
137  /* Less than left child, so promote biggest child */
138  if (cpos + 1 < heap->cnt) {
139  val3 = get_heap_comp_val(heap->arr[cpos + 1],
140  cat);
141  if (val3 > val2)
142  cpos += 1; /* Right child is bigger */
143  }
144  heap->arr[cpos]->hpos = hpos;
145  heap->arr[hpos] = heap->arr[cpos];
146  heap->arr[cpos] = lprops;
147  lprops->hpos = cpos;
148  hpos = cpos;
149  continue;
150  }
151  /* Compare to right child */
152  cpos += 1;
153  if (cpos >= heap->cnt)
154  return;
155  val3 = get_heap_comp_val(heap->arr[cpos], cat);
156  if (val1 < val3) {
157  /* Less than right child, so promote right child */
158  heap->arr[cpos]->hpos = hpos;
159  heap->arr[hpos] = heap->arr[cpos];
160  heap->arr[cpos] = lprops;
161  lprops->hpos = cpos;
162  hpos = cpos;
163  continue;
164  }
165  return;
166  }
167 }
168 
178 static int add_to_lpt_heap(struct ubifs_info *c, struct ubifs_lprops *lprops,
179  int cat)
180 {
181  struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
182 
183  if (heap->cnt >= heap->max_cnt) {
184  const int b = LPT_HEAP_SZ / 2 - 1;
185  int cpos, val1, val2;
186 
187  /* Compare to some other LEB on the bottom of heap */
188  /* Pick a position kind of randomly */
189  cpos = (((size_t)lprops >> 4) & b) + b;
190  ubifs_assert(cpos >= b);
191  ubifs_assert(cpos < LPT_HEAP_SZ);
192  ubifs_assert(cpos < heap->cnt);
193 
194  val1 = get_heap_comp_val(lprops, cat);
195  val2 = get_heap_comp_val(heap->arr[cpos], cat);
196  if (val1 > val2) {
197  struct ubifs_lprops *lp;
198 
199  lp = heap->arr[cpos];
200  lp->flags &= ~LPROPS_CAT_MASK;
201  lp->flags |= LPROPS_UNCAT;
202  list_add(&lp->list, &c->uncat_list);
203  lprops->hpos = cpos;
204  heap->arr[cpos] = lprops;
205  move_up_lpt_heap(c, heap, lprops, cat);
206  dbg_check_heap(c, heap, cat, lprops->hpos);
207  return 1; /* Added to heap */
208  }
209  dbg_check_heap(c, heap, cat, -1);
210  return 0; /* Not added to heap */
211  } else {
212  lprops->hpos = heap->cnt++;
213  heap->arr[lprops->hpos] = lprops;
214  move_up_lpt_heap(c, heap, lprops, cat);
215  dbg_check_heap(c, heap, cat, lprops->hpos);
216  return 1; /* Added to heap */
217  }
218 }
219 
226 static void remove_from_lpt_heap(struct ubifs_info *c,
227  struct ubifs_lprops *lprops, int cat)
228 {
229  struct ubifs_lpt_heap *heap;
230  int hpos = lprops->hpos;
231 
232  heap = &c->lpt_heap[cat - 1];
233  ubifs_assert(hpos >= 0 && hpos < heap->cnt);
234  ubifs_assert(heap->arr[hpos] == lprops);
235  heap->cnt -= 1;
236  if (hpos < heap->cnt) {
237  heap->arr[hpos] = heap->arr[heap->cnt];
238  heap->arr[hpos]->hpos = hpos;
239  adjust_lpt_heap(c, heap, heap->arr[hpos], hpos, cat);
240  }
241  dbg_check_heap(c, heap, cat, -1);
242 }
243 
256 static void lpt_heap_replace(struct ubifs_info *c,
257  struct ubifs_lprops *old_lprops,
258  struct ubifs_lprops *new_lprops, int cat)
259 {
260  struct ubifs_lpt_heap *heap;
261  int hpos = new_lprops->hpos;
262 
263  heap = &c->lpt_heap[cat - 1];
264  heap->arr[hpos] = new_lprops;
265 }
266 
275 void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
276  int cat)
277 {
278  switch (cat) {
279  case LPROPS_DIRTY:
280  case LPROPS_DIRTY_IDX:
281  case LPROPS_FREE:
282  if (add_to_lpt_heap(c, lprops, cat))
283  break;
284  /* No more room on heap so make it un-categorized */
285  cat = LPROPS_UNCAT;
286  /* Fall through */
287  case LPROPS_UNCAT:
288  list_add(&lprops->list, &c->uncat_list);
289  break;
290  case LPROPS_EMPTY:
291  list_add(&lprops->list, &c->empty_list);
292  break;
293  case LPROPS_FREEABLE:
294  list_add(&lprops->list, &c->freeable_list);
295  c->freeable_cnt += 1;
296  break;
297  case LPROPS_FRDI_IDX:
298  list_add(&lprops->list, &c->frdi_idx_list);
299  break;
300  default:
301  ubifs_assert(0);
302  }
303 
304  lprops->flags &= ~LPROPS_CAT_MASK;
305  lprops->flags |= cat;
306  c->in_a_category_cnt += 1;
308 }
309 
318 static void ubifs_remove_from_cat(struct ubifs_info *c,
319  struct ubifs_lprops *lprops, int cat)
320 {
321  switch (cat) {
322  case LPROPS_DIRTY:
323  case LPROPS_DIRTY_IDX:
324  case LPROPS_FREE:
325  remove_from_lpt_heap(c, lprops, cat);
326  break;
327  case LPROPS_FREEABLE:
328  c->freeable_cnt -= 1;
329  ubifs_assert(c->freeable_cnt >= 0);
330  /* Fall through */
331  case LPROPS_UNCAT:
332  case LPROPS_EMPTY:
333  case LPROPS_FRDI_IDX:
334  ubifs_assert(!list_empty(&lprops->list));
335  list_del(&lprops->list);
336  break;
337  default:
338  ubifs_assert(0);
339  }
340 
341  c->in_a_category_cnt -= 1;
343 }
344 
355 void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
356  struct ubifs_lprops *new_lprops)
357 {
358  int cat;
359 
360  cat = new_lprops->flags & LPROPS_CAT_MASK;
361  switch (cat) {
362  case LPROPS_DIRTY:
363  case LPROPS_DIRTY_IDX:
364  case LPROPS_FREE:
365  lpt_heap_replace(c, old_lprops, new_lprops, cat);
366  break;
367  case LPROPS_UNCAT:
368  case LPROPS_EMPTY:
369  case LPROPS_FREEABLE:
370  case LPROPS_FRDI_IDX:
371  list_replace(&old_lprops->list, &new_lprops->list);
372  break;
373  default:
374  ubifs_assert(0);
375  }
376 }
377 
387 void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops)
388 {
389  int cat = lprops->flags & LPROPS_CAT_MASK;
390 
391  if (cat != LPROPS_UNCAT)
392  return;
393  cat = ubifs_categorize_lprops(c, lprops);
394  if (cat == LPROPS_UNCAT)
395  return;
396  ubifs_remove_from_cat(c, lprops, LPROPS_UNCAT);
397  ubifs_add_to_cat(c, lprops, cat);
398 }
399 
411  const struct ubifs_lprops *lprops)
412 {
413  if (lprops->flags & LPROPS_TAKEN)
414  return LPROPS_UNCAT;
415 
416  if (lprops->free == c->leb_size) {
417  ubifs_assert(!(lprops->flags & LPROPS_INDEX));
418  return LPROPS_EMPTY;
419  }
420 
421  if (lprops->free + lprops->dirty == c->leb_size) {
422  if (lprops->flags & LPROPS_INDEX)
423  return LPROPS_FRDI_IDX;
424  else
425  return LPROPS_FREEABLE;
426  }
427 
428  if (lprops->flags & LPROPS_INDEX) {
429  if (lprops->dirty + lprops->free >= c->min_idx_node_sz)
430  return LPROPS_DIRTY_IDX;
431  } else {
432  if (lprops->dirty >= c->dead_wm &&
433  lprops->dirty > lprops->free)
434  return LPROPS_DIRTY;
435  if (lprops->free > 0)
436  return LPROPS_FREE;
437  }
438 
439  return LPROPS_UNCAT;
440 }
441 
450 static void change_category(struct ubifs_info *c, struct ubifs_lprops *lprops)
451 {
452  int old_cat = lprops->flags & LPROPS_CAT_MASK;
453  int new_cat = ubifs_categorize_lprops(c, lprops);
454 
455  if (old_cat == new_cat) {
456  struct ubifs_lpt_heap *heap;
457 
458  /* lprops on a heap now must be moved up or down */
459  if (new_cat < 1 || new_cat > LPROPS_HEAP_CNT)
460  return; /* Not on a heap */
461  heap = &c->lpt_heap[new_cat - 1];
462  adjust_lpt_heap(c, heap, lprops, lprops->hpos, new_cat);
463  } else {
464  ubifs_remove_from_cat(c, lprops, old_cat);
465  ubifs_add_to_cat(c, lprops, new_cat);
466  }
467 }
468 
481 int ubifs_calc_dark(const struct ubifs_info *c, int spc)
482 {
483  ubifs_assert(!(spc & 7));
484 
485  if (spc < c->dark_wm)
486  return spc;
487 
488  /*
489  * If we have slightly more space then the dark space watermark, we can
490  * anyway safely assume it we'll be able to write a node of the
491  * smallest size there.
492  */
493  if (spc - c->dark_wm < MIN_WRITE_SZ)
494  return spc - MIN_WRITE_SZ;
495 
496  return c->dark_wm;
497 }
498 
504 static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
505 {
506  struct ubifs_pnode *pnode;
507  int pos;
508 
509  pos = (lprops->lnum - c->main_first) & (UBIFS_LPT_FANOUT - 1);
510  pnode = (struct ubifs_pnode *)container_of(lprops - pos,
511  struct ubifs_pnode,
512  lprops[0]);
513  return !test_bit(COW_CNODE, &pnode->flags) &&
514  test_bit(DIRTY_CNODE, &pnode->flags);
515 }
516 
534 const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
535  const struct ubifs_lprops *lp,
536  int free, int dirty, int flags,
537  int idx_gc_cnt)
538 {
539  /*
540  * This is the only function that is allowed to change lprops, so we
541  * discard the "const" qualifier.
542  */
543  struct ubifs_lprops *lprops = (struct ubifs_lprops *)lp;
544 
545  dbg_lp("LEB %d, free %d, dirty %d, flags %d",
546  lprops->lnum, free, dirty, flags);
547 
548  ubifs_assert(mutex_is_locked(&c->lp_mutex));
549  ubifs_assert(c->lst.empty_lebs >= 0 &&
550  c->lst.empty_lebs <= c->main_lebs);
551  ubifs_assert(c->freeable_cnt >= 0);
553  ubifs_assert(c->lst.taken_empty_lebs >= 0);
554  ubifs_assert(c->lst.taken_empty_lebs <= c->lst.empty_lebs);
555  ubifs_assert(!(c->lst.total_free & 7) && !(c->lst.total_dirty & 7));
556  ubifs_assert(!(c->lst.total_dead & 7) && !(c->lst.total_dark & 7));
557  ubifs_assert(!(c->lst.total_used & 7));
558  ubifs_assert(free == LPROPS_NC || free >= 0);
559  ubifs_assert(dirty == LPROPS_NC || dirty >= 0);
560 
561  if (!is_lprops_dirty(c, lprops)) {
562  lprops = ubifs_lpt_lookup_dirty(c, lprops->lnum);
563  if (IS_ERR(lprops))
564  return lprops;
565  } else
566  ubifs_assert(lprops == ubifs_lpt_lookup_dirty(c, lprops->lnum));
567 
568  ubifs_assert(!(lprops->free & 7) && !(lprops->dirty & 7));
569 
570  spin_lock(&c->space_lock);
571  if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
572  c->lst.taken_empty_lebs -= 1;
573 
574  if (!(lprops->flags & LPROPS_INDEX)) {
575  int old_spc;
576 
577  old_spc = lprops->free + lprops->dirty;
578  if (old_spc < c->dead_wm)
579  c->lst.total_dead -= old_spc;
580  else
581  c->lst.total_dark -= ubifs_calc_dark(c, old_spc);
582 
583  c->lst.total_used -= c->leb_size - old_spc;
584  }
585 
586  if (free != LPROPS_NC) {
587  free = ALIGN(free, 8);
588  c->lst.total_free += free - lprops->free;
589 
590  /* Increase or decrease empty LEBs counter if needed */
591  if (free == c->leb_size) {
592  if (lprops->free != c->leb_size)
593  c->lst.empty_lebs += 1;
594  } else if (lprops->free == c->leb_size)
595  c->lst.empty_lebs -= 1;
596  lprops->free = free;
597  }
598 
599  if (dirty != LPROPS_NC) {
600  dirty = ALIGN(dirty, 8);
601  c->lst.total_dirty += dirty - lprops->dirty;
602  lprops->dirty = dirty;
603  }
604 
605  if (flags != LPROPS_NC) {
606  /* Take care about indexing LEBs counter if needed */
607  if ((lprops->flags & LPROPS_INDEX)) {
608  if (!(flags & LPROPS_INDEX))
609  c->lst.idx_lebs -= 1;
610  } else if (flags & LPROPS_INDEX)
611  c->lst.idx_lebs += 1;
612  lprops->flags = flags;
613  }
614 
615  if (!(lprops->flags & LPROPS_INDEX)) {
616  int new_spc;
617 
618  new_spc = lprops->free + lprops->dirty;
619  if (new_spc < c->dead_wm)
620  c->lst.total_dead += new_spc;
621  else
622  c->lst.total_dark += ubifs_calc_dark(c, new_spc);
623 
624  c->lst.total_used += c->leb_size - new_spc;
625  }
626 
627  if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
628  c->lst.taken_empty_lebs += 1;
629 
630  change_category(c, lprops);
631  c->idx_gc_cnt += idx_gc_cnt;
632  spin_unlock(&c->space_lock);
633  return lprops;
634 }
635 
641 void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst)
642 {
643  spin_lock(&c->space_lock);
644  memcpy(lst, &c->lst, sizeof(struct ubifs_lp_stats));
645  spin_unlock(&c->space_lock);
646 }
647 
663 int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
664  int flags_set, int flags_clean, int idx_gc_cnt)
665 {
666  int err = 0, flags;
667  const struct ubifs_lprops *lp;
668 
669  ubifs_get_lprops(c);
670 
671  lp = ubifs_lpt_lookup_dirty(c, lnum);
672  if (IS_ERR(lp)) {
673  err = PTR_ERR(lp);
674  goto out;
675  }
676 
677  flags = (lp->flags | flags_set) & ~flags_clean;
678  lp = ubifs_change_lp(c, lp, free, dirty, flags, idx_gc_cnt);
679  if (IS_ERR(lp))
680  err = PTR_ERR(lp);
681 
682 out:
683  ubifs_release_lprops(c);
684  if (err)
685  ubifs_err("cannot change properties of LEB %d, error %d",
686  lnum, err);
687  return err;
688 }
689 
702 int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
703  int flags_set, int flags_clean)
704 {
705  int err = 0, flags;
706  const struct ubifs_lprops *lp;
707 
708  ubifs_get_lprops(c);
709 
710  lp = ubifs_lpt_lookup_dirty(c, lnum);
711  if (IS_ERR(lp)) {
712  err = PTR_ERR(lp);
713  goto out;
714  }
715 
716  flags = (lp->flags | flags_set) & ~flags_clean;
717  lp = ubifs_change_lp(c, lp, free, lp->dirty + dirty, flags, 0);
718  if (IS_ERR(lp))
719  err = PTR_ERR(lp);
720 
721 out:
722  ubifs_release_lprops(c);
723  if (err)
724  ubifs_err("cannot update properties of LEB %d, error %d",
725  lnum, err);
726  return err;
727 }
728 
739 int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp)
740 {
741  int err = 0;
742  const struct ubifs_lprops *lpp;
743 
744  ubifs_get_lprops(c);
745 
746  lpp = ubifs_lpt_lookup(c, lnum);
747  if (IS_ERR(lpp)) {
748  err = PTR_ERR(lpp);
749  ubifs_err("cannot read properties of LEB %d, error %d",
750  lnum, err);
751  goto out;
752  }
753 
754  memcpy(lp, lpp, sizeof(struct ubifs_lprops));
755 
756 out:
757  ubifs_release_lprops(c);
758  return err;
759 }
760 
769 {
770  struct ubifs_lprops *lprops;
771  struct ubifs_lpt_heap *heap;
772 
773  ubifs_assert(mutex_is_locked(&c->lp_mutex));
774 
775  heap = &c->lpt_heap[LPROPS_FREE - 1];
776  if (heap->cnt == 0)
777  return NULL;
778 
779  lprops = heap->arr[0];
780  ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
781  ubifs_assert(!(lprops->flags & LPROPS_INDEX));
782  return lprops;
783 }
784 
793 {
794  struct ubifs_lprops *lprops;
795 
796  ubifs_assert(mutex_is_locked(&c->lp_mutex));
797 
798  if (list_empty(&c->empty_list))
799  return NULL;
800 
801  lprops = list_entry(c->empty_list.next, struct ubifs_lprops, list);
802  ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
803  ubifs_assert(!(lprops->flags & LPROPS_INDEX));
804  ubifs_assert(lprops->free == c->leb_size);
805  return lprops;
806 }
807 
816 {
817  struct ubifs_lprops *lprops;
818 
819  ubifs_assert(mutex_is_locked(&c->lp_mutex));
820 
821  if (list_empty(&c->freeable_list))
822  return NULL;
823 
824  lprops = list_entry(c->freeable_list.next, struct ubifs_lprops, list);
825  ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
826  ubifs_assert(!(lprops->flags & LPROPS_INDEX));
827  ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
828  ubifs_assert(c->freeable_cnt > 0);
829  return lprops;
830 }
831 
840 {
841  struct ubifs_lprops *lprops;
842 
843  ubifs_assert(mutex_is_locked(&c->lp_mutex));
844 
845  if (list_empty(&c->frdi_idx_list))
846  return NULL;
847 
848  lprops = list_entry(c->frdi_idx_list.next, struct ubifs_lprops, list);
849  ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
850  ubifs_assert((lprops->flags & LPROPS_INDEX));
851  ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
852  return lprops;
853 }
854 
855 /*
856  * Everything below is related to debugging.
857  */
858 
866 {
867  struct ubifs_lprops *lprops;
868  struct list_head *pos;
869  int i, cat;
870 
871  if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
872  return 0;
873 
874  list_for_each_entry(lprops, &c->empty_list, list) {
875  if (lprops->free != c->leb_size) {
876  ubifs_err("non-empty LEB %d on empty list (free %d dirty %d flags %d)",
877  lprops->lnum, lprops->free, lprops->dirty,
878  lprops->flags);
879  return -EINVAL;
880  }
881  if (lprops->flags & LPROPS_TAKEN) {
882  ubifs_err("taken LEB %d on empty list (free %d dirty %d flags %d)",
883  lprops->lnum, lprops->free, lprops->dirty,
884  lprops->flags);
885  return -EINVAL;
886  }
887  }
888 
889  i = 0;
890  list_for_each_entry(lprops, &c->freeable_list, list) {
891  if (lprops->free + lprops->dirty != c->leb_size) {
892  ubifs_err("non-freeable LEB %d on freeable list (free %d dirty %d flags %d)",
893  lprops->lnum, lprops->free, lprops->dirty,
894  lprops->flags);
895  return -EINVAL;
896  }
897  if (lprops->flags & LPROPS_TAKEN) {
898  ubifs_err("taken LEB %d on freeable list (free %d dirty %d flags %d)",
899  lprops->lnum, lprops->free, lprops->dirty,
900  lprops->flags);
901  return -EINVAL;
902  }
903  i += 1;
904  }
905  if (i != c->freeable_cnt) {
906  ubifs_err("freeable list count %d expected %d", i,
907  c->freeable_cnt);
908  return -EINVAL;
909  }
910 
911  i = 0;
912  list_for_each(pos, &c->idx_gc)
913  i += 1;
914  if (i != c->idx_gc_cnt) {
915  ubifs_err("idx_gc list count %d expected %d", i,
916  c->idx_gc_cnt);
917  return -EINVAL;
918  }
919 
920  list_for_each_entry(lprops, &c->frdi_idx_list, list) {
921  if (lprops->free + lprops->dirty != c->leb_size) {
922  ubifs_err("non-freeable LEB %d on frdi_idx list (free %d dirty %d flags %d)",
923  lprops->lnum, lprops->free, lprops->dirty,
924  lprops->flags);
925  return -EINVAL;
926  }
927  if (lprops->flags & LPROPS_TAKEN) {
928  ubifs_err("taken LEB %d on frdi_idx list (free %d dirty %d flags %d)",
929  lprops->lnum, lprops->free, lprops->dirty,
930  lprops->flags);
931  return -EINVAL;
932  }
933  if (!(lprops->flags & LPROPS_INDEX)) {
934  ubifs_err("non-index LEB %d on frdi_idx list (free %d dirty %d flags %d)",
935  lprops->lnum, lprops->free, lprops->dirty,
936  lprops->flags);
937  return -EINVAL;
938  }
939  }
940 
941  for (cat = 1; cat <= LPROPS_HEAP_CNT; cat++) {
942  struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
943 
944  for (i = 0; i < heap->cnt; i++) {
945  lprops = heap->arr[i];
946  if (!lprops) {
947  ubifs_err("null ptr in LPT heap cat %d", cat);
948  return -EINVAL;
949  }
950  if (lprops->hpos != i) {
951  ubifs_err("bad ptr in LPT heap cat %d", cat);
952  return -EINVAL;
953  }
954  if (lprops->flags & LPROPS_TAKEN) {
955  ubifs_err("taken LEB in LPT heap cat %d", cat);
956  return -EINVAL;
957  }
958  }
959  }
960 
961  return 0;
962 }
963 
964 void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
965  int add_pos)
966 {
967  int i = 0, j, err = 0;
968 
969  if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
970  return;
971 
972  for (i = 0; i < heap->cnt; i++) {
973  struct ubifs_lprops *lprops = heap->arr[i];
974  struct ubifs_lprops *lp;
975 
976  if (i != add_pos)
977  if ((lprops->flags & LPROPS_CAT_MASK) != cat) {
978  err = 1;
979  goto out;
980  }
981  if (lprops->hpos != i) {
982  err = 2;
983  goto out;
984  }
985  lp = ubifs_lpt_lookup(c, lprops->lnum);
986  if (IS_ERR(lp)) {
987  err = 3;
988  goto out;
989  }
990  if (lprops != lp) {
991  ubifs_err("lprops %zx lp %zx lprops->lnum %d lp->lnum %d",
992  (size_t)lprops, (size_t)lp, lprops->lnum,
993  lp->lnum);
994  err = 4;
995  goto out;
996  }
997  for (j = 0; j < i; j++) {
998  lp = heap->arr[j];
999  if (lp == lprops) {
1000  err = 5;
1001  goto out;
1002  }
1003  if (lp->lnum == lprops->lnum) {
1004  err = 6;
1005  goto out;
1006  }
1007  }
1008  }
1009 out:
1010  if (err) {
1011  ubifs_err("failed cat %d hpos %d err %d", cat, i, err);
1012  dump_stack();
1013  ubifs_dump_heap(c, heap, cat);
1014  }
1015 }
1016 
1029 static int scan_check_cb(struct ubifs_info *c,
1030  const struct ubifs_lprops *lp, int in_tree,
1031  struct ubifs_lp_stats *lst)
1032 {
1033  struct ubifs_scan_leb *sleb;
1034  struct ubifs_scan_node *snod;
1035  int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
1036  void *buf = NULL;
1037 
1038  cat = lp->flags & LPROPS_CAT_MASK;
1039  if (cat != LPROPS_UNCAT) {
1040  cat = ubifs_categorize_lprops(c, lp);
1041  if (cat != (lp->flags & LPROPS_CAT_MASK)) {
1042  ubifs_err("bad LEB category %d expected %d",
1043  (lp->flags & LPROPS_CAT_MASK), cat);
1044  return -EINVAL;
1045  }
1046  }
1047 
1048  /* Check lp is on its category list (if it has one) */
1049  if (in_tree) {
1050  struct list_head *list = NULL;
1051 
1052  switch (cat) {
1053  case LPROPS_EMPTY:
1054  list = &c->empty_list;
1055  break;
1056  case LPROPS_FREEABLE:
1057  list = &c->freeable_list;
1058  break;
1059  case LPROPS_FRDI_IDX:
1060  list = &c->frdi_idx_list;
1061  break;
1062  case LPROPS_UNCAT:
1063  list = &c->uncat_list;
1064  break;
1065  }
1066  if (list) {
1067  struct ubifs_lprops *lprops;
1068  int found = 0;
1069 
1070  list_for_each_entry(lprops, list, list) {
1071  if (lprops == lp) {
1072  found = 1;
1073  break;
1074  }
1075  }
1076  if (!found) {
1077  ubifs_err("bad LPT list (category %d)", cat);
1078  return -EINVAL;
1079  }
1080  }
1081  }
1082 
1083  /* Check lp is on its category heap (if it has one) */
1084  if (in_tree && cat > 0 && cat <= LPROPS_HEAP_CNT) {
1085  struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
1086 
1087  if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) ||
1088  lp != heap->arr[lp->hpos]) {
1089  ubifs_err("bad LPT heap (category %d)", cat);
1090  return -EINVAL;
1091  }
1092  }
1093 
1094  buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
1095  if (!buf)
1096  return -ENOMEM;
1097 
1098  /*
1099  * After an unclean unmount, empty and freeable LEBs
1100  * may contain garbage - do not scan them.
1101  */
1102  if (lp->free == c->leb_size) {
1103  lst->empty_lebs += 1;
1104  lst->total_free += c->leb_size;
1105  lst->total_dark += ubifs_calc_dark(c, c->leb_size);
1106  return LPT_SCAN_CONTINUE;
1107  }
1108  if (lp->free + lp->dirty == c->leb_size &&
1109  !(lp->flags & LPROPS_INDEX)) {
1110  lst->total_free += lp->free;
1111  lst->total_dirty += lp->dirty;
1112  lst->total_dark += ubifs_calc_dark(c, c->leb_size);
1113  return LPT_SCAN_CONTINUE;
1114  }
1115 
1116  sleb = ubifs_scan(c, lnum, 0, buf, 0);
1117  if (IS_ERR(sleb)) {
1118  ret = PTR_ERR(sleb);
1119  if (ret == -EUCLEAN) {
1120  ubifs_dump_lprops(c);
1121  ubifs_dump_budg(c, &c->bi);
1122  }
1123  goto out;
1124  }
1125 
1126  is_idx = -1;
1127  list_for_each_entry(snod, &sleb->nodes, list) {
1128  int found, level = 0;
1129 
1130  cond_resched();
1131 
1132  if (is_idx == -1)
1133  is_idx = (snod->type == UBIFS_IDX_NODE) ? 1 : 0;
1134 
1135  if (is_idx && snod->type != UBIFS_IDX_NODE) {
1136  ubifs_err("indexing node in data LEB %d:%d",
1137  lnum, snod->offs);
1138  goto out_destroy;
1139  }
1140 
1141  if (snod->type == UBIFS_IDX_NODE) {
1142  struct ubifs_idx_node *idx = snod->node;
1143 
1144  key_read(c, ubifs_idx_key(c, idx), &snod->key);
1145  level = le16_to_cpu(idx->level);
1146  }
1147 
1148  found = ubifs_tnc_has_node(c, &snod->key, level, lnum,
1149  snod->offs, is_idx);
1150  if (found) {
1151  if (found < 0)
1152  goto out_destroy;
1153  used += ALIGN(snod->len, 8);
1154  }
1155  }
1156 
1157  free = c->leb_size - sleb->endpt;
1158  dirty = sleb->endpt - used;
1159 
1160  if (free > c->leb_size || free < 0 || dirty > c->leb_size ||
1161  dirty < 0) {
1162  ubifs_err("bad calculated accounting for LEB %d: free %d, dirty %d",
1163  lnum, free, dirty);
1164  goto out_destroy;
1165  }
1166 
1167  if (lp->free + lp->dirty == c->leb_size &&
1168  free + dirty == c->leb_size)
1169  if ((is_idx && !(lp->flags & LPROPS_INDEX)) ||
1170  (!is_idx && free == c->leb_size) ||
1171  lp->free == c->leb_size) {
1172  /*
1173  * Empty or freeable LEBs could contain index
1174  * nodes from an uncompleted commit due to an
1175  * unclean unmount. Or they could be empty for
1176  * the same reason. Or it may simply not have been
1177  * unmapped.
1178  */
1179  free = lp->free;
1180  dirty = lp->dirty;
1181  is_idx = 0;
1182  }
1183 
1184  if (is_idx && lp->free + lp->dirty == free + dirty &&
1185  lnum != c->ihead_lnum) {
1186  /*
1187  * After an unclean unmount, an index LEB could have a different
1188  * amount of free space than the value recorded by lprops. That
1189  * is because the in-the-gaps method may use free space or
1190  * create free space (as a side-effect of using ubi_leb_change
1191  * and not writing the whole LEB). The incorrect free space
1192  * value is not a problem because the index is only ever
1193  * allocated empty LEBs, so there will never be an attempt to
1194  * write to the free space at the end of an index LEB - except
1195  * by the in-the-gaps method for which it is not a problem.
1196  */
1197  free = lp->free;
1198  dirty = lp->dirty;
1199  }
1200 
1201  if (lp->free != free || lp->dirty != dirty)
1202  goto out_print;
1203 
1204  if (is_idx && !(lp->flags & LPROPS_INDEX)) {
1205  if (free == c->leb_size)
1206  /* Free but not unmapped LEB, it's fine */
1207  is_idx = 0;
1208  else {
1209  ubifs_err("indexing node without indexing flag");
1210  goto out_print;
1211  }
1212  }
1213 
1214  if (!is_idx && (lp->flags & LPROPS_INDEX)) {
1215  ubifs_err("data node with indexing flag");
1216  goto out_print;
1217  }
1218 
1219  if (free == c->leb_size)
1220  lst->empty_lebs += 1;
1221 
1222  if (is_idx)
1223  lst->idx_lebs += 1;
1224 
1225  if (!(lp->flags & LPROPS_INDEX))
1226  lst->total_used += c->leb_size - free - dirty;
1227  lst->total_free += free;
1228  lst->total_dirty += dirty;
1229 
1230  if (!(lp->flags & LPROPS_INDEX)) {
1231  int spc = free + dirty;
1232 
1233  if (spc < c->dead_wm)
1234  lst->total_dead += spc;
1235  else
1236  lst->total_dark += ubifs_calc_dark(c, spc);
1237  }
1238 
1239  ubifs_scan_destroy(sleb);
1240  vfree(buf);
1241  return LPT_SCAN_CONTINUE;
1242 
1243 out_print:
1244  ubifs_err("bad accounting of LEB %d: free %d, dirty %d flags %#x, should be free %d, dirty %d",
1245  lnum, lp->free, lp->dirty, lp->flags, free, dirty);
1246  ubifs_dump_leb(c, lnum);
1247 out_destroy:
1248  ubifs_scan_destroy(sleb);
1249  ret = -EINVAL;
1250 out:
1251  vfree(buf);
1252  return ret;
1253 }
1254 
1267 {
1268  int i, err;
1269  struct ubifs_lp_stats lst;
1270 
1271  if (!dbg_is_chk_lprops(c))
1272  return 0;
1273 
1274  /*
1275  * As we are going to scan the media, the write buffers have to be
1276  * synchronized.
1277  */
1278  for (i = 0; i < c->jhead_cnt; i++) {
1279  err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
1280  if (err)
1281  return err;
1282  }
1283 
1284  memset(&lst, 0, sizeof(struct ubifs_lp_stats));
1285  err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
1286  (ubifs_lpt_scan_callback)scan_check_cb,
1287  &lst);
1288  if (err && err != -ENOSPC)
1289  goto out;
1290 
1291  if (lst.empty_lebs != c->lst.empty_lebs ||
1292  lst.idx_lebs != c->lst.idx_lebs ||
1293  lst.total_free != c->lst.total_free ||
1294  lst.total_dirty != c->lst.total_dirty ||
1295  lst.total_used != c->lst.total_used) {
1296  ubifs_err("bad overall accounting");
1297  ubifs_err("calculated: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
1298  lst.empty_lebs, lst.idx_lebs, lst.total_free,
1299  lst.total_dirty, lst.total_used);
1300  ubifs_err("read from lprops: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
1301  c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free,
1302  c->lst.total_dirty, c->lst.total_used);
1303  err = -EINVAL;
1304  goto out;
1305  }
1306 
1307  if (lst.total_dead != c->lst.total_dead ||
1308  lst.total_dark != c->lst.total_dark) {
1309  ubifs_err("bad dead/dark space accounting");
1310  ubifs_err("calculated: total_dead %lld, total_dark %lld",
1311  lst.total_dead, lst.total_dark);
1312  ubifs_err("read from lprops: total_dead %lld, total_dark %lld",
1313  c->lst.total_dead, c->lst.total_dark);
1314  err = -EINVAL;
1315  goto out;
1316  }
1317 
1318  err = dbg_check_cats(c);
1319 out:
1320  return err;
1321 }