UBIFS文件系统分析6 - LPT分析1 .

LPT area - LEB Properties Tree
LPT area包含LEB properties tree, ltab: a table of LPT area eraseblocks, 以及针对big model的saved LEB number - lsave
LPT area是一个自包含的文件系统,LPT有自己的Garbage collection系统,LPT Properties Tree的实现是一棵wandering tree

LPT有两种不同的形式big model和small model,使用哪种模式由LEB Properties table的大小决定的,当整个LEB Properties table可以写入单个eraseblock中时使用small model,否则big model。对于big model,lsave被用来保存部分重要的LEB properties, 以加快超找特定LEB的速度。


LPT磁盘结构

LPT树保存在LPT area的LEB,包含两种类型的节点: pnode和nnode,pnode是LPT的叶子节点保存着LEB properties,nnode是中间节点

nnode on-flash结构如下, n为nnode的扇出数,
| CRC | node type | pcnt(仅big model) | nbranch-1 | nbranch-2 | ... | nbranch-n |
CRC:16bits, node type:4bits, pcnt 位数要能保存nnode number, nbranch-n是从该节点扇出的子节点位置参数

pnode on-flash结构如下, n为pnode的扇出数:
| CRC | node type | pcnt | lprops-1 | lprops-2 | ... | lprops-n |

nbranch on-flash结构
| LEB number | LEB offs |

lprops on-flash结构
| free | dirty | index flag |

lsave on-flash结构
| CRC | LPT type | LEB num-1 | LEB num-2 | LEB num-n |

ltab on-flash结构, m是LPT占用的LEB的数目
| CRC | LPT type | LPT LEB-1 | LPT LEB-2 | ... | LPT LEB-m |
每个LPT LEB-m 描述了LPT LEB的free和dirty大小,单位为bytes


LPT内存结构

LPT树的高度保存在ubifs_info->lpt_hght中,root nnode的level是ubifs_info->lpt_hght,child nnode level为parent level减1,最低的nnode节点level为1; pnode的level为0

struct ubifs_nnode {
    struct ubifs_nnode *parent;
    struct ubifs_cnode *cnext;
    unsigned long flags;
    int iip;
    int level;
    int num;
    struct ubifs_nbranch nbranch[UBIFS_LPT_FANOUT];
};
@parent: 父nnode节点
@cnext: 提交时这个nnode通过cnext挂到commit list中
@iip: index in parent
@level: 节点在tree中的level,对于nnode来说,level一直大于0
@num: nnode num可以唯一的标识一个nnode
@nbranch: 子节点描述符


/**
 * struct ubifs_pnode - LEB Properties Tree leaf node.
 * @parent: parent nnode
 * @cnext: next cnode to commit
 * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
 * @iip: index in parent
 * @level: level in the tree (always zero for pnodes)
 * @num: node number
 * @lprops: LEB properties array
 */
struct ubifs_pnode {
    struct ubifs_nnode *parent;
    struct ubifs_cnode *cnext;
    unsigned long flags;
    int iip;
    int level;
    int num;
    struct ubifs_lprops lprops[UBIFS_LPT_FANOUT];
};
@parent: parent nnode
@cnext: 下一个要提交的common node
@iip: index in parent
@level: node在树中的level,对于pnode来说,这个值为0
@num: node number
@lprops: LEB properties array


/**
 * struct ubifs_lprops - logical eraseblock properties.
 * @free: amount of free space in bytes
 * @dirty: amount of dirty space in bytes
 * @flags: LEB properties flags (see above)
 * @lnum: LEB number
 * @list: list of same-category lprops (for LPROPS_EMPTY and LPROPS_FREEABLE)
 * @hpos: heap position in heap of same-category lprops (other categories)
 */
struct ubifs_lprops {
    int free;
    int dirty;
    int flags;
    int lnum;
    union {
        struct list_head list;
        int hpos;
    };  
};
@free: LEB空闲空间大小
@dirty: LEB dirty空间大小
@lnum: LEB number
@list: ubifs_lprops通过list挂接到系统的uncat, freeable, empty链表

fs/ubifs/lpt.c代码分析

 958 /**
 959  * unpack_pnode - unpack a pnode.
 960  * @c: UBIFS file-system description object
 961  * @buf: buffer containing packed pnode to unpack
 962  * @pnode: pnode structure to fill
 963  *
 964  * This function returns %0 on success and a negative error code on failure.
 965  */
 966 static int unpack_pnode(const struct ubifs_info *c, void *buf,
 967             struct ubifs_pnode *pnode)
 968 {
 969     uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
 970     int i, pos = 0, err;
 971
 972     err = check_lpt_type(&addr, &pos, UBIFS_LPT_PNODE);
 973     if (err)
 974         return err;
 975     if (c->big_lpt)
 976         pnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
 977     for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
 978         struct ubifs_lprops * const lprops = &pnode->lprops[i];
 979
 980         lprops->free = ubifs_unpack_bits(&addr, &pos, c->space_bits);
 981         lprops->free <<= 3;
 982         lprops->dirty = ubifs_unpack_bits(&addr, &pos, c->space_bits);
 983         lprops->dirty <<= 3;
 984
 985         if (ubifs_unpack_bits(&addr, &pos, 1))
 986             lprops->flags = LPROPS_INDEX;
 987         else
 988             lprops->flags = 0;
 989         lprops->flags |= ubifs_categorize_lprops(c, lprops);
 990     }
 991     err = check_lpt_crc(buf, c->pnode_sz);
 992     return err;
 993 }
解析@buf中的flash pnode到内存结构中
flash上的lprops结构包含了free, dirty以及LEB的index标记
975 ~ 976 pnode number仅存在于big model
981 983之所以把读取的free和dirty乘8,是因为这两个值是8 bytes对齐的,储存的单位是8 bytes
985 ~ 988 设置index 标志
989 已知free dirty的情况下,对这个lprops进行分类

 995 /**
 996  * ubifs_unpack_nnode - unpack a nnode.
 997  * @c: UBIFS file-system description object
 998  * @buf: buffer containing packed nnode to unpack
 999  * @nnode: nnode structure to fill
1000  *
1001  * This function returns %0 on success and a negative error code on failure.
1002  */
1003 int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
1004                struct ubifs_nnode *nnode)
1005 {
1006     uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
1007     int i, pos = 0, err;
1008
1009     err = check_lpt_type(&addr, &pos, UBIFS_LPT_NNODE);
1010     if (err)
1011         return err;
1012     if (c->big_lpt)
1013         nnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
1014     for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
1015         int lnum;
1016
1017         lnum = ubifs_unpack_bits(&addr, &pos, c->lpt_lnum_bits) +
1018                c->lpt_first;
1019         if (lnum == c->lpt_last + 1)
1020             lnum = 0;
1021         nnode->nbranch[i].lnum = lnum;
1022         nnode->nbranch[i].offs = ubifs_unpack_bits(&addr, &pos,
1023                              c->lpt_offs_bits);
1024     }
1025     err = check_lpt_crc(buf, c->nnode_sz);
1026     return err;
1027 }
解析on_flash nnode结构为ubifs_nnode, @buf保存着待解析的nnode内容
1012 ~ 1013 仅仅big model,flash nnode才有nnode num, 对于small model,需要计算出来。
1014 ~ 1024 取得每一个branch的flash坐标(lnum, offs)


1029 /**
1030  * unpack_ltab - unpack the LPT's own lprops table.
1031  * @c: UBIFS file-system description object
1032  * @buf: buffer from which to unpack
1033  *
1034  * This function returns %0 on success and a negative error code on failure.
1035  */
1036 static int unpack_ltab(const struct ubifs_info *c, void *buf)
1037 {
1038     uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
1039     int i, pos = 0, err;
1040
1041     err = check_lpt_type(&addr, &pos, UBIFS_LPT_LTAB);
1042     if (err)
1043         return err;
1044     for (i = 0; i < c->lpt_lebs; i++) {
1045         int free = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
1046         int dirty = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
1047
1048         if (free < 0 || free > c->leb_size || dirty < 0 ||
1049             dirty > c->leb_size || free + dirty > c->leb_size)
1050             return -EINVAL;
1051
1052         c->ltab[i].free = free;
1053         c->ltab[i].dirty = dirty;
1054         c->ltab[i].tgc = 0;
1055         c->ltab[i].cmt = 0;
1056     }
1057     err = check_lpt_crc(buf, c->ltab_sz);
1058     return err;
1059 }
该函数解析ltab内容到ubifs_info->ltab中,每一项都对应LPT的一个LEB
@buf 保存着需要解析的ltab内容

1044 ~ 1056 把ltab每一项赋值给ubifs_info的ltab表,其中free是LPT LEB的空闲字节数,dirty是LPT LEB的dirty字节数


1187 /**
1188  * ubifs_read_nnode - read a nnode from flash and link it to the tree in memory.
1189  * @c: UBIFS file-system description object
1190  * @parent: parent nnode (or NULL for the root)
1191  * @iip: index in parent
1192  *
1193  * This function returns %0 on success and a negative error code on failure.
1194  */
1195 int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
1196 {
1197     struct ubifs_nbranch *branch = NULL;
1198     struct ubifs_nnode *nnode = NULL;
1199     void *buf = c->lpt_nod_buf;
1200     int err, lnum, offs;
1201
1202     if (parent) {
1203         branch = &parent->nbranch[iip];
1204         lnum = branch->lnum;
1205         offs = branch->offs;
1206     } else {
1207         lnum = c->lpt_lnum;
1208         offs = c->lpt_offs;
1209     }
1210     nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
1211     if (!nnode) {
1212         err = -ENOMEM;
1213         goto out;
1214     }
1215     if (lnum == 0) {
1216         /*
1217          * This nnode was not written which just means that the LEB
1218          * properties in the subtree below it describe empty LEBs. We
1219          * make the nnode as though we had read it, which in fact means
1220          * doing almost nothing.
1221          */
1222         if (c->big_lpt)
1223             nnode->num = calc_nnode_num_from_parent(c, parent, iip);
1224     } else {
1225         err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz);
1226         if (err)
1227             goto out;
1228         err = ubifs_unpack_nnode(c, buf, nnode);
1229         if (err)
1230             goto out;
1231     }
1232     err = validate_nnode(c, nnode, parent, iip);
1233     if (err)
1234         goto out;
1235     if (!c->big_lpt)
1236         nnode->num = calc_nnode_num_from_parent(c, parent, iip);
1237     if (parent) {
1238         branch->nnode = nnode;
1239         nnode->level = parent->level - 1;
1240     } else {
1241         c->nroot = nnode;
1242         nnode->level = c->lpt_hght;
1243     }
1244     nnode->parent = parent;
1245     nnode->iip = iip;
1246     return 0;
1247
1248 out:
1249     ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
1250     kfree(nnode);
1251     return err;
1252 }
这个函数读取@parent指定的nnode中第@iip个子nnode
1202 ~ 1209 如果@parent存在,那么要放问的是这个parent的第@iip个子nnode,否则说明我们要访问的是root nnode

1215 ~ 1223 如果lnum为0说明这个branch是空的,这个branch描述的LEB都是empty eraseblock

1224 ~ 1231 从flash读取nnode到buf,并解析on-flash nnode到内存nnode结构内

1235 small model并没有在on-flash上保存nnode num,需要根据@parent和iip计算出来
1237 ~ 1243 parent存在,则建立parent和这个nnode的关系,并且根据parent->level计算child nnode的leve;否则为root nnode

1254 /**
1255  * read_pnode - read a pnode from flash and link it to the tree in memory.
1256  * @c: UBIFS file-system description object
1257  * @parent: parent nnode
1258  * @iip: index in parent
1259  *
1260  * This function returns %0 on success and a negative error code on failure.
1261  */
1262 static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
1263 {
1264     struct ubifs_nbranch *branch;
1265     struct ubifs_pnode *pnode = NULL;
1266     void *buf = c->lpt_nod_buf;
1267     int err, lnum, offs;
1268
1269     branch = &parent->nbranch[iip];
1270     lnum = branch->lnum;
1271     offs = branch->offs;
1272     pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
1273     if (!pnode) {
1274         err = -ENOMEM;
1275         goto out;
1276     }
1277     if (lnum == 0) {
1278         /*
1279          * This pnode was not written which just means that the LEB
1280          * properties in it describe empty LEBs. We make the pnode as
1281          * though we had read it.
1282          */
1283         int i;
1284
1285         if (c->big_lpt)
1286             pnode->num = calc_pnode_num_from_parent(c, parent, iip);
1287         for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
1288             struct ubifs_lprops * const lprops = &pnode->lprops[i];
1289
1290             lprops->free = c->leb_size;
1291             lprops->flags = ubifs_categorize_lprops(c, lprops);
1292         }
1293     } else {
1294         err = ubi_read(c->ubi, lnum, buf, offs, c->pnode_sz);
1295         if (err)
1296             goto out;
1297         err = unpack_pnode(c, buf, pnode);
1298         if (err)
1299             goto out;
1300     }
1301     err = validate_pnode(c, pnode, parent, iip);
1302     if (err)
1303         goto out;
1304     if (!c->big_lpt)
1305         pnode->num = calc_pnode_num_from_parent(c, parent, iip);
1306     branch->pnode = pnode;
1307     pnode->parent = parent;
1308     pnode->iip = iip;
1309     set_pnode_lnum(c, pnode);
1310     c->pnodes_have += 1;
1311     return 0;
1312
1313 out:
1314     ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
1315     dbg_dump_pnode(c, pnode, parent, iip);
1316     dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
1317     kfree(pnode);
1318     return err;
1319 }

读取@parent的第@iip个子pnode,读取的pnode挂接到@parent上
1277 ~ 1292 如果lnum为0说明这个pnode还没有被写,那么它应该描述的LEB是empty,无须读取on-flash pnode,直接生成这个pnode。
1286 pnode num仅对big model的LPT有效
1291 已知了lprops的free和dirty,调用ubifs_categorize_lprops获取这个lprops的分类标志.
1293 ~ 1300 从flash读取pnode磁盘结构,然后填充到@pnode结构中去
1304 ~ 1305 对于small model来说 pnode number不是从on-flash获取,而是通过@parent和@iip计算来的
1306 ~ 1308 把pnode和parent 关联起来
1309 set_pnode_lnum 设置pnode对应leb number
1310 当前系统已经cache的pnode数目。


1321 /**
1322  * read_ltab - read LPT's own lprops table.
1323  * @c: UBIFS file-system description object
1324  *
1325  * This function returns %0 on success and a negative error code on failure.
1326  */
1327 static int read_ltab(struct ubifs_info *c)
1328 {
1329     int err;
1330     void *buf;
1331
1332     buf = vmalloc(c->ltab_sz);
1333     if (!buf)
1334         return -ENOMEM;
1335     err = ubi_read(c->ubi, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz);
1336     if (err)
1337         goto out;
1338     err = unpack_ltab(c, buf);
1339 out:
1340     vfree(buf);
1341     return err;
1342 }
读取LPT自身的lprops table,ltab放在一个LEB中,位置为ubifs_info->ltab_lnum, 偏移ubifs_info->ltab_offs, 大小为ubifs_info->ltab_sz
1335 读取ltab到buf中
1338 把on-flash ltab内容解析到ubifs_info->ltab[i]中

1344 /**
1345  * read_lsave - read LPT's save table.
1346  * @c: UBIFS file-system description object
1347  *
1348  * This function returns %0 on success and a negative error code on failure.
1349  */
1350 static int read_lsave(struct ubifs_info *c)
1351 {
1352     int err, i;
1353     void *buf;
1354
1355     buf = vmalloc(c->lsave_sz);
1356     if (!buf)
1357         return -ENOMEM;
1358     err = ubi_read(c->ubi, c->lsave_lnum, buf, c->lsave_offs, c->lsave_sz);
1359     if (err)
1360         goto out;
1361     err = unpack_lsave(c, buf);
1362     if (err)
1363         goto out;
1364     for (i = 0; i < c->lsave_cnt; i++) {
1365         int lnum = c->lsave[i];
1366
1367         /*
1368          * Due to automatic resizing, the values in the lsave table
1369          * could be beyond the volume size - just ignore them.
1370          */
1371         if (lnum >= c->leb_cnt)
1372             continue;
1373         ubifs_lpt_lookup(c, lnum);
1374     }
1375 out:
1376     vfree(buf);
1377     return err;
1378 }
读取LPT save table, lsave是用来保存比较重要的LEB,这样,执行某些操作时,就不需要扫描整个LPT查找需要的LEB属性
1355 ~ 1360 从flash上读取所有的lsave
1361 unpack_lsave 从flash lsave表中获取LEB number,存入ubifs_info->lsave
1364 ~ 1373 把lsave表中指定的LEB number对应的LEB properties读取出来


1380 /**
1381  * ubifs_get_nnode - get a nnode.
1382  * @c: UBIFS file-system description object
1383  * @parent: parent nnode (or NULL for the root)
1384  * @iip: index in parent
1385  *
1386  * This function returns a pointer to the nnode on success or a negative error
1387  * code on failure.
1388  */
1389 struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c,
1390                     struct ubifs_nnode *parent, int iip)
1391 {
1392     struct ubifs_nbranch *branch;
1393     struct ubifs_nnode *nnode;
1394     int err;
1395
1396     branch = &parent->nbranch[iip];
1397     nnode = branch->nnode;
1398     if (nnode)
1399         return nnode;
1400     err = ubifs_read_nnode(c, parent, iip);
1401     if (err)
1402         return ERR_PTR(err);
1403     return branch->nnode;
1404 }
获取@parent的第@iip个子nnode,如果这个nnode已经挂接到nbranch上,那么直接返回,否则从flash 读取这个nnode,并且把这个nnode挂接到@parent的nbranch上。


1406 /**
1407  * ubifs_get_pnode - get a pnode.
1408  * @c: UBIFS file-system description object
1409  * @parent: parent nnode
1410  * @iip: index in parent
1411  *
1412  * This function returns a pointer to the pnode on success or a negative error
1413  * code on failure.
1414  */
1415 struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
1416                     struct ubifs_nnode *parent, int iip)
1417 {
1418     struct ubifs_nbranch *branch;
1419     struct ubifs_pnode *pnode;
1420     int err;
1421
1422     branch = &parent->nbranch[iip];
1423     pnode = branch->pnode;
1424     if (pnode)
1425         return pnode;
1426     err = read_pnode(c, parent, iip);
1427     if (err)
1428         return ERR_PTR(err);
1429     update_cats(c, branch->pnode);
1430     return branch->pnode;
1431 }
获取@parent的第@iip个子节点,@parent的level是1,其子节点都是pnode
1423 ~ 1425 这个nnode的第@iip个子节点可能在之前的某次操作中已经挂到cache中,此时直接返回即可
1426 不在cache中,调用read_pnode从flash中读取
1429 把pnode的每一个lprops分类到相应的链表


1433 /**
1434  * ubifs_lpt_lookup - lookup LEB properties in the LPT.
1435  * @c: UBIFS file-system description object
1436  * @lnum: LEB number to lookup
1437  *
1438  * This function returns a pointer to the LEB properties on success or a
1439  * negative error code on failure.
1440  */
1441 struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
1442 {
1443     int err, i, h, iip, shft;
1444     struct ubifs_nnode *nnode;
1445     struct ubifs_pnode *pnode;
1446
1447     if (!c->nroot) {
1448         err = ubifs_read_nnode(c, NULL, 0);
1449         if (err)
1450             return ERR_PTR(err);
1451     }
1452     nnode = c->nroot;
1453     i = lnum - c->main_first;
1454     shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
1455     for (h = 1; h < c->lpt_hght; h++) {
1456         iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
1457         shft -= UBIFS_LPT_FANOUT_SHIFT;
1458         nnode = ubifs_get_nnode(c, nnode, iip);
1459         if (IS_ERR(nnode))
1460             return ERR_PTR(PTR_ERR(nnode));
1461     }
1462     iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
1463     shft -= UBIFS_LPT_FANOUT_SHIFT;
1464     pnode = ubifs_get_pnode(c, nnode, iip);
1465     if (IS_ERR(pnode))
1466         return ERR_PTR(PTR_ERR(pnode));
1467     iip = (i & (UBIFS_LPT_FANOUT - 1));
1468     dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
1469            pnode->lprops[iip].free, pnode->lprops[iip].dirty,
1470            pnode->lprops[iip].flags);
1471     return &pnode->lprops[iip];
1472 }
这个函数在LPT中查找@lnum指定LEB的properties结构
1477 ~ 1451 c->nroot是LPT根节点,如果根节点不存在,读取root nnode
1453 ~ 1461 在LPT树中找到要寻找pnode所在的nnode, 这个过程会在memory建立一条nnode路径
1462 ~ 1466 获取LEB properties项所在的pnode,并把这个pnode 挂到到上面建立的nnode路径上

1474 /**
1475  * dirty_cow_nnode - ensure a nnode is not being committed.
1476  * @c: UBIFS file-system description object
1477  * @nnode: nnode to check
1478  *
1479  * Returns dirtied nnode on success or negative error code on failure.
1480  */
1481 static struct ubifs_nnode *dirty_cow_nnode(struct ubifs_info *c,
1482                        struct ubifs_nnode *nnode)
1483 {
1484     struct ubifs_nnode *n;
1485     int i;
1486
1487     if (!test_bit(COW_CNODE, &nnode->flags)) {
1488         /* nnode is not being committed */
1489         if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
1490             c->dirty_nn_cnt += 1;
1491             ubifs_add_nnode_dirt(c, nnode);
1492         }
1493         return nnode;
1494     }
1495
1496     /* nnode is being committed, so copy it */
1497     n = kmalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
1498     if (unlikely(!n))
1499         return ERR_PTR(-ENOMEM);
1500
1501     memcpy(n, nnode, sizeof(struct ubifs_nnode));
1502     n->cnext = NULL;
1503     __set_bit(DIRTY_CNODE, &n->flags);
1504     __clear_bit(COW_CNODE, &n->flags);
1505
1506     /* The children now have new parent */
1507     for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
1508         struct ubifs_nbranch *branch = &n->nbranch[i];
1509
1510         if (branch->cnode)
1511             branch->cnode->parent = n;
1512     }
1513
1514     ubifs_assert(!test_bit(OBSOLETE_CNODE, &nnode->flags));
1515     __set_bit(OBSOLETE_CNODE, &nnode->flags);
1516
1517     c->dirty_nn_cnt += 1;
1518     ubifs_add_nnode_dirt(c, nnode);
1519     if (nnode->parent)
1520         nnode->parent->nbranch[n->iip].nnode = n;
1521     else
1522         c->nroot = n;
1523     return n;
1524 }
这个函数确保给定的@nnode不在commit 状态,如果@nnode正在commit,那么复制一个新的nnode取代原有的nnode

1526 /**
1527  * dirty_cow_pnode - ensure a pnode is not being committed.
1528  * @c: UBIFS file-system description object
1529  * @pnode: pnode to check
1530  *
1531  * Returns dirtied pnode on success or negative error code on failure.
1532  */
1533 static struct ubifs_pnode *dirty_cow_pnode(struct ubifs_info *c,
1534                        struct ubifs_pnode *pnode)
1535 {
1536     struct ubifs_pnode *p;
1537
1538     if (!test_bit(COW_CNODE, &pnode->flags)) {
1539         /* pnode is not being committed */
1540         if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) {
1541             c->dirty_pn_cnt += 1;
1542             add_pnode_dirt(c, pnode);
1543         }
1544         return pnode;
1545     }
1546
1547     /* pnode is being committed, so copy it */
1548     p = kmalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
1549     if (unlikely(!p))
1550         return ERR_PTR(-ENOMEM);
1551
1552     memcpy(p, pnode, sizeof(struct ubifs_pnode));
1553     p->cnext = NULL;
1554     __set_bit(DIRTY_CNODE, &p->flags);
1555     __clear_bit(COW_CNODE, &p->flags);
1556     replace_cats(c, pnode, p);
1557
1558     ubifs_assert(!test_bit(OBSOLETE_CNODE, &pnode->flags));
1559     __set_bit(OBSOLETE_CNODE, &pnode->flags);
1560
1561     c->dirty_pn_cnt += 1;
1562     add_pnode_dirt(c, pnode);
1563     pnode->parent->nbranch[p->iip].pnode = p;
1564     return p;
1565 }
这个函数确保给定的@pnode不在commit状态,如果pnode正在commit,那么复制一个新的pnode代替原有的pnode
1559 pnode正在commit并且已经被copied,所以必须在commit之后释放掉

1567 /**
1568  * ubifs_lpt_lookup_dirty - lookup LEB properties in the LPT.
1569  * @c: UBIFS file-system description object
1570  * @lnum: LEB number to lookup
1571  *
1572  * This function returns a pointer to the LEB properties on success or a
1573  * negative error code on failure.
1574  */
1575 struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
1576 {
1577     int err, i, h, iip, shft;
1578     struct ubifs_nnode *nnode;
1579     struct ubifs_pnode *pnode;
1580
1581     if (!c->nroot) {
1582         err = ubifs_read_nnode(c, NULL, 0);
1583         if (err)
1584             return ERR_PTR(err);
1585     }
1586     nnode = c->nroot;
1587     nnode = dirty_cow_nnode(c, nnode);
1588     if (IS_ERR(nnode))
1589         return ERR_PTR(PTR_ERR(nnode));
1590     i = lnum - c->main_first;
1591     shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
1592     for (h = 1; h < c->lpt_hght; h++) {
1593         iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
1594         shft -= UBIFS_LPT_FANOUT_SHIFT;
1595         nnode = ubifs_get_nnode(c, nnode, iip);
1596         if (IS_ERR(nnode))
1597             return ERR_PTR(PTR_ERR(nnode));
1598         nnode = dirty_cow_nnode(c, nnode);
1599         if (IS_ERR(nnode))
1600             return ERR_PTR(PTR_ERR(nnode));
1601     }
1602     iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
1603     shft -= UBIFS_LPT_FANOUT_SHIFT;
1604     pnode = ubifs_get_pnode(c, nnode, iip);
1605     if (IS_ERR(pnode))
1606         return ERR_PTR(PTR_ERR(pnode));
1607     pnode = dirty_cow_pnode(c, pnode);
1608     if (IS_ERR(pnode))
1609         return ERR_PTR(PTR_ERR(pnode));
1610     iip = (i & (UBIFS_LPT_FANOUT - 1));
1611     dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
1612            pnode->lprops[iip].free, pnode->lprops[iip].dirty,
1613            pnode->lprops[iip].flags);
1614     ubifs_assert(test_bit(DIRTY_CNODE, &pnode->flags));
1615     return &pnode->lprops[iip];
1616 }  
这个函数和ubifs_lpt_lookup的区别就在于,这个函数调用者将要修改@lnum对应的pnode,这也导致整个查找路径都要被修改
1587 dirty_cow_nnode 确保nnode没有被commit,否则就复制一个新的nnode,dirty_cow_nnode返回一个包含DIRTY_CNODE,COW_CNODE标志的nnode
1607 dirty_cow_pnode 同dirty_cow_nnode


1901 /**
1902  * ubifs_lpt_scan_nolock - scan the LPT.
1903  * @c: the UBIFS file-system description object
1904  * @start_lnum: LEB number from which to start scanning
1905  * @end_lnum: LEB number at which to stop scanning
1906  * @scan_cb: callback function called for each lprops
1907  * @data: data to be passed to the callback function
1908  *
1909  * This function returns %0 on success and a negative error code on failure.
1910  */
1911 int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum,
1912               ubifs_lpt_scan_callback scan_cb, void *data)
1913 {
1914     int err = 0, i, h, iip, shft;
1915     struct ubifs_nnode *nnode;
1916     struct ubifs_pnode *pnode;
1917     struct lpt_scan_node *path;
1918
1919     if (start_lnum == -1) {
1920         start_lnum = end_lnum + 1;
1921         if (start_lnum >= c->leb_cnt)
1922             start_lnum = c->main_first;
1923     }
1924
1925     ubifs_assert(start_lnum >= c->main_first && start_lnum < c->leb_cnt);
1926     ubifs_assert(end_lnum >= c->main_first && end_lnum < c->leb_cnt);
1927
1928     if (!c->nroot) {
1929         err = ubifs_read_nnode(c, NULL, 0);
1930         if (err)
1931             return err;
1932     }
1933
1934     path = kmalloc(sizeof(struct lpt_scan_node) * (c->lpt_hght + 1),
1935                GFP_NOFS);
1936     if (!path)
1937         return -ENOMEM;
1938
1939     path[0].ptr.nnode = c->nroot;
1940     path[0].in_tree = 1;
1941 again:
1942     /* Descend to the pnode containing start_lnum */
1943     nnode = c->nroot;
1944     i = start_lnum - c->main_first;
1945     shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
1946     for (h = 1; h < c->lpt_hght; h++) {
1947         iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
1948         shft -= UBIFS_LPT_FANOUT_SHIFT;
1949         nnode = scan_get_nnode(c, path + h, nnode, iip);
1950         if (IS_ERR(nnode)) {
1951             err = PTR_ERR(nnode);
1952             goto out;
1953         }
1954     }
1955     iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
1956     shft -= UBIFS_LPT_FANOUT_SHIFT;
1957     pnode = scan_get_pnode(c, path + h, nnode, iip);
1958     if (IS_ERR(pnode)) {
1959         err = PTR_ERR(pnode);
1960         goto out;
1961     }
1962     iip = (i & (UBIFS_LPT_FANOUT - 1));
1963
1964     /* Loop for each lprops */
1965     while (1) {
1966         struct ubifs_lprops *lprops = &pnode->lprops[iip];
1967         int ret, lnum = lprops->lnum;
1968
1969         ret = scan_cb(c, lprops, path[h].in_tree, data);
1970         if (ret < 0) {
1971             err = ret;
1972             goto out;
1973         }
1974         if (ret & LPT_SCAN_ADD) {
1975             /* Add all the nodes in path to the tree in memory */
1976             for (h = 1; h < c->lpt_hght; h++) {
1977                 const size_t sz = sizeof(struct ubifs_nnode);
1978                 struct ubifs_nnode *parent;
1979
1980                 if (path[h].in_tree)
1981                     continue;
1982                 nnode = kmalloc(sz, GFP_NOFS);
1983                 if (!nnode) {
1984                     err = -ENOMEM;
1985                     goto out;
1986                 }
1987                 memcpy(nnode, &path[h].nnode, sz);
1988                 parent = nnode->parent;
1989                 parent->nbranch[nnode->iip].nnode = nnode;
1990                 path[h].ptr.nnode = nnode;
1991                 path[h].in_tree = 1;
1992                 path[h + 1].cnode.parent = nnode;
1993             }
1994             if (path[h].in_tree)
1995                 ubifs_ensure_cat(c, lprops);
1996             else {
1997                 const size_t sz = sizeof(struct ubifs_pnode);
1998                 struct ubifs_nnode *parent;
1999
2000                 pnode = kmalloc(sz, GFP_NOFS);
2001                 if (!pnode) {
2002                     err = -ENOMEM;
2003                     goto out;
2004                 }
2005                 memcpy(pnode, &path[h].pnode, sz);
2006                 parent = pnode->parent;
2007                 parent->nbranch[pnode->iip].pnode = pnode;
2008                 path[h].ptr.pnode = pnode;
2009                 path[h].in_tree = 1;
2010                 update_cats(c, pnode);
2011                 c->pnodes_have += 1;
2012             }
2013             err = dbg_check_lpt_nodes(c, (struct ubifs_cnode *)
2014                           c->nroot, 0, 0);
2015             if (err)
2016                 goto out;
2017             err = dbg_check_cats(c);
2018             if (err)
2019                 goto out;
2020         }
2021         if (ret & LPT_SCAN_STOP) {
2022             err = 0;
2023             break;
2024         }
2025         /* Get the next lprops */
2026         if (lnum == end_lnum) {
2027             /*
2028              * We got to the end without finding what we were
2029              * looking for
2030              */
2031             err = -ENOSPC;
2032             goto out;
2033         }
2034         if (lnum + 1 >= c->leb_cnt) {
2035             /* Wrap-around to the beginning */
2036             start_lnum = c->main_first;
2037             goto again;
2038         }
2039         if (iip + 1 < UBIFS_LPT_FANOUT) {
2040             /* Next lprops is in the same pnode */
2041             iip += 1;
2042             continue;
2043         }
2044         /* We need to get the next pnode. Go up until we can go right */
2045         iip = pnode->iip;
2046         while (1) {
2047             h -= 1;
2048             ubifs_assert(h >= 0);
2049             nnode = path[h].ptr.nnode;
2050             if (iip + 1 < UBIFS_LPT_FANOUT)
2051                 break;
2052             iip = nnode->iip;
2053         }
2054         /* Go right */
2055         iip += 1;
2056         /* Descend to the pnode */
2057         h += 1;
2058         for (; h < c->lpt_hght; h++) {
2059             nnode = scan_get_nnode(c, path + h, nnode, iip);
2060             if (IS_ERR(nnode)) {
2061                 err = PTR_ERR(nnode);
2062                 goto out;
2063             }
2064             iip = 0;
2065         }
2066         pnode = scan_get_pnode(c, path + h, nnode, iip);
2067         if (IS_ERR(pnode)) {
2068             err = PTR_ERR(pnode);
2069             goto out;
2070         }
2071         iip = 0;
2072     }
2073 out:
2074     kfree(path);
2075     return err;
2076 }
该函数扫描给定范围内的lprops,对每一个lprops调用@scan_cb,扫描范围由@start_lnum和@end_lnum指定
1943 ~ 1954 生成起始LEB lprops对应的nnode路径
1955 ~ 1961 取得起始lprops 所在的pnode
1965 ~2072 从起始的lprops开始,遍历每一个lprops,注意范围(@start_lnum,@end_lnum)的@end_lnum可能小于@start_lnum,因此需要wrap-around 到LPT tree的前面
1969 调用参数@scan_cb指定的callback
1974 ~ 2020 如果scan_cb返回的参数是LPT_SCAN_ADD,那么说明需要把整条路径都cache起来
1976 ~ 1993 复制路径上的nnode, 除了root nnode
1994 ~ 2012 如果pnode已经在cache tree中,那么只需确保lprops已经分类即可;否则复制pnode,并加到路径上
2021 ~ 2024 scan_cb返回值要求停止scan
2026 ~ 2033 没有找到符合条件的lprops,退出
2034 ~ 2038 已经到了系统最后一个LEB,说明end_lnum 小于start_lnum,那么wrapped 到系统前面的LEB
2044 ~ 2065 建立下一个lprops所在路径的nnodes
2066 获取下一个lprops所在的pnode,返回1965行,继续查找过程


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值