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行,继续查找过程