UBIFS文件系统分析7 - LPROPS

fs/ubifs/lprops.c


lprops结构包含着一个list成员,类型是list_head,通过这个成员lprops链接到ubifs_info的freeable_list, frdi_idx_list, empty_list, uncat_list;
如果lprops类型为LPROPS_DIRTY, LPROPS_FREE, LPROPS_DIRTY_IDX,lprops则由heap管理
heap是一个二叉树,并且二叉树的大小是有限制的,当这个二叉树已满的时候,向二叉树插入新的lprops时,会随机在二叉树最底层找一个节点执行替换,如果待插入lprops的值小于随机节点,那么取消插入操作;否则执行插入操作,并把随机节点链入LPROPS_UNCAT链表


  50 /**
  51  * move_up_lpt_heap - move a new heap entry up as far as possible.
  52  * @c: UBIFS file-system description object
  53  * @heap: LEB category heap
  54  * @lprops: LEB properties to move
  55  * @cat: LEB category
  56  *
  57  * New entries to a heap are added at the bottom and then moved up until the
  58  * parent's value is greater.  In the case of LPT's category heaps, the value
  59  * is either the amount of free space or the amount of dirty space, depending
  60  * on the category.
  61  */
  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 }
新增加的heap entry最初都放在heap的最底部,通过move_up_lpt_heap向上移动直到合适的位置
合适的位置是指@lprops的值小于parent的值


  87 /**
  88  * adjust_lpt_heap - move a changed heap entry up or down the heap.
  89  * @c: UBIFS file-system description object
  90  * @heap: LEB category heap
  91  * @lprops: LEB properties to move
  92  * @hpos: heap position of @lprops
  93  * @cat: LEB category
  94  *
  95  * Changed entries in a heap are moved up or down until the parent's value is
  96  * greater.  In the case of LPT's category heaps, the value is either the amount
  97  * of free space or the amount of dirty space, depending on the category.
  98  */
  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 }
改变@lprops在heap中的位置,@hpos是当前的位置,@cat是heap类别
heap是一棵二叉树,父节点的值大于两个子节点,这个值是free,dirty或者free+dirty,具体使用哪个值与heap的类型相关
如果@lprops的值大于父节点,那么把这个节点和父节点互换,直到小于父节点为止;如果小于左右子节点,那么和最大的子节点互换



 169 /**
 170  * add_to_lpt_heap - add LEB properties to a LEB category heap.
 171  * @c: UBIFS file-system description object
 172  * @lprops: LEB properties to add
 173  * @cat: LEB category
 174  *
 175  * This function returns %1 if @lprops is added to the heap for LEB category
 176  * @cat, otherwise %0 is returned because the heap is full.
 177  */
 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 }
add_to_lpt_heap是可能失败的,比如heap已经满了,并且要加入的lprops不满足替换heap中其他lprops的条件.
183 ~ 210
211 ~ 217 heap还有空间,把lprops加到heap的最后,并调用move_up_lpt_head调整这个lprops的位置

 220 /**
 221  * remove_from_lpt_heap - remove LEB properties from a LEB category heap.
 222  * @c: UBIFS file-system description object
 223  * @lprops: LEB properties to remove
 224  * @cat: LEB category
 225  */
 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 }
从heap中移除@lprops,@cat指定heap的类型
235 heap->cnt是heap中包含的lprops数目
236 ~ 240 从heap中删除一个lprops后,需要调整heap中的其他项的位置,以符合heap的排序标准

 244 /**
 245  * lpt_heap_replace - replace lprops in a category heap.
 246  * @c: UBIFS file-system description object
 247  * @old_lprops: LEB properties to replace
 248  * @new_lprops: LEB properties with which to replace
 249  * @cat: LEB category
 250  *
 251  * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
 252  * and the lprops that the pnode contains.  When that happens, references in
 253  * the category heaps to those lprops must be updated to point to the new
 254  * lprops.  This function does that.
 255  */
 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 }
替换heap中old_lprops为new_lprops,因为new_lprops是old_lprops 经过dirty_cow_pnode得到的lprops,所以二者除了内存地址不同外,内容完全相同
因此old_lprops参数在这里并没有用到

 267 /**
 268  * ubifs_add_to_cat - add LEB properties to a category list or heap.
 269  * @c: UBIFS file-system description object
 270  * @lprops: LEB properties to add
 271  * @cat: LEB category to which to add
 272  *
 273  * LEB properties are categorized to enable fast find operations.
 274  */
 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     lprops->flags &= ~LPROPS_CAT_MASK;
 304     lprops->flags |= cat;
 305 }
282 ~ 286 add_to_lpt_heap并不总是成功的,在heap已满的情况下,如果新加的@lprops和heap中原有的lprops相比优先级低
则加入失败,这个@lprops会被加入到UNCAT list
295 c->freeable_cnt 描述的是c->freeable_list的长度

 307 /**
 308  * ubifs_remove_from_cat - remove LEB properties from a category list or heap.
 309  * @c: UBIFS file-system description object
 310  * @lprops: LEB properties to remove
 311  * @cat: LEB category from which to remove
 312  *
 313  * LEB properties are categorized to enable fast find operations.
 314  */
 315 static void ubifs_remove_from_cat(struct ubifs_info *c,
 316                   struct ubifs_lprops *lprops, int cat)
 317 {
 318     switch (cat) {
 319     case LPROPS_DIRTY:
 320     case LPROPS_DIRTY_IDX:
 321     case LPROPS_FREE:
 322         remove_from_lpt_heap(c, lprops, cat);
 323         break;
 324     case LPROPS_FREEABLE:
 325         c->freeable_cnt -= 1;
 326         ubifs_assert(c->freeable_cnt >= 0);
 327         /* Fall through */
 328     case LPROPS_UNCAT:
 329     case LPROPS_EMPTY:
 330     case LPROPS_FRDI_IDX:
 331         ubifs_assert(!list_empty(&lprops->list));
 332         list_del(&lprops->list);
 333         break;
 334     default:
 335         ubifs_assert(0);
 336     }
 337 }
根据给定的@cat类型,从heap或list中删除lprops项


 339 /**
 340  * ubifs_replace_cat - replace lprops in a category list or heap.
 341  * @c: UBIFS file-system description object
 342  * @old_lprops: LEB properties to replace
 343  * @new_lprops: LEB properties with which to replace
 344  *
 345  * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
 346  * and the lprops that the pnode contains. When that happens, references in
 347  * category lists and heaps must be replaced. This function does that.
 348  */
 349 void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
 350                struct ubifs_lprops *new_lprops)
 351 {
 352     int cat;
 353
 354     cat = new_lprops->flags & LPROPS_CAT_MASK;
 355     switch (cat) {
 356     case LPROPS_DIRTY:
 357     case LPROPS_DIRTY_IDX:
 358     case LPROPS_FREE:
 359         lpt_heap_replace(c, old_lprops, new_lprops, cat);
 360         break;
 361     case LPROPS_UNCAT:
 362     case LPROPS_EMPTY:
 363     case LPROPS_FREEABLE:
 364     case LPROPS_FRDI_IDX:
 365         list_replace(&old_lprops->list, &new_lprops->list);
 366         break;
 367     default:
 368         ubifs_assert(0);
 369     }
 370 }
当dirty_cow_pnode发生时,heap和lprops list中保存的地址还是旧的lprops地址,通过ubifs_replace_cat做替换
359 替换heap, old_lprops实际并没有起到作用
365 替换相应的list


 372 /**
 373  * ubifs_ensure_cat - ensure LEB properties are categorized.
 374  * @c: UBIFS file-system description object
 375  * @lprops: LEB properties
 376  *
 377  * A LEB may have fallen off of the bottom of a heap, and ended up as
 378  * un-categorized even though it has enough space for us now. If that is the
 379  * case this function will put the LEB back onto a heap.
 380  */
 381 void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops)
 382 {
 383     int cat = lprops->flags & LPROPS_CAT_MASK;
 384
 385     if (cat != LPROPS_UNCAT)
 386         return;
 387     cat = ubifs_categorize_lprops(c, lprops);
 388     if (cat == LPROPS_UNCAT)
 389         return;
 390     ubifs_remove_from_cat(c, lprops, LPROPS_UNCAT);
 391     ubifs_add_to_cat(c, lprops, cat);
 392 }
在正常情况下,一个LEB properties可能会被挤出heap,
比如调用ubifs_add_to_cat时heap已经达到最大值,此时一个lprops被挤出heap,category类型也会被设置为LPROPS_UNCAT,并加入LPROS_UNCAT.
390 从LPROPS_UNCAT移除
391 加到相应的分类中


 394 /**
 395  * ubifs_categorize_lprops - categorize LEB properties.
 396  * @c: UBIFS file-system description object
 397  * @lprops: LEB properties to categorize
 398  *
 399  * LEB properties are categorized to enable fast find operations. This function
 400  * returns the LEB category to which the LEB properties belong. Note however
 401  * that if the LEB category is stored as a heap and the heap is full, the
 402  * LEB properties may have their category changed to %LPROPS_UNCAT.
 403  */
 404 int ubifs_categorize_lprops(const struct ubifs_info *c,
 405                 const struct ubifs_lprops *lprops)
 406 {
 407     if (lprops->flags & LPROPS_TAKEN)
 408         return LPROPS_UNCAT;
 409
 410     if (lprops->free == c->leb_size) {
 411         ubifs_assert(!(lprops->flags & LPROPS_INDEX));
 412         return LPROPS_EMPTY;
 413     }
 414
 415     if (lprops->free + lprops->dirty == c->leb_size) {
 416         if (lprops->flags & LPROPS_INDEX)
 417             return LPROPS_FRDI_IDX;
 418         else
 419             return LPROPS_FREEABLE;
 420     }
 421
 422     if (lprops->flags & LPROPS_INDEX) {
 423         if (lprops->dirty + lprops->free >= c->min_idx_node_sz)
 424             return LPROPS_DIRTY_IDX;
 425     } else {
 426         if (lprops->dirty >= c->dead_wm &&
 427             lprops->dirty > lprops->free)
 428             return LPROPS_DIRTY;
 429         if (lprops->free > 0)
 430             return LPROPS_FREE;
 431     }
 432
 433     return LPROPS_UNCAT;
 434 }
获取给定@lprops描述的LEB properties分类
410 ~ 413 如果free正好等于LEB 尺寸,那么类型为LPROPS_EMPTY,此时不可能为LPROPS_INDEX
415 ~ 420 如果free加dirty正好等于LEB大小,那么根据LPRPOS_INDEX,分别对应LPROPS_FRDI_IDX
421 LEB除了free和dirty外还有其他空间,比如dark dead
422 ~ 424 Index LEB并且dirty和free空间之和大于最小index node size,分类为LPROPS_DIRTY_IDX
425 ~ 428 not index, not empty, dirty > c->dead_wm && dirty > free
429 ~ 420 not index, not empty, dirty < c->dead_wm || dirty < free, free > 0

 436 /**
 437  * change_category - change LEB properties category.
 438  * @c: UBIFS file-system description object
 439  * @lprops: LEB properties to re-categorize
 440  *
 441  * LEB properties are categorized to enable fast find operations. When the LEB
 442  * properties change they must be re-categorized.
 443  */
 444 static void change_category(struct ubifs_info *c, struct ubifs_lprops *lprops)
 445 {
 446     int old_cat = lprops->flags & LPROPS_CAT_MASK;
 447     int new_cat = ubifs_categorize_lprops(c, lprops);
 448
 449     if (old_cat == new_cat) {
 450         struct ubifs_lpt_heap *heap = &c->lpt_heap[new_cat - 1];
 451
 452         /* lprops on a heap now must be moved up or down */
 453         if (new_cat < 1 || new_cat > LPROPS_HEAP_CNT)
 454             return; /* Not on a heap */
 455         heap = &c->lpt_heap[new_cat - 1];
 456         adjust_lpt_heap(c, heap, lprops, lprops->hpos, new_cat);
 457     } else {
 458         ubifs_remove_from_cat(c, lprops, old_cat);
 459         ubifs_add_to_cat(c, lprops, new_cat);
 460     }
 461 }
449 ~ 456 如果并没有引起category的改变,那么需要调整在heap中的位置, 因为free 或者dirty space已经发生了变化
457 ~ 460 从category中删除这个lprops,再加入到category中


 493 /**
 494  * is_lprops_dirty - determine if LEB properties are dirty.
 495  * @c: the UBIFS file-system description object
 496  * @lprops: LEB properties to test
 497  */
 498 static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
 499 {
 500     struct ubifs_pnode *pnode;
 501     int pos;
 502     
 503     pos = (lprops->lnum - c->main_first) & (UBIFS_LPT_FANOUT - 1);
 504     pnode = (struct ubifs_pnode *)container_of(lprops - pos,
 505                            struct ubifs_pnode,
 506                            lprops[0]);
 507     return !test_bit(COW_ZNODE, &pnode->flags) &&
 508            test_bit(DIRTY_CNODE, &pnode->flags);
 509 }
判断LEB properties是否为dirty,一个lprops是否为dirty是通过查看这个lprops所在的pnode来判断的
503 ~ 504找到这个lprops所在的pnode
507 所在pnode为DIRTY则lprops也为DIRTY

 511 /**
 512  * ubifs_change_lp - change LEB properties.
 513  * @c: the UBIFS file-system description object
 514  * @lp: LEB properties to change
 515  * @free: new free space amount
 516  * @dirty: new dirty space amount
 517  * @flags: new flags
 518  * @idx_gc_cnt: change to the count of @idx_gc list
 519  *
 520  * This function changes LEB properties (@free, @dirty or @flag). However, the
 521  * property which has the %LPROPS_NC value is not changed. Returns a pointer to
 522  * the updated LEB properties on success and a negative error code on failure.
 523  *
 524  * Note, the LEB properties may have had to be copied (due to COW) and
 525  * consequently the pointer returned may not be the same as the pointer
 526  * passed.
 527  */
 528 const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
 529                        const struct ubifs_lprops *lp,
 530                        int free, int dirty, int flags,
 531                        int idx_gc_cnt)
 532 {
 533     /*
 534      * This is the only function that is allowed to change lprops, so we
 535      * discard the "const" qualifier.
 536      */
 537     struct ubifs_lprops *lprops = (struct ubifs_lprops *)lp;
 538
 539     dbg_lp("LEB %d, free %d, dirty %d, flags %d",
 540            lprops->lnum, free, dirty, flags);
 541
 542     ubifs_assert(mutex_is_locked(&c->lp_mutex));
 543     ubifs_assert(c->lst.empty_lebs >= 0 &&
 544              c->lst.empty_lebs <= c->main_lebs);
 545     ubifs_assert(c->freeable_cnt >= 0);
 546     ubifs_assert(c->freeable_cnt <= c->main_lebs);
 547     ubifs_assert(c->lst.taken_empty_lebs >= 0);
 548     ubifs_assert(c->lst.taken_empty_lebs <= c->lst.empty_lebs);
 549     ubifs_assert(!(c->lst.total_free & 7) && !(c->lst.total_dirty & 7));
 550     ubifs_assert(!(c->lst.total_dead & 7) && !(c->lst.total_dark & 7));
 551     ubifs_assert(!(c->lst.total_used & 7));
 552     ubifs_assert(free == LPROPS_NC || free >= 0);
 553     ubifs_assert(dirty == LPROPS_NC || dirty >= 0);
 554
 555     if (!is_lprops_dirty(c, lprops)) {
 556         lprops = ubifs_lpt_lookup_dirty(c, lprops->lnum);
 557         if (IS_ERR(lprops))
 558             return lprops;
 559     } else
 560         ubifs_assert(lprops == ubifs_lpt_lookup_dirty(c, lprops->lnum));
 561
 562     ubifs_assert(!(lprops->free & 7) && !(lprops->dirty & 7));
 563
 564     spin_lock(&c->space_lock);
 565     if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
 566         c->lst.taken_empty_lebs -= 1;
 567
 568     if (!(lprops->flags & LPROPS_INDEX)) {
 569         int old_spc;
 570
 571         old_spc = lprops->free + lprops->dirty;
 572         if (old_spc < c->dead_wm)
 573             c->lst.total_dead -= old_spc;
 574         else
 575             c->lst.total_dark -= ubifs_calc_dark(c, old_spc);
 576
 577         c->lst.total_used -= c->leb_size - old_spc;
 578     }
 579
 580     if (free != LPROPS_NC) {
 581         free = ALIGN(free, 8);
 582         c->lst.total_free += free - lprops->free;
 583
 584         /* Increase or decrease empty LEBs counter if needed */
 585         if (free == c->leb_size) {
 586             if (lprops->free != c->leb_size)
 587                 c->lst.empty_lebs += 1;
 588         } else if (lprops->free == c->leb_size)
 589             c->lst.empty_lebs -= 1;
 590         lprops->free = free;
 591     }
 592
 593     if (dirty != LPROPS_NC) {
 594         dirty = ALIGN(dirty, 8);
 595         c->lst.total_dirty += dirty - lprops->dirty;
 596         lprops->dirty = dirty;
 597     }
 598
 599     if (flags != LPROPS_NC) {
 600         /* Take care about indexing LEBs counter if needed */
 601         if ((lprops->flags & LPROPS_INDEX)) {
 602             if (!(flags & LPROPS_INDEX))
 603                 c->lst.idx_lebs -= 1;
 604         } else if (flags & LPROPS_INDEX)
 605             c->lst.idx_lebs += 1;
 606         lprops->flags = flags;
 607     }
 608
 609     if (!(lprops->flags & LPROPS_INDEX)) {
 610         int new_spc;
 611
 612         new_spc = lprops->free + lprops->dirty;
 613         if (new_spc < c->dead_wm)
 614             c->lst.total_dead += new_spc;
 615         else
 616             c->lst.total_dark += ubifs_calc_dark(c, new_spc);
 617
 618         c->lst.total_used += c->leb_size - new_spc;
 619     }
 620
 621     if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
 622         c->lst.taken_empty_lebs += 1;
 623
 624     change_category(c, lprops);
 625     c->idx_gc_cnt += idx_gc_cnt;
 626     spin_unlock(&c->space_lock);
 627     return lprops;
 628 }

555 ~ 560 确保这个lprops是dirty的,否则调用ubifs_lpt_lookup_dirty dirty整条查找路径
560 如果是dirty的,那么ubifs_lpt_lookup_dirty返回的地址必然等于lprops
568 ~ 578 首先把total_dead total_dark和total_used减去原始LEB所占的份额,将来还会用更改过的空间加回来,这三个统计值都仅对非index节点有效
dead 是指free和dirty的部分小于dead_wm(最小的写单位),导致这部分区域无法使用
dark 则是系统内的dirty space小于最大的node size的空间大小,因此最坏的情况下,dark space无法回收。
used 使用的空间
580 ~ 591 重新计算total_free,以及empty_lebs,最后更新lprops本身的free space
lst.total_free 系统内的free space(包含index LEBs)
lst.empty_lebs 是指系统内的空闲LEB数目
593 ~ 597 重新计算lst.total_dirty
599 ~ 607 如果LEB的INDEX标记发生了变化,那么更新lst.idx_lebs
609 ~ 619 已经更新了lprops->dirty和lprops->free,现在重新计算total_dead total_dark total_used
624 LEB的free, dirty已经发生变化,需要更新LEB properties的分类

 642 /**
 643  * ubifs_change_one_lp - change LEB properties.
 644  * @c: the UBIFS file-system description object
 645  * @lnum: LEB to change properties for
 646  * @free: amount of free space
 647  * @dirty: amount of dirty space
 648  * @flags_set: flags to set
 649  * @flags_clean: flags to clean
 650  * @idx_gc_cnt: change to the count of idx_gc list
 651  *
 652  * This function changes properties of LEB @lnum. It is a helper wrapper over
 653  * 'ubifs_change_lp()' which hides lprops get/release. The arguments are the
 654  * same as in case of 'ubifs_change_lp()'. Returns zero in case of success and
 655  * a negative error code in case of failure.
 656  */
 657 int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
 658             int flags_set, int flags_clean, int idx_gc_cnt)
 659 {
 660     int err = 0, flags;
 661     const struct ubifs_lprops *lp;
 662
 663     ubifs_get_lprops(c);
 664
 665     lp = ubifs_lpt_lookup_dirty(c, lnum);
 666     if (IS_ERR(lp)) {
 667         err = PTR_ERR(lp);
 668         goto out;
 669     }
 670
 671     flags = (lp->flags | flags_set) & ~flags_clean;
 672     lp = ubifs_change_lp(c, lp, free, dirty, flags, idx_gc_cnt);
 673     if (IS_ERR(lp))
 674         err = PTR_ERR(lp);
 675
 676 out:
 677     ubifs_release_lprops(c);
 678     if (err)
 679         ubifs_err("cannot change properties of LEB %d, error %d",
 680               lnum, err);
 681     return err;
 682 }
ubifs_change_one_lp和ubifs_update_lp的区别就是前者直接用@dirty替换当前的dirty space,而后者则加到当前的dirty space
这个函数仅仅是对ubifs_change_lp的包装,使得ubifs_change_lp不需要考虑lprops get/release

 684 /**
 685  * ubifs_update_one_lp - update LEB properties.
 686  * @c: the UBIFS file-system description object
 687  * @lnum: LEB to change properties for
 688  * @free: amount of free space
 689  * @dirty: amount of dirty space to add
 690  * @flags_set: flags to set
 691  * @flags_clean: flags to clean
 692  *
 693  * This function is the same as 'ubifs_change_one_lp()' but @dirty is added to
 694  * current dirty space, not substitutes it.
 695  */
 696 int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
 697             int flags_set, int flags_clean)
 698 {   
 699     int err = 0, flags;
 700     const struct ubifs_lprops *lp;
 701             
 702     ubifs_get_lprops(c);
 703     
 704     lp = ubifs_lpt_lookup_dirty(c, lnum);
 705     if (IS_ERR(lp)) {
 706         err = PTR_ERR(lp);
 707         goto out;
 708     }   
 709         
 710     flags = (lp->flags | flags_set) & ~flags_clean;
 711     lp = ubifs_change_lp(c, lp, free, lp->dirty + dirty, flags, 0);
 712     if (IS_ERR(lp))
 713         err = PTR_ERR(lp);
 714     
 715 out:
 716     ubifs_release_lprops(c);
 717     if (err)
 718         ubifs_err("cannot update properties of LEB %d, error %d",
 719               lnum, err);
 720     return err;
 721 }
704调用ubifs_lpt_lookup_dirty获取lp,使得lp标记为dirty,ubifs_lpt_lookup_dirty还保证返回的lp没有处于commit状态。
711 调用ubifs_change_lp修改LEB properties

 723 /**
 724  * ubifs_read_one_lp - read LEB properties.
 725  * @c: the UBIFS file-system description object
 726  * @lnum: LEB to read properties for
 727  * @lp: where to store read properties
 728  *
 729  * This helper function reads properties of a LEB @lnum and stores them in @lp.
 730  * Returns zero in case of success and a negative error code in case of
 731  * failure.
 732  */
 733 int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp)
 734 {
 735     int err = 0;
 736     const struct ubifs_lprops *lpp;
 737
 738     ubifs_get_lprops(c);
 739
 740     lpp = ubifs_lpt_lookup(c, lnum);
 741     if (IS_ERR(lpp)) {
 742         err = PTR_ERR(lpp);
 743         ubifs_err("cannot read properties of LEB %d, error %d",
 744               lnum, err);
 745         goto out;
 746     }
 747
 748     memcpy(lp, lpp, sizeof(struct ubifs_lprops));
 749
 750 out:
 751     ubifs_release_lprops(c);
 752     return err;
 753 }
读取@lnum指定LEB的lprops,结果复制到@lp中

 755 /**
 756  * ubifs_fast_find_free - try to find a LEB with free space quickly.
 757  * @c: the UBIFS file-system description object
 758  *
 759  * This function returns LEB properties for a LEB with free space or %NULL if
 760  * the function is unable to find a LEB quickly.
 761  */
 762 const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c)
 763 {
 764     struct ubifs_lprops *lprops;
 765     struct ubifs_lpt_heap *heap;
 766
 767     ubifs_assert(mutex_is_locked(&c->lp_mutex));
 768
 769     heap = &c->lpt_heap[LPROPS_FREE - 1];
 770     if (heap->cnt == 0)
 771         return NULL;
 772
 773     lprops = heap->arr[0];
 774     ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
 775     ubifs_assert(!(lprops->flags & LPROPS_INDEX));
 776     return lprops;
 777 }
ubifs_info->lpt_heap[LPROPS_FREE - 1]包含LPROPS_FREE的LEBs
LPROPS_FREE和LPROPS_FREEABLE是不同的,前者是必须有dead space,后者则没有dead space,ubifs_categorize_lprops函数可以看出
他们的区别


 779 /**
 780  * ubifs_fast_find_empty - try to find an empty LEB quickly.
 781  * @c: the UBIFS file-system description object
 782  *
 783  * This function returns LEB properties for an empty LEB or %NULL if the
 784  * function is unable to find an empty LEB quickly.
 785  */
 786 const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c)
 787 {
 788     struct ubifs_lprops *lprops;
 789
 790     ubifs_assert(mutex_is_locked(&c->lp_mutex));
 791
 792     if (list_empty(&c->empty_list))
 793         return NULL;
 794
 795     lprops = list_entry(c->empty_list.next, struct ubifs_lprops, list);
 796     ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
 797     ubifs_assert(!(lprops->flags & LPROPS_INDEX));
 798     ubifs_assert(lprops->free == c->leb_size);
 799     return lprops;
 800 }
ubifs_info->empty_list是系统empty LEBs list
empty LEB应该是free 空间等于leb_size,并且不应该有LPROPS_INDEX标记

 802 /**
 803  * ubifs_fast_find_freeable - try to find a freeable LEB quickly.
 804  * @c: the UBIFS file-system description object
 805  *
 806  * This function returns LEB properties for a freeable LEB or %NULL if the
 807  * function is unable to find a freeable LEB quickly.
 808  */
 809 const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c)
 810 {
 811     struct ubifs_lprops *lprops;
 812
 813     ubifs_assert(mutex_is_locked(&c->lp_mutex));
 814
 815     if (list_empty(&c->freeable_list))
 816         return NULL;
 817
 818     lprops = list_entry(c->freeable_list.next, struct ubifs_lprops, list);
 819     ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
 820     ubifs_assert(!(lprops->flags & LPROPS_INDEX));
 821     ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
 822     ubifs_assert(c->freeable_cnt > 0);
 823     return lprops;
 824 }
ubifs->freeable_list 是系统freeable LEBs list
ubifs->freeable_cnt 应该等于freeable_list的长度,也就是freeable LEBs的数目


 826 /**
 827  * ubifs_fast_find_frdi_idx - try to find a freeable index LEB quickly.
 828  * @c: the UBIFS file-system description object
 829  *
 830  * This function returns LEB properties for a freeable index LEB or %NULL if the
 831  * function is unable to find a freeable index LEB quickly.
 832  */
 833 const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c)
 834 {
 835     struct ubifs_lprops *lprops;
 836
 837     ubifs_assert(mutex_is_locked(&c->lp_mutex));
 838
 839     if (list_empty(&c->frdi_idx_list))
 840         return NULL;
 841
 842     lprops = list_entry(c->frdi_idx_list.next, struct ubifs_lprops, list);
 843     ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
 844     ubifs_assert((lprops->flags & LPROPS_INDEX));
 845     ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
 846     return lprops;
 847 }

ubifs_info->frdi_idx_list freeable index LEBs list
frdi_idx_list保存着系统内所有空闲index LEBS lprops

你可能感兴趣的:(嵌入式Linux,Linux,Kernel)