Home | History | Annotate | Download | only in fsck
      1 /**
      2  * dump.c
      3  *
      4  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
      5  *             http://www.samsung.com/
      6  *
      7  * This program is free software; you can redistribute it and/or modify
      8  * it under the terms of the GNU General Public License version 2 as
      9  * published by the Free Software Foundation.
     10  */
     11 #include <inttypes.h>
     12 
     13 #include "fsck.h"
     14 
     15 #define BUF_SZ	80
     16 
     17 const char *seg_type_name[SEG_TYPE_MAX] = {
     18 	"SEG_TYPE_DATA",
     19 	"SEG_TYPE_CUR_DATA",
     20 	"SEG_TYPE_NODE",
     21 	"SEG_TYPE_CUR_NODE",
     22 };
     23 
     24 void sit_dump(struct f2fs_sb_info *sbi, int start_sit, int end_sit)
     25 {
     26 	struct seg_entry *se;
     27 	int segno;
     28 	char buf[BUF_SZ];
     29 	u32 free_segs = 0;;
     30 	u64 valid_blocks = 0;
     31 	int ret;
     32 	int fd;
     33 
     34 	fd = open("dump_sit", O_CREAT|O_WRONLY|O_TRUNC, 0666);
     35 	ASSERT(fd >= 0);
     36 
     37 	for (segno = start_sit; segno < end_sit; segno++) {
     38 		se = get_seg_entry(sbi, segno);
     39 
     40 		memset(buf, 0, BUF_SZ);
     41 		snprintf(buf, BUF_SZ, "%5d %8d\n", segno, se->valid_blocks);
     42 
     43 		ret = write(fd, buf, strlen(buf));
     44 		ASSERT(ret >= 0);
     45 
     46 		DBG(4, "SIT[0x%3x] : 0x%x\n", segno, se->valid_blocks);
     47 		if (se->valid_blocks == 0x0) {
     48 			free_segs++;
     49 		} else {
     50 			ASSERT(se->valid_blocks <= 512);
     51 			valid_blocks += se->valid_blocks;
     52 		}
     53 	}
     54 
     55 	memset(buf, 0, BUF_SZ);
     56 	snprintf(buf, BUF_SZ, "valid_segs:%d\t free_segs:%d\n",
     57 			SM_I(sbi)->main_segments - free_segs, free_segs);
     58 	ret = write(fd, buf, strlen(buf));
     59 	ASSERT(ret >= 0);
     60 
     61 	close(fd);
     62 	DBG(1, "Blocks [0x%" PRIx64 "] Free Segs [0x%x]\n", valid_blocks, free_segs);
     63 }
     64 
     65 void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa)
     66 {
     67 	struct f2fs_summary_block sum_blk;
     68 	char buf[BUF_SZ];
     69 	int segno, i, ret;
     70 	int fd;
     71 
     72 	fd = open("dump_ssa", O_CREAT|O_WRONLY|O_TRUNC, 0666);
     73 	ASSERT(fd >= 0);
     74 
     75 	snprintf(buf, BUF_SZ, "Note: dump.f2fs -b blkaddr = 0x%x + segno * "
     76 				" 0x200 + offset\n",
     77 				sbi->sm_info->main_blkaddr);
     78 	ret = write(fd, buf, strlen(buf));
     79 	ASSERT(ret >= 0);
     80 
     81 	for (segno = start_ssa; segno < end_ssa; segno++) {
     82 		ret = get_sum_block(sbi, segno, &sum_blk);
     83 
     84 		memset(buf, 0, BUF_SZ);
     85 		switch (ret) {
     86 		case SEG_TYPE_CUR_NODE:
     87 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Current Node\n", segno);
     88 			break;
     89 		case SEG_TYPE_CUR_DATA:
     90 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Current Data\n", segno);
     91 			break;
     92 		case SEG_TYPE_NODE:
     93 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Node\n", segno);
     94 			break;
     95 		case SEG_TYPE_DATA:
     96 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Data\n", segno);
     97 			break;
     98 		}
     99 		ret = write(fd, buf, strlen(buf));
    100 		ASSERT(ret >= 0);
    101 
    102 		for (i = 0; i < ENTRIES_IN_SUM; i++) {
    103 			memset(buf, 0, BUF_SZ);
    104 			if (i % 10 == 0) {
    105 				buf[0] = '\n';
    106 				ret = write(fd, buf, strlen(buf));
    107 				ASSERT(ret >= 0);
    108 			}
    109 			snprintf(buf, BUF_SZ, "[%3d: %6x]", i,
    110 					le32_to_cpu(sum_blk.entries[i].nid));
    111 			ret = write(fd, buf, strlen(buf));
    112 			ASSERT(ret >= 0);
    113 		}
    114 	}
    115 	close(fd);
    116 }
    117 
    118 static void dump_data_blk(__u64 offset, u32 blkaddr)
    119 {
    120 	char buf[F2FS_BLKSIZE];
    121 
    122 	if (blkaddr == NULL_ADDR)
    123 		return;
    124 
    125 	/* get data */
    126 	if (blkaddr == NEW_ADDR) {
    127 		memset(buf, 0, F2FS_BLKSIZE);
    128 	} else {
    129 		int ret;
    130 		ret = dev_read_block(buf, blkaddr);
    131 		ASSERT(ret >= 0);
    132 	}
    133 
    134 	/* write blkaddr */
    135 	dev_write_dump(buf, offset, F2FS_BLKSIZE);
    136 }
    137 
    138 static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
    139 						u32 nid, u64 *ofs)
    140 {
    141 	struct node_info ni;
    142 	struct f2fs_node *node_blk;
    143 	u32 skip = 0;
    144 	u32 i, idx;
    145 
    146 	switch (ntype) {
    147 	case TYPE_DIRECT_NODE:
    148 		skip = idx = ADDRS_PER_BLOCK;
    149 		break;
    150 	case TYPE_INDIRECT_NODE:
    151 		idx = NIDS_PER_BLOCK;
    152 		skip = idx * ADDRS_PER_BLOCK;
    153 		break;
    154 	case TYPE_DOUBLE_INDIRECT_NODE:
    155 		skip = 0;
    156 		idx = NIDS_PER_BLOCK;
    157 		break;
    158 	}
    159 
    160 	if (nid == 0) {
    161 		*ofs += skip;
    162 		return;
    163 	}
    164 
    165 	get_node_info(sbi, nid, &ni);
    166 
    167 	node_blk = calloc(BLOCK_SZ, 1);
    168 	dev_read_block(node_blk, ni.blk_addr);
    169 
    170 	for (i = 0; i < idx; i++, (*ofs)++) {
    171 		switch (ntype) {
    172 		case TYPE_DIRECT_NODE:
    173 			dump_data_blk(*ofs * F2FS_BLKSIZE,
    174 					le32_to_cpu(node_blk->dn.addr[i]));
    175 			break;
    176 		case TYPE_INDIRECT_NODE:
    177 			dump_node_blk(sbi, TYPE_DIRECT_NODE,
    178 					le32_to_cpu(node_blk->in.nid[i]), ofs);
    179 			break;
    180 		case TYPE_DOUBLE_INDIRECT_NODE:
    181 			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
    182 					le32_to_cpu(node_blk->in.nid[i]), ofs);
    183 			break;
    184 		}
    185 	}
    186 	free(node_blk);
    187 }
    188 
    189 static void dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
    190 					struct f2fs_node *node_blk)
    191 {
    192 	u32 i = 0;
    193 	u64 ofs = 0;
    194 
    195 	/* TODO: need to dump xattr */
    196 
    197 	if((node_blk->i.i_inline & F2FS_INLINE_DATA)){
    198 		DBG(3, "ino[0x%x] has inline data!\n", nid);
    199 		/* recover from inline data */
    200 		dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
    201 							0, MAX_INLINE_DATA);
    202 		return;
    203 	}
    204 
    205 	/* check data blocks in inode */
    206 	for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
    207 		dump_data_blk(ofs * F2FS_BLKSIZE,
    208 				le32_to_cpu(node_blk->i.i_addr[i]));
    209 
    210 	/* check node blocks in inode */
    211 	for (i = 0; i < 5; i++) {
    212 		if (i == 0 || i == 1)
    213 			dump_node_blk(sbi, TYPE_DIRECT_NODE,
    214 					node_blk->i.i_nid[i], &ofs);
    215 		else if (i == 2 || i == 3)
    216 			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
    217 					node_blk->i.i_nid[i], &ofs);
    218 		else if (i == 4)
    219 			dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
    220 					node_blk->i.i_nid[i], &ofs);
    221 		else
    222 			ASSERT(0);
    223 	}
    224 }
    225 
    226 void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
    227 					struct f2fs_node *node_blk)
    228 {
    229 	struct f2fs_inode *inode = &node_blk->i;
    230 	u32 imode = le32_to_cpu(inode->i_mode);
    231 	char name[255] = {0};
    232 	char path[1024] = {0};
    233 	char ans[255] = {0};
    234 	int ret;
    235 
    236 	if (!S_ISREG(imode)) {
    237 		MSG(0, "Not a regular file\n\n");
    238 		return;
    239 	}
    240 
    241 	printf("Do you want to dump this file into ./lost_found/? [Y/N] ");
    242 	ret = scanf("%s", ans);
    243 	ASSERT(ret >= 0);
    244 
    245 	if (!strcasecmp(ans, "y")) {
    246 		ret = system("mkdir -p ./lost_found");
    247 		ASSERT(ret >= 0);
    248 
    249 		/* make a file */
    250 		strncpy(name, (const char *)inode->i_name,
    251 					le32_to_cpu(inode->i_namelen));
    252 		name[le32_to_cpu(inode->i_namelen)] = 0;
    253 		sprintf(path, "./lost_found/%s", name);
    254 
    255 		config.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
    256 		ASSERT(config.dump_fd >= 0);
    257 
    258 		/* dump file's data */
    259 		dump_inode_blk(sbi, ni->ino, node_blk);
    260 
    261 		/* adjust file size */
    262 		ret = ftruncate(config.dump_fd, le32_to_cpu(inode->i_size));
    263 		ASSERT(ret >= 0);
    264 
    265 		close(config.dump_fd);
    266 	}
    267 }
    268 
    269 void dump_node(struct f2fs_sb_info *sbi, nid_t nid)
    270 {
    271 	struct node_info ni;
    272 	struct f2fs_node *node_blk;
    273 
    274 	get_node_info(sbi, nid, &ni);
    275 
    276 	node_blk = calloc(BLOCK_SZ, 1);
    277 	dev_read_block(node_blk, ni.blk_addr);
    278 
    279 	DBG(1, "Node ID               [0x%x]\n", nid);
    280 	DBG(1, "nat_entry.block_addr  [0x%x]\n", ni.blk_addr);
    281 	DBG(1, "nat_entry.version     [0x%x]\n", ni.version);
    282 	DBG(1, "nat_entry.ino         [0x%x]\n", ni.ino);
    283 
    284 	if (ni.blk_addr == 0x0)
    285 		MSG(0, "Invalid nat entry\n\n");
    286 
    287 	DBG(1, "node_blk.footer.ino [0x%x]\n", le32_to_cpu(node_blk->footer.ino));
    288 	DBG(1, "node_blk.footer.nid [0x%x]\n", le32_to_cpu(node_blk->footer.nid));
    289 
    290 	if (le32_to_cpu(node_blk->footer.ino) == ni.ino &&
    291 			le32_to_cpu(node_blk->footer.nid) == ni.nid) {
    292 		print_node_info(node_blk);
    293 		dump_file(sbi, &ni, node_blk);
    294 	} else {
    295 		MSG(0, "Invalid node block\n\n");
    296 	}
    297 
    298 	free(node_blk);
    299 }
    300 
    301 int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
    302 {
    303 	nid_t ino, nid;
    304 	int type, ret;
    305 	struct f2fs_summary sum_entry;
    306 	struct node_info ni;
    307 	struct f2fs_node *node_blk;
    308 
    309 	type = get_sum_entry(sbi, blk_addr, &sum_entry);
    310 	nid = le32_to_cpu(sum_entry.nid);
    311 
    312 	get_node_info(sbi, nid, &ni);
    313 
    314 	DBG(1, "Note: blkaddr = main_blkaddr + segno * 512 + offset\n");
    315 	DBG(1, "Block_addr            [0x%x]\n", blk_addr);
    316 	DBG(1, " - Segno              [0x%x]\n", GET_SEGNO(sbi, blk_addr));
    317 	DBG(1, " - Offset             [0x%x]\n", OFFSET_IN_SEG(sbi, blk_addr));
    318 	DBG(1, "SUM.nid               [0x%x]\n", nid);
    319 	DBG(1, "SUM.type              [%s]\n", seg_type_name[type]);
    320 	DBG(1, "SUM.version           [%d]\n", sum_entry.version);
    321 	DBG(1, "SUM.ofs_in_node       [%d]\n", sum_entry.ofs_in_node);
    322 	DBG(1, "NAT.blkaddr           [0x%x]\n", ni.blk_addr);
    323 	DBG(1, "NAT.ino               [0x%x]\n", ni.ino);
    324 
    325 	node_blk = calloc(BLOCK_SZ, 1);
    326 
    327 read_node_blk:
    328 	ret = dev_read_block(node_blk, blk_addr);
    329 	ASSERT(ret >= 0);
    330 
    331 	ino = le32_to_cpu(node_blk->footer.ino);
    332 	nid = le32_to_cpu(node_blk->footer.nid);
    333 
    334 	if (ino == nid) {
    335 		print_node_info(node_blk);
    336 	} else {
    337 		get_node_info(sbi, ino, &ni);
    338 		goto read_node_blk;
    339 	}
    340 
    341 	free(node_blk);
    342 	return ino;
    343 }
    344