aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk2
-rw-r--r--VERSION4
-rw-r--r--configure.ac2
-rw-r--r--fsck/dump.c170
-rw-r--r--fsck/f2fs.h63
-rw-r--r--fsck/fsck.c981
-rw-r--r--fsck/fsck.h112
-rw-r--r--fsck/main.c190
-rw-r--r--fsck/mount.c492
-rw-r--r--include/f2fs_fs.h190
-rw-r--r--lib/libf2fs.c47
-rw-r--r--lib/libf2fs_io.c14
-rw-r--r--mkfs/Makefile.am2
-rw-r--r--mkfs/f2fs_format.c81
-rw-r--r--mkfs/f2fs_format_main.c3
-rw-r--r--mkfs/f2fs_format_utils.c6
-rwxr-xr-xscripts/tracepoint.sh24
-rw-r--r--tools/f2fstat.c83
18 files changed, 1649 insertions, 817 deletions
diff --git a/Android.mk b/Android.mk
index bee1071..48cdb55 100644
--- a/Android.mk
+++ b/Android.mk
@@ -4,7 +4,7 @@ LOCAL_PATH:= $(call my-dir)
ifeq ($(HOST_OS),linux)
# The versions depend on $(LOCAL_PATH)/VERSION
-version_CFLAGS := -DF2FS_MAJOR_VERSION=1 -DF2FS_MINOR_VERSION=2 -DF2FS_TOOLS_VERSION=\"1.2.0\" -DF2FS_TOOLS_DATE=\"2013-10-25\"
+version_CFLAGS := -DF2FS_MAJOR_VERSION=1 -DF2FS_MINOR_VERSION=4 -DF2FS_TOOLS_VERSION=\"1.4.0\" -DF2FS_TOOLS_DATE=\"2014-10-18\"
# external/e2fsprogs/lib is needed for uuid/uuid.h
common_C_INCLUDES := $(LOCAL_PATH)/include external/e2fsprogs/lib/
diff --git a/VERSION b/VERSION
index c3a3dd8..4e11b43 100644
--- a/VERSION
+++ b/VERSION
@@ -1,2 +1,2 @@
-1.2.0
-2013-10-25
+1.4.0
+2014-09-18
diff --git a/configure.ac b/configure.ac
index c2dafb0..0111e72 100644
--- a/configure.ac
+++ b/configure.ac
@@ -56,7 +56,7 @@ AC_PATH_PROG([LDCONFIG], [ldconfig],
PKG_CHECK_MODULES([libuuid], [uuid])
# Checks for header files.
-AC_CHECK_HEADERS([fcntl.h mntent.h stdlib.h string.h \
+AC_CHECK_HEADERS([linux/fs.h fcntl.h mntent.h stdlib.h string.h \
sys/ioctl.h sys/mount.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
diff --git a/fsck/dump.c b/fsck/dump.c
index 765e9db..4bb906f 100644
--- a/fsck/dump.c
+++ b/fsck/dump.c
@@ -8,6 +8,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <inttypes.h>
+
#include "fsck.h"
#define BUF_SZ 80
@@ -57,7 +59,7 @@ void sit_dump(struct f2fs_sb_info *sbi, int start_sit, int end_sit)
ASSERT(ret >= 0);
close(fd);
- DBG(1, "Blocks [0x%lx] Free Segs [0x%x]\n", valid_blocks, free_segs);
+ DBG(1, "Blocks [0x%" PRIx64 "] Free Segs [0x%x]\n", valid_blocks, free_segs);
}
void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa)
@@ -113,15 +115,164 @@ void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa)
close(fd);
}
-int dump_node(struct f2fs_sb_info *sbi, nid_t nid)
+static void dump_data_blk(__u64 offset, u32 blkaddr)
+{
+ char buf[F2FS_BLKSIZE];
+
+ if (blkaddr == NULL_ADDR)
+ return;
+
+ /* get data */
+ if (blkaddr == NEW_ADDR) {
+ memset(buf, 0, F2FS_BLKSIZE);
+ } else {
+ int ret;
+ ret = dev_read_block(buf, blkaddr);
+ ASSERT(ret >= 0);
+ }
+
+ /* write blkaddr */
+ dev_write_dump(buf, offset, F2FS_BLKSIZE);
+}
+
+static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
+ u32 nid, u64 *ofs)
{
struct node_info ni;
struct f2fs_node *node_blk;
+ u32 skip = 0;
+ u32 i, idx;
+
+ switch (ntype) {
+ case TYPE_DIRECT_NODE:
+ skip = idx = ADDRS_PER_BLOCK;
+ break;
+ case TYPE_INDIRECT_NODE:
+ idx = NIDS_PER_BLOCK;
+ skip = idx * ADDRS_PER_BLOCK;
+ break;
+ case TYPE_DOUBLE_INDIRECT_NODE:
+ skip = 0;
+ idx = NIDS_PER_BLOCK;
+ break;
+ }
+
+ if (nid == 0) {
+ *ofs += skip;
+ return;
+ }
+
+ get_node_info(sbi, nid, &ni);
+
+ node_blk = calloc(BLOCK_SZ, 1);
+ dev_read_block(node_blk, ni.blk_addr);
+
+ for (i = 0; i < idx; i++, (*ofs)++) {
+ switch (ntype) {
+ case TYPE_DIRECT_NODE:
+ dump_data_blk(*ofs * F2FS_BLKSIZE,
+ le32_to_cpu(node_blk->dn.addr[i]));
+ break;
+ case TYPE_INDIRECT_NODE:
+ dump_node_blk(sbi, TYPE_DIRECT_NODE,
+ le32_to_cpu(node_blk->in.nid[i]), ofs);
+ break;
+ case TYPE_DOUBLE_INDIRECT_NODE:
+ dump_node_blk(sbi, TYPE_INDIRECT_NODE,
+ le32_to_cpu(node_blk->in.nid[i]), ofs);
+ break;
+ }
+ }
+ free(node_blk);
+}
+
+static void dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
+ struct f2fs_node *node_blk)
+{
+ u32 i = 0;
+ u64 ofs = 0;
+
+ /* TODO: need to dump xattr */
+
+ if((node_blk->i.i_inline & F2FS_INLINE_DATA)){
+ DBG(3, "ino[0x%x] has inline data!\n", nid);
+ /* recover from inline data */
+ dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
+ 0, MAX_INLINE_DATA);
+ return;
+ }
+
+ /* check data blocks in inode */
+ for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
+ dump_data_blk(ofs * F2FS_BLKSIZE,
+ le32_to_cpu(node_blk->i.i_addr[i]));
+
+ /* check node blocks in inode */
+ for (i = 0; i < 5; i++) {
+ if (i == 0 || i == 1)
+ dump_node_blk(sbi, TYPE_DIRECT_NODE,
+ node_blk->i.i_nid[i], &ofs);
+ else if (i == 2 || i == 3)
+ dump_node_blk(sbi, TYPE_INDIRECT_NODE,
+ node_blk->i.i_nid[i], &ofs);
+ else if (i == 4)
+ dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
+ node_blk->i.i_nid[i], &ofs);
+ else
+ ASSERT(0);
+ }
+}
+
+void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
+ struct f2fs_node *node_blk)
+{
+ struct f2fs_inode *inode = &node_blk->i;
+ u32 imode = le32_to_cpu(inode->i_mode);
+ char name[255] = {0};
+ char path[1024] = {0};
+ char ans[255] = {0};
int ret;
- ret = get_node_info(sbi, nid, &ni);
+ if (!S_ISREG(imode)) {
+ MSG(0, "Not a regular file\n\n");
+ return;
+ }
+
+ printf("Do you want to dump this file into ./lost_found/? [Y/N] ");
+ ret = scanf("%s", ans);
ASSERT(ret >= 0);
+ if (!strcasecmp(ans, "y")) {
+ ret = system("mkdir -p ./lost_found");
+ ASSERT(ret >= 0);
+
+ /* make a file */
+ strncpy(name, (const char *)inode->i_name,
+ le32_to_cpu(inode->i_namelen));
+ name[le32_to_cpu(inode->i_namelen)] = 0;
+ sprintf(path, "./lost_found/%s", name);
+
+ config.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
+ ASSERT(config.dump_fd >= 0);
+
+ /* dump file's data */
+ dump_inode_blk(sbi, ni->ino, node_blk);
+
+ /* adjust file size */
+ ret = ftruncate(config.dump_fd, le32_to_cpu(inode->i_size));
+ ASSERT(ret >= 0);
+
+ close(config.dump_fd);
+ }
+}
+
+void dump_node(struct f2fs_sb_info *sbi, nid_t nid)
+{
+ struct node_info ni;
+ struct f2fs_node *node_blk;
+
+ get_node_info(sbi, nid, &ni);
+
node_blk = calloc(BLOCK_SZ, 1);
dev_read_block(node_blk, ni.blk_addr);
@@ -130,9 +281,8 @@ int dump_node(struct f2fs_sb_info *sbi, nid_t nid)
DBG(1, "nat_entry.version [0x%x]\n", ni.version);
DBG(1, "nat_entry.ino [0x%x]\n", ni.ino);
- if (ni.blk_addr == 0x0) {
+ if (ni.blk_addr == 0x0)
MSG(0, "Invalid nat entry\n\n");
- }
DBG(1, "node_blk.footer.ino [0x%x]\n", le32_to_cpu(node_blk->footer.ino));
DBG(1, "node_blk.footer.nid [0x%x]\n", le32_to_cpu(node_blk->footer.nid));
@@ -140,12 +290,12 @@ int dump_node(struct f2fs_sb_info *sbi, nid_t nid)
if (le32_to_cpu(node_blk->footer.ino) == ni.ino &&
le32_to_cpu(node_blk->footer.nid) == ni.nid) {
print_node_info(node_blk);
+ dump_file(sbi, &ni, node_blk);
} else {
MSG(0, "Invalid node block\n\n");
}
free(node_blk);
- return 0;
}
int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
@@ -159,8 +309,7 @@ int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
type = get_sum_entry(sbi, blk_addr, &sum_entry);
nid = le32_to_cpu(sum_entry.nid);
- ret = get_node_info(sbi, nid, &ni);
- ASSERT(ret >= 0);
+ get_node_info(sbi, nid, &ni);
DBG(1, "Note: blkaddr = main_blkaddr + segno * 512 + offset\n");
DBG(1, "Block_addr [0x%x]\n", blk_addr);
@@ -176,7 +325,8 @@ int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
node_blk = calloc(BLOCK_SZ, 1);
read_node_blk:
- dev_read_block(node_blk, blk_addr);
+ ret = dev_read_block(node_blk, blk_addr);
+ ASSERT(ret >= 0);
ino = le32_to_cpu(node_blk->footer.ino);
nid = le32_to_cpu(node_blk->footer.nid);
@@ -184,7 +334,7 @@ read_node_blk:
if (ino == nid) {
print_node_info(node_blk);
} else {
- ret = get_node_info(sbi, ino, &ni);
+ get_node_info(sbi, ino, &ni);
goto read_node_blk;
}
diff --git a/fsck/f2fs.h b/fsck/f2fs.h
index 427a733..47f785d 100644
--- a/fsck/f2fs.h
+++ b/fsck/f2fs.h
@@ -26,7 +26,6 @@
#include <sys/mount.h>
#include <assert.h>
-#include <list.h>
#include <f2fs_fs.h>
#define EXIT_ERR_CODE (-1)
@@ -34,6 +33,10 @@
typecheck(unsigned long long, b) && \
((long long)((a) - (b)) > 0))
+struct list_head {
+ struct list_head *next, *prev;
+};
+
enum {
NAT_BITMAP,
SIT_BITMAP
@@ -126,6 +129,7 @@ struct f2fs_sb_info {
struct f2fs_nm_info *nm_info;
struct f2fs_sm_info *sm_info;
struct f2fs_checkpoint *ckpt;
+ int cur_cp;
struct list_head orphan_inode_list;
unsigned int n_orphans;
@@ -187,6 +191,11 @@ static inline struct sit_info *SIT_I(struct f2fs_sb_info *sbi)
return (struct sit_info *)(SM_I(sbi)->sit_info);
}
+static inline void *inline_data_addr(struct f2fs_node *node_blk)
+{
+ return (void *)&(node_blk->i.i_addr[1]);
+}
+
static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
@@ -265,10 +274,15 @@ static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi)
#define GET_SEGNO_FROM_SEG0(sbi, blk_addr) \
(GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg)
-#define FREE_I_START_SEGNO(sbi) GET_SEGNO_FROM_SEG0(sbi, SM_I(sbi)->main_blkaddr)
+#define GET_BLKOFF_FROM_SEG0(sbi, blk_addr) \
+ (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & (sbi->blocks_per_seg - 1))
+
+#define FREE_I_START_SEGNO(sbi) \
+ GET_SEGNO_FROM_SEG0(sbi, SM_I(sbi)->main_blkaddr)
#define GET_R2L_SEGNO(sbi, segno) (segno + FREE_I_START_SEGNO(sbi))
-#define START_BLOCK(sbi, segno) (SM_I(sbi)->main_blkaddr + (segno << sbi->log_blocks_per_seg))
+#define START_BLOCK(sbi, segno) (SM_I(sbi)->main_blkaddr + \
+ (segno << sbi->log_blocks_per_seg))
static inline struct curseg_info *CURSEG_I(struct f2fs_sb_info *sbi, int type)
{
@@ -301,23 +315,32 @@ static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type)
(segno / SIT_ENTRY_PER_BLOCK)
#define TOTAL_SEGS(sbi) (SM_I(sbi)->main_segments)
-#define IS_VALID_NID(sbi, nid) \
- do { \
- ASSERT(nid <= (NAT_ENTRY_PER_BLOCK * \
- F2FS_RAW_SUPER(sbi)->segment_count_nat \
- << (sbi->log_blocks_per_seg - 1))); \
- } while (0);
-
-#define IS_VALID_BLK_ADDR(sbi, addr) \
- do { \
- if (addr >= F2FS_RAW_SUPER(sbi)->block_count || \
- addr < SM_I(sbi)->main_blkaddr) \
- { \
- DBG(0, "block addr [0x%x]\n", addr); \
- ASSERT(addr < F2FS_RAW_SUPER(sbi)->block_count); \
- ASSERT(addr >= SM_I(sbi)->main_blkaddr); \
- } \
- } while (0);
+static inline bool IS_VALID_NID(struct f2fs_sb_info *sbi, u32 nid)
+{
+ return (nid <= (NAT_ENTRY_PER_BLOCK *
+ F2FS_RAW_SUPER(sbi)->segment_count_nat
+ << (sbi->log_blocks_per_seg - 1)));
+}
+
+static inline bool IS_VALID_BLK_ADDR(struct f2fs_sb_info *sbi, u32 addr)
+{
+ int i;
+
+ if (addr >= F2FS_RAW_SUPER(sbi)->block_count ||
+ addr < SM_I(sbi)->main_blkaddr) {
+ ASSERT_MSG("block addr [0x%x]\n", addr);
+ return 0;
+ }
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+
+ if (START_BLOCK(sbi, curseg->segno) +
+ curseg->next_blkoff == addr)
+ return 0;
+ }
+ return 1;
+}
static inline u64 BLKOFF_FROM_MAIN(struct f2fs_sb_info *sbi, u64 blk_addr)
{
diff --git a/fsck/fsck.c b/fsck/fsck.c
index 0f48918..f6039b8 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -13,7 +13,30 @@
char *tree_mark;
uint32_t tree_mark_size = 256;
-static int add_into_hard_link_list(struct f2fs_sb_info *sbi, u32 nid, u32 link_cnt)
+static inline int f2fs_set_main_bitmap(struct f2fs_sb_info *sbi, u32 blk)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+
+ return f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->main_area_bitmap);
+}
+
+static inline int f2fs_test_main_bitmap(struct f2fs_sb_info *sbi, u32 blk)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+
+ return f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk),
+ fsck->main_area_bitmap);
+}
+
+static inline int f2fs_test_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+
+ return f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->sit_area_bitmap);
+}
+
+static int add_into_hard_link_list(struct f2fs_sb_info *sbi,
+ u32 nid, u32 link_cnt)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct hard_link_node *node = NULL, *tmp = NULL, *prev = NULL;
@@ -57,10 +80,8 @@ static int find_and_dec_hard_link_list(struct f2fs_sb_info *sbi, u32 nid)
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct hard_link_node *node = NULL, *prev = NULL;
- if (fsck->hard_link_list_head == NULL) {
- ASSERT(0);
- return -1;
- }
+ if (fsck->hard_link_list_head == NULL)
+ return -EINVAL;
node = fsck->hard_link_list_head;
@@ -69,10 +90,8 @@ static int find_and_dec_hard_link_list(struct f2fs_sb_info *sbi, u32 nid)
node = node->next;
}
- if (node == NULL || (nid != node->nid)) {
- ASSERT(0);
- return -1;
- }
+ if (node == NULL || (nid != node->nid))
+ return -EINVAL;
/* Decrease link count */
node->links = node->links - 1;
@@ -85,40 +104,38 @@ static int find_and_dec_hard_link_list(struct f2fs_sb_info *sbi, u32 nid)
prev->next = node->next;
free(node);
}
-
return 0;
-
}
-static int is_valid_ssa_node_blk(struct f2fs_sb_info *sbi, u32 nid, u32 blk_addr)
+static int is_valid_ssa_node_blk(struct f2fs_sb_info *sbi, u32 nid,
+ u32 blk_addr)
{
int ret = 0;
struct f2fs_summary sum_entry;
ret = get_sum_entry(sbi, blk_addr, &sum_entry);
- ASSERT(ret >= 0);
- if (ret == SEG_TYPE_DATA || ret == SEG_TYPE_CUR_DATA) {
- ASSERT_MSG(0, "Summary footer is not a node segment summary\n");;
- } else if (ret == SEG_TYPE_NODE) {
- if (le32_to_cpu(sum_entry.nid) != nid) {
- DBG(0, "nid [0x%x]\n", nid);
- DBG(0, "target blk_addr [0x%x]\n", blk_addr);
- DBG(0, "summary blk_addr [0x%x]\n",
- GET_SUM_BLKADDR(sbi, GET_SEGNO(sbi, blk_addr)));
- DBG(0, "seg no / offset [0x%x / 0x%x]\n",
- GET_SEGNO(sbi, blk_addr), OFFSET_IN_SEG(sbi, blk_addr));
- DBG(0, "summary_entry.nid [0x%x]\n", le32_to_cpu(sum_entry.nid));
- DBG(0, "--> node block's nid [0x%x]\n", nid);
- ASSERT_MSG(0, "Invalid node seg summary\n");
- }
- } else if (ret == SEG_TYPE_CUR_NODE) {
- /* current node segment has no ssa */
- } else {
- ASSERT_MSG(0, "Invalid return value of 'get_sum_entry'");
+ if (ret != SEG_TYPE_NODE && ret != SEG_TYPE_CUR_NODE) {
+ ASSERT_MSG("Summary footer is not for node segment");
+ return -EINVAL;
}
- return 1;
+ if (le32_to_cpu(sum_entry.nid) != nid) {
+ DBG(0, "nid [0x%x]\n", nid);
+ DBG(0, "target blk_addr [0x%x]\n", blk_addr);
+ DBG(0, "summary blk_addr [0x%x]\n",
+ GET_SUM_BLKADDR(sbi,
+ GET_SEGNO(sbi, blk_addr)));
+ DBG(0, "seg no / offset [0x%x / 0x%x]\n",
+ GET_SEGNO(sbi, blk_addr),
+ OFFSET_IN_SEG(sbi, blk_addr));
+ DBG(0, "summary_entry.nid [0x%x]\n",
+ le32_to_cpu(sum_entry.nid));
+ DBG(0, "--> node block's nid [0x%x]\n", nid);
+ ASSERT_MSG("Invalid node seg summary\n");
+ return -EINVAL;
+ }
+ return 0;
}
static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
@@ -128,143 +145,200 @@ static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
struct f2fs_summary sum_entry;
ret = get_sum_entry(sbi, blk_addr, &sum_entry);
- ASSERT(ret == SEG_TYPE_DATA || ret == SEG_TYPE_CUR_DATA);
+
+ if (ret != SEG_TYPE_DATA && ret != SEG_TYPE_CUR_DATA) {
+ ASSERT_MSG("Summary footer is not for data segment");
+ return -EINVAL;
+ }
if (le32_to_cpu(sum_entry.nid) != parent_nid ||
sum_entry.version != version ||
le16_to_cpu(sum_entry.ofs_in_node) != idx_in_node) {
- DBG(0, "summary_entry.nid [0x%x]\n", le32_to_cpu(sum_entry.nid));
- DBG(0, "summary_entry.version [0x%x]\n", sum_entry.version);
- DBG(0, "summary_entry.ofs_in_node [0x%x]\n", le16_to_cpu(sum_entry.ofs_in_node));
-
+ DBG(0, "summary_entry.nid [0x%x]\n",
+ le32_to_cpu(sum_entry.nid));
+ DBG(0, "summary_entry.version [0x%x]\n",
+ sum_entry.version);
+ DBG(0, "summary_entry.ofs_in_node [0x%x]\n",
+ le16_to_cpu(sum_entry.ofs_in_node));
DBG(0, "parent nid [0x%x]\n", parent_nid);
DBG(0, "version from nat [0x%x]\n", version);
DBG(0, "idx in parent node [0x%x]\n", idx_in_node);
DBG(0, "Target data block addr [0x%x]\n", blk_addr);
- ASSERT_MSG(0, "Invalid data seg summary\n");
+ ASSERT_MSG("Invalid data seg summary\n");
+ return -EINVAL;
}
-
- return 1;
+ return 0;
}
-int fsck_chk_node_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- enum NODE_TYPE ntype,
- u32 *blk_cnt)
+static int sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid,
+ struct f2fs_node *node_blk,
+ enum FILE_TYPE ftype, enum NODE_TYPE ntype,
+ struct node_info *ni)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
- struct node_info ni;
- struct f2fs_node *node_blk = NULL;
- int ret = 0;
+ int ret;
+
+ if (!IS_VALID_NID(sbi, nid)) {
+ ASSERT_MSG("nid is not valid. [0x%x]", nid);
+ return -EINVAL;
+ }
- IS_VALID_NID(sbi, nid);
+ get_node_info(sbi, nid, ni);
+ if (ni->blk_addr == NEW_ADDR) {
+ ASSERT_MSG("nid is NEW_ADDR. [0x%x]", nid);
+ return -EINVAL;
+ }
- if (ftype != F2FS_FT_ORPHAN ||
- f2fs_test_bit(nid, fsck->nat_area_bitmap) != 0x0)
- f2fs_clear_bit(nid, fsck->nat_area_bitmap);
- else
- ASSERT_MSG(0, "nid duplicated [0x%x]\n", nid);
+ if (!IS_VALID_BLK_ADDR(sbi, ni->blk_addr)) {
+ ASSERT_MSG("blkaddres is not valid. [0x%x]", ni->blk_addr);
+ return -EINVAL;
+ }
+
+ if (is_valid_ssa_node_blk(sbi, nid, ni->blk_addr)) {
+ ASSERT_MSG("summary node block is not valid. [0x%x]", nid);
+ return -EINVAL;
+ }
- ret = get_node_info(sbi, nid, &ni);
+ ret = dev_read_block(node_blk, ni->blk_addr);
ASSERT(ret >= 0);
- /* Is it reserved block?
- * if block addresss was 0xffff,ffff,ffff,ffff
- * it means that block was already allocated, but not stored in disk
- */
- if (ni.blk_addr == NEW_ADDR) {
- fsck->chk.valid_blk_cnt++;
- fsck->chk.valid_node_cnt++;
- if (ntype == TYPE_INODE)
- fsck->chk.valid_inode_cnt++;
- return 0;
+ if (ntype == TYPE_INODE &&
+ node_blk->footer.nid != node_blk->footer.ino) {
+ ASSERT_MSG("nid[0x%x] footer.nid[0x%x] footer.ino[0x%x]",
+ nid, le32_to_cpu(node_blk->footer.nid),
+ le32_to_cpu(node_blk->footer.ino));
+ return -EINVAL;
+ }
+ if (ntype != TYPE_INODE &&
+ node_blk->footer.nid == node_blk->footer.ino) {
+ ASSERT_MSG("nid[0x%x] footer.nid[0x%x] footer.ino[0x%x]",
+ nid, le32_to_cpu(node_blk->footer.nid),
+ le32_to_cpu(node_blk->footer.ino));
+ return -EINVAL;
}
- IS_VALID_BLK_ADDR(sbi, ni.blk_addr);
+ if (le32_to_cpu(node_blk->footer.nid) != nid) {
+ ASSERT_MSG("nid[0x%x] blk_addr[0x%x] footer.nid[0x%x]",
+ nid, ni->blk_addr,
+ le32_to_cpu(node_blk->footer.nid));
+ return -EINVAL;
+ }
- is_valid_ssa_node_blk(sbi, nid, ni.blk_addr);
+ if (ntype == TYPE_XATTR) {
+ u32 flag = le32_to_cpu(node_blk->footer.flag);
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->sit_area_bitmap) == 0x0) {
- DBG(0, "SIT bitmap is 0x0. blk_addr[0x%x]\n", ni.blk_addr);
- ASSERT(0);
+ if ((flag >> OFFSET_BIT_SHIFT) != XATTR_NODE_OFFSET) {
+ ASSERT_MSG("xnid[0x%x] has wrong ofs:[0x%x]",
+ nid, flag);
+ return -EINVAL;
+ }
}
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap) == 0x0) {
+ if ((ntype == TYPE_INODE && ftype == F2FS_FT_DIR) ||
+ (ntype == TYPE_XATTR && ftype == F2FS_FT_XATTR)) {
+ /* not included '.' & '..' */
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) != 0) {
+ ASSERT_MSG("Duplicated node blk. nid[0x%x][0x%x]\n",
+ nid, ni->blk_addr);
+ return -EINVAL;
+ }
+ }
+
+ /* workaround to fix later */
+ if (ftype != F2FS_FT_ORPHAN ||
+ f2fs_test_bit(nid, fsck->nat_area_bitmap) != 0)
+ f2fs_clear_bit(nid, fsck->nat_area_bitmap);
+ else
+ ASSERT_MSG("orphan or xattr nid is duplicated [0x%x]\n",
+ nid);
+
+ if (f2fs_test_sit_bitmap(sbi, ni->blk_addr) == 0)
+ ASSERT_MSG("SIT bitmap is 0x0. blk_addr[0x%x]",
+ ni->blk_addr);
+
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) {
fsck->chk.valid_blk_cnt++;
fsck->chk.valid_node_cnt++;
}
+ return 0;
+}
+
+static int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino,
+ u32 x_nid, u32 *blk_cnt)
+{
+ struct f2fs_node *node_blk = NULL;
+ struct node_info ni;
+ int ret = 0;
+
+ if (x_nid == 0x0)
+ return 0;
node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
ASSERT(node_blk != NULL);
- ret = dev_read_block(node_blk, ni.blk_addr);
- ASSERT(ret >= 0);
+ /* Sanity check */
+ if (sanity_check_nid(sbi, x_nid, node_blk,
+ F2FS_FT_XATTR, TYPE_XATTR, &ni)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ *blk_cnt = *blk_cnt + 1;
+ f2fs_set_main_bitmap(sbi, ni.blk_addr);
+ DBG(2, "ino[0x%x] x_nid[0x%x]\n", ino, x_nid);
+out:
+ free(node_blk);
+ return ret;
+}
- ASSERT_MSG(nid == le32_to_cpu(node_blk->footer.nid),
- "nid[0x%x] blk_addr[0x%x] footer.nid[0x%x]\n",
- nid, ni.blk_addr, le32_to_cpu(node_blk->footer.nid));
+int fsck_chk_node_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
+ u32 nid, enum FILE_TYPE ftype, enum NODE_TYPE ntype,
+ u32 *blk_cnt)
+{
+ struct node_info ni;
+ struct f2fs_node *node_blk = NULL;
+
+ node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
+ ASSERT(node_blk != NULL);
+
+ if (sanity_check_nid(sbi, nid, node_blk, ftype, ntype, &ni))
+ goto err;
if (ntype == TYPE_INODE) {
- ret = fsck_chk_inode_blk(sbi,
- nid,
- ftype,
- node_blk,
- blk_cnt,
- &ni);
+ fsck_chk_inode_blk(sbi, nid, ftype, node_blk, blk_cnt, &ni);
} else {
- /* it's not inode */
- ASSERT(node_blk->footer.nid != node_blk->footer.ino);
-
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap) != 0) {
- DBG(0, "Duplicated node block. ino[0x%x][0x%x]\n", nid, ni.blk_addr);
- ASSERT(0);
- }
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap);
+ f2fs_set_main_bitmap(sbi, ni.blk_addr);
switch (ntype) {
case TYPE_DIRECT_NODE:
- ret = fsck_chk_dnode_blk(sbi,
- inode,
- nid,
- ftype,
- node_blk,
- blk_cnt,
- &ni);
+ fsck_chk_dnode_blk(sbi, inode, nid, ftype, node_blk,
+ blk_cnt, &ni);
break;
case TYPE_INDIRECT_NODE:
- ret = fsck_chk_idnode_blk(sbi,
- inode,
- ftype,
- node_blk,
+ fsck_chk_idnode_blk(sbi, inode, ftype, node_blk,
blk_cnt);
break;
case TYPE_DOUBLE_INDIRECT_NODE:
- ret = fsck_chk_didnode_blk(sbi,
- inode,
- ftype,
- node_blk,
+ fsck_chk_didnode_blk(sbi, inode, ftype, node_blk,
blk_cnt);
break;
default:
ASSERT(0);
}
}
- ASSERT(ret >= 0);
-
free(node_blk);
return 0;
+err:
+ free(node_blk);
+ return -EINVAL;
}
-int fsck_chk_inode_blk(struct f2fs_sb_info *sbi,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt,
- struct node_info *ni)
+/* start with valid nid and blkaddr */
+void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
+ enum FILE_TYPE ftype, struct f2fs_node *node_blk,
+ u32 *blk_cnt, struct node_info *ni)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
u32 child_cnt = 0, child_files = 0;
@@ -272,81 +346,104 @@ int fsck_chk_inode_blk(struct f2fs_sb_info *sbi,
u32 i_links = le32_to_cpu(node_blk->i.i_links);
u64 i_blocks = le64_to_cpu(node_blk->i.i_blocks);
unsigned int idx = 0;
- int ret = 0;
-
- ASSERT(node_blk->footer.nid == node_blk->footer.ino);
- ASSERT(le32_to_cpu(node_blk->footer.nid) == nid);
+ int need_fix = 0;
+ int ret;
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap) == 0x0)
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0)
fsck->chk.valid_inode_cnt++;
- /* Orphan node. i_links should be 0 */
- if (ftype == F2FS_FT_ORPHAN) {
- ASSERT(i_links == 0);
- } else {
- ASSERT(i_links > 0);
- }
-
if (ftype == F2FS_FT_DIR) {
-
- /* not included '.' & '..' */
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap) != 0) {
- DBG(0, "Duplicated inode blk. ino[0x%x][0x%x]\n", nid, ni->blk_addr);
- ASSERT(0);
- }
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap);
-
+ f2fs_set_main_bitmap(sbi, ni->blk_addr);
} else {
-
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap) == 0x0) {
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap);
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) {
+ f2fs_set_main_bitmap(sbi, ni->blk_addr);
if (i_links > 1) {
/* First time. Create new hard link node */
add_into_hard_link_list(sbi, nid, i_links);
fsck->chk.multi_hard_link_files++;
}
} else {
- if (i_links <= 1) {
- DBG(0, "Error. Node ID [0x%x]."
- " There are one more hard links."
- " But i_links is [0x%x]\n",
+ DBG(3, "[0x%x] has hard links [0x%x]\n", nid, i_links);
+ if (find_and_dec_hard_link_list(sbi, nid)) {
+ ASSERT_MSG("[0x%x] needs more i_links=0x%x",
nid, i_links);
- ASSERT(0);
+ if (config.fix_on) {
+ node_blk->i.i_links =
+ cpu_to_le32(i_links + 1);
+ need_fix = 1;
+ FIX_MSG("File: 0x%x "
+ "i_links= 0x%x -> 0x%x",
+ nid, i_links, i_links + 1);
+ }
+ goto check;
}
-
- DBG(3, "ino[0x%x] has hard links [0x%x]\n", nid, i_links);
- ret = find_and_dec_hard_link_list(sbi, nid);
- ASSERT(ret >= 0);
-
/* No need to go deep into the node */
- goto out;
+ return;
}
}
- fsck_chk_xattr_blk(sbi, nid, le32_to_cpu(node_blk->i.i_xattr_nid), blk_cnt);
+ if (fsck_chk_xattr_blk(sbi, nid,
+ le32_to_cpu(node_blk->i.i_xattr_nid), blk_cnt) &&
+ config.fix_on) {
+ node_blk->i.i_xattr_nid = 0;
+ need_fix = 1;
+ FIX_MSG("Remove xattr block: 0x%x, x_nid = 0x%x",
+ nid, le32_to_cpu(node_blk->i.i_xattr_nid));
+ }
if (ftype == F2FS_FT_CHRDEV || ftype == F2FS_FT_BLKDEV ||
ftype == F2FS_FT_FIFO || ftype == F2FS_FT_SOCK)
goto check;
- if((node_blk->i.i_inline & F2FS_INLINE_DATA)){
+
+ if((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
+ if (le32_to_cpu(node_blk->i.i_addr[0]) != 0) {
+ /* should fix this bug all the time */
+ FIX_MSG("inline_data has wrong 0'th block = %x",
+ le32_to_cpu(node_blk->i.i_addr[0]));
+ node_blk->i.i_addr[0] = 0;
+ node_blk->i.i_blocks = cpu_to_le64(*blk_cnt);
+ need_fix = 1;
+ }
+ if (!(node_blk->i.i_inline & F2FS_DATA_EXIST)) {
+ char buf[MAX_INLINE_DATA];
+ memset(buf, 0, MAX_INLINE_DATA);
+
+ if (memcmp(buf, &node_blk->i.i_addr[1],
+ MAX_INLINE_DATA)) {
+ FIX_MSG("inline_data has DATA_EXIST");
+ node_blk->i.i_inline |= F2FS_DATA_EXIST;
+ need_fix = 1;
+ }
+ }
DBG(3, "ino[0x%x] has inline data!\n", nid);
goto check;
}
+ if((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) {
+ DBG(3, "ino[0x%x] has inline dentry!\n", nid);
+ ret = fsck_chk_inline_dentries(sbi, node_blk,
+ &child_cnt, &child_files);
+ if (ret < 0) {
+ /* should fix this bug all the time */
+ need_fix = 1;
+ }
+ goto check;
+ }
/* check data blocks in inode */
for (idx = 0; idx < ADDRS_PER_INODE(&node_blk->i); idx++) {
if (le32_to_cpu(node_blk->i.i_addr[idx]) != 0) {
- *blk_cnt = *blk_cnt + 1;
ret = fsck_chk_data_blk(sbi,
le32_to_cpu(node_blk->i.i_addr[idx]),
- &child_cnt,
- &child_files,
+ &child_cnt, &child_files,
(i_blocks == *blk_cnt),
- ftype,
- nid,
- idx,
- ni->version);
- ASSERT(ret >= 0);
+ ftype, nid, idx, ni->version);
+ if (!ret) {
+ *blk_cnt = *blk_cnt + 1;
+ } else if (config.fix_on) {
+ node_blk->i.i_addr[idx] = 0;
+ need_fix = 1;
+ FIX_MSG("[0x%x] i_addr[%d] = 0", nid, idx);
+ }
}
}
@@ -362,116 +459,127 @@ int fsck_chk_inode_blk(struct f2fs_sb_info *sbi,
ASSERT(0);
if (le32_to_cpu(node_blk->i.i_nid[idx]) != 0) {
- *blk_cnt = *blk_cnt + 1;
- ret = fsck_chk_node_blk(sbi,
- &node_blk->i,
+ ret = fsck_chk_node_blk(sbi, &node_blk->i,
le32_to_cpu(node_blk->i.i_nid[idx]),
- ftype,
- ntype,
- blk_cnt);
- ASSERT(ret >= 0);
+ ftype, ntype, blk_cnt);
+ if (!ret) {
+ *blk_cnt = *blk_cnt + 1;
+ } else if (config.fix_on) {
+ node_blk->i.i_nid[idx] = 0;
+ need_fix = 1;
+ FIX_MSG("[0x%x] i_nid[%d] = 0", nid, idx);
+ }
}
}
check:
if (ftype == F2FS_FT_DIR)
- DBG(1, "Directory Inode: ino: %x name: %s depth: %d child files: %d\n\n",
- le32_to_cpu(node_blk->footer.ino), node_blk->i.i_name,
- le32_to_cpu(node_blk->i.i_current_depth), child_files);
+ DBG(1, "Directory Inode: 0x%x [%s] depth: %d has %d files\n\n",
+ le32_to_cpu(node_blk->footer.ino),
+ node_blk->i.i_name,
+ le32_to_cpu(node_blk->i.i_current_depth),
+ child_files);
if (ftype == F2FS_FT_ORPHAN)
- DBG(1, "Orphan Inode: ino: %x name: %s i_blocks: %u\n\n",
- le32_to_cpu(node_blk->footer.ino), node_blk->i.i_name,
+ DBG(1, "Orphan Inode: 0x%x [%s] i_blocks: %u\n\n",
+ le32_to_cpu(node_blk->footer.ino),
+ node_blk->i.i_name,
(u32)i_blocks);
- if ((ftype == F2FS_FT_DIR && i_links != child_cnt) ||
- (i_blocks != *blk_cnt)) {
- print_node_info(node_blk);
- DBG(1, "blk cnt [0x%x]\n", *blk_cnt);
- DBG(1, "child cnt [0x%x]\n", child_cnt);
+
+ if (i_blocks != *blk_cnt) {
+ ASSERT_MSG("ino: 0x%x has i_blocks: %08"PRIx64", "
+ "but has %u blocks",
+ nid, i_blocks, *blk_cnt);
+ if (config.fix_on) {
+ node_blk->i.i_blocks = cpu_to_le64(*blk_cnt);
+ need_fix = 1;
+ FIX_MSG("[0x%x] i_blocks=0x%08"PRIx64" -> 0x%x",
+ nid, i_blocks, *blk_cnt);
+ }
+ }
+ if (ftype == F2FS_FT_DIR && i_links != child_cnt) {
+ ASSERT_MSG("ino: 0x%x has i_links: %u but real links: %u",
+ nid, i_links, child_cnt);
+ if (config.fix_on) {
+ node_blk->i.i_links = cpu_to_le32(child_cnt);
+ need_fix = 1;
+ FIX_MSG("Dir: 0x%x i_links= 0x%x -> 0x%x",
+ nid, i_links, child_cnt);
+ }
}
- ASSERT(i_blocks == *blk_cnt);
- if (ftype == F2FS_FT_DIR)
- ASSERT(i_links == child_cnt);
-out:
- return 0;
+ if (ftype == F2FS_FT_ORPHAN && i_links)
+ ASSERT_MSG("ino: 0x%x is orphan inode, but has i_links: %u",
+ nid, i_links);
+ if (need_fix) {
+ ret = dev_write_block(node_blk, ni->blk_addr);
+ ASSERT(ret >= 0);
+ }
}
-int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt,
- struct node_info *ni)
+int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
+ u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk,
+ u32 *blk_cnt, struct node_info *ni)
{
- int idx;
+ int idx, ret;
u32 child_cnt = 0, child_files = 0;
for (idx = 0; idx < ADDRS_PER_BLOCK; idx++) {
if (le32_to_cpu(node_blk->dn.addr[idx]) == 0x0)
continue;
- *blk_cnt = *blk_cnt + 1;
- fsck_chk_data_blk(sbi,
- le32_to_cpu(node_blk->dn.addr[idx]),
- &child_cnt,
- &child_files,
- le64_to_cpu(inode->i_blocks) == *blk_cnt,
- ftype,
- nid,
- idx,
- ni->version);
+ ret = fsck_chk_data_blk(sbi,
+ le32_to_cpu(node_blk->dn.addr[idx]),
+ &child_cnt, &child_files,
+ le64_to_cpu(inode->i_blocks) == *blk_cnt, ftype,
+ nid, idx, ni->version);
+ if (!ret)
+ *blk_cnt = *blk_cnt + 1;
}
-
return 0;
}
-int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt)
+int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
+ enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt)
{
+ int ret;
int i = 0;
for (i = 0 ; i < NIDS_PER_BLOCK; i++) {
if (le32_to_cpu(node_blk->in.nid[i]) == 0x0)
continue;
- *blk_cnt = *blk_cnt + 1;
- fsck_chk_node_blk(sbi,
- inode,
+ ret = fsck_chk_node_blk(sbi, inode,
le32_to_cpu(node_blk->in.nid[i]),
- ftype,
- TYPE_DIRECT_NODE,
- blk_cnt);
+ ftype, TYPE_DIRECT_NODE, blk_cnt);
+ if (!ret)
+ *blk_cnt = *blk_cnt + 1;
+ else if (ret == -EINVAL)
+ printf("delete in.nid[i] = 0;\n");
}
-
return 0;
}
-int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt)
+int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
+ enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt)
{
int i = 0;
+ int ret = 0;
for (i = 0; i < NIDS_PER_BLOCK; i++) {
if (le32_to_cpu(node_blk->in.nid[i]) == 0x0)
continue;
- *blk_cnt = *blk_cnt + 1;
- fsck_chk_node_blk(sbi,
- inode,
+ ret = fsck_chk_node_blk(sbi, inode,
le32_to_cpu(node_blk->in.nid[i]),
- ftype,
- TYPE_INDIRECT_NODE,
- blk_cnt);
+ ftype, TYPE_INDIRECT_NODE, blk_cnt);
+ if (!ret)
+ *blk_cnt = *blk_cnt + 1;
+ else if (ret == -EINVAL)
+ printf("delete in.nid[i] = 0;\n");
}
-
return 0;
}
static void print_dentry(__u32 depth, __u8 *name,
- struct f2fs_dentry_block *de_blk, int idx, int last_blk)
+ unsigned long *bitmap,
+ struct f2fs_dir_entry *dentry,
+ int max, int idx, int last_blk)
{
int last_de = 0;
int next_idx = 0;
@@ -482,12 +590,11 @@ static void print_dentry(__u32 depth, __u8 *name,
if (config.dbg_lv != -1)
return;
- name_len = le16_to_cpu(de_blk->dentry[idx].name_len);
+ name_len = le16_to_cpu(dentry[idx].name_len);
next_idx = idx + (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN;
- bit_offset = find_next_bit((unsigned long *)de_blk->dentry_bitmap,
- NR_DENTRY_IN_BLOCK, next_idx);
- if (bit_offset >= NR_DENTRY_IN_BLOCK && last_blk)
+ bit_offset = find_next_bit(bitmap, max, next_idx);
+ if (bit_offset >= max && last_blk)
last_de = 1;
if (tree_mark_size <= depth) {
@@ -506,101 +613,185 @@ static void print_dentry(__u32 depth, __u8 *name,
for (i = 1; i < depth; i++)
printf("%c ", tree_mark[i]);
- printf("%c-- %s\n", last_de ? '`' : '|', name);
+ printf("%c-- %s 0x%x\n", last_de ? '`' : '|',
+ name, le32_to_cpu(dentry[idx].ino));
}
-int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
- u32 blk_addr,
- u32 *child_cnt,
- u32 *child_files,
- int last_blk)
+static int __chk_dentries(struct f2fs_sb_info *sbi, u32 *child_cnt,
+ u32* child_files,
+ unsigned long *bitmap,
+ struct f2fs_dir_entry *dentry,
+ __u8 (*filenames)[F2FS_SLOT_LEN],
+ int max, int last_blk)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
- int i;
- int ret = 0;
+ enum FILE_TYPE ftype;
int dentries = 0;
+ u32 blk_cnt;
u8 *name;
u32 hash_code;
- u32 blk_cnt;
u16 name_len;;
+ int ret = 0;
+ int fixed = 0;
+ int i;
- enum FILE_TYPE ftype;
- struct f2fs_dentry_block *de_blk;
-
- de_blk = (struct f2fs_dentry_block *)calloc(BLOCK_SZ, 1);
- ASSERT(de_blk != NULL);
-
- ret = dev_read_block(de_blk, blk_addr);
- ASSERT(ret >= 0);
-
- fsck->dentry_depth++;
-
- for (i = 0; i < NR_DENTRY_IN_BLOCK;) {
- if (test_bit(i, (unsigned long *)de_blk->dentry_bitmap) == 0x0) {
+ for (i = 0; i < max;) {
+ if (test_bit(i, bitmap) == 0) {
i++;
continue;
}
-
- name_len = le32_to_cpu(de_blk->dentry[i].name_len);
+ if (!IS_VALID_NID(sbi, le32_to_cpu(dentry[i].ino))) {
+ DBG(1, "Bad dentry 0x%x with invalid NID/ino 0x%x",
+ i, le32_to_cpu(dentry[i].ino));
+ if (config.fix_on) {
+ FIX_MSG("Clear bad dentry 0x%x with bad ino 0x%x",
+ i, le32_to_cpu(dentry[i].ino));
+ clear_bit(i, bitmap);
+ i++;
+ fixed = 1;
+ continue;
+ }
+ }
+ ftype = dentry[i].file_type;
+ if ((ftype <= F2FS_FT_UNKNOWN || ftype > F2FS_FT_LAST_FILE_TYPE) && config.fix_on) {
+ DBG(1, "Bad dentry 0x%x with unexpected ftype 0x%x",
+ i, ftype);
+ if (config.fix_on) {
+ FIX_MSG("Clear bad dentry 0x%x with bad ftype 0x%x",
+ i, ftype);
+ clear_bit(i, bitmap);
+ i++;
+ fixed = 1;
+ continue;
+ }
+ }
+ name_len = le16_to_cpu(dentry[i].name_len);
name = calloc(name_len + 1, 1);
- memcpy(name, de_blk->filename[i], name_len);
-
- hash_code = f2fs_dentry_hash((const char *)name, name_len);
- ASSERT(le32_to_cpu(de_blk->dentry[i].hash_code) == hash_code);
-
- ftype = de_blk->dentry[i].file_type;
+ memcpy(name, filenames[i], name_len);
+ hash_code = f2fs_dentry_hash((const unsigned char *)name,
+ name_len);
+
+ /* fix hash_code made by old buggy code */
+ if (le32_to_cpu(dentry[i].hash_code) != hash_code) {
+ dentry[i].hash_code = hash_code;
+ fixed = 1;
+ FIX_MSG("hash_code[%d] of %s", i, name);
+ }
/* Becareful. 'dentry.file_type' is not imode. */
if (ftype == F2FS_FT_DIR) {
*child_cnt = *child_cnt + 1;
- if ((name[0] == '.' && name[1] == '.' && name_len == 2) ||
- (name[0] == '.' && name_len == 1)) {
+ if ((name[0] == '.' && name_len == 1) ||
+ (name[0] == '.' && name[1] == '.' &&
+ name_len == 2)) {
i++;
free(name);
continue;
}
}
- DBG(2, "[%3u] - no[0x%x] name[%s] len[0x%x] ino[0x%x] type[0x%x]\n",
+ DBG(1, "[%3u]-[0x%x] name[%s] len[0x%x] ino[0x%x] type[0x%x]\n",
fsck->dentry_depth, i, name, name_len,
- le32_to_cpu(de_blk->dentry[i].ino),
- de_blk->dentry[i].file_type);
+ le32_to_cpu(dentry[i].ino),
+ dentry[i].file_type);
- print_dentry(fsck->dentry_depth, name, de_blk, i, last_blk);
+ print_dentry(fsck->dentry_depth, name, bitmap,
+ dentry, max, i, last_blk);
blk_cnt = 1;
ret = fsck_chk_node_blk(sbi,
- NULL,
- le32_to_cpu(de_blk->dentry[i].ino),
- ftype,
- TYPE_INODE,
- &blk_cnt);
-
- ASSERT(ret >= 0);
+ NULL, le32_to_cpu(dentry[i].ino),
+ ftype, TYPE_INODE, &blk_cnt);
+
+ if (ret && config.fix_on) {
+ int j;
+ int slots = (name_len + F2FS_SLOT_LEN - 1) /
+ F2FS_SLOT_LEN;
+ for (j = 0; j < slots; j++)
+ clear_bit(i + j, bitmap);
+ FIX_MSG("Unlink [0x%x] - %s len[0x%x], type[0x%x]",
+ le32_to_cpu(dentry[i].ino),
+ name, name_len,
+ dentry[i].file_type);
+ i += slots;
+ free(name);
+ continue;
+ }
i += (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN;
dentries++;
*child_files = *child_files + 1;
free(name);
}
+ return fixed ? -1 : dentries;
+}
+
+int fsck_chk_inline_dentries(struct f2fs_sb_info *sbi,
+ struct f2fs_node *node_blk, u32 *child_cnt, u32 *child_files)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ struct f2fs_inline_dentry *de_blk;
+ int dentries;
- DBG(1, "[%3d] Dentry Block [0x%x] Done : dentries:%d in %d slots (len:%d)\n\n",
- fsck->dentry_depth, blk_addr, dentries, NR_DENTRY_IN_BLOCK, F2FS_NAME_LEN);
+ de_blk = inline_data_addr(node_blk);
+ ASSERT(de_blk != NULL);
+
+ fsck->dentry_depth++;
+ dentries = __chk_dentries(sbi, child_cnt, child_files,
+ (unsigned long *)de_blk->dentry_bitmap,
+ de_blk->dentry, de_blk->filename,
+ NR_INLINE_DENTRY, 1);
+ if (dentries < 0) {
+ DBG(1, "[%3d] Inline Dentry Block Fixed hash_codes\n\n",
+ fsck->dentry_depth);
+ } else {
+ DBG(1, "[%3d] Inline Dentry Block Done : "
+ "dentries:%d in %d slots (len:%d)\n\n",
+ fsck->dentry_depth, dentries,
+ (int)NR_INLINE_DENTRY, F2FS_NAME_LEN);
+ }
fsck->dentry_depth--;
+ return dentries;
+}
+
+int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
+ u32 *child_cnt, u32 *child_files, int last_blk)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ struct f2fs_dentry_block *de_blk;
+ int dentries, ret;
+
+ de_blk = (struct f2fs_dentry_block *)calloc(BLOCK_SZ, 1);
+ ASSERT(de_blk != NULL);
+
+ ret = dev_read_block(de_blk, blk_addr);
+ ASSERT(ret >= 0);
+
+ fsck->dentry_depth++;
+ dentries = __chk_dentries(sbi, child_cnt, child_files,
+ (unsigned long *)de_blk->dentry_bitmap,
+ de_blk->dentry, de_blk->filename,
+ NR_DENTRY_IN_BLOCK, last_blk);
+ if (dentries < 0) {
+ ret = dev_write_block(de_blk, blk_addr);
+ ASSERT(ret >= 0);
+ DBG(1, "[%3d] Dentry Block [0x%x] Fixed hash_codes\n\n",
+ fsck->dentry_depth, blk_addr);
+ } else {
+ DBG(1, "[%3d] Dentry Block [0x%x] Done : "
+ "dentries:%d in %d slots (len:%d)\n\n",
+ fsck->dentry_depth, blk_addr, dentries,
+ NR_DENTRY_IN_BLOCK, F2FS_NAME_LEN);
+ }
+ fsck->dentry_depth--;
free(de_blk);
return 0;
}
-int fsck_chk_data_blk(struct f2fs_sb_info *sbi,
- u32 blk_addr,
- u32 *child_cnt,
- u32 *child_files,
- int last_blk,
- enum FILE_TYPE ftype,
- u32 parent_nid,
- u16 idx_in_node,
- u8 ver)
+int fsck_chk_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
+ u32 *child_cnt, u32 *child_files, int last_blk,
+ enum FILE_TYPE ftype, u32 parent_nid, u16 idx_in_node, u8 ver)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
@@ -610,114 +801,80 @@ int fsck_chk_data_blk(struct f2fs_sb_info *sbi,
return 0;
}
- IS_VALID_BLK_ADDR(sbi, blk_addr);
-
- is_valid_ssa_data_blk(sbi, blk_addr, parent_nid, idx_in_node, ver);
-
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk_addr), fsck->sit_area_bitmap) == 0x0) {
- ASSERT_MSG(0, "SIT bitmap is 0x0. blk_addr[0x%x]\n", blk_addr);
+ if (!IS_VALID_BLK_ADDR(sbi, blk_addr)) {
+ ASSERT_MSG("blkaddres is not valid. [0x%x]", blk_addr);
+ return -EINVAL;
}
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk_addr), fsck->main_area_bitmap) != 0) {
- ASSERT_MSG(0, "Duplicated data block. pnid[0x%x] idx[0x%x] blk_addr[0x%x]\n",
- parent_nid, idx_in_node, blk_addr);
+ if (is_valid_ssa_data_blk(sbi, blk_addr, parent_nid,
+ idx_in_node, ver)) {
+ ASSERT_MSG("summary data block is not valid. [0x%x]",
+ parent_nid);
+ return -EINVAL;
}
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk_addr), fsck->main_area_bitmap);
- fsck->chk.valid_blk_cnt++;
+ if (f2fs_test_sit_bitmap(sbi, blk_addr) == 0)
+ ASSERT_MSG("SIT bitmap is 0x0. blk_addr[0x%x]", blk_addr);
- if (ftype == F2FS_FT_DIR) {
- fsck_chk_dentry_blk(sbi,
- blk_addr,
- child_cnt,
- child_files,
- last_blk);
- }
+ if (f2fs_test_main_bitmap(sbi, blk_addr) != 0)
+ ASSERT_MSG("Duplicated data [0x%x]. pnid[0x%x] idx[0x%x]",
+ blk_addr, parent_nid, idx_in_node);
+ f2fs_set_main_bitmap(sbi, blk_addr);
+
+ fsck->chk.valid_blk_cnt++;
+
+ if (ftype == F2FS_FT_DIR)
+ return fsck_chk_dentry_blk(sbi, blk_addr, child_cnt,
+ child_files, last_blk);
return 0;
}
-int fsck_chk_orphan_node(struct f2fs_sb_info *sbi)
+void fsck_chk_orphan_node(struct f2fs_sb_info *sbi)
{
- int ret = 0;
u32 blk_cnt = 0;
-
block_t start_blk, orphan_blkaddr, i, j;
struct f2fs_orphan_block *orphan_blk;
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
if (!is_set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG))
- return 0;
+ return;
+
+ if (config.fix_on)
+ return;
start_blk = __start_cp_addr(sbi) + 1 +
le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);
-
orphan_blkaddr = __start_sum_addr(sbi) - 1;
-
orphan_blk = calloc(BLOCK_SZ, 1);
for (i = 0; i < orphan_blkaddr; i++) {
- dev_read_block(orphan_blk, start_blk + i);
+ int ret = dev_read_block(orphan_blk, start_blk + i);
+
+ ASSERT(ret >= 0);
for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) {
nid_t ino = le32_to_cpu(orphan_blk->ino[j]);
DBG(1, "[%3d] ino [0x%x]\n", i, ino);
blk_cnt = 1;
- ret = fsck_chk_node_blk(sbi,
- NULL,
- ino,
- F2FS_FT_ORPHAN,
- TYPE_INODE,
- &blk_cnt);
- ASSERT(ret >= 0);
+ fsck_chk_node_blk(sbi, NULL, ino,
+ F2FS_FT_ORPHAN, TYPE_INODE, &blk_cnt);
}
memset(orphan_blk, 0, BLOCK_SZ);
}
free(orphan_blk);
-
-
- return 0;
}
-int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino, u32 x_nid, u32 *blk_cnt)
-{
- struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
- struct node_info ni;
-
- if (x_nid == 0x0)
- return 0;
-
- if (f2fs_test_bit(x_nid, fsck->nat_area_bitmap) != 0x0) {
- f2fs_clear_bit(x_nid, fsck->nat_area_bitmap);
- } else {
- ASSERT_MSG(0, "xattr_nid duplicated [0x%x]\n", x_nid);
- }
-
- *blk_cnt = *blk_cnt + 1;
- fsck->chk.valid_blk_cnt++;
- fsck->chk.valid_node_cnt++;
-
- ASSERT(get_node_info(sbi, x_nid, &ni) >= 0);
-
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap) != 0) {
- ASSERT_MSG(0, "Duplicated node block for x_attr. "
- "x_nid[0x%x] block addr[0x%x]\n",
- x_nid, ni.blk_addr);
- }
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap);
-
- DBG(2, "ino[0x%x] x_nid[0x%x]\n", ino, x_nid);
- return 0;
-}
-
-int fsck_init(struct f2fs_sb_info *sbi)
+void fsck_init(struct f2fs_sb_info *sbi)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_sm_info *sm_i = SM_I(sbi);
/*
- * We build three bitmap for main/sit/nat so that may check consistency of filesystem.
- * 1. main_area_bitmap will be used to check whether all blocks of main area is used or not.
+ * We build three bitmap for main/sit/nat so that may check consistency
+ * of filesystem.
+ * 1. main_area_bitmap will be used to check whether all blocks of main
+ * area is used or not.
* 2. nat_area_bitmap has bitmap information of used nid in NAT.
* 3. sit_area_bitmap has bitmap information of used main block.
* At Last sequence, we compare main_area_bitmap with sit_area_bitmap.
@@ -732,6 +889,83 @@ int fsck_init(struct f2fs_sb_info *sbi)
build_sit_area_bitmap(sbi);
tree_mark = calloc(tree_mark_size, 1);
+ ASSERT(tree_mark != NULL);
+}
+
+static void fix_nat_entries(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ u32 i;
+
+ for (i = 0; i < fsck->nr_nat_entries; i++)
+ if (f2fs_test_bit(i, fsck->nat_area_bitmap) != 0)
+ nullify_nat_entry(sbi, i);
+}
+
+static void fix_checkpoint(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ struct f2fs_super_block *raw_sb = sbi->raw_super;
+ struct f2fs_checkpoint *ckp = F2FS_CKPT(sbi);
+ unsigned long long cp_blk_no;
+ u32 i;
+ int ret;
+ u_int32_t crc = 0;
+
+ ckp->ckpt_flags = cpu_to_le32(CP_UMOUNT_FLAG);
+ ckp->cp_pack_total_block_count =
+ cpu_to_le32(8 + le32_to_cpu(raw_sb->cp_payload));
+ ckp->cp_pack_start_sum = cpu_to_le32(1 +
+ le32_to_cpu(raw_sb->cp_payload));
+
+ ckp->free_segment_count = cpu_to_le32(fsck->chk.free_segs);
+ ckp->valid_block_count = cpu_to_le32(fsck->chk.valid_blk_cnt);
+ ckp->valid_node_count = cpu_to_le32(fsck->chk.valid_node_cnt);
+ ckp->valid_inode_count = cpu_to_le32(fsck->chk.valid_inode_cnt);
+
+ crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, ckp, CHECKSUM_OFFSET);
+ *((__le32 *)((unsigned char *)ckp + CHECKSUM_OFFSET)) =
+ cpu_to_le32(crc);
+
+ cp_blk_no = le32_to_cpu(raw_sb->cp_blkaddr);
+ if (sbi->cur_cp == 2)
+ cp_blk_no += 1 << le32_to_cpu(raw_sb->log_blocks_per_seg);
+
+ ret = dev_write_block(ckp, cp_blk_no++);
+ ASSERT(ret >= 0);
+
+ for (i = 0; i < le32_to_cpu(raw_sb->cp_payload); i++) {
+ ret = dev_write_block(((unsigned char *)ckp) + i * F2FS_BLKSIZE,
+ cp_blk_no++);
+ ASSERT(ret >= 0);
+ }
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+
+ ret = dev_write_block(curseg->sum_blk, cp_blk_no++);
+ ASSERT(ret >= 0);
+ }
+
+ ret = dev_write_block(ckp, cp_blk_no++);
+ ASSERT(ret >= 0);
+}
+
+int check_curseg_offset(struct f2fs_sb_info *sbi)
+{
+ int i;
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+ struct seg_entry *se;
+
+ se = get_seg_entry(sbi, curseg->segno);
+ if (f2fs_test_bit(curseg->next_blkoff,
+ (const char *)se->cur_valid_map) == 1) {
+ ASSERT_MSG("Next block offset is not free, type:%d", i);
+ return -EINVAL;
+ }
+ }
return 0;
}
@@ -759,6 +993,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
node->nid, node->links);
node = node->next;
}
+ config.bug_on = 1;
}
printf("[FSCK] Unreachable nat entries ");
@@ -767,14 +1002,17 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", nr_unref_nid);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] SIT valid block bitmap checking ");
- if (memcmp(fsck->sit_area_bitmap, fsck->main_area_bitmap, fsck->sit_area_bitmap_sz) == 0x0) {
+ if (memcmp(fsck->sit_area_bitmap, fsck->main_area_bitmap,
+ fsck->sit_area_bitmap_sz) == 0x0) {
printf("[Ok..]\n");
} else {
printf("[Fail]\n");
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] Hard link checking for regular file ");
@@ -783,6 +1021,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.multi_hard_link_files);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_block_count matching with CP ");
@@ -791,6 +1030,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", (u32)fsck->chk.valid_blk_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_node_count matcing with CP (de lookup) ");
@@ -799,6 +1039,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.valid_node_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_node_count matcing with CP (nat lookup) ");
@@ -807,6 +1048,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.valid_nat_entry_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_inode_count matched with CP ");
@@ -815,8 +1057,43 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.valid_inode_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
+ printf("[FSCK] free segment_count matched with CP ");
+ if (le32_to_cpu(F2FS_CKPT(sbi)->free_segment_count) ==
+ fsck->chk.sit_free_segs) {
+ printf(" [Ok..] [0x%x]\n", fsck->chk.sit_free_segs);
+ } else {
+ printf(" [Fail] [0x%x]\n", fsck->chk.sit_free_segs);
+ ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
+ }
+
+ printf("[FSCK] next block offset is free ");
+ if (check_curseg_offset(sbi) == 0) {
+ printf(" [Ok..]\n");
+ } else {
+ printf(" [Fail]\n");
+ ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
+ }
+
+ printf("[FSCK] other corrupted bugs ");
+ if (config.bug_on == 0) {
+ printf(" [Ok..]\n");
+ } else {
+ printf(" [Fail]\n");
+ ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
+ }
+
+ /* fix global metadata */
+ if (config.bug_on && config.fix_on) {
+ fix_nat_entries(sbi);
+ rewrite_sit_area_bitmap(sbi);
+ fix_checkpoint(sbi);
+ }
return ret;
}
diff --git a/fsck/fsck.h b/fsck/fsck.h
index e5a3841..49d6d1d 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -31,6 +31,7 @@ struct f2fs_fsck {
u32 multi_hard_link_files;
u64 sit_valid_blocks;
u32 sit_free_segs;
+ u32 free_segs;
} chk;
struct hard_link_node *hard_link_list_head;
@@ -59,7 +60,8 @@ enum NODE_TYPE {
TYPE_INODE = 37,
TYPE_DIRECT_NODE = 43,
TYPE_INDIRECT_NODE = 53,
- TYPE_DOUBLE_INDIRECT_NODE = 67
+ TYPE_DOUBLE_INDIRECT_NODE = 67,
+ TYPE_XATTR = 77
};
struct hard_link_node {
@@ -76,72 +78,40 @@ enum seg_type {
SEG_TYPE_MAX,
};
-extern int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino, u32 x_nid, u32 *blk_cnt);
-extern int fsck_chk_orphan_node(struct f2fs_sb_info *sbi);
-
-extern int fsck_chk_node_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- enum NODE_TYPE ntype,
- u32 *blk_cnt);
-
-extern int fsck_chk_inode_blk(struct f2fs_sb_info *sbi,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt,
- struct node_info *ni);
-
-extern int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt,
- struct node_info *ni);
-
-extern int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt);
-
-extern int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt);
-
-extern int fsck_chk_data_blk(struct f2fs_sb_info *sbi,
- u32 blk_addr,
- u32 *child_cnt,
- u32 *child_files,
- int last_blk,
- enum FILE_TYPE ftype,
- u32 parent_nid,
- u16 idx_in_node,
- u8 ver);
-
-extern int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
- u32 blk_addr,
- u32 *child_cnt,
- u32 *child_files,
- int last_blk);
-
-extern void print_node_info(struct f2fs_node *node_block);
-extern void print_inode_info(struct f2fs_inode *inode);
-extern struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi, unsigned int segno);
-extern int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summary_block *sum_blk);
-extern int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, struct f2fs_summary *sum_entry);
-extern int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni);
-extern void build_nat_area_bitmap(struct f2fs_sb_info *sbi);
-extern int build_sit_area_bitmap(struct f2fs_sb_info *sbi);
-extern int fsck_init(struct f2fs_sb_info *sbi);
-extern int fsck_verify(struct f2fs_sb_info *sbi);
-extern void fsck_free(struct f2fs_sb_info *sbi);
-extern int f2fs_do_mount(struct f2fs_sb_info *sbi);
-extern void f2fs_do_umount(struct f2fs_sb_info *sbi);
+extern void fsck_chk_orphan_node(struct f2fs_sb_info *);
+extern int fsck_chk_node_blk(struct f2fs_sb_info *, struct f2fs_inode *, u32,
+ enum FILE_TYPE, enum NODE_TYPE, u32 *);
+extern void fsck_chk_inode_blk(struct f2fs_sb_info *, u32, enum FILE_TYPE,
+ struct f2fs_node *, u32 *, struct node_info *);
+extern int fsck_chk_dnode_blk(struct f2fs_sb_info *, struct f2fs_inode *,
+ u32, enum FILE_TYPE, struct f2fs_node *, u32 *,
+ struct node_info *);
+extern int fsck_chk_idnode_blk(struct f2fs_sb_info *, struct f2fs_inode *,
+ enum FILE_TYPE, struct f2fs_node *, u32 *);
+extern int fsck_chk_didnode_blk(struct f2fs_sb_info *, struct f2fs_inode *,
+ enum FILE_TYPE, struct f2fs_node *, u32 *);
+extern int fsck_chk_data_blk(struct f2fs_sb_info *sbi, u32, u32 *, u32 *,
+ int, enum FILE_TYPE, u32, u16, u8);
+extern int fsck_chk_dentry_blk(struct f2fs_sb_info *, u32, u32 *, u32 *, int);
+int fsck_chk_inline_dentries(struct f2fs_sb_info *, struct f2fs_node *,
+ u32 *, u32 *);
+
+extern void print_node_info(struct f2fs_node *);
+extern void print_inode_info(struct f2fs_inode *);
+extern struct seg_entry *get_seg_entry(struct f2fs_sb_info *, unsigned int);
+extern int get_sum_block(struct f2fs_sb_info *, unsigned int,
+ struct f2fs_summary_block *);
+extern int get_sum_entry(struct f2fs_sb_info *, u32, struct f2fs_summary *);
+extern void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
+extern void nullify_nat_entry(struct f2fs_sb_info *, u32);
+extern void rewrite_sit_area_bitmap(struct f2fs_sb_info *);
+extern void build_nat_area_bitmap(struct f2fs_sb_info *);
+extern void build_sit_area_bitmap(struct f2fs_sb_info *);
+extern void fsck_init(struct f2fs_sb_info *);
+extern int fsck_verify(struct f2fs_sb_info *);
+extern void fsck_free(struct f2fs_sb_info *);
+extern int f2fs_do_mount(struct f2fs_sb_info *);
+extern void f2fs_do_umount(struct f2fs_sb_info *);
/* dump.c */
struct dump_option {
@@ -153,9 +123,9 @@ struct dump_option {
int32_t blk_addr;
};
-extern void sit_dump(struct f2fs_sb_info *sbi, int start_sit, int end_sit);
-extern void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa);
-extern int dump_node(struct f2fs_sb_info *sbi, nid_t nid);
-extern int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr);
+extern void sit_dump(struct f2fs_sb_info *, int, int);
+extern void ssa_dump(struct f2fs_sb_info *, int, int);
+extern void dump_node(struct f2fs_sb_info *, nid_t);
+extern int dump_inode_from_blkaddr(struct f2fs_sb_info *, u32);
#endif /* _FSCK_H_ */
diff --git a/fsck/main.c b/fsck/main.c
index 46f5d04..2af3daf 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -11,15 +11,16 @@
#include "fsck.h"
#include <libgen.h>
-struct f2fs_fsck gfsck = {
- .sbi = { .fsck = &gfsck, },
-};
+struct f2fs_fsck gfsck;
void fsck_usage()
{
MSG(0, "\nUsage: fsck.f2fs [options] device\n");
MSG(0, "[options]:\n");
+ MSG(0, " -a check/fix potential corruption, reported by f2fs\n");
MSG(0, " -d debug level [default:0]\n");
+ MSG(0, " -f check/fix entire partition\n");
+ MSG(0, " -t show directory tree [-d -1]\n");
exit(1);
}
@@ -42,22 +43,31 @@ void f2fs_parse_options(int argc, char *argv[])
char *prog = basename(argv[0]);
if (!strcmp("fsck.f2fs", prog)) {
- const char *option_string = "d:t";
+ const char *option_string = "ad:ft";
config.func = FSCK;
while ((option = getopt(argc, argv, option_string)) != EOF) {
switch (option) {
- case 'd':
- config.dbg_lv = atoi(optarg);
- MSG(0, "Info: Debug level = %d\n", config.dbg_lv);
- break;
- case 't':
- config.dbg_lv = -1;
- break;
- default:
- MSG(0, "\tError: Unknown option %c\n",option);
- fsck_usage();
- break;
+ case 'a':
+ config.auto_fix = 1;
+ MSG(0, "Info: Fix the reported corruption.\n");
+ break;
+ case 'd':
+ config.dbg_lv = atoi(optarg);
+ MSG(0, "Info: Debug level = %d\n",
+ config.dbg_lv);
+ break;
+ case 'f':
+ config.fix_on = 1;
+ MSG(0, "Info: Force to fix corruption\n");
+ break;
+ case 't':
+ config.dbg_lv = -1;
+ break;
+ default:
+ MSG(0, "\tError: Unknown option %c\n", option);
+ fsck_usage();
+ break;
}
}
} else if (!strcmp("dump.f2fs", prog)) {
@@ -73,34 +83,46 @@ void f2fs_parse_options(int argc, char *argv[])
config.func = DUMP;
while ((option = getopt(argc, argv, option_string)) != EOF) {
+ int ret = 0;
+
switch (option) {
- case 'd':
- config.dbg_lv = atoi(optarg);
- MSG(0, "Info: Debug level = %d\n", config.dbg_lv);
- break;
- case 'i':
- if (strncmp(optarg, "0x", 2))
- sscanf(optarg, "%d", &dump_opt.nid);
- else
- sscanf(optarg, "%x", &dump_opt.nid);
- break;
- case 's':
- sscanf(optarg, "%d~%d", &dump_opt.start_sit, &dump_opt.end_sit);
- break;
- case 'a':
- sscanf(optarg, "%d~%d", &dump_opt.start_ssa, &dump_opt.end_ssa);
- break;
- case 'b':
- if (strncmp(optarg, "0x", 2))
- sscanf(optarg, "%d", &dump_opt.blk_addr);
- else
- sscanf(optarg, "%x", &dump_opt.blk_addr);
- break;
- default:
- MSG(0, "\tError: Unknown option %c\n", option);
- dump_usage();
- break;
+ case 'd':
+ config.dbg_lv = atoi(optarg);
+ MSG(0, "Info: Debug level = %d\n",
+ config.dbg_lv);
+ break;
+ case 'i':
+ if (strncmp(optarg, "0x", 2))
+ ret = sscanf(optarg, "%d",
+ &dump_opt.nid);
+ else
+ ret = sscanf(optarg, "%x",
+ &dump_opt.nid);
+ break;
+ case 's':
+ ret = sscanf(optarg, "%d~%d",
+ &dump_opt.start_sit,
+ &dump_opt.end_sit);
+ break;
+ case 'a':
+ ret = sscanf(optarg, "%d~%d",
+ &dump_opt.start_ssa,
+ &dump_opt.end_ssa);
+ break;
+ case 'b':
+ if (strncmp(optarg, "0x", 2))
+ ret = sscanf(optarg, "%d",
+ &dump_opt.blk_addr);
+ else
+ ret = sscanf(optarg, "%x",
+ &dump_opt.blk_addr);
+ break;
+ default:
+ MSG(0, "\tError: Unknown option %c\n", option);
+ dump_usage();
+ break;
}
+ ASSERT(ret >= 0);
}
config.private = &dump_opt;
@@ -116,43 +138,27 @@ void f2fs_parse_options(int argc, char *argv[])
config.device_name = argv[optind];
}
-int do_fsck(struct f2fs_sb_info *sbi)
+static void do_fsck(struct f2fs_sb_info *sbi)
{
u32 blk_cnt;
- int ret;
- ret = fsck_init(sbi);
- if (ret < 0)
- return ret;
+ fsck_init(sbi);
fsck_chk_orphan_node(sbi);
- /* Travses all block recursively from root inode */
+ /* Traverse all block recursively from root inode */
blk_cnt = 1;
- ret = fsck_chk_node_blk(sbi,
- NULL,
- sbi->root_ino_num,
- F2FS_FT_DIR,
- TYPE_INODE,
- &blk_cnt);
- if (ret < 0)
- goto out1;
-
- ret = fsck_verify(sbi);
-
-out1:
+ fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num,
+ F2FS_FT_DIR, TYPE_INODE, &blk_cnt);
+ fsck_verify(sbi);
fsck_free(sbi);
- return ret;
}
-int do_dump(struct f2fs_sb_info *sbi)
+static void do_dump(struct f2fs_sb_info *sbi)
{
struct dump_option *opt = (struct dump_option *)config.private;
- int ret;
- ret = fsck_init(sbi);
- if (ret < 0)
- return ret;
+ fsck_init(sbi);
if (opt->end_sit == -1)
opt->end_sit = SM_I(sbi)->main_segments;
@@ -166,17 +172,14 @@ int do_dump(struct f2fs_sb_info *sbi)
dump_inode_from_blkaddr(sbi, opt->blk_addr);
goto cleanup;
}
-
dump_node(sbi, opt->nid);
-
cleanup:
fsck_free(sbi);
- return 0;
}
-int main (int argc, char **argv)
+int main(int argc, char **argv)
{
- struct f2fs_sb_info *sbi = &gfsck.sbi;
+ struct f2fs_sb_info *sbi;
int ret = 0;
f2fs_init_configuration(&config);
@@ -189,23 +192,50 @@ int main (int argc, char **argv)
/* Get device */
if (f2fs_get_device_info(&config) < 0)
return -1;
-
- if (f2fs_do_mount(sbi) < 0)
+fsck_again:
+ memset(&gfsck, 0, sizeof(gfsck));
+ gfsck.sbi.fsck = &gfsck;
+ sbi = &gfsck.sbi;
+
+ ret = f2fs_do_mount(sbi);
+ if (ret == 1) {
+ free(sbi->ckpt);
+ free(sbi->raw_super);
+ goto out;
+ } else if (ret < 0)
return -1;
switch (config.func) {
- case FSCK:
- ret = do_fsck(sbi);
- break;
- case DUMP:
- ret = do_dump(sbi);
- break;
+ case FSCK:
+ do_fsck(sbi);
+ break;
+ case DUMP:
+ do_dump(sbi);
+ break;
}
f2fs_do_umount(sbi);
-
+out:
+ if (config.func == FSCK && config.bug_on) {
+ if (config.fix_on == 0 && config.auto_fix == 0) {
+ char ans[255] = {0};
+retry:
+ printf("Do you want to fix this partition? [Y/N] ");
+ ret = scanf("%s", ans);
+ ASSERT(ret >= 0);
+ if (!strcasecmp(ans, "y"))
+ config.fix_on = 1;
+ else if (!strcasecmp(ans, "n"))
+ config.fix_on = 0;
+ else
+ goto retry;
+
+ if (config.fix_on)
+ goto fsck_again;
+ }
+ }
f2fs_finalize_device(&config);
printf("\nDone.\n");
- return ret;
+ return 0;
}
diff --git a/fsck/mount.c b/fsck/mount.c
index 5d3231f..9ec6004 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -33,6 +33,7 @@ void print_inode_info(struct f2fs_inode *inode)
DISP_u32(inode, i_current_depth);
DISP_u32(inode, i_xattr_nid);
DISP_u32(inode, i_flags);
+ DISP_u32(inode, i_inline);
DISP_u32(inode, i_pino);
if (namelen) {
@@ -53,7 +54,7 @@ void print_inode_info(struct f2fs_inode *inode)
for (i = 4; i < ADDRS_PER_INODE(inode); i++) {
if (inode->i_addr[i] != 0x0) {
- printf("i_addr[0x%x] points data block\r\t\t\t\t[0x%4x]\n",
+ printf("i_addr[0x%x] points data block\r\t\t[0x%4x]\n",
i, inode->i_addr[i]);
break;
}
@@ -79,9 +80,11 @@ void print_node_info(struct f2fs_node *node_block)
} else {
int i;
u32 *dump_blk = (u32 *)node_block;
- DBG(0, "Node ID [0x%x:%u] is direct node or indirect node.\n", nid, nid);
+ DBG(0, "Node ID [0x%x:%u] is direct node or indirect node.\n",
+ nid, nid);
for (i = 0; i <= 10; i++)
- MSG(0, "[%d]\t\t\t[0x%8x : %d]\n", i, dump_blk[i], dump_blk[i]);
+ MSG(0, "[%d]\t\t\t[0x%8x : %d]\n",
+ i, dump_blk[i], dump_blk[i]);
}
}
@@ -211,7 +214,8 @@ int sanity_check_raw_super(struct f2fs_super_block *raw_super)
return -1;
}
- if (F2FS_LOG_SECTORS_PER_BLOCK != le32_to_cpu(raw_super->log_sectors_per_block)) {
+ if (F2FS_LOG_SECTORS_PER_BLOCK !=
+ le32_to_cpu(raw_super->log_sectors_per_block)) {
return -1;
}
@@ -220,9 +224,14 @@ int sanity_check_raw_super(struct f2fs_super_block *raw_super)
int validate_super_block(struct f2fs_sb_info *sbi, int block)
{
- u64 offset = (block + 1) * F2FS_SUPER_OFFSET;
+ u64 offset;
sbi->raw_super = malloc(sizeof(struct f2fs_super_block));
+ if (block == 0)
+ offset = F2FS_SUPER_OFFSET;
+ else
+ offset = F2FS_BLKSIZE + F2FS_SUPER_OFFSET;
+
if (dev_read(sbi->raw_super, offset, sizeof(struct f2fs_super_block)))
return -1;
@@ -230,7 +239,7 @@ int validate_super_block(struct f2fs_sb_info *sbi, int block)
return 0;
free(sbi->raw_super);
- MSG(0, "\tCan't find a valid F2FS filesystem in %d superblock\n", block);
+ MSG(0, "\tCan't find a valid F2FS superblock at 0x%x\n", block);
return -EINVAL;
}
@@ -258,7 +267,8 @@ int init_sb_info(struct f2fs_sb_info *sbi)
return 0;
}
-void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr, unsigned long long *version)
+void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr,
+ unsigned long long *version)
{
void *cp_page_1, *cp_page_2;
struct f2fs_checkpoint *cp_block;
@@ -322,6 +332,7 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
unsigned long long cp1_version = 0, cp2_version = 0;
unsigned long long cp_start_blk_no;
unsigned int cp_blks = 1 + le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);
+ int ret;
sbi->ckpt = malloc(cp_blks * blk_size);
if (!sbi->ckpt)
@@ -338,14 +349,19 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version);
if (cp1 && cp2) {
- if (ver_after(cp2_version, cp1_version))
+ if (ver_after(cp2_version, cp1_version)) {
cur_page = cp2;
- else
+ sbi->cur_cp = 2;
+ } else {
cur_page = cp1;
+ sbi->cur_cp = 1;
+ }
} else if (cp1) {
cur_page = cp1;
+ sbi->cur_cp = 1;
} else if (cp2) {
cur_page = cp2;
+ sbi->cur_cp = 2;
} else {
free(cp1);
free(cp2);
@@ -355,16 +371,18 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
memcpy(sbi->ckpt, cur_page, blk_size);
if (cp_blks > 1) {
- int i;
+ unsigned int i;
unsigned long long cp_blk_no;
cp_blk_no = le32_to_cpu(raw_sb->cp_blkaddr);
if (cur_page == cp2)
- cp_blk_no += 1 << le32_to_cpu(raw_sb->log_blocks_per_seg);
+ cp_blk_no += 1 <<
+ le32_to_cpu(raw_sb->log_blocks_per_seg);
/* copy sit bitmap */
for (i = 1; i < cp_blks; i++) {
unsigned char *ckpt = (unsigned char *)sbi->ckpt;
- dev_read_block(cur_page, cp_blk_no + i);
+ ret = dev_read_block(cur_page, cp_blk_no + i);
+ ASSERT(ret >= 0);
memcpy(ckpt + i * blk_size, cur_page, blk_size);
}
}
@@ -490,196 +508,178 @@ int build_sit_info(struct f2fs_sb_info *sbi)
void reset_curseg(struct f2fs_sb_info *sbi, int type)
{
struct curseg_info *curseg = CURSEG_I(sbi, type);
+ struct summary_footer *sum_footer;
+ struct seg_entry *se;
- curseg->segno = curseg->next_segno;
- curseg->zone = GET_ZONENO_FROM_SEGNO(sbi, curseg->segno);
- curseg->next_blkoff = 0;
- curseg->next_segno = NULL_SEGNO;
-
+ sum_footer = &(curseg->sum_blk->footer);
+ memset(sum_footer, 0, sizeof(struct summary_footer));
+ if (IS_DATASEG(type))
+ SET_SUM_TYPE(sum_footer, SUM_TYPE_DATA);
+ if (IS_NODESEG(type))
+ SET_SUM_TYPE(sum_footer, SUM_TYPE_NODE);
+ se = get_seg_entry(sbi, curseg->segno);
+ se->type = type;
}
-int read_compacted_summaries(struct f2fs_sb_info *sbi)
+static void read_compacted_summaries(struct f2fs_sb_info *sbi)
{
- struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct curseg_info *curseg;
+ unsigned int i, j, offset;
block_t start;
char *kaddr;
- unsigned int i, j, offset;
+ int ret;
start = start_sum_block(sbi);
kaddr = (char *)malloc(PAGE_SIZE);
- dev_read_block(kaddr, start++);
+ ret = dev_read_block(kaddr, start++);
+ ASSERT(ret >= 0);
curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
memcpy(&curseg->sum_blk->n_nats, kaddr, SUM_JOURNAL_SIZE);
curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
- memcpy(&curseg->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE);
+ memcpy(&curseg->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE,
+ SUM_JOURNAL_SIZE);
offset = 2 * SUM_JOURNAL_SIZE;
for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
unsigned short blk_off;
- unsigned int segno;
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
- curseg = CURSEG_I(sbi, i);
- segno = le32_to_cpu(ckpt->cur_data_segno[i]);
- blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]);
- curseg->next_segno = segno;
reset_curseg(sbi, i);
- curseg->alloc_type = ckpt->alloc_type[i];
- curseg->next_blkoff = blk_off;
if (curseg->alloc_type == SSR)
blk_off = sbi->blocks_per_seg;
+ else
+ blk_off = curseg->next_blkoff;
for (j = 0; j < blk_off; j++) {
struct f2fs_summary *s;
s = (struct f2fs_summary *)(kaddr + offset);
curseg->sum_blk->entries[j] = *s;
offset += SUMMARY_SIZE;
- if (offset + SUMMARY_SIZE <= PAGE_CACHE_SIZE - SUM_FOOTER_SIZE)
+ if (offset + SUMMARY_SIZE <=
+ PAGE_CACHE_SIZE - SUM_FOOTER_SIZE)
continue;
memset(kaddr, 0, PAGE_SIZE);
- dev_read_block(kaddr, start++);
+ ret = dev_read_block(kaddr, start++);
+ ASSERT(ret >= 0);
offset = 0;
}
}
-
free(kaddr);
- return 0;
}
-int restore_node_summary(struct f2fs_sb_info *sbi,
+static void restore_node_summary(struct f2fs_sb_info *sbi,
unsigned int segno, struct f2fs_summary_block *sum_blk)
{
struct f2fs_node *node_blk;
struct f2fs_summary *sum_entry;
- void *page;
block_t addr;
unsigned int i;
+ int ret;
- page = malloc(PAGE_SIZE);
- if (!page)
- return -ENOMEM;
+ node_blk = malloc(F2FS_BLKSIZE);
+ ASSERT(node_blk);
/* scan the node segment */
addr = START_BLOCK(sbi, segno);
sum_entry = &sum_blk->entries[0];
for (i = 0; i < sbi->blocks_per_seg; i++, sum_entry++) {
- if (dev_read_block(page, addr))
- goto out;
-
- node_blk = (struct f2fs_node *)page;
+ ret = dev_read_block(node_blk, addr);
+ ASSERT(ret >= 0);
sum_entry->nid = node_blk->footer.nid;
- /* do not change original value */
-#if 0
- sum_entry->version = 0;
- sum_entry->ofs_in_node = 0;
-#endif
addr++;
-
}
-out:
- free(page);
- return 0;
+ free(node_blk);
}
-int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
+static void read_normal_summaries(struct f2fs_sb_info *sbi, int type)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct f2fs_summary_block *sum_blk;
struct curseg_info *curseg;
- unsigned short blk_off;
unsigned int segno = 0;
block_t blk_addr = 0;
+ int ret;
if (IS_DATASEG(type)) {
segno = le32_to_cpu(ckpt->cur_data_segno[type]);
- blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - CURSEG_HOT_DATA]);
-
if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG))
blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type);
else
blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type);
} else {
- segno = le32_to_cpu(ckpt->cur_node_segno[type - CURSEG_HOT_NODE]);
- blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type - CURSEG_HOT_NODE]);
-
+ segno = le32_to_cpu(ckpt->cur_node_segno[type -
+ CURSEG_HOT_NODE]);
if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG))
- blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, type - CURSEG_HOT_NODE);
+ blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE,
+ type - CURSEG_HOT_NODE);
else
blk_addr = GET_SUM_BLKADDR(sbi, segno);
}
sum_blk = (struct f2fs_summary_block *)malloc(PAGE_SIZE);
- dev_read_block(sum_blk, blk_addr);
-
- if (IS_NODESEG(type)) {
- if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) {
- struct f2fs_summary *sum_entry = &sum_blk->entries[0];
- unsigned int i;
- for (i = 0; i < sbi->blocks_per_seg; i++, sum_entry++) {
- /* do not change original value */
-#if 0
- sum_entry->version = 0;
- sum_entry->ofs_in_node = 0;
-#endif
- }
- } else {
- if (restore_node_summary(sbi, segno, sum_blk)) {
- free(sum_blk);
- return -EINVAL;
- }
- }
- }
+ ret = dev_read_block(sum_blk, blk_addr);
+ ASSERT(ret >= 0);
+
+ if (IS_NODESEG(type) && !is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG))
+ restore_node_summary(sbi, segno, sum_blk);
curseg = CURSEG_I(sbi, type);
memcpy(curseg->sum_blk, sum_blk, PAGE_CACHE_SIZE);
- curseg->next_segno = segno;
reset_curseg(sbi, type);
- curseg->alloc_type = ckpt->alloc_type[type];
- curseg->next_blkoff = blk_off;
free(sum_blk);
-
- return 0;
}
-int restore_curseg_summaries(struct f2fs_sb_info *sbi)
+static void restore_curseg_summaries(struct f2fs_sb_info *sbi)
{
int type = CURSEG_HOT_DATA;
if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) {
- if (read_compacted_summaries(sbi))
- return -EINVAL;
+ read_compacted_summaries(sbi);
type = CURSEG_HOT_NODE;
}
- for (; type <= CURSEG_COLD_NODE; type++) {
- if (read_normal_summaries(sbi, type))
- return -EINVAL;
- }
- return 0;
+ for (; type <= CURSEG_COLD_NODE; type++)
+ read_normal_summaries(sbi, type);
}
-int build_curseg(struct f2fs_sb_info *sbi)
+static void build_curseg(struct f2fs_sb_info *sbi)
{
+ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct curseg_info *array;
+ unsigned short blk_off;
+ unsigned int segno;
int i;
array = malloc(sizeof(*array) * NR_CURSEG_TYPE);
+ ASSERT(array);
SM_I(sbi)->curseg_array = array;
for (i = 0; i < NR_CURSEG_TYPE; i++) {
array[i].sum_blk = malloc(PAGE_CACHE_SIZE);
- if (!array[i].sum_blk)
- return -ENOMEM;
- array[i].segno = NULL_SEGNO;
- array[i].next_blkoff = 0;
+ ASSERT(array[i].sum_blk);
+ if (i <= CURSEG_COLD_DATA) {
+ blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]);
+ segno = le32_to_cpu(ckpt->cur_data_segno[i]);
+ }
+ if (i > CURSEG_COLD_DATA) {
+ blk_off = le16_to_cpu(ckpt->cur_node_blkoff[i -
+ CURSEG_HOT_NODE]);
+ segno = le32_to_cpu(ckpt->cur_node_segno[i -
+ CURSEG_HOT_NODE]);
+ }
+ array[i].segno = segno;
+ array[i].zone = GET_ZONENO_FROM_SEGNO(sbi, segno);
+ array[i].next_segno = NULL_SEGNO;
+ array[i].next_blkoff = blk_off;
+ array[i].alloc_type = ckpt->alloc_type[i];
}
- return restore_curseg_summaries(sbi);
+ restore_curseg_summaries(sbi);
}
inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
@@ -688,12 +688,14 @@ inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
ASSERT(segno <= end_segno);
}
-struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *sbi, unsigned int segno)
+static struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *sbi,
+ unsigned int segno)
{
struct sit_info *sit_i = SIT_I(sbi);
unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno);
block_t blk_addr = sit_i->sit_base_addr + offset;
struct f2fs_sit_block *sit_blk = calloc(BLOCK_SZ, 1);
+ int ret;
check_seg_range(sbi, segno);
@@ -701,11 +703,28 @@ struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *sbi, unsigned i
if (f2fs_test_bit(offset, sit_i->sit_bitmap))
blk_addr += sit_i->sit_blocks;
- dev_read_block(sit_blk, blk_addr);
+ ret = dev_read_block(sit_blk, blk_addr);
+ ASSERT(ret >= 0);
return sit_blk;
}
+void rewrite_current_sit_page(struct f2fs_sb_info *sbi,
+ unsigned int segno, struct f2fs_sit_block *sit_blk)
+{
+ struct sit_info *sit_i = SIT_I(sbi);
+ unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno);
+ block_t blk_addr = sit_i->sit_base_addr + offset;
+ int ret;
+
+ /* calculate sit block address */
+ if (f2fs_test_bit(offset, sit_i->sit_bitmap))
+ blk_addr += sit_i->sit_blocks;
+
+ ret = dev_write_block(sit_blk, blk_addr);
+ ASSERT(ret >= 0);
+}
+
void check_block_count(struct f2fs_sb_info *sbi,
unsigned int segno, struct f2fs_sit_entry *raw_sit)
{
@@ -714,18 +733,26 @@ void check_block_count(struct f2fs_sb_info *sbi,
int valid_blocks = 0;
unsigned int i;
-
/* check segment usage */
- ASSERT(GET_SIT_VBLOCKS(raw_sit) <= sbi->blocks_per_seg);
+ if (GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg)
+ ASSERT_MSG("Invalid SIT vblocks: segno=0x%x, %u",
+ segno, GET_SIT_VBLOCKS(raw_sit));
/* check boundary of a given segment number */
- ASSERT(segno <= end_segno);
+ if (segno > end_segno)
+ ASSERT_MSG("Invalid SEGNO: 0x%x", segno);
/* check bitmap with valid block count */
- for (i = 0; i < sbi->blocks_per_seg; i++)
- if (f2fs_test_bit(i, (char *)raw_sit->valid_map))
- valid_blocks++;
- ASSERT(GET_SIT_VBLOCKS(raw_sit) == valid_blocks);
+ for (i = 0; i < SIT_VBLOCK_MAP_SIZE; i++)
+ valid_blocks += get_bits_in_byte(raw_sit->valid_map[i]);
+
+ if (GET_SIT_VBLOCKS(raw_sit) != valid_blocks)
+ ASSERT_MSG("Wrong SIT valid blocks: segno=0x%x, %u vs. %u",
+ segno, GET_SIT_VBLOCKS(raw_sit), valid_blocks);
+
+ if (GET_SIT_TYPE(raw_sit) >= NO_CHECK_TYPE)
+ ASSERT_MSG("Wrong SIT type: segno=0x%x, %u",
+ segno, GET_SIT_TYPE(raw_sit));
}
void seg_info_from_raw_sit(struct seg_entry *se,
@@ -746,7 +773,8 @@ struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi,
return &sit_i->sentries[segno];
}
-int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summary_block *sum_blk)
+int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno,
+ struct f2fs_summary_block *sum_blk)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct curseg_info *curseg;
@@ -757,18 +785,30 @@ int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summ
for (type = 0; type < NR_CURSEG_NODE_TYPE; type++) {
if (segno == ckpt->cur_node_segno[type]) {
curseg = CURSEG_I(sbi, CURSEG_HOT_NODE + type);
+ if (!IS_SUM_NODE_SEG(curseg->sum_blk->footer)) {
+ ASSERT_MSG("segno [0x%x] indicates a data "
+ "segment, but should be node",
+ segno);
+ return -EINVAL;
+ }
memcpy(sum_blk, curseg->sum_blk, BLOCK_SZ);
- return SEG_TYPE_CUR_NODE; /* current node seg was not stored */
+ return SEG_TYPE_CUR_NODE;
}
}
for (type = 0; type < NR_CURSEG_DATA_TYPE; type++) {
if (segno == ckpt->cur_data_segno[type]) {
curseg = CURSEG_I(sbi, type);
+ if (IS_SUM_NODE_SEG(curseg->sum_blk->footer)) {
+ ASSERT_MSG("segno [0x%x] indicates a node "
+ "segment, but should be data",
+ segno);
+ return -EINVAL;
+ }
+ DBG(2, "segno [0x%x] is current data seg[0x%x]\n",
+ segno, type);
memcpy(sum_blk, curseg->sum_blk, BLOCK_SZ);
- ASSERT(!IS_SUM_NODE_SEG(sum_blk->footer));
- DBG(2, "segno [0x%x] is current data seg[0x%x]\n", segno, type);
- return SEG_TYPE_CUR_DATA; /* current data seg was not stored */
+ return SEG_TYPE_CUR_DATA;
}
}
@@ -782,7 +822,8 @@ int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summ
}
-int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, struct f2fs_summary *sum_entry)
+int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr,
+ struct f2fs_summary *sum_entry)
{
struct f2fs_summary_block *sum_blk;
u32 segno, offset;
@@ -794,16 +835,15 @@ int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, struct f2fs_summary *s
sum_blk = calloc(BLOCK_SZ, 1);
ret = get_sum_block(sbi, segno, sum_blk);
-
- memcpy(sum_entry, &(sum_blk->entries[offset]), sizeof(struct f2fs_summary));
-
+ memcpy(sum_entry, &(sum_blk->entries[offset]),
+ sizeof(struct f2fs_summary));
free(sum_blk);
return ret;
}
-int get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, struct f2fs_nat_entry *raw_nat)
+static void get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid,
+ struct f2fs_nat_entry *raw_nat)
{
- struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct f2fs_nat_block *nat_block;
pgoff_t block_off;
@@ -811,13 +851,8 @@ int get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, struct f2fs_nat_entry *ra
int seg_off, entry_off;
int ret;
- if ((nid / NAT_ENTRY_PER_BLOCK) > fsck->nr_nat_entries) {
- DBG(0, "nid is over max nid\n");
- return -EINVAL;
- }
-
if (lookup_nat_in_journal(sbi, nid, raw_nat) >= 0)
- return 0;
+ return;
nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
@@ -835,21 +870,17 @@ int get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, struct f2fs_nat_entry *ra
ret = dev_read_block(nat_block, block_addr);
ASSERT(ret >= 0);
- memcpy(raw_nat, &nat_block->entries[entry_off], sizeof(struct f2fs_nat_entry));
+ memcpy(raw_nat, &nat_block->entries[entry_off],
+ sizeof(struct f2fs_nat_entry));
free(nat_block);
-
- return 0;
}
-int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
+void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
{
struct f2fs_nat_entry raw_nat;
- int ret;
-
- ret = get_nat_entry(sbi, nid, &raw_nat);
+ get_nat_entry(sbi, nid, &raw_nat);
ni->nid = nid;
node_info_from_raw_nat(ni, &raw_nat);
- return ret;
}
void build_sit_entries(struct f2fs_sb_info *sbi)
@@ -910,18 +941,14 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
return 0;
}
-int build_sit_area_bitmap(struct f2fs_sb_info *sbi)
+void build_sit_area_bitmap(struct f2fs_sb_info *sbi)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_sm_info *sm_i = SM_I(sbi);
unsigned int segno = 0;
- int j = 0;
char *ptr = NULL;
-
u32 sum_vblocks = 0;
u32 free_segs = 0;
- u32 vblocks = 0;
-
struct seg_entry *se;
fsck->sit_area_bitmap_sz = sm_i->main_segments * SIT_VBLOCK_MAP_SIZE;
@@ -930,20 +957,13 @@ int build_sit_area_bitmap(struct f2fs_sb_info *sbi)
ASSERT(fsck->sit_area_bitmap_sz == fsck->main_area_bitmap_sz);
- for (segno = 0; segno < sm_i->main_segments; segno++) {
+ for (segno = 0; segno < TOTAL_SEGS(sbi); segno++) {
se = get_seg_entry(sbi, segno);
memcpy(ptr, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
ptr += SIT_VBLOCK_MAP_SIZE;
- vblocks = 0;
- for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++) {
- vblocks += get_bits_in_byte(se->cur_valid_map[j]);
- }
- ASSERT(vblocks == se->valid_blocks);
-
if (se->valid_blocks == 0x0) {
-
if (sbi->ckpt->cur_node_segno[0] == segno ||
sbi->ckpt->cur_data_segno[0] == segno ||
sbi->ckpt->cur_node_segno[1] == segno ||
@@ -954,22 +974,76 @@ int build_sit_area_bitmap(struct f2fs_sb_info *sbi)
} else {
free_segs++;
}
-
} else {
- ASSERT(se->valid_blocks <= 512);
sum_vblocks += se->valid_blocks;
}
}
-
fsck->chk.sit_valid_blocks = sum_vblocks;
fsck->chk.sit_free_segs = free_segs;
- DBG(1, "Blocks [0x%x : %d] Free Segs [0x%x : %d]\n\n", sum_vblocks, sum_vblocks,
+ DBG(1, "Blocks [0x%x : %d] Free Segs [0x%x : %d]\n\n",
+ sum_vblocks, sum_vblocks,
free_segs, free_segs);
- return 0;
}
-int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_entry *raw_nat)
+void rewrite_sit_area_bitmap(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
+ struct sit_info *sit_i = SIT_I(sbi);
+ unsigned int segno = 0;
+ struct f2fs_summary_block *sum = curseg->sum_blk;
+ char *ptr = NULL;
+
+ /* remove sit journal */
+ sum->n_sits = 0;
+
+ fsck->chk.free_segs = 0;
+
+ ptr = fsck->main_area_bitmap;
+
+ for (segno = 0; segno < TOTAL_SEGS(sbi); segno++) {
+ struct f2fs_sit_block *sit_blk;
+ struct f2fs_sit_entry *sit;
+ struct seg_entry *se;
+ u16 valid_blocks = 0;
+ u16 type;
+ int i;
+
+ sit_blk = get_current_sit_page(sbi, segno);
+ sit = &sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno)];
+ memcpy(sit->valid_map, ptr, SIT_VBLOCK_MAP_SIZE);
+
+ /* update valid block count */
+ for (i = 0; i < SIT_VBLOCK_MAP_SIZE; i++)
+ valid_blocks += get_bits_in_byte(sit->valid_map[i]);
+
+ se = get_seg_entry(sbi, segno);
+ type = se->type;
+ if (type >= NO_CHECK_TYPE) {
+ ASSERT(valid_blocks);
+ type = 0;
+ }
+ sit->vblocks = cpu_to_le16((type << SIT_VBLOCKS_SHIFT) |
+ valid_blocks);
+ rewrite_current_sit_page(sbi, segno, sit_blk);
+ free(sit_blk);
+
+ if (valid_blocks == 0 &&
+ sbi->ckpt->cur_node_segno[0] != segno &&
+ sbi->ckpt->cur_data_segno[0] != segno &&
+ sbi->ckpt->cur_node_segno[1] != segno &&
+ sbi->ckpt->cur_data_segno[1] != segno &&
+ sbi->ckpt->cur_node_segno[2] != segno &&
+ sbi->ckpt->cur_data_segno[2] != segno)
+ fsck->chk.free_segs++;
+
+ ptr += SIT_VBLOCK_MAP_SIZE;
+ }
+}
+
+int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid,
+ struct f2fs_nat_entry *raw_nat)
{
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
struct f2fs_summary_block *sum = curseg->sum_blk;
@@ -977,7 +1051,8 @@ int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_ent
for (i = 0; i < nats_in_cursum(sum); i++) {
if (le32_to_cpu(nid_in_journal(sum, i)) == nid) {
- memcpy(raw_nat, &nat_in_journal(sum, i), sizeof(struct f2fs_nat_entry));
+ memcpy(raw_nat, &nat_in_journal(sum, i),
+ sizeof(struct f2fs_nat_entry));
DBG(3, "==> Found nid [0x%x] in nat cache\n", nid);
return i;
}
@@ -985,6 +1060,51 @@ int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_ent
return -1;
}
+void nullify_nat_entry(struct f2fs_sb_info *sbi, u32 nid)
+{
+ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
+ struct f2fs_summary_block *sum = curseg->sum_blk;
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+ struct f2fs_nat_block *nat_block;
+ pgoff_t block_off;
+ pgoff_t block_addr;
+ int seg_off, entry_off;
+ int ret;
+ int i = 0;
+
+ /* check in journal */
+ for (i = 0; i < nats_in_cursum(sum); i++) {
+ if (le32_to_cpu(nid_in_journal(sum, i)) == nid) {
+ memset(&nat_in_journal(sum, i), 0,
+ sizeof(struct f2fs_nat_entry));
+ FIX_MSG("Remove nid [0x%x] in nat journal\n", nid);
+ return;
+ }
+ }
+ nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
+
+ block_off = nid / NAT_ENTRY_PER_BLOCK;
+ entry_off = nid % NAT_ENTRY_PER_BLOCK;
+
+ seg_off = block_off >> sbi->log_blocks_per_seg;
+ block_addr = (pgoff_t)(nm_i->nat_blkaddr +
+ (seg_off << sbi->log_blocks_per_seg << 1) +
+ (block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
+
+ if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
+ block_addr += sbi->blocks_per_seg;
+
+ ret = dev_read_block(nat_block, block_addr);
+ ASSERT(ret >= 0);
+
+ memset(&nat_block->entries[entry_off], 0,
+ sizeof(struct f2fs_nat_entry));
+
+ ret = dev_write_block(nat_block, block_addr);
+ ASSERT(ret >= 0);
+ free(nat_block);
+}
+
void build_nat_area_bitmap(struct f2fs_sb_info *sbi)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
@@ -992,18 +1112,18 @@ void build_nat_area_bitmap(struct f2fs_sb_info *sbi)
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct f2fs_nat_block *nat_block;
u32 nid, nr_nat_blks;
-
pgoff_t block_off;
pgoff_t block_addr;
int seg_off;
int ret;
unsigned int i;
-
nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
+ ASSERT(nat_block);
/* Alloc & build nat entry bitmap */
- nr_nat_blks = (le32_to_cpu(raw_sb->segment_count_nat) / 2) << sbi->log_blocks_per_seg;
+ nr_nat_blks = (le32_to_cpu(raw_sb->segment_count_nat) / 2) <<
+ sbi->log_blocks_per_seg;
fsck->nr_nat_entries = nr_nat_blks * NAT_ENTRY_PER_BLOCK;
fsck->nat_area_bitmap_sz = (fsck->nr_nat_entries + 7) / 8;
@@ -1014,8 +1134,8 @@ void build_nat_area_bitmap(struct f2fs_sb_info *sbi)
seg_off = block_off >> sbi->log_blocks_per_seg;
block_addr = (pgoff_t)(nm_i->nat_blkaddr +
- (seg_off << sbi->log_blocks_per_seg << 1) +
- (block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
+ (seg_off << sbi->log_blocks_per_seg << 1) +
+ (block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
block_addr += sbi->blocks_per_seg;
@@ -1029,44 +1149,47 @@ void build_nat_area_bitmap(struct f2fs_sb_info *sbi)
struct node_info ni;
ni.nid = nid + i;
- if ((nid + i) == F2FS_NODE_INO(sbi) || (nid + i) == F2FS_META_INO(sbi)) {
+ if ((nid + i) == F2FS_NODE_INO(sbi) ||
+ (nid + i) == F2FS_META_INO(sbi)) {
ASSERT(nat_block->entries[i].block_addr != 0x0);
continue;
}
- if (lookup_nat_in_journal(sbi, nid + i, &raw_nat) >= 0) {
+ if (lookup_nat_in_journal(sbi, nid + i,
+ &raw_nat) >= 0) {
node_info_from_raw_nat(&ni, &raw_nat);
if (ni.blk_addr != 0x0) {
- f2fs_set_bit(nid + i, fsck->nat_area_bitmap);
+ f2fs_set_bit(nid + i,
+ fsck->nat_area_bitmap);
fsck->chk.valid_nat_entry_cnt++;
- DBG(3, "nid[0x%x] in nat cache\n", nid + i);
+ DBG(3, "nid[0x%x] in nat cache\n",
+ nid + i);
}
} else {
- node_info_from_raw_nat(&ni, &nat_block->entries[i]);
- if (ni.blk_addr != 0) {
- ASSERT(nid + i != 0x0);
-
- DBG(3, "nid[0x%8x] in nat entry [0x%16x] [0x%8x]\n",
- nid + i,
- ni.blk_addr,
- ni.ino);
-
- f2fs_set_bit(nid + i, fsck->nat_area_bitmap);
- fsck->chk.valid_nat_entry_cnt++;
- }
+ node_info_from_raw_nat(&ni,
+ &nat_block->entries[i]);
+ if (ni.blk_addr == 0)
+ continue;
+ ASSERT(nid + i != 0x0);
+
+ DBG(3, "nid[0x%8x] addr[0x%16x] ino[0x%8x]\n",
+ nid + i, ni.blk_addr, ni.ino);
+ f2fs_set_bit(nid + i, fsck->nat_area_bitmap);
+ fsck->chk.valid_nat_entry_cnt++;
}
}
}
free(nat_block);
DBG(1, "valid nat entries (block_addr != 0x0) [0x%8x : %u]\n",
- fsck->chk.valid_nat_entry_cnt, fsck->chk.valid_nat_entry_cnt);
-
+ fsck->chk.valid_nat_entry_cnt,
+ fsck->chk.valid_nat_entry_cnt);
}
int f2fs_do_mount(struct f2fs_sb_info *sbi)
{
int ret;
+
sbi->active_logs = NR_CURSEG_TYPE;
ret = validate_super_block(sbi, 0);
if (ret) {
@@ -1092,10 +1215,23 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
print_ckpt_info(sbi);
+ if (config.auto_fix) {
+ u32 flag = le32_to_cpu(sbi->ckpt->ckpt_flags);
+
+ if (flag & CP_FSCK_FLAG)
+ config.fix_on = 1;
+ else
+ return 1;
+ }
+
+ config.bug_on = 0;
+
sbi->total_valid_node_count = le32_to_cpu(sbi->ckpt->valid_node_count);
- sbi->total_valid_inode_count = le32_to_cpu(sbi->ckpt->valid_inode_count);
+ sbi->total_valid_inode_count =
+ le32_to_cpu(sbi->ckpt->valid_inode_count);
sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count);
- sbi->total_valid_block_count = le64_to_cpu(sbi->ckpt->valid_block_count);
+ sbi->total_valid_block_count =
+ le64_to_cpu(sbi->ckpt->valid_block_count);
sbi->last_valid_block_count = sbi->total_valid_block_count;
sbi->alloc_valid_block_count = 0;
@@ -1109,7 +1245,7 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
return -1;
}
- return ret;
+ return 0;
}
void f2fs_do_umount(struct f2fs_sb_info *sbi)
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index 53b8cb9..b02002c 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -5,6 +5,9 @@
* http://www.samsung.com/
*
* Dual licensed under the GPL or LGPL version 2 licenses.
+ *
+ * The byteswap codes are copied from:
+ * samba_3_master/lib/ccan/endian/endian.h under LGPL 2.1
*/
#ifndef __F2FS_FS_H__
#define __F2FS_FS_H__
@@ -26,6 +29,63 @@ typedef u32 nid_t;
typedef u8 bool;
typedef unsigned long pgoff_t;
+#if HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+/**
+ * bswap_16 - reverse bytes in a uint16_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ * // Output contains "1024 is 4 as two bytes reversed"
+ * printf("1024 is %u as two bytes reversed\n", bswap_16(1024));
+ */
+static inline uint16_t bswap_16(uint16_t val)
+{
+ return ((val & (uint16_t)0x00ffU) << 8)
+ | ((val & (uint16_t)0xff00U) >> 8);
+}
+
+/**
+ * bswap_32 - reverse bytes in a uint32_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ * // Output contains "1024 is 262144 as four bytes reversed"
+ * printf("1024 is %u as four bytes reversed\n", bswap_32(1024));
+ */
+static inline uint32_t bswap_32(uint32_t val)
+{
+ return ((val & (uint32_t)0x000000ffUL) << 24)
+ | ((val & (uint32_t)0x0000ff00UL) << 8)
+ | ((val & (uint32_t)0x00ff0000UL) >> 8)
+ | ((val & (uint32_t)0xff000000UL) >> 24);
+}
+#endif /* !HAVE_BYTESWAP_H */
+
+#if !HAVE_BSWAP_64
+/**
+ * bswap_64 - reverse bytes in a uint64_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ * // Output contains "1024 is 1125899906842624 as eight bytes reversed"
+ * printf("1024 is %llu as eight bytes reversed\n",
+ * (unsigned long long)bswap_64(1024));
+ */
+static inline uint64_t bswap_64(uint64_t val)
+{
+ return ((val & (uint64_t)0x00000000000000ffULL) << 56)
+ | ((val & (uint64_t)0x000000000000ff00ULL) << 40)
+ | ((val & (uint64_t)0x0000000000ff0000ULL) << 24)
+ | ((val & (uint64_t)0x00000000ff000000ULL) << 8)
+ | ((val & (uint64_t)0x000000ff00000000ULL) >> 8)
+ | ((val & (uint64_t)0x0000ff0000000000ULL) >> 24)
+ | ((val & (uint64_t)0x00ff000000000000ULL) >> 40)
+ | ((val & (uint64_t)0xff00000000000000ULL) >> 56);
+}
+#endif
+
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define le16_to_cpu(x) ((__u16)(x))
#define le32_to_cpu(x) ((__u32)(x))
@@ -54,37 +114,39 @@ typedef unsigned long pgoff_t;
/*
* Debugging interfaces
*/
-#define ASSERT_MSG(exp, fmt, ...) \
+#define FIX_MSG(fmt, ...) \
do { \
- if (!(exp)) { \
- printf("\nAssertion failed!\n"); \
- printf("[%s:%4d] " #exp, __func__, __LINE__); \
- printf("\n --> "fmt, ##__VA_ARGS__); \
- exit(-1); \
- } \
- } while (0);
+ printf("[FIX] (%s:%4d) ", __func__, __LINE__); \
+ printf(" --> "fmt"\n", ##__VA_ARGS__); \
+ } while (0)
+
+#define ASSERT_MSG(fmt, ...) \
+ do { \
+ printf("[ASSERT] (%s:%4d) ", __func__, __LINE__); \
+ printf(" --> "fmt"\n", ##__VA_ARGS__); \
+ config.bug_on = 1; \
+ } while (0)
#define ASSERT(exp) \
do { \
if (!(exp)) { \
- printf("\nAssertion failed!\n"); \
- printf("[%s:%4d] " #exp"\n", __func__, __LINE__);\
+ printf("[ASSERT] (%s:%4d) " #exp"\n", \
+ __func__, __LINE__); \
exit(-1); \
} \
- } while (0);
+ } while (0)
#define ERR_MSG(fmt, ...) \
do { \
- printf("[%s:%d] " fmt, __func__, __LINE__, ##__VA_ARGS__); \
- } while (0);
-
+ printf("[%s:%d] " fmt, __func__, __LINE__, ##__VA_ARGS__); \
+ } while (0)
#define MSG(n, fmt, ...) \
do { \
if (config.dbg_lv >= n) { \
printf(fmt, ##__VA_ARGS__); \
} \
- } while (0);
+ } while (0)
#define DBG(n, fmt, ...) \
do { \
@@ -92,52 +154,52 @@ typedef unsigned long pgoff_t;
printf("[%s:%4d] " fmt, \
__func__, __LINE__, ##__VA_ARGS__); \
} \
- } while (0);
+ } while (0)
/* Display on console */
#define DISP(fmt, ptr, member) \
do { \
printf("%-30s" fmt, #member, ((ptr)->member)); \
- } while (0);
+ } while (0)
#define DISP_u32(ptr, member) \
do { \
assert(sizeof((ptr)->member) <= 4); \
printf("%-30s" "\t\t[0x%8x : %u]\n", \
- #member, ((ptr)->member), ((ptr)->member) ); \
- } while (0);
+ #member, ((ptr)->member), ((ptr)->member)); \
+ } while (0)
#define DISP_u64(ptr, member) \
do { \
assert(sizeof((ptr)->member) == 8); \
printf("%-30s" "\t\t[0x%8llx : %llu]\n", \
- #member, ((ptr)->member), ((ptr)->member) ); \
- } while (0);
+ #member, ((ptr)->member), ((ptr)->member)); \
+ } while (0)
#define DISP_utf(ptr, member) \
do { \
- printf("%-30s" "\t\t[%s]\n", #member, ((ptr)->member) ); \
- } while (0);
+ printf("%-30s" "\t\t[%s]\n", #member, ((ptr)->member)); \
+ } while (0)
/* Display to buffer */
-#define BUF_DISP_u32(buf, data, len, ptr, member) \
- do { \
- assert(sizeof((ptr)->member) <= 4); \
- snprintf(buf, len, #member); \
- snprintf(data, len, "0x%x : %u", ((ptr)->member), ((ptr)->member)); \
- } while (0);
-
-#define BUF_DISP_u64(buf, data, len, ptr, member) \
- do { \
- assert(sizeof((ptr)->member) == 8); \
- snprintf(buf, len, #member); \
- snprintf(data, len, "0x%llx : %llu", ((ptr)->member), ((ptr)->member)); \
- } while (0);
-
-#define BUF_DISP_utf(buf, data, len, ptr, member) \
- do { \
- snprintf(buf, len, #member); \
- } while (0);
+#define BUF_DISP_u32(buf, data, len, ptr, member) \
+ do { \
+ assert(sizeof((ptr)->member) <= 4); \
+ snprintf(buf, len, #member); \
+ snprintf(data, len, "0x%x : %u", ((ptr)->member), \
+ ((ptr)->member)); \
+ } while (0)
+
+#define BUF_DISP_u64(buf, data, len, ptr, member) \
+ do { \
+ assert(sizeof((ptr)->member) == 8); \
+ snprintf(buf, len, #member); \
+ snprintf(data, len, "0x%llx : %llu", ((ptr)->member), \
+ ((ptr)->member)); \
+ } while (0)
+
+#define BUF_DISP_utf(buf, data, len, ptr, member) \
+ snprintf(buf, len, #member)
/* these are defined in kernel */
#define PAGE_SIZE 4096
@@ -173,12 +235,16 @@ struct f2fs_configuration {
char *vol_label;
int heap;
int32_t fd;
+ int32_t dump_fd;
char *device_name;
char *extension_list;
int dbg_lv;
int trim;
int func;
void *private;
+ int fix_on;
+ int bug_on;
+ int auto_fix;
} __attribute__((packed));
#ifdef CONFIG_64BIT
@@ -221,6 +287,7 @@ enum {
#define F2FS_LOG_SECTORS_PER_BLOCK 3 /* 4KB: F2FS_BLKSIZE */
#define F2FS_BLKSIZE 4096 /* support only 4KB block */
#define F2FS_MAX_EXTENSION 64 /* # of extension entries */
+#define F2FS_BLK_ALIGN(x) (((x) + F2FS_BLKSIZE - 1) / F2FS_BLKSIZE)
#define NULL_ADDR 0x0U
#define NEW_ADDR -1U
@@ -283,6 +350,7 @@ struct f2fs_super_block {
/*
* For checkpoint
*/
+#define CP_FSCK_FLAG 0x00000010
#define CP_ERROR_FLAG 0x00000008
#define CP_COMPACT_SUM_FLAG 0x00000004
#define CP_ORPHAN_PRESENT_FLAG 0x00000002
@@ -357,6 +425,9 @@ struct f2fs_extent {
#define F2FS_INLINE_XATTR 0x01 /* file inline xattr flag */
#define F2FS_INLINE_DATA 0x02 /* file inline data flag */
+#define F2FS_INLINE_DENTRY 0x04 /* file inline dentry flag */
+#define F2FS_DATA_EXIST 0x08 /* file inline data exist flag */
+
#define MAX_INLINE_DATA (sizeof(__le32) * (DEF_ADDRS_PER_INODE - \
F2FS_INLINE_XATTR_ADDRS - 1))
@@ -412,6 +483,9 @@ enum {
OFFSET_BIT_SHIFT
};
+#define XATTR_NODE_OFFSET ((((unsigned int)-1) << OFFSET_BIT_SHIFT) \
+ >> OFFSET_BIT_SHIFT)
+
struct node_footer {
__le32 nid; /* node id */
__le32 ino; /* inode nunmber */
@@ -456,6 +530,13 @@ struct f2fs_nat_block {
#define SIT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_sit_entry))
/*
+ * F2FS uses 4 bytes to represent block address. As a result, supported size of
+ * disk is 16 TB and it equals to 16 * 1024 * 1024 / 2 segments.
+ */
+#define F2FS_MAX_SEGMENT ((16 * 1024 * 1024) / 2)
+#define MAX_SIT_BITMAP_SIZE ((F2FS_MAX_SEGMENT / SIT_ENTRY_PER_BLOCK) / 8)
+
+/*
* Note that f2fs_sit_entry->vblocks has the following bit-field information.
* [15:10] : allocation type such as CURSEG_XXXX_TYPE
* [9:0] : valid block count
@@ -619,6 +700,24 @@ struct f2fs_dentry_block {
__u8 filename[NR_DENTRY_IN_BLOCK][F2FS_SLOT_LEN];
} __attribute__((packed));
+/* for inline dir */
+#define NR_INLINE_DENTRY (MAX_INLINE_DATA * BITS_PER_BYTE / \
+ ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
+ BITS_PER_BYTE + 1))
+#define INLINE_DENTRY_BITMAP_SIZE ((NR_INLINE_DENTRY + \
+ BITS_PER_BYTE - 1) / BITS_PER_BYTE)
+#define INLINE_RESERVED_SIZE (MAX_INLINE_DATA - \
+ ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
+ NR_INLINE_DENTRY + INLINE_DENTRY_BITMAP_SIZE))
+
+/* inline directory entry structure */
+struct f2fs_inline_dentry {
+ __u8 dentry_bitmap[INLINE_DENTRY_BITMAP_SIZE];
+ __u8 reserved[INLINE_RESERVED_SIZE];
+ struct f2fs_dir_entry dentry[NR_INLINE_DENTRY];
+ __u8 filename[NR_INLINE_DENTRY][F2FS_SLOT_LEN];
+} __packed;
+
/* file types used in inode_info->flags */
enum FILE_TYPE {
F2FS_FT_UNKNOWN,
@@ -632,6 +731,8 @@ enum FILE_TYPE {
F2FS_FT_MAX,
/* added for fsck */
F2FS_FT_ORPHAN,
+ F2FS_FT_XATTR,
+ F2FS_FT_LAST_FILE_TYPE = F2FS_FT_XATTR,
};
/* from f2fs/segment.h */
@@ -651,7 +752,8 @@ extern int test_bit(unsigned int nr, const void * addr);
extern int f2fs_test_bit(unsigned int, const char *);
extern int f2fs_set_bit(unsigned int, char *);
extern int f2fs_clear_bit(unsigned int, char *);
-extern unsigned long find_next_bit(const unsigned long *, unsigned long, unsigned long);
+extern unsigned long find_next_bit(const unsigned long *,
+ unsigned long, unsigned long);
extern u_int32_t f2fs_cal_crc32(u_int32_t, void *, int);
extern int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len);
@@ -663,13 +765,15 @@ extern void f2fs_finalize_device(struct f2fs_configuration *);
extern int dev_read(void *, __u64, size_t);
extern int dev_write(void *, __u64, size_t);
+extern int dev_write_block(void *, __u64);
+extern int dev_write_dump(void *, __u64, size_t);
/* All bytes in the buffer must be 0 use dev_fill(). */
extern int dev_fill(void *, __u64, size_t);
extern int dev_read_block(void *, __u64);
extern int dev_read_blocks(void *, __u64, __u32 );
-f2fs_hash_t f2fs_dentry_hash(const char *, int);
+f2fs_hash_t f2fs_dentry_hash(const unsigned char *, int);
extern struct f2fs_configuration config;
diff --git a/lib/libf2fs.c b/lib/libf2fs.c
index 6168c5c..73c551b 100644
--- a/lib/libf2fs.c
+++ b/lib/libf2fs.c
@@ -235,7 +235,8 @@ static void TEA_transform(unsigned int buf[4], unsigned int const in[])
}
-static void str2hashbuf(const char *msg, int len, unsigned int *buf, int num)
+static void str2hashbuf(const unsigned char *msg, int len,
+ unsigned int *buf, int num)
{
unsigned pad, val;
int i;
@@ -269,24 +270,17 @@ static void str2hashbuf(const char *msg, int len, unsigned int *buf, int num)
* @param len name lenth
* @return return on success hash value, errno on failure
*/
-f2fs_hash_t f2fs_dentry_hash(const char *name, int len)
+f2fs_hash_t f2fs_dentry_hash(const unsigned char *name, int len)
{
__u32 hash;
f2fs_hash_t f2fs_hash;
- const char *p;
+ const unsigned char *p;
__u32 in[8], buf[4];
/* special hash codes for special dentries */
- if (name[0] == '.') {
- if (name[1] == '\0') {
- f2fs_hash = F2FS_DOT_HASH;
- goto exit;
- }
- if (name[1] == '.' && name[2] == '\0') {
- f2fs_hash = F2FS_DDOT_HASH;
- goto exit;
- }
- }
+ if ((len <= 2) && (name[0] == '.') &&
+ (name[1] == '.' || name[1] == '\0'))
+ return 0;
/* Initialize the default seed for the hash checksum functions */
buf[0] = 0x67452301;
@@ -295,18 +289,17 @@ f2fs_hash_t f2fs_dentry_hash(const char *name, int len)
buf[3] = 0x10325476;
p = name;
- while (len > 0) {
+ while (1) {
str2hashbuf(p, len, in, 4);
TEA_transform(buf, in);
- len -= 16;
p += 16;
+ if (len <= 16)
+ break;
+ len -= 16;
}
hash = buf[0];
- f2fs_hash = hash;
-exit:
- f2fs_hash &= ~F2FS_HASH_COL_BIT;
-
+ f2fs_hash = cpu_to_le32(hash & ~F2FS_HASH_COL_BIT);
return f2fs_hash;
}
@@ -429,6 +422,9 @@ int f2fs_get_device_info(struct f2fs_configuration *c)
{
int32_t fd = 0;
uint32_t sector_size;
+#ifndef BLKGETSIZE64
+ uint32_t total_sectors;
+#endif
struct stat stat_buf;
struct hd_geometry geom;
u_int64_t wanted_total_sectors = c->total_sectors;
@@ -461,11 +457,20 @@ int f2fs_get_device_info(struct f2fs_configuration *c)
}
}
- if (ioctl(fd, BLKGETSIZE, &c->total_sectors) < 0) {
+#ifdef BLKGETSIZE64
+ if (ioctl(fd, BLKGETSIZE64, &c->total_sectors) < 0) {
MSG(0, "\tError: Cannot get the device size\n");
return -1;
}
-
+ c->total_sectors /= c->sector_size;
+#else
+ if (ioctl(fd, BLKGETSIZE, &total_sectors) < 0) {
+ MSG(0, "\tError: Cannot get the device size\n");
+ return -1;
+ }
+ total_sectors /= c->sector_size;
+ c->total_sectors = total_sectors;
+#endif
if (ioctl(fd, HDIO_GETGEO, &geom) < 0)
c->start_sector = 0;
else
diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
index 5d9b68d..0c89ee4 100644
--- a/lib/libf2fs_io.c
+++ b/lib/libf2fs_io.c
@@ -46,6 +46,20 @@ int dev_write(void *buf, __u64 offset, size_t len)
return 0;
}
+int dev_write_block(void *buf, __u64 blk_addr)
+{
+ return dev_write(buf, blk_addr * F2FS_BLKSIZE, F2FS_BLKSIZE);
+}
+
+int dev_write_dump(void *buf, __u64 offset, size_t len)
+{
+ if (lseek64(config.dump_fd, (off64_t)offset, SEEK_SET) < 0)
+ return -1;
+ if (write(config.dump_fd, buf, len) < 0)
+ return -1;
+ return 0;
+}
+
int dev_fill(void *buf, __u64 offset, size_t len)
{
/* Only allow fill to zero */
diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am
index ff136a7..fa48699 100644
--- a/mkfs/Makefile.am
+++ b/mkfs/Makefile.am
@@ -1,7 +1,7 @@
## Makefile.am
AM_CPPFLAGS = ${libuuid_CFLAGS} -I$(top_srcdir)/include
-AM_CFLAGS = -Wall -DBLKDISCARD
+AM_CFLAGS = -Wall -DWITH_BLKDISCARD
sbin_PROGRAMS = mkfs.f2fs
mkfs_f2fs_SOURCES = f2fs_format_main.c f2fs_format.c f2fs_format_utils.c
mkfs_f2fs_LDADD = ${libuuid_LIBS} $(top_builddir)/lib/libf2fs.la
diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c
index 1568545..e300731 100644
--- a/mkfs/f2fs_format.c
+++ b/mkfs/f2fs_format.c
@@ -101,7 +101,8 @@ static int f2fs_prepare_super_block(void)
u_int32_t blocks_for_sit, blocks_for_nat, blocks_for_ssa;
u_int32_t total_valid_blks_available;
u_int64_t zone_align_start_offset, diff, total_meta_segments;
- u_int32_t sit_bitmap_size, max_nat_bitmap_size, max_nat_segments;
+ u_int32_t sit_bitmap_size, max_sit_bitmap_size;
+ u_int32_t max_nat_bitmap_size, max_nat_segments;
u_int32_t total_zones;
super_block.magic = cpu_to_le32(F2FS_SUPER_MAGIC);
@@ -197,8 +198,26 @@ static int f2fs_prepare_super_block(void)
*/
sit_bitmap_size = ((le32_to_cpu(super_block.segment_count_sit) / 2) <<
log_blks_per_seg) / 8;
- max_nat_bitmap_size = CHECKSUM_OFFSET - sizeof(struct f2fs_checkpoint) + 1 -
- sit_bitmap_size;
+
+ if (sit_bitmap_size > MAX_SIT_BITMAP_SIZE)
+ max_sit_bitmap_size = MAX_SIT_BITMAP_SIZE;
+ else
+ max_sit_bitmap_size = sit_bitmap_size;
+
+ /*
+ * It should be reserved minimum 1 segment for nat.
+ * When sit is too large, we should expand cp area. It requires more pages for cp.
+ */
+ if (max_sit_bitmap_size >
+ (CHECKSUM_OFFSET - sizeof(struct f2fs_checkpoint) + 65)) {
+ max_nat_bitmap_size = CHECKSUM_OFFSET - sizeof(struct f2fs_checkpoint) + 1;
+ super_block.cp_payload = F2FS_BLK_ALIGN(max_sit_bitmap_size);
+ } else {
+ max_nat_bitmap_size = CHECKSUM_OFFSET - sizeof(struct f2fs_checkpoint) + 1
+ - max_sit_bitmap_size;
+ super_block.cp_payload = 0;
+ }
+
max_nat_segments = (max_nat_bitmap_size * 8) >> log_blks_per_seg;
if (le32_to_cpu(super_block.segment_count_nat) > max_nat_segments)
@@ -413,7 +432,8 @@ static int f2fs_write_check_point_pack(void)
u_int32_t blk_size_bytes;
u_int64_t cp_seg_blk_offset = 0;
u_int32_t crc = 0;
- int i;
+ unsigned int i;
+ char *cp_payload = NULL;
ckp = calloc(F2FS_BLKSIZE, 1);
if (ckp == NULL) {
@@ -427,6 +447,12 @@ static int f2fs_write_check_point_pack(void)
return -1;
}
+ cp_payload = calloc(F2FS_BLKSIZE, 1);
+ if (cp_payload == NULL) {
+ MSG(1, "\tError: Calloc Failed for cp_payload!!!\n");
+ return -1;
+ }
+
/* 1. cp page 1 of checkpoint pack 1 */
ckp->checkpoint_ver = cpu_to_le64(1);
ckp->cur_node_segno[0] =
@@ -465,9 +491,10 @@ static int f2fs_write_check_point_pack(void)
((le32_to_cpu(ckp->free_segment_count) + 6 -
le32_to_cpu(ckp->overprov_segment_count)) *
config.blks_per_seg));
- ckp->cp_pack_total_block_count = cpu_to_le32(8);
+ ckp->cp_pack_total_block_count =
+ cpu_to_le32(8 + le32_to_cpu(super_block.cp_payload));
ckp->ckpt_flags = cpu_to_le32(CP_UMOUNT_FLAG);
- ckp->cp_pack_start_sum = cpu_to_le32(1);
+ ckp->cp_pack_start_sum = cpu_to_le32(1 + le32_to_cpu(super_block.cp_payload));
ckp->valid_node_count = cpu_to_le32(1);
ckp->valid_inode_count = cpu_to_le32(1);
ckp->next_free_nid = cpu_to_le32(
@@ -491,11 +518,20 @@ static int f2fs_write_check_point_pack(void)
cp_seg_blk_offset *= blk_size_bytes;
DBG(1, "\tWriting main segments, ckp at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
- if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ if (dev_write(ckp, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the ckp to disk!!!\n");
return -1;
}
+ for (i = 0; i < le32_to_cpu(super_block.cp_payload); i++) {
+ cp_seg_blk_offset += blk_size_bytes;
+ if (dev_fill(cp_payload, cp_seg_blk_offset, blk_size_bytes)) {
+ MSG(1, "\tError: While zeroing out the sit bitmap area \
+ on disk!!!\n");
+ return -1;
+ }
+ }
+
/* 2. Prepare and write Segment summary for data blocks */
memset(sum, 0, sizeof(struct f2fs_summary_block));
SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
@@ -505,7 +541,7 @@ static int f2fs_write_check_point_pack(void)
cp_seg_blk_offset += blk_size_bytes;
DBG(1, "\tWriting segment summary for data, ckp at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
- if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
return -1;
}
@@ -516,7 +552,7 @@ static int f2fs_write_check_point_pack(void)
cp_seg_blk_offset += blk_size_bytes;
DBG(1, "\tWriting segment summary, ckp at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
- if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
return -1;
}
@@ -546,7 +582,7 @@ static int f2fs_write_check_point_pack(void)
cp_seg_blk_offset += blk_size_bytes;
DBG(1, "\tWriting data sit for root, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
- if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
return -1;
}
@@ -560,7 +596,7 @@ static int f2fs_write_check_point_pack(void)
cp_seg_blk_offset += blk_size_bytes;
DBG(1, "\tWriting Segment summary for node blocks, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
- if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
return -1;
}
@@ -571,7 +607,7 @@ static int f2fs_write_check_point_pack(void)
cp_seg_blk_offset += blk_size_bytes;
DBG(1, "\tWriting Segment summary for data block (1/2), at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
- if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
return -1;
}
@@ -581,7 +617,7 @@ static int f2fs_write_check_point_pack(void)
SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
cp_seg_blk_offset += blk_size_bytes;
DBG(1, "\tWriting Segment summary for data block (2/2), at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
- if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
return -1;
}
@@ -589,7 +625,7 @@ static int f2fs_write_check_point_pack(void)
/* 8. cp page2 */
cp_seg_blk_offset += blk_size_bytes;
DBG(1, "\tWriting cp page2, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
- if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ if (dev_write(ckp, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the ckp to disk!!!\n");
return -1;
}
@@ -606,21 +642,32 @@ static int f2fs_write_check_point_pack(void)
config.blks_per_seg) *
blk_size_bytes;
DBG(1, "\tWriting cp page 1 of checkpoint pack 2, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
- if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ if (dev_write(ckp, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the ckp to disk!!!\n");
return -1;
}
+ for (i = 0; i < le32_to_cpu(super_block.cp_payload); i++) {
+ cp_seg_blk_offset += blk_size_bytes;
+ if (dev_fill(cp_payload, cp_seg_blk_offset, blk_size_bytes)) {
+ MSG(1, "\tError: While zeroing out the sit bitmap area \
+ on disk!!!\n");
+ return -1;
+ }
+ }
+
/* 10. cp page 2 of check point pack 2 */
- cp_seg_blk_offset += blk_size_bytes * (le32_to_cpu(ckp->cp_pack_total_block_count) - 1);
+ cp_seg_blk_offset += blk_size_bytes * (le32_to_cpu(ckp->cp_pack_total_block_count)
+ - le32_to_cpu(super_block.cp_payload) - 1);
DBG(1, "\tWriting cp page 2 of checkpoint pack 2, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
- if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ if (dev_write(ckp, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the ckp to disk!!!\n");
return -1;
}
free(sum) ;
free(ckp) ;
+ free(cp_payload);
return 0;
}
diff --git a/mkfs/f2fs_format_main.c b/mkfs/f2fs_format_main.c
index 19c52e4..e1f7c69 100644
--- a/mkfs/f2fs_format_main.c
+++ b/mkfs/f2fs_format_main.c
@@ -103,7 +103,8 @@ static void f2fs_parse_options(int argc, char *argv[])
if ((optind + 1) < argc) {
/* We have a sector count. */
config.total_sectors = atoll(argv[optind+1]);
- MSG(0, "\ttotal_sectors=%lu (%s bytes)\n", config.total_sectors, argv[optind+1]);
+ MSG(0, "\ttotal_sectors=%08"PRIx64" (%s bytes)\n",
+ config.total_sectors, argv[optind+1]);
}
config.reserved_segments =
diff --git a/mkfs/f2fs_format_utils.c b/mkfs/f2fs_format_utils.c
index 8f7e094..9892a8f 100644
--- a/mkfs/f2fs_format_utils.c
+++ b/mkfs/f2fs_format_utils.c
@@ -15,6 +15,10 @@
#include "f2fs_fs.h"
+#ifdef HAVE_LINUX_FS_H
+#include <linux/fs.h>
+#endif
+
int f2fs_trim_device()
{
unsigned long long range[2];
@@ -31,7 +35,7 @@ int f2fs_trim_device()
return -1;
}
-#if defined(BLKDISCARD)
+#if defined(WITH_BLKDISCARD) && defined(BLKDISCARD)
MSG(0, "Info: Discarding device\n");
if (S_ISREG(stat_buf.st_mode))
return 0;
diff --git a/scripts/tracepoint.sh b/scripts/tracepoint.sh
index b0d2fcb..15588d7 100755
--- a/scripts/tracepoint.sh
+++ b/scripts/tracepoint.sh
@@ -1,13 +1,16 @@
-#!/bin/bash
+#!/system/bin/sh
TRACE=/sys/kernel/debug/tracing/
dev=$(((8<<20) + 17)) # sdb1 (8,17)
-echo 1 > tracing_on
+echo 1 > $TRACE/tracing_on
+
+# mmc tracepoints
+echo 0 > $TRACE/events/mmc/enable
# block tracepoints
-echo "dev == $dev" > $TRACE/events/block/block_rq_complete/filter
-echo 1 > $TRACE/events/block/block_rq_complete/enable
+#echo "dev == $dev" > $TRACE/events/block/block_rq_complete/filter
+echo 0 > $TRACE/events/block/block_rq_complete/enable
echo 0 > $TRACE/events/block/block_bio_complete/enable
# GC
@@ -41,9 +44,18 @@ echo $S > $TRACE/events/f2fs/f2fs_get_data_block/enable
# IOs
R=0
W=0
-echo $W > $TRACE/events/f2fs/f2fs_submit_write_page/enable
-echo $W > $TRACE/events/f2fs/f2fs_do_submit_bio/enable
echo $R > $TRACE/events/f2fs/f2fs_readpage/enable
+echo $W > $TRACE/events/f2fs/f2fs_writepage/enable
+echo $W > $TRACE/events/f2fs/f2fs_write_begin/enable
+echo $W > $TRACE/events/f2fs/f2fs_write_end/enable
+
+echo 0 > $TRACE/events/f2fs/f2fs_submit_page_bio/enable
+echo 0 > $TRACE/events/f2fs/f2fs_submit_page_mbio/enable
+echo $R > $TRACE/events/f2fs/f2fs_submit_read_bio/enable
+echo $W > $TRACE/events/f2fs/f2fs_submit_write_bio/enable
+
+echo 0 > $TRACE/events/f2fs/f2fs_issue_discard/enable
+echo 0 > $TRACE/events/f2fs/f2fs_issue_flush/enable
# VFS interfaces
V=0
diff --git a/tools/f2fstat.c b/tools/f2fstat.c
index c9c1d30..8643797 100644
--- a/tools/f2fstat.c
+++ b/tools/f2fstat.c
@@ -212,15 +212,72 @@ void parse_option(int argc, char *argv[], struct options *opt)
}
}
-void print_head(void)
+void __make_head(char *head, int index, int i, int len)
{
- fprintf(stderr, "---utilization--- -----------main area-------- ---------balancing async------- ---gc--- ---alloc--- -----memory-----\n");
- fprintf(stderr, "util node data free valid dirty prefree node dent meta sit nat fnid cp gc ssr lfs total node meta\n");
+ char name_h[5][20] = {"main segments", "page/slab caches", "cp/gc", "blks", "memory"};
+ int half = (len - strlen(name_h[i])) / 2;
+
+ *(head + index) = '|';
+ index++;
+ memset(head + index, '-', half);
+ index += half;
+ strcpy(head + index, name_h[i]);
+ index += strlen(name_h[i]);
+ memset(head + index, '-', half);
+}
+
+void print_head(char *res)
+{
+ char *ptr, *ptr_buf;
+ char buf[1024], head[1024];
+ char name[20][10] = {"util", "node", "data", "free", "valid", "dirty", "prefree", "node", "dent", "meta",
+ "sit", "nat", "fnid", "cp", "gc", "ssr", "lfs", "total", "node", "meta"};
+ int i, len, prev_index = 0;
+
+ ptr_buf = buf;
+ memset(buf, ' ', 1024);
+ memset(head, ' ', 1024);
+
+ for (i = 0; i < 20; i++) {
+ ptr = (i == 0) ? strtok(res, " ") : strtok(NULL, " ");
+ strncpy(ptr_buf, name[i], strlen(name[i]));
+ if (i == 1) {
+ prev_index = ptr_buf - buf - 1;
+ } else if (i == 7) {
+ len = (ptr_buf - buf) - 1 - prev_index;
+ __make_head(head, prev_index, 0, len);
+ prev_index = ptr_buf - buf - 1;
+ } else if (i == 13) {
+ len = (ptr_buf - buf) - 1 - prev_index;
+ __make_head(head, prev_index, 1, len);
+ prev_index = ptr_buf - buf - 1;
+ } else if (i == 15) {
+ len = (ptr_buf - buf) - 1 - prev_index;
+ __make_head(head, prev_index, 2, len);
+ prev_index = ptr_buf - buf - 1;
+ } else if (i == 17) {
+ len = (ptr_buf - buf) - 1 - prev_index;
+ __make_head(head, prev_index, 3, len);
+ prev_index = ptr_buf - buf - 1;
+ }
+
+ len = strlen(ptr);
+ ptr_buf += (len > strlen(name[i]) ? len : strlen(name[i])) + 1;
+ }
+
+ len = (ptr_buf - buf) - 1 - prev_index;
+ __make_head(head, prev_index, 4, len);
+
+ *ptr_buf = 0;
+ *(head + (ptr_buf - buf - 1)) = '|';
+ *(head + (ptr_buf - buf)) = 0;
+ fprintf(stderr, "%s\n%s\n", head, buf);
}
int main(int argc, char *argv[])
{
- char format[] = "%3ld %6ld %6ld %6ld %6ld %6ld %6ld %5ld %5ld %3ld %5ld %5ld %3ld %3ld %3ld %6ld %6ld %6ld %6ld %6ld\n";
+ char format[] = "%4ld %4ld %4ld %4ld %5ld %5ld %7ld %4ld %4ld %4ld %3ld %3ld %4ld %2ld %2ld %3ld %3ld %5ld %4ld %4ld";
+ char buf[1024], tmp[1024];
int head_interval;
struct options opt = {
.delay = 1,
@@ -231,20 +288,22 @@ int main(int argc, char *argv[])
parse_option(argc, argv, &opt);
head_interval = opt.interval;
- print_head();
while (1) {
- if (head_interval-- == 0) {
- print_head();
- head_interval = opt.interval;
- }
-
+ memset(buf, 0, 1024);
f2fstat(&opt);
-
- fprintf(stderr, format, util, used_node_blks, used_data_blks,
+ sprintf(buf, format, util, used_node_blks, used_data_blks,
free_segs, valid_segs, dirty_segs, prefree_segs,
dirty_node, dirty_dents, dirty_meta, dirty_sit, nat_caches, free_nids,
cp, gc, ssr_blks, lfs_blks, memory_kb, node_kb, meta_kb);
+ strcpy(tmp, buf);
+ if (head_interval == opt.interval)
+ print_head(tmp);
+ if (head_interval-- == 0)
+ head_interval = opt.interval;
+
+ fprintf(stderr, "%s\n", buf);
+
sleep(opt.delay);
}