spacepaste

  1.  
  2. commit 18076aac0276719f1476f5371d942328a6483a1b (HEAD -> master)
  3. Author: Luke Dashjr <luke-jr+git@utopios.org>
  4. Date: Sat Aug 25 02:25:31 2018 +0000
  5. rebase rebuild-root.diff
  6. diff --git a/fsck/fsck.c b/fsck/fsck.c
  7. index 05a6301..08b117b 100644
  8. --- a/fsck/fsck.c
  9. +++ b/fsck/fsck.c
  10. @@ -391,6 +391,8 @@ static int sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid,
  11. ASSERT_MSG("nid[0x%x] ino is 0", nid);
  12. return -EINVAL;
  13. }
  14. + if (nid == 3)
  15. + printf("DEBUG: %s: root inode blk_addr %#x\n", __func__, ni->blk_addr);
  16. if (ni->blk_addr == NEW_ADDR) {
  17. ASSERT_MSG("nid is NEW_ADDR. [0x%x]", nid);
  18. @@ -563,6 +565,457 @@ err:
  19. return -EINVAL;
  20. }
  21. +struct wrapper {
  22. + union {
  23. + /*
  24. + * direct/indirect/double-indirect and xattr
  25. + * offs in node_footer->flags is used to sort nodes
  26. + */
  27. + struct f2fs_node *node;
  28. + /* FIXME: data block should be all dentries */
  29. + struct data {
  30. + struct f2fs_dentry_block *dentry;
  31. + /* sum_entry->ofs_in_node is used to sort data */
  32. + struct f2fs_summary *sum;
  33. + } data;
  34. + };
  35. + block_t blk_addr;
  36. + struct wrapper *next;
  37. +};
  38. +struct wrapper *node_head = NULL, *data_head = NULL, *xattr_head = NULL;
  39. +/*
  40. + * if nat entry of root inode is corrupted, we may find correct root inode
  41. + * block during scanning. So we save them
  42. + */
  43. +struct wrapper *root_head = NULL;
  44. +
  45. +static void add_wrapper(struct wrapper **head, struct wrapper *new)
  46. +{
  47. + if (*head == NULL) {
  48. + *head = new;
  49. + } else {
  50. + new->next = *head;
  51. + *head = new;
  52. + }
  53. +}
  54. +
  55. +static int get_all_wrappers(struct f2fs_sb_info *sbi)
  56. +{
  57. + struct seg_entry *se;
  58. + struct f2fs_dentry_block *dentry_blk;
  59. + struct f2fs_node *node_blk;
  60. + struct f2fs_summary_block *sum_blk;
  61. + struct f2fs_summary *sum_entry;
  62. + u32 seg_idx, sum_idx;
  63. + int sum_type, ret;
  64. + nid_t root_ino = F2FS_ROOT_INO(sbi);
  65. + struct wrapper *new;
  66. +
  67. + for (seg_idx = 0; seg_idx < TOTAL_SEGS(sbi); seg_idx++) {
  68. + se = get_seg_entry(sbi, seg_idx);
  69. + if (!se->valid_blocks)
  70. + /* skip unused segment */
  71. + continue;
  72. +
  73. + sum_blk = get_sum_block(sbi, seg_idx, &sum_type);
  74. + if (!sum_blk)
  75. + return -ENOMEM;
  76. +
  77. + for (sum_idx = 0; sum_idx < ENTRIES_IN_SUM; sum_idx++) {
  78. + block_t blkaddr = SM_I(sbi)->main_blkaddr +
  79. + seg_idx * sbi->blocks_per_seg +
  80. + sum_idx;
  81. +
  82. + if (!f2fs_test_sit_bitmap(sbi, blkaddr))
  83. + /* skip unused block */
  84. + continue;
  85. +
  86. + sum_entry = &sum_blk->entries[sum_idx];
  87. + if (le32_to_cpu(sum_entry->nid) != root_ino)
  88. + /* skip block whose parent nid is not root ino */
  89. + continue;
  90. +
  91. + new = (struct wrapper *)calloc(sizeof(struct wrapper), 1);
  92. + ASSERT(new);
  93. +
  94. + if (sum_type == SEG_TYPE_NODE || sum_type == SEG_TYPE_CUR_NODE) {
  95. + node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
  96. + ASSERT(node_blk);
  97. +
  98. + ret = dev_read_block(node_blk, blkaddr);
  99. + ASSERT(ret >= 0);
  100. + if (le32_to_cpu(node_blk->footer.ino) == le32_to_cpu(node_blk->footer.nid)) {
  101. + /* skip the root inode itself */
  102. + if (le32_to_cpu(node_blk->footer.ino) == root_ino) {
  103. + DBG(1, "add block %#x to root_head\n", blkaddr);
  104. + new->node = node_blk;
  105. + new->blk_addr = blkaddr;
  106. + new->next = NULL;
  107. + add_wrapper(&root_head, new);
  108. + continue;
  109. + }
  110. + }
  111. + /* FIXME: shall we do some check here? if it
  112. + * does not pass, we should drop the data
  113. + * block.
  114. + * Or, we don't need to check this, fsck
  115. + * will do this later
  116. + */
  117. + new->node = node_blk;
  118. + new->blk_addr = blkaddr;
  119. + new->next = NULL;
  120. + if (ofs_of_node(node_blk) == XATTR_NODE_OFFSET)
  121. + add_wrapper(&xattr_head, new);
  122. + else
  123. + add_wrapper(&node_head, new);
  124. + } else if (sum_type == SEG_TYPE_DATA || sum_type == SEG_TYPE_CUR_DATA) {
  125. + dentry_blk = (struct f2fs_dentry_block *)calloc(BLOCK_SZ, 1);
  126. + ASSERT(dentry_blk);
  127. +
  128. + ret = dev_read_block(dentry_blk, blkaddr);
  129. + ASSERT(ret >= 0);
  130. + /* FIXME: shall we do some check here? if it
  131. + * does not pass, we should drop the data
  132. + * block.
  133. + * Or, we don't need to check this, fsck
  134. + * will do this later
  135. + */
  136. + new->data.dentry = dentry_blk;
  137. + new->data.sum = calloc(sizeof(struct f2fs_summary), 1);
  138. + memcpy(new->data.sum, sum_entry, sizeof(struct f2fs_summary));
  139. + new->blk_addr = blkaddr;
  140. + new->next = NULL;
  141. + add_wrapper(&data_head, new);
  142. + } else {
  143. + ASSERT_MSG("segment 0x%x: unknown summary type %d\n",
  144. + seg_idx, sum_type);
  145. + break;
  146. + }
  147. + }
  148. + if (sum_type == SEG_TYPE_NODE ||
  149. + sum_type == SEG_TYPE_DATA ||
  150. + sum_type == SEG_TYPE_MAX)
  151. + free(sum_blk);
  152. + }
  153. + return 0;
  154. +}
  155. +
  156. +static int update_nat_entry(struct f2fs_sb_info *sbi, u32 nid, block_t newblk)
  157. +{
  158. + struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
  159. + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
  160. + struct f2fs_summary_block *sum = curseg->sum_blk;
  161. + struct f2fs_nm_info *nm_i = NM_I(sbi);
  162. + struct f2fs_nat_block *nat_block;
  163. + struct f2fs_nat_entry *ne;
  164. + pgoff_t block_off;
  165. + pgoff_t nat_blk_addr;
  166. + block_t wrong_addr;
  167. + int seg_off, entry_off;
  168. + int i, ret;
  169. +
  170. + /* look up nat entry in journal */
  171. + for (i = 0; i < nats_in_cursum((&sum->journal)); i++) {
  172. + if (le32_to_cpu(nid_in_journal((&sum->journal), i)) == nid) {
  173. + ne = &nat_in_journal((&sum->journal), i);
  174. + wrong_addr = le32_to_cpu(ne->block_addr);
  175. + ne->block_addr = cpu_to_le32(newblk);
  176. + goto out;
  177. + }
  178. + }
  179. +
  180. + /* look up nat entry in NAT area */
  181. + nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
  182. + ASSERT(nat_block);
  183. +
  184. + block_off = nid / NAT_ENTRY_PER_BLOCK;
  185. + entry_off = nid % NAT_ENTRY_PER_BLOCK;
  186. +
  187. + seg_off = block_off >> sbi->log_blocks_per_seg;
  188. + nat_blk_addr = (pgoff_t)(nm_i->nat_blkaddr +
  189. + (seg_off << sbi->log_blocks_per_seg << 1) +
  190. + (block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
  191. +
  192. + if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
  193. + nat_blk_addr += sbi->blocks_per_seg;
  194. +
  195. + ret = dev_read_block(nat_block, nat_blk_addr);
  196. + ASSERT(ret >= 0);
  197. +
  198. + ne = &nat_block->entries[entry_off];
  199. + wrong_addr = le32_to_cpu(ne->block_addr);
  200. + ne->block_addr = cpu_to_le32(newblk);
  201. +
  202. + dev_write_block(nat_block, nat_blk_addr);
  203. +
  204. +out:
  205. + f2fs_set_bit(nid, fsck->nat_area_bitmap);
  206. + FIX_MSG("nat entry [%d] block_addr [0x%x] -> [0x%x]\n",
  207. + i, wrong_addr, newblk);
  208. + return 0;
  209. +}
  210. +
  211. +static int update_sit_entry(struct f2fs_sb_info *sbi, block_t blk_addr)
  212. +{
  213. + struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
  214. + struct seg_entry *se;
  215. +
  216. + if (f2fs_test_sit_bitmap(sbi, blk_addr)) {
  217. + se = get_seg_entry(sbi, GET_SEGNO(sbi, blk_addr));
  218. + se->valid_blocks += 1;
  219. + f2fs_set_bit(OFFSET_IN_SEG(sbi, blk_addr), (char *)se->cur_valid_map);
  220. + f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk_addr), fsck->sit_area_bitmap);
  221. + }
  222. +
  223. + return 0;
  224. +}
  225. +
  226. +static int do_fix_root_inode(struct f2fs_sb_info *sbi,
  227. + struct f2fs_node *root_node)
  228. +{
  229. + struct node_info ni;
  230. + u32 noffset;
  231. + u64 cnt;
  232. + struct wrapper *new, *ptr = NULL;
  233. + struct f2fs_inode *root_inode;
  234. + block_t blkaddr;
  235. + /* shall we truct that the inode block really is root inode block */
  236. + int weight = 0, pre_weight = 0;
  237. + int fixed = 0;
  238. + nid_t root_ino = F2FS_ROOT_INO(sbi);
  239. + int ret;
  240. +
  241. + /* get inode block */
  242. + ASSERT(root_node);
  243. + new = (struct wrapper *)calloc(sizeof(struct wrapper), 1);
  244. + get_node_info(sbi, root_ino, &ni);
  245. + new->node = root_node;
  246. + new->blk_addr = ni.blk_addr;
  247. + new->next = NULL;
  248. + add_wrapper(&root_head, new);
  249. +
  250. + /*
  251. + * check if the inode block is really the root inode block, choose
  252. + * the node block which has the largest weight
  253. + */
  254. + while (root_head) {
  255. + if (le32_to_cpu(root_head->node->footer.ino) == root_ino)
  256. + weight++;
  257. + if (le32_to_cpu(root_head->node->footer.nid) == root_ino)
  258. + weight++;
  259. + if (S_ISDIR(le16_to_cpu(root_head->node->i.i_mode)))
  260. + weight++;
  261. + /* FIXME: more weight? */
  262. +
  263. + if (weight > pre_weight) {
  264. + /* FIXME: then how about >=? */
  265. + new = root_head;
  266. + pre_weight = weight;
  267. + DBG(1, "find new root_node block %#x\n", new->blk_addr);
  268. + root_head = root_head->next;
  269. + continue;
  270. + }
  271. + ptr = root_head;
  272. + root_head = root_head->next;
  273. + free(ptr->node);
  274. + free(ptr);
  275. + }
  276. + if (pre_weight < 2) {
  277. + /*
  278. + * nat entry may be corrupted, we should not trust what we
  279. + * read. We should select a new place to write it back
  280. + */
  281. + blkaddr = 0; //FIXME: find a new position
  282. + } else {
  283. + blkaddr = new->blk_addr;
  284. + root_node = new->node;
  285. + }
  286. + if (new->blk_addr != ni.blk_addr || root_node != new->node) {
  287. + ret = update_nat_entry(sbi, root_ino, new->blk_addr);
  288. + ASSERT(ret == 0);
  289. + ret = update_sit_entry(sbi, new->blk_addr);
  290. + ASSERT(ret == 0);
  291. + }
  292. +
  293. + root_inode = &root_node->i;
  294. + /* recover i_addr[] */
  295. + cnt = 0;
  296. + while (data_head) {
  297. + ASSERT(cnt < DEF_ADDRS_PER_INODE);
  298. + noffset = le32_to_cpu(data_head->data.sum->ofs_in_node);
  299. + if (le32_to_cpu(root_inode->i_addr[noffset]) != data_head->blk_addr) {
  300. + ASSERT_MSG("root inode: i_addr[%u] = 0x%x, 0x%x\n",
  301. + noffset, le32_to_cpu(root_inode->i_addr[noffset]),
  302. + data_head->blk_addr);
  303. + root_inode->i_addr[noffset] = cpu_to_le32(data_head->blk_addr);
  304. + FIX_MSG("set i_addr[%u] = 0x%x\n", noffset, data_head->blk_addr);
  305. + fixed = 1;
  306. + }
  307. + ptr = data_head;
  308. + data_head = data_head->next;
  309. + free(ptr->data.dentry);
  310. + free(ptr->data.sum);
  311. + free(ptr);
  312. + cnt++;
  313. + }
  314. + DBG(1, "root inode: data blocks %lu\n", cnt);
  315. +
  316. + /* recover i_nid[] */
  317. + cnt = 0;
  318. + while (node_head) {
  319. + ASSERT(cnt < 5);
  320. + noffset = ofs_of_node(node_head->node);
  321. + /* check if noffset is valid */
  322. + if (noffset == 1 || noffset == 2 || noffset == 3) {
  323. + /* noffset is valid, calc the index in i_nid */
  324. + noffset = noffset - 1;
  325. + } else if (noffset == 4 + ADDRS_PER_BLOCK) {
  326. + /* i_nid[3] */
  327. + noffset = 3;
  328. + } else if (noffset == 4 + ADDRS_PER_BLOCK + NIDS_PER_BLOCK) {
  329. + /* i_nid[4] */
  330. + noffset = 4;
  331. + } else {
  332. + /* noffset = 0, node is in i_addr, this must be wrong.
  333. + * noffset = other value, node is in indirect/didirect
  334. + * node. We drop these nodes.
  335. + */
  336. + ASSERT_MSG("root inode: offset of node 0x%x\n", noffset);
  337. + FIX_MSG(" drop node block 0x%x\n", node_head->blk_addr);
  338. + fixed = 1;
  339. + break;
  340. + }
  341. + if (root_inode->i_nid[noffset] != node_head->node->footer.nid) {
  342. + ASSERT_MSG("root inode: i_nid[%u] = 0x%x, 0x%x\n",
  343. + noffset, le32_to_cpu(root_inode->i_nid[noffset]),
  344. + le32_to_cpu(node_head->node->footer.nid));
  345. + root_inode->i_nid[noffset] = node_head->node->footer.nid;
  346. + FIX_MSG("set i_nid[%u] = 0x%x\n", noffset,
  347. + le32_to_cpu(node_head->node->footer.nid));
  348. + fixed = 1;
  349. + }
  350. + ptr = node_head;
  351. + node_head = node_head->next;
  352. + free(ptr->node);
  353. + free(ptr);
  354. + cnt++;
  355. + }
  356. + DBG(1, "root inode: node blocks %lu\n", cnt);
  357. +
  358. + /* recover i_xattr_nid */
  359. + cnt = 0;
  360. + while (xattr_head) {
  361. + ASSERT(cnt < 1);
  362. + if (root_inode->i_xattr_nid != xattr_head->node->footer.nid) {
  363. + root_inode->i_xattr_nid = xattr_head->node->footer.nid;
  364. + FIX_MSG("set i_xattr_nid = 0x%x\n",
  365. + le32_to_cpu(xattr_head->node->footer.nid));
  366. + fixed = 1;
  367. + }
  368. + ptr = xattr_head;
  369. + xattr_head = xattr_head->next;
  370. + free(ptr->node);
  371. + free(ptr);
  372. + cnt++;
  373. + }
  374. + DBG(1, "root inode: xattr blocks %lu\n", cnt);
  375. +
  376. + /* recover other meta of root inode */
  377. + if (le16_to_cpu(root_inode->i_mode) != 0x41ed) {
  378. + root_inode->i_mode = cpu_to_le16(0x41ed); // from f2fs_write_root_inode
  379. + FIX_MSG("set i_mode = 0x41ed\n");
  380. + fixed = 1;
  381. + }
  382. + /* FIXME: how to set appropriate values to these 2 level */
  383. + if (le32_to_cpu(root_inode->i_current_depth) > MAX_DIR_HASH_DEPTH) {
  384. + root_inode->i_current_depth = cpu_to_le32(MAX_DIR_HASH_DEPTH);
  385. + FIX_MSG("set i_current_depth = %u\n", MAX_DIR_HASH_DEPTH);
  386. + fixed = 1;
  387. + }
  388. + if (le32_to_cpu(root_inode->i_dir_level) > MAX_DIR_HASH_DEPTH) {
  389. + root_inode->i_dir_level = cpu_to_le32(DEF_DIR_LEVEL);
  390. + FIX_MSG("set i_dir_level = %u\n", DEF_DIR_LEVEL);
  391. + fixed = 1;
  392. + }
  393. + /* FIXME: is root_inode->i_pino 3? why I get 0 in my case? */
  394. +// if (le32_to_cpu(root_inode->i_pino) != root_ino) {
  395. +// root_inode->i_pino = cpu_to_le32(root_ino);
  396. +// FIX_MSG("set i_pino = %u\n", root_ino);
  397. +// fixed = 1;
  398. +// }
  399. + /*
  400. + * XXX: i_advise, i_inline, i_uid, i_gid, i_*time, i_*time_nsec,
  401. + * i_generation, i_flagsi_flags, i_namelen, i_name
  402. + *
  403. + * XXX: the later fsck -f will fix: i_links, i_blocks, i_ext
  404. + */
  405. +
  406. + if (fixed && !c.ro) {
  407. + ret = dev_write_block(root_node, blkaddr);
  408. + ASSERT(ret >= 0);
  409. + }
  410. +
  411. + return fixed;
  412. +}
  413. +
  414. +/*
  415. + * we can only recover root inode by scanning SSA. Because inode may
  416. + * contains data, only SSA saves which nid the block belonging to
  417. + */
  418. +static int fix_root_inode(struct f2fs_sb_info *sbi, struct f2fs_node *root_node)
  419. +{
  420. + int ret;
  421. +
  422. + /* 1. get all node/data blocks of root inode */
  423. + ret = get_all_wrappers(sbi);
  424. + if (ret)
  425. + return ret;
  426. +
  427. + /* 2. recover root inode and write it back */
  428. + ret = do_fix_root_inode(sbi, root_node);
  429. + if (ret)
  430. + FIX_MSG("fixed root inode\n");
  431. +
  432. + return 0;
  433. +}
  434. +
  435. +int fsck_chk_fs(struct f2fs_sb_info *sbi, u32 *blk_cnt)
  436. +{
  437. + struct node_info ni;
  438. + struct f2fs_node *node_blk = NULL;
  439. + struct f2fs_inode *root_inode;
  440. + enum FILE_TYPE ftype = F2FS_FT_DIR;
  441. + enum NODE_TYPE ntype = TYPE_INODE;
  442. + u32 ino = F2FS_ROOT_INO(sbi);
  443. + int retries = 0, ret;
  444. +
  445. + node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
  446. + ASSERT(node_blk != NULL);
  447. +
  448. +retry:
  449. + /* check if F2FS_ROOT_INO is a correct inode */
  450. + ret = sanity_check_nid(sbi, ino, node_blk, ftype, ntype, &ni);
  451. + if (ret)
  452. + goto fix;
  453. +
  454. + root_inode = &node_blk->i;
  455. +
  456. + /* check if F2FS_ROOT_INO is a directory */
  457. + if (!S_ISDIR(le16_to_cpu(root_inode->i_mode))) {
  458. + ASSERT_MSG("Root inode is not a directory\n");
  459. + goto fix;
  460. + }
  461. +
  462. + fsck_chk_inode_blk(sbi, ino, ftype, node_blk, blk_cnt, &ni, NULL);
  463. + return 0;
  464. +fix:
  465. + ret = fix_root_inode(sbi, node_blk);
  466. + retries++;
  467. + ASSERT(ret == 0);
  468. + ASSERT(retries < 2); // FIXME: how many times to retry?
  469. + goto retry;
  470. +}
  471. +
  472. static inline void get_extent_info(struct extent_info *ext,
  473. struct f2fs_extent *i_ext)
  474. {
  475. @@ -1410,6 +1863,8 @@ static int __chk_dentries(struct f2fs_sb_info *sbi, struct child_info *child,
  476. }
  477. i++;
  478. + print_dentry(fsck->dentry_depth, name, bitmap,
  479. + dentry, max, i, last_blk, enc_name);
  480. free(name);
  481. continue;
  482. }
  483. diff --git a/fsck/fsck.h b/fsck/fsck.h
  484. index 8e133fa..2267492 100644
  485. --- a/fsck/fsck.h
  486. +++ b/fsck/fsck.h
  487. @@ -125,6 +125,7 @@ struct selabel_handle;
  488. extern int fsck_chk_orphan_node(struct f2fs_sb_info *);
  489. extern int fsck_chk_quota_node(struct f2fs_sb_info *);
  490. extern int fsck_chk_quota_files(struct f2fs_sb_info *);
  491. +extern int fsck_chk_fs(struct f2fs_sb_info *sbi, u32 *blk_cnt);
  492. extern int fsck_chk_node_blk(struct f2fs_sb_info *, struct f2fs_inode *, u32,
  493. enum FILE_TYPE, enum NODE_TYPE, u32 *,
  494. struct child_info *);
  495. diff --git a/fsck/main.c b/fsck/main.c
  496. index bbf82c3..97a0d9d 100644
  497. --- a/fsck/main.c
  498. +++ b/fsck/main.c
  499. @@ -562,8 +562,7 @@ static void do_fsck(struct f2fs_sb_info *sbi)
  500. }
  501. }
  502. fsck_chk_orphan_node(sbi);
  503. - fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num,
  504. - F2FS_FT_DIR, TYPE_INODE, &blk_cnt, NULL);
  505. + fsck_chk_fs(sbi, &blk_cnt);
  506. fsck_chk_quota_files(sbi);
  507. fsck_verify(sbi);
  508. diff --git a/fsck/mount.c b/fsck/mount.c
  509. index 4a14320..dd874e5 100644
  510. --- a/fsck/mount.c
  511. +++ b/fsck/mount.c
  512. @@ -245,10 +245,11 @@ void print_inode_info(struct f2fs_sb_info *sbi,
  513. DISP_u32(inode, i_addr[ofs + 3]); /* Pointers to data blocks */
  514. for (i = ofs + 3; i < ADDRS_PER_INODE(inode); i++) {
  515. - if (inode->i_addr[i] == 0x0)
  516. - break;
  517. - printf("i_addr[0x%x] points data block\t\t[0x%4x]\n",
  518. - i, le32_to_cpu(inode->i_addr[i]));
  519. +// if (inode->i_addr[i] == 0x0)
  520. +// break;
  521. +// printf("i_addr[0x%x] points data block\t\t[0x%4x]\n",
  522. +// i, le32_to_cpu(inode->i_addr[i]));
  523. + DISP_u32(inode, i_addr[i]); /* Pointers to data blocks */
  524. }
  525. DISP_u32(inode, i_nid[0]); /* direct */
  526.