0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/sort.h>
0018 #include "ubifs.h"
0019
0020
0021
0022
0023
0024
0025
0026
0027 struct scan_data {
0028 int min_space;
0029 int pick_free;
0030 int lnum;
0031 int exclude_index;
0032 };
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 static int valuable(struct ubifs_info *c, const struct ubifs_lprops *lprops)
0043 {
0044 int n, cat = lprops->flags & LPROPS_CAT_MASK;
0045 struct ubifs_lpt_heap *heap;
0046
0047 switch (cat) {
0048 case LPROPS_DIRTY:
0049 case LPROPS_DIRTY_IDX:
0050 case LPROPS_FREE:
0051 heap = &c->lpt_heap[cat - 1];
0052 if (heap->cnt < heap->max_cnt)
0053 return 1;
0054 if (lprops->free + lprops->dirty >= c->dark_wm)
0055 return 1;
0056 return 0;
0057 case LPROPS_EMPTY:
0058 n = c->lst.empty_lebs + c->freeable_cnt -
0059 c->lst.taken_empty_lebs;
0060 if (n < c->lsave_cnt)
0061 return 1;
0062 return 0;
0063 case LPROPS_FREEABLE:
0064 return 1;
0065 case LPROPS_FRDI_IDX:
0066 return 1;
0067 }
0068 return 0;
0069 }
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083 static int scan_for_dirty_cb(struct ubifs_info *c,
0084 const struct ubifs_lprops *lprops, int in_tree,
0085 struct scan_data *data)
0086 {
0087 int ret = LPT_SCAN_CONTINUE;
0088
0089
0090 if (lprops->flags & LPROPS_TAKEN)
0091 return LPT_SCAN_CONTINUE;
0092
0093 if (!in_tree && valuable(c, lprops))
0094 ret |= LPT_SCAN_ADD;
0095
0096 if (lprops->free + lprops->dirty < data->min_space)
0097 return ret;
0098
0099 if (data->exclude_index && lprops->flags & LPROPS_INDEX)
0100 return ret;
0101
0102 if (lprops->free + lprops->dirty == c->leb_size) {
0103 if (!data->pick_free)
0104 return ret;
0105
0106 } else if (lprops->dirty < c->dead_wm)
0107 return ret;
0108
0109 data->lnum = lprops->lnum;
0110 return LPT_SCAN_ADD | LPT_SCAN_STOP;
0111 }
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124 static const struct ubifs_lprops *scan_for_dirty(struct ubifs_info *c,
0125 int min_space, int pick_free,
0126 int exclude_index)
0127 {
0128 const struct ubifs_lprops *lprops;
0129 struct ubifs_lpt_heap *heap;
0130 struct scan_data data;
0131 int err, i;
0132
0133
0134 heap = &c->lpt_heap[LPROPS_FREE - 1];
0135 for (i = 0; i < heap->cnt; i++) {
0136 lprops = heap->arr[i];
0137 if (lprops->free + lprops->dirty < min_space)
0138 continue;
0139 if (lprops->dirty < c->dead_wm)
0140 continue;
0141 return lprops;
0142 }
0143
0144
0145
0146
0147
0148
0149
0150 list_for_each_entry(lprops, &c->uncat_list, list) {
0151 if (lprops->flags & LPROPS_TAKEN)
0152 continue;
0153 if (lprops->free + lprops->dirty < min_space)
0154 continue;
0155 if (exclude_index && (lprops->flags & LPROPS_INDEX))
0156 continue;
0157 if (lprops->dirty < c->dead_wm)
0158 continue;
0159 return lprops;
0160 }
0161
0162 if (c->pnodes_have >= c->pnode_cnt)
0163
0164 return ERR_PTR(-ENOSPC);
0165 data.min_space = min_space;
0166 data.pick_free = pick_free;
0167 data.lnum = -1;
0168 data.exclude_index = exclude_index;
0169 err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum,
0170 (ubifs_lpt_scan_callback)scan_for_dirty_cb,
0171 &data);
0172 if (err)
0173 return ERR_PTR(err);
0174 ubifs_assert(c, data.lnum >= c->main_first && data.lnum < c->leb_cnt);
0175 c->lscan_lnum = data.lnum;
0176 lprops = ubifs_lpt_lookup_dirty(c, data.lnum);
0177 if (IS_ERR(lprops))
0178 return lprops;
0179 ubifs_assert(c, lprops->lnum == data.lnum);
0180 ubifs_assert(c, lprops->free + lprops->dirty >= min_space);
0181 ubifs_assert(c, lprops->dirty >= c->dead_wm ||
0182 (pick_free &&
0183 lprops->free + lprops->dirty == c->leb_size));
0184 ubifs_assert(c, !(lprops->flags & LPROPS_TAKEN));
0185 ubifs_assert(c, !exclude_index || !(lprops->flags & LPROPS_INDEX));
0186 return lprops;
0187 }
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221 int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
0222 int min_space, int pick_free)
0223 {
0224 int err = 0, sum, exclude_index = pick_free == 2 ? 1 : 0;
0225 const struct ubifs_lprops *lp = NULL, *idx_lp = NULL;
0226 struct ubifs_lpt_heap *heap, *idx_heap;
0227
0228 ubifs_get_lprops(c);
0229
0230 if (pick_free) {
0231 int lebs, rsvd_idx_lebs = 0;
0232
0233 spin_lock(&c->space_lock);
0234 lebs = c->lst.empty_lebs + c->idx_gc_cnt;
0235 lebs += c->freeable_cnt - c->lst.taken_empty_lebs;
0236
0237
0238
0239
0240
0241
0242
0243 if (c->bi.min_idx_lebs >= c->lst.idx_lebs) {
0244 rsvd_idx_lebs = c->bi.min_idx_lebs - c->lst.idx_lebs;
0245 exclude_index = 1;
0246 }
0247 spin_unlock(&c->space_lock);
0248
0249
0250 if (rsvd_idx_lebs < lebs) {
0251
0252 lp = ubifs_fast_find_empty(c);
0253 if (lp)
0254 goto found;
0255
0256
0257 lp = ubifs_fast_find_freeable(c);
0258 if (lp)
0259 goto found;
0260 } else
0261
0262
0263
0264 pick_free = 0;
0265 } else {
0266 spin_lock(&c->space_lock);
0267 exclude_index = (c->bi.min_idx_lebs >= c->lst.idx_lebs);
0268 spin_unlock(&c->space_lock);
0269 }
0270
0271
0272 heap = &c->lpt_heap[LPROPS_DIRTY - 1];
0273 idx_heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1];
0274
0275 if (idx_heap->cnt && !exclude_index) {
0276 idx_lp = idx_heap->arr[0];
0277 sum = idx_lp->free + idx_lp->dirty;
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288 if (sum < min_space || sum < c->half_leb_size)
0289 idx_lp = NULL;
0290 }
0291
0292 if (heap->cnt) {
0293 lp = heap->arr[0];
0294 if (lp->dirty + lp->free < min_space)
0295 lp = NULL;
0296 }
0297
0298
0299 if (idx_lp && lp) {
0300 if (idx_lp->free + idx_lp->dirty >= lp->free + lp->dirty)
0301 lp = idx_lp;
0302 } else if (idx_lp && !lp)
0303 lp = idx_lp;
0304
0305 if (lp) {
0306 ubifs_assert(c, lp->free + lp->dirty >= c->dead_wm);
0307 goto found;
0308 }
0309
0310
0311 dbg_find("scanning LPT for a dirty LEB");
0312 lp = scan_for_dirty(c, min_space, pick_free, exclude_index);
0313 if (IS_ERR(lp)) {
0314 err = PTR_ERR(lp);
0315 goto out;
0316 }
0317 ubifs_assert(c, lp->dirty >= c->dead_wm ||
0318 (pick_free && lp->free + lp->dirty == c->leb_size));
0319
0320 found:
0321 dbg_find("found LEB %d, free %d, dirty %d, flags %#x",
0322 lp->lnum, lp->free, lp->dirty, lp->flags);
0323
0324 lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC,
0325 lp->flags | LPROPS_TAKEN, 0);
0326 if (IS_ERR(lp)) {
0327 err = PTR_ERR(lp);
0328 goto out;
0329 }
0330
0331 memcpy(ret_lp, lp, sizeof(struct ubifs_lprops));
0332
0333 out:
0334 ubifs_release_lprops(c);
0335 return err;
0336 }
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350 static int scan_for_free_cb(struct ubifs_info *c,
0351 const struct ubifs_lprops *lprops, int in_tree,
0352 struct scan_data *data)
0353 {
0354 int ret = LPT_SCAN_CONTINUE;
0355
0356
0357 if (lprops->flags & LPROPS_TAKEN)
0358 return LPT_SCAN_CONTINUE;
0359
0360 if (!in_tree && valuable(c, lprops))
0361 ret |= LPT_SCAN_ADD;
0362
0363 if (lprops->flags & LPROPS_INDEX)
0364 return ret;
0365
0366 if (lprops->free < data->min_space)
0367 return ret;
0368
0369 if (!data->pick_free && lprops->free == c->leb_size)
0370 return ret;
0371
0372
0373
0374
0375
0376
0377 if (lprops->free + lprops->dirty == c->leb_size && lprops->dirty > 0)
0378 return ret;
0379
0380 data->lnum = lprops->lnum;
0381 return LPT_SCAN_ADD | LPT_SCAN_STOP;
0382 }
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394 static
0395 const struct ubifs_lprops *do_find_free_space(struct ubifs_info *c,
0396 int min_space, int pick_free,
0397 int squeeze)
0398 {
0399 const struct ubifs_lprops *lprops;
0400 struct ubifs_lpt_heap *heap;
0401 struct scan_data data;
0402 int err, i;
0403
0404 if (squeeze) {
0405 lprops = ubifs_fast_find_free(c);
0406 if (lprops && lprops->free >= min_space)
0407 return lprops;
0408 }
0409 if (pick_free) {
0410 lprops = ubifs_fast_find_empty(c);
0411 if (lprops)
0412 return lprops;
0413 }
0414 if (!squeeze) {
0415 lprops = ubifs_fast_find_free(c);
0416 if (lprops && lprops->free >= min_space)
0417 return lprops;
0418 }
0419
0420 heap = &c->lpt_heap[LPROPS_DIRTY - 1];
0421 for (i = 0; i < heap->cnt; i++) {
0422 lprops = heap->arr[i];
0423 if (lprops->free >= min_space)
0424 return lprops;
0425 }
0426
0427
0428
0429
0430
0431
0432
0433 list_for_each_entry(lprops, &c->uncat_list, list) {
0434 if (lprops->flags & LPROPS_TAKEN)
0435 continue;
0436 if (lprops->flags & LPROPS_INDEX)
0437 continue;
0438 if (lprops->free >= min_space)
0439 return lprops;
0440 }
0441
0442 if (c->pnodes_have >= c->pnode_cnt)
0443
0444 return ERR_PTR(-ENOSPC);
0445 data.min_space = min_space;
0446 data.pick_free = pick_free;
0447 data.lnum = -1;
0448 err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum,
0449 (ubifs_lpt_scan_callback)scan_for_free_cb,
0450 &data);
0451 if (err)
0452 return ERR_PTR(err);
0453 ubifs_assert(c, data.lnum >= c->main_first && data.lnum < c->leb_cnt);
0454 c->lscan_lnum = data.lnum;
0455 lprops = ubifs_lpt_lookup_dirty(c, data.lnum);
0456 if (IS_ERR(lprops))
0457 return lprops;
0458 ubifs_assert(c, lprops->lnum == data.lnum);
0459 ubifs_assert(c, lprops->free >= min_space);
0460 ubifs_assert(c, !(lprops->flags & LPROPS_TAKEN));
0461 ubifs_assert(c, !(lprops->flags & LPROPS_INDEX));
0462 return lprops;
0463 }
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481 int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *offs,
0482 int squeeze)
0483 {
0484 const struct ubifs_lprops *lprops;
0485 int lebs, rsvd_idx_lebs, pick_free = 0, err, lnum, flags;
0486
0487 dbg_find("min_space %d", min_space);
0488 ubifs_get_lprops(c);
0489
0490
0491 spin_lock(&c->space_lock);
0492 if (c->bi.min_idx_lebs > c->lst.idx_lebs)
0493 rsvd_idx_lebs = c->bi.min_idx_lebs - c->lst.idx_lebs;
0494 else
0495 rsvd_idx_lebs = 0;
0496 lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
0497 c->lst.taken_empty_lebs;
0498 if (rsvd_idx_lebs < lebs)
0499
0500
0501
0502
0503 if (c->lst.empty_lebs - c->lst.taken_empty_lebs > 0) {
0504 pick_free = 1;
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524 c->lst.taken_empty_lebs += 1;
0525 }
0526 spin_unlock(&c->space_lock);
0527
0528 lprops = do_find_free_space(c, min_space, pick_free, squeeze);
0529 if (IS_ERR(lprops)) {
0530 err = PTR_ERR(lprops);
0531 goto out;
0532 }
0533
0534 lnum = lprops->lnum;
0535 flags = lprops->flags | LPROPS_TAKEN;
0536
0537 lprops = ubifs_change_lp(c, lprops, LPROPS_NC, LPROPS_NC, flags, 0);
0538 if (IS_ERR(lprops)) {
0539 err = PTR_ERR(lprops);
0540 goto out;
0541 }
0542
0543 if (pick_free) {
0544 spin_lock(&c->space_lock);
0545 c->lst.taken_empty_lebs -= 1;
0546 spin_unlock(&c->space_lock);
0547 }
0548
0549 *offs = c->leb_size - lprops->free;
0550 ubifs_release_lprops(c);
0551
0552 if (*offs == 0) {
0553
0554
0555
0556
0557
0558
0559 err = ubifs_leb_unmap(c, lnum);
0560 if (err)
0561 return err;
0562 }
0563
0564 dbg_find("found LEB %d, free %d", lnum, c->leb_size - *offs);
0565 ubifs_assert(c, *offs <= c->leb_size - min_space);
0566 return lnum;
0567
0568 out:
0569 if (pick_free) {
0570 spin_lock(&c->space_lock);
0571 c->lst.taken_empty_lebs -= 1;
0572 spin_unlock(&c->space_lock);
0573 }
0574 ubifs_release_lprops(c);
0575 return err;
0576 }
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590 static int scan_for_idx_cb(struct ubifs_info *c,
0591 const struct ubifs_lprops *lprops, int in_tree,
0592 struct scan_data *data)
0593 {
0594 int ret = LPT_SCAN_CONTINUE;
0595
0596
0597 if (lprops->flags & LPROPS_TAKEN)
0598 return LPT_SCAN_CONTINUE;
0599
0600 if (!in_tree && valuable(c, lprops))
0601 ret |= LPT_SCAN_ADD;
0602
0603 if (lprops->flags & LPROPS_INDEX)
0604 return ret;
0605
0606 if (lprops->free + lprops->dirty != c->leb_size)
0607 return ret;
0608
0609
0610
0611
0612
0613 data->lnum = lprops->lnum;
0614 return LPT_SCAN_ADD | LPT_SCAN_STOP;
0615 }
0616
0617
0618
0619
0620
0621 static const struct ubifs_lprops *scan_for_leb_for_idx(struct ubifs_info *c)
0622 {
0623 const struct ubifs_lprops *lprops;
0624 struct scan_data data;
0625 int err;
0626
0627 data.lnum = -1;
0628 err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum,
0629 (ubifs_lpt_scan_callback)scan_for_idx_cb,
0630 &data);
0631 if (err)
0632 return ERR_PTR(err);
0633 ubifs_assert(c, data.lnum >= c->main_first && data.lnum < c->leb_cnt);
0634 c->lscan_lnum = data.lnum;
0635 lprops = ubifs_lpt_lookup_dirty(c, data.lnum);
0636 if (IS_ERR(lprops))
0637 return lprops;
0638 ubifs_assert(c, lprops->lnum == data.lnum);
0639 ubifs_assert(c, lprops->free + lprops->dirty == c->leb_size);
0640 ubifs_assert(c, !(lprops->flags & LPROPS_TAKEN));
0641 ubifs_assert(c, !(lprops->flags & LPROPS_INDEX));
0642 return lprops;
0643 }
0644
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661 int ubifs_find_free_leb_for_idx(struct ubifs_info *c)
0662 {
0663 const struct ubifs_lprops *lprops;
0664 int lnum = -1, err, flags;
0665
0666 ubifs_get_lprops(c);
0667
0668 lprops = ubifs_fast_find_empty(c);
0669 if (!lprops) {
0670 lprops = ubifs_fast_find_freeable(c);
0671 if (!lprops) {
0672
0673
0674
0675
0676
0677
0678
0679 if (c->in_a_category_cnt != c->main_lebs ||
0680 c->lst.empty_lebs - c->lst.taken_empty_lebs > 0) {
0681 ubifs_assert(c, c->freeable_cnt == 0);
0682 lprops = scan_for_leb_for_idx(c);
0683 if (IS_ERR(lprops)) {
0684 err = PTR_ERR(lprops);
0685 goto out;
0686 }
0687 }
0688 }
0689 }
0690
0691 if (!lprops) {
0692 err = -ENOSPC;
0693 goto out;
0694 }
0695
0696 lnum = lprops->lnum;
0697
0698 dbg_find("found LEB %d, free %d, dirty %d, flags %#x",
0699 lnum, lprops->free, lprops->dirty, lprops->flags);
0700
0701 flags = lprops->flags | LPROPS_TAKEN | LPROPS_INDEX;
0702 lprops = ubifs_change_lp(c, lprops, c->leb_size, 0, flags, 0);
0703 if (IS_ERR(lprops)) {
0704 err = PTR_ERR(lprops);
0705 goto out;
0706 }
0707
0708 ubifs_release_lprops(c);
0709
0710
0711
0712
0713
0714
0715 err = ubifs_leb_unmap(c, lnum);
0716 if (err) {
0717 ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
0718 LPROPS_TAKEN | LPROPS_INDEX, 0);
0719 return err;
0720 }
0721
0722 return lnum;
0723
0724 out:
0725 ubifs_release_lprops(c);
0726 return err;
0727 }
0728
0729 static int cmp_dirty_idx(const struct ubifs_lprops **a,
0730 const struct ubifs_lprops **b)
0731 {
0732 const struct ubifs_lprops *lpa = *a;
0733 const struct ubifs_lprops *lpb = *b;
0734
0735 return lpa->dirty + lpa->free - lpb->dirty - lpb->free;
0736 }
0737
0738
0739
0740
0741
0742
0743
0744
0745
0746 int ubifs_save_dirty_idx_lnums(struct ubifs_info *c)
0747 {
0748 int i;
0749
0750 ubifs_get_lprops(c);
0751
0752 c->dirty_idx.cnt = c->lpt_heap[LPROPS_DIRTY_IDX - 1].cnt;
0753 memcpy(c->dirty_idx.arr, c->lpt_heap[LPROPS_DIRTY_IDX - 1].arr,
0754 sizeof(void *) * c->dirty_idx.cnt);
0755
0756 sort(c->dirty_idx.arr, c->dirty_idx.cnt, sizeof(void *),
0757 (int (*)(const void *, const void *))cmp_dirty_idx, NULL);
0758 dbg_find("found %d dirty index LEBs", c->dirty_idx.cnt);
0759 if (c->dirty_idx.cnt)
0760 dbg_find("dirtiest index LEB is %d with dirty %d and free %d",
0761 c->dirty_idx.arr[c->dirty_idx.cnt - 1]->lnum,
0762 c->dirty_idx.arr[c->dirty_idx.cnt - 1]->dirty,
0763 c->dirty_idx.arr[c->dirty_idx.cnt - 1]->free);
0764
0765 for (i = 0; i < c->dirty_idx.cnt; i++)
0766 c->dirty_idx.arr[i] = (void *)(size_t)c->dirty_idx.arr[i]->lnum;
0767 ubifs_release_lprops(c);
0768 return 0;
0769 }
0770
0771
0772
0773
0774
0775
0776
0777
0778
0779
0780
0781
0782
0783 static int scan_dirty_idx_cb(struct ubifs_info *c,
0784 const struct ubifs_lprops *lprops, int in_tree,
0785 struct scan_data *data)
0786 {
0787 int ret = LPT_SCAN_CONTINUE;
0788
0789
0790 if (lprops->flags & LPROPS_TAKEN)
0791 return LPT_SCAN_CONTINUE;
0792
0793 if (!in_tree && valuable(c, lprops))
0794 ret |= LPT_SCAN_ADD;
0795
0796 if (!(lprops->flags & LPROPS_INDEX))
0797 return ret;
0798
0799 if (lprops->free + lprops->dirty < c->min_idx_node_sz)
0800 return ret;
0801
0802 data->lnum = lprops->lnum;
0803 return LPT_SCAN_ADD | LPT_SCAN_STOP;
0804 }
0805
0806
0807
0808
0809
0810
0811
0812
0813
0814
0815
0816 static int find_dirty_idx_leb(struct ubifs_info *c)
0817 {
0818 const struct ubifs_lprops *lprops;
0819 struct ubifs_lpt_heap *heap;
0820 struct scan_data data;
0821 int err, i, ret;
0822
0823
0824 data.lnum = -1;
0825 heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1];
0826 for (i = 0; i < heap->cnt; i++) {
0827 lprops = heap->arr[i];
0828 ret = scan_dirty_idx_cb(c, lprops, 1, &data);
0829 if (ret & LPT_SCAN_STOP)
0830 goto found;
0831 }
0832 list_for_each_entry(lprops, &c->frdi_idx_list, list) {
0833 ret = scan_dirty_idx_cb(c, lprops, 1, &data);
0834 if (ret & LPT_SCAN_STOP)
0835 goto found;
0836 }
0837 list_for_each_entry(lprops, &c->uncat_list, list) {
0838 ret = scan_dirty_idx_cb(c, lprops, 1, &data);
0839 if (ret & LPT_SCAN_STOP)
0840 goto found;
0841 }
0842 if (c->pnodes_have >= c->pnode_cnt)
0843
0844 return -ENOSPC;
0845 err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum,
0846 (ubifs_lpt_scan_callback)scan_dirty_idx_cb,
0847 &data);
0848 if (err)
0849 return err;
0850 found:
0851 ubifs_assert(c, data.lnum >= c->main_first && data.lnum < c->leb_cnt);
0852 c->lscan_lnum = data.lnum;
0853 lprops = ubifs_lpt_lookup_dirty(c, data.lnum);
0854 if (IS_ERR(lprops))
0855 return PTR_ERR(lprops);
0856 ubifs_assert(c, lprops->lnum == data.lnum);
0857 ubifs_assert(c, lprops->free + lprops->dirty >= c->min_idx_node_sz);
0858 ubifs_assert(c, !(lprops->flags & LPROPS_TAKEN));
0859 ubifs_assert(c, (lprops->flags & LPROPS_INDEX));
0860
0861 dbg_find("found dirty LEB %d, free %d, dirty %d, flags %#x",
0862 lprops->lnum, lprops->free, lprops->dirty, lprops->flags);
0863
0864 lprops = ubifs_change_lp(c, lprops, LPROPS_NC, LPROPS_NC,
0865 lprops->flags | LPROPS_TAKEN, 0);
0866 if (IS_ERR(lprops))
0867 return PTR_ERR(lprops);
0868
0869 return lprops->lnum;
0870 }
0871
0872
0873
0874
0875
0876 static int get_idx_gc_leb(struct ubifs_info *c)
0877 {
0878 const struct ubifs_lprops *lp;
0879 int err, lnum;
0880
0881 err = ubifs_get_idx_gc_leb(c);
0882 if (err < 0)
0883 return err;
0884 lnum = err;
0885
0886
0887
0888
0889 lp = ubifs_lpt_lookup_dirty(c, lnum);
0890 if (IS_ERR(lp))
0891 return PTR_ERR(lp);
0892 lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC,
0893 lp->flags | LPROPS_INDEX, -1);
0894 if (IS_ERR(lp))
0895 return PTR_ERR(lp);
0896 dbg_find("LEB %d, dirty %d and free %d flags %#x",
0897 lp->lnum, lp->dirty, lp->free, lp->flags);
0898 return lnum;
0899 }
0900
0901
0902
0903
0904
0905 static int find_dirtiest_idx_leb(struct ubifs_info *c)
0906 {
0907 const struct ubifs_lprops *lp;
0908 int lnum;
0909
0910 while (1) {
0911 if (!c->dirty_idx.cnt)
0912 return -ENOSPC;
0913
0914 lnum = (size_t)c->dirty_idx.arr[--c->dirty_idx.cnt];
0915 lp = ubifs_lpt_lookup(c, lnum);
0916 if (IS_ERR(lp))
0917 return PTR_ERR(lp);
0918 if ((lp->flags & LPROPS_TAKEN) || !(lp->flags & LPROPS_INDEX))
0919 continue;
0920 lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC,
0921 lp->flags | LPROPS_TAKEN, 0);
0922 if (IS_ERR(lp))
0923 return PTR_ERR(lp);
0924 break;
0925 }
0926 dbg_find("LEB %d, dirty %d and free %d flags %#x", lp->lnum, lp->dirty,
0927 lp->free, lp->flags);
0928 ubifs_assert(c, lp->flags & LPROPS_TAKEN);
0929 ubifs_assert(c, lp->flags & LPROPS_INDEX);
0930 return lnum;
0931 }
0932
0933
0934
0935
0936
0937
0938
0939
0940
0941 int ubifs_find_dirty_idx_leb(struct ubifs_info *c)
0942 {
0943 int err;
0944
0945 ubifs_get_lprops(c);
0946
0947
0948
0949
0950
0951 err = find_dirtiest_idx_leb(c);
0952
0953
0954 if (err == -ENOSPC)
0955 err = find_dirty_idx_leb(c);
0956
0957
0958 if (err == -ENOSPC)
0959 err = get_idx_gc_leb(c);
0960
0961 ubifs_release_lprops(c);
0962 return err;
0963 }