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 #include "xattr.h"
     15 #ifdef HAVE_ATTR_XATTR_H
     16 #include <attr/xattr.h>
     17 #endif
     18 #ifdef HAVE_LINUX_XATTR_H
     19 #include <linux/xattr.h>
     20 #endif
     21 #include <locale.h>
     22 
     23 #define BUF_SZ	80
     24 
     25 const char *seg_type_name[SEG_TYPE_MAX + 1] = {
     26 	"SEG_TYPE_DATA",
     27 	"SEG_TYPE_CUR_DATA",
     28 	"SEG_TYPE_NODE",
     29 	"SEG_TYPE_CUR_NODE",
     30 	"SEG_TYPE_NONE",
     31 };
     32 
     33 void nat_dump(struct f2fs_sb_info *sbi)
     34 {
     35 	struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
     36 	struct f2fs_nm_info *nm_i = NM_I(sbi);
     37 	struct f2fs_nat_block *nat_block;
     38 	struct f2fs_node *node_block;
     39 	u32 nr_nat_blks, nid;
     40 	pgoff_t block_off;
     41 	pgoff_t block_addr;
     42 	char buf[BUF_SZ];
     43 	int seg_off;
     44 	int fd, ret, pack;
     45 	unsigned int i;
     46 
     47 	nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
     48 	node_block = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
     49 	ASSERT(nat_block);
     50 
     51 	nr_nat_blks = get_sb(segment_count_nat) <<
     52 				(sbi->log_blocks_per_seg - 1);
     53 
     54 	fd = open("dump_nat", O_CREAT|O_WRONLY|O_TRUNC, 0666);
     55 	ASSERT(fd >= 0);
     56 
     57 	for (block_off = 0; block_off < nr_nat_blks; pack = 1, block_off++) {
     58 
     59 		seg_off = block_off >> sbi->log_blocks_per_seg;
     60 		block_addr = (pgoff_t)(nm_i->nat_blkaddr +
     61 			(seg_off << sbi->log_blocks_per_seg << 1) +
     62 			(block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
     63 
     64 		if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) {
     65 			block_addr += sbi->blocks_per_seg;
     66 			pack = 2;
     67 		}
     68 
     69 		ret = dev_read_block(nat_block, block_addr);
     70 		ASSERT(ret >= 0);
     71 
     72 		nid = block_off * NAT_ENTRY_PER_BLOCK;
     73 		for (i = 0; i < NAT_ENTRY_PER_BLOCK; i++) {
     74 			struct f2fs_nat_entry raw_nat;
     75 			struct node_info ni;
     76 			ni.nid = nid + i;
     77 
     78 			if(nid + i  == 0 || nid + i  == 1 || nid + i == 2 )
     79 				continue;
     80 			if (lookup_nat_in_journal(sbi, nid + i,
     81 							&raw_nat) >= 0) {
     82 				node_info_from_raw_nat(&ni, &raw_nat);
     83 				ret = dev_read_block(node_block, ni.blk_addr);
     84 				ASSERT(ret >= 0);
     85 				if (ni.blk_addr != 0x0) {
     86 					memset(buf, 0, BUF_SZ);
     87 					snprintf(buf, BUF_SZ,
     88 						"nid:%5u\tino:%5u\toffset:%5u"
     89 						"\tblkaddr:%10u\tpack:%d\n",
     90 						ni.nid, ni.ino,
     91 						le32_to_cpu(node_block->footer.flag) >>
     92 							OFFSET_BIT_SHIFT,
     93 						ni.blk_addr, pack);
     94 					ret = write(fd, buf, strlen(buf));
     95 					ASSERT(ret >= 0);
     96 				}
     97 			} else {
     98 				node_info_from_raw_nat(&ni,
     99 						&nat_block->entries[i]);
    100 				if (ni.blk_addr == 0)
    101 					continue;
    102 
    103 				ret = dev_read_block(node_block, ni.blk_addr);
    104 				ASSERT(ret >= 0);
    105 				memset(buf, 0, BUF_SZ);
    106 				snprintf(buf, BUF_SZ,
    107 					"nid:%5u\tino:%5u\toffset:%5u"
    108 					"\tblkaddr:%10u\tpack:%d\n",
    109 					ni.nid, ni.ino,
    110 					le32_to_cpu(node_block->footer.flag) >>
    111 						OFFSET_BIT_SHIFT,
    112 					ni.blk_addr, pack);
    113 				ret = write(fd, buf, strlen(buf));
    114 				ASSERT(ret >= 0);
    115 			}
    116 		}
    117 	}
    118 
    119 	free(nat_block);
    120 	free(node_block);
    121 
    122 	close(fd);
    123 }
    124 
    125 void sit_dump(struct f2fs_sb_info *sbi, unsigned int start_sit,
    126 					unsigned int end_sit)
    127 {
    128 	struct seg_entry *se;
    129 	struct sit_info *sit_i = SIT_I(sbi);
    130 	unsigned int segno;
    131 	char buf[BUF_SZ];
    132 	u32 free_segs = 0;;
    133 	u64 valid_blocks = 0;
    134 	int ret;
    135 	int fd, i;
    136 	unsigned int offset;
    137 
    138 	fd = open("dump_sit", O_CREAT|O_WRONLY|O_TRUNC, 0666);
    139 	ASSERT(fd >= 0);
    140 
    141 	snprintf(buf, BUF_SZ, "segment_type(0:HD, 1:WD, 2:CD, "
    142 						"3:HN, 4:WN, 5:CN)\n");
    143 	ret = write(fd, buf, strlen(buf));
    144 	ASSERT(ret >= 0);
    145 
    146 	for (segno = start_sit; segno < end_sit; segno++) {
    147 		se = get_seg_entry(sbi, segno);
    148 		offset = SIT_BLOCK_OFFSET(sit_i, segno);
    149 		memset(buf, 0, BUF_SZ);
    150 		snprintf(buf, BUF_SZ,
    151 		"\nsegno:%8u\tvblocks:%3u\tseg_type:%d\tsit_pack:%d\n\n",
    152 			segno, se->valid_blocks, se->type,
    153 			f2fs_test_bit(offset, sit_i->sit_bitmap) ? 2 : 1);
    154 
    155 		ret = write(fd, buf, strlen(buf));
    156 		ASSERT(ret >= 0);
    157 
    158 		if (se->valid_blocks == 0x0) {
    159 			free_segs++;
    160 			continue;
    161 		}
    162 
    163 		ASSERT(se->valid_blocks <= 512);
    164 		valid_blocks += se->valid_blocks;
    165 
    166 		for (i = 0; i < 64; i++) {
    167 			memset(buf, 0, BUF_SZ);
    168 			snprintf(buf, BUF_SZ, "  %02x",
    169 					*(se->cur_valid_map + i));
    170 			ret = write(fd, buf, strlen(buf));
    171 			ASSERT(ret >= 0);
    172 
    173 			if ((i + 1) % 16 == 0) {
    174 				snprintf(buf, BUF_SZ, "\n");
    175 				ret = write(fd, buf, strlen(buf));
    176 				ASSERT(ret >= 0);
    177 			}
    178 		}
    179 	}
    180 
    181 	memset(buf, 0, BUF_SZ);
    182 	snprintf(buf, BUF_SZ,
    183 		"valid_blocks:[0x%" PRIx64 "]\tvalid_segs:%d\t free_segs:%d\n",
    184 			valid_blocks,
    185 			SM_I(sbi)->main_segments - free_segs,
    186 			free_segs);
    187 	ret = write(fd, buf, strlen(buf));
    188 	ASSERT(ret >= 0);
    189 
    190 	close(fd);
    191 }
    192 
    193 void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa)
    194 {
    195 	struct f2fs_summary_block *sum_blk;
    196 	char buf[BUF_SZ];
    197 	int segno, i, ret;
    198 	int fd;
    199 
    200 	fd = open("dump_ssa", O_CREAT|O_WRONLY|O_TRUNC, 0666);
    201 	ASSERT(fd >= 0);
    202 
    203 	snprintf(buf, BUF_SZ, "Note: dump.f2fs -b blkaddr = 0x%x + segno * "
    204 				" 0x200 + offset\n",
    205 				sbi->sm_info->main_blkaddr);
    206 	ret = write(fd, buf, strlen(buf));
    207 	ASSERT(ret >= 0);
    208 
    209 	for (segno = start_ssa; segno < end_ssa; segno++) {
    210 		sum_blk = get_sum_block(sbi, segno, &ret);
    211 
    212 		memset(buf, 0, BUF_SZ);
    213 		switch (ret) {
    214 		case SEG_TYPE_CUR_NODE:
    215 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Current Node\n", segno);
    216 			break;
    217 		case SEG_TYPE_CUR_DATA:
    218 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Current Data\n", segno);
    219 			break;
    220 		case SEG_TYPE_NODE:
    221 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Node\n", segno);
    222 			break;
    223 		case SEG_TYPE_DATA:
    224 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Data\n", segno);
    225 			break;
    226 		}
    227 		ret = write(fd, buf, strlen(buf));
    228 		ASSERT(ret >= 0);
    229 
    230 		for (i = 0; i < ENTRIES_IN_SUM; i++) {
    231 			memset(buf, 0, BUF_SZ);
    232 			if (i % 10 == 0) {
    233 				buf[0] = '\n';
    234 				ret = write(fd, buf, strlen(buf));
    235 				ASSERT(ret >= 0);
    236 			}
    237 			snprintf(buf, BUF_SZ, "[%3d: %6x]", i,
    238 					le32_to_cpu(sum_blk->entries[i].nid));
    239 			ret = write(fd, buf, strlen(buf));
    240 			ASSERT(ret >= 0);
    241 		}
    242 		if (ret == SEG_TYPE_NODE || ret == SEG_TYPE_DATA ||
    243 					ret == SEG_TYPE_MAX)
    244 			free(sum_blk);
    245 	}
    246 	close(fd);
    247 }
    248 
    249 static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr)
    250 {
    251 	char buf[F2FS_BLKSIZE];
    252 
    253 	if (blkaddr == NULL_ADDR)
    254 		return;
    255 
    256 	/* get data */
    257 	if (blkaddr == NEW_ADDR || !IS_VALID_BLK_ADDR(sbi, blkaddr)) {
    258 		memset(buf, 0, F2FS_BLKSIZE);
    259 	} else {
    260 		int ret;
    261 		ret = dev_read_block(buf, blkaddr);
    262 		ASSERT(ret >= 0);
    263 	}
    264 
    265 	/* write blkaddr */
    266 	dev_write_dump(buf, offset, F2FS_BLKSIZE);
    267 }
    268 
    269 static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
    270 						u32 nid, u64 *ofs)
    271 {
    272 	struct node_info ni;
    273 	struct f2fs_node *node_blk;
    274 	u32 skip = 0;
    275 	u32 i, idx;
    276 
    277 	switch (ntype) {
    278 	case TYPE_DIRECT_NODE:
    279 		skip = idx = ADDRS_PER_BLOCK;
    280 		break;
    281 	case TYPE_INDIRECT_NODE:
    282 		idx = NIDS_PER_BLOCK;
    283 		skip = idx * ADDRS_PER_BLOCK;
    284 		break;
    285 	case TYPE_DOUBLE_INDIRECT_NODE:
    286 		skip = 0;
    287 		idx = NIDS_PER_BLOCK;
    288 		break;
    289 	}
    290 
    291 	if (nid == 0) {
    292 		*ofs += skip;
    293 		return;
    294 	}
    295 
    296 	get_node_info(sbi, nid, &ni);
    297 
    298 	node_blk = calloc(BLOCK_SZ, 1);
    299 	dev_read_block(node_blk, ni.blk_addr);
    300 
    301 	for (i = 0; i < idx; i++, (*ofs)++) {
    302 		switch (ntype) {
    303 		case TYPE_DIRECT_NODE:
    304 			dump_data_blk(sbi, *ofs * F2FS_BLKSIZE,
    305 					le32_to_cpu(node_blk->dn.addr[i]));
    306 			break;
    307 		case TYPE_INDIRECT_NODE:
    308 			dump_node_blk(sbi, TYPE_DIRECT_NODE,
    309 					le32_to_cpu(node_blk->in.nid[i]), ofs);
    310 			break;
    311 		case TYPE_DOUBLE_INDIRECT_NODE:
    312 			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
    313 					le32_to_cpu(node_blk->in.nid[i]), ofs);
    314 			break;
    315 		}
    316 	}
    317 	free(node_blk);
    318 }
    319 
    320 #ifdef HAVE_FSETXATTR
    321 static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk)
    322 {
    323 	void *xattr;
    324 	struct f2fs_xattr_entry *ent;
    325 	char xattr_name[F2FS_NAME_LEN] = {0};
    326 	int ret;
    327 
    328 	xattr = read_all_xattrs(sbi, node_blk);
    329 
    330 	list_for_each_xattr(ent, xattr) {
    331 		char *name = strndup(ent->e_name, ent->e_name_len);
    332 		void *value = ent->e_name + ent->e_name_len;
    333 
    334 		if (!name)
    335 			continue;
    336 
    337 		switch (ent->e_name_index) {
    338 		case F2FS_XATTR_INDEX_USER:
    339 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
    340 				       XATTR_USER_PREFIX, name);
    341 			break;
    342 
    343 		case F2FS_XATTR_INDEX_SECURITY:
    344 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
    345 				       XATTR_SECURITY_PREFIX, name);
    346 			break;
    347 		case F2FS_XATTR_INDEX_TRUSTED:
    348 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
    349 				       XATTR_TRUSTED_PREFIX, name);
    350 			break;
    351 		default:
    352 			MSG(0, "Unknown xattr index 0x%x\n", ent->e_name_index);
    353 			free(name);
    354 			continue;
    355 		}
    356 		if (ret >= F2FS_NAME_LEN) {
    357 			MSG(0, "XATTR index 0x%x name too long\n", ent->e_name_index);
    358 			free(name);
    359 			continue;
    360 		}
    361 
    362 		DBG(1, "fd %d xattr_name %s\n", c.dump_fd, xattr_name);
    363 #if defined(__linux__)
    364 		ret = fsetxattr(c.dump_fd, xattr_name, value,
    365 				le16_to_cpu(ent->e_value_size), 0);
    366 #elif defined(__APPLE__)
    367 		ret = fsetxattr(c.dump_fd, xattr_name, value,
    368 				le16_to_cpu(ent->e_value_size), 0,
    369 				XATTR_CREATE);
    370 #endif
    371 		if (ret)
    372 			MSG(0, "XATTR index 0x%x set xattr failed error %d\n",
    373 			    ent->e_name_index, errno);
    374 
    375 		free(name);
    376 	}
    377 
    378 	free(xattr);
    379 }
    380 #else
    381 static void dump_xattr(struct f2fs_sb_info *UNUSED(sbi),
    382 				struct f2fs_node *UNUSED(node_blk))
    383 {
    384 	MSG(0, "XATTR does not support\n");
    385 }
    386 #endif
    387 
    388 static void dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
    389 					struct f2fs_node *node_blk)
    390 {
    391 	u32 i = 0;
    392 	u64 ofs = 0;
    393 
    394 	if((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
    395 		DBG(3, "ino[0x%x] has inline data!\n", nid);
    396 		/* recover from inline data */
    397 		dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
    398 						0, MAX_INLINE_DATA(node_blk));
    399 		return;
    400 	}
    401 
    402 	/* check data blocks in inode */
    403 	for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
    404 		dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu(
    405 			node_blk->i.i_addr[get_extra_isize(node_blk) + i]));
    406 
    407 	/* check node blocks in inode */
    408 	for (i = 0; i < 5; i++) {
    409 		if (i == 0 || i == 1)
    410 			dump_node_blk(sbi, TYPE_DIRECT_NODE,
    411 					le32_to_cpu(node_blk->i.i_nid[i]), &ofs);
    412 		else if (i == 2 || i == 3)
    413 			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
    414 					le32_to_cpu(node_blk->i.i_nid[i]), &ofs);
    415 		else if (i == 4)
    416 			dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
    417 					le32_to_cpu(node_blk->i.i_nid[i]), &ofs);
    418 		else
    419 			ASSERT(0);
    420 	}
    421 
    422 	dump_xattr(sbi, node_blk);
    423 }
    424 
    425 static void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
    426 				struct f2fs_node *node_blk, int force)
    427 {
    428 	struct f2fs_inode *inode = &node_blk->i;
    429 	u32 imode = le32_to_cpu(inode->i_mode);
    430 	u32 namelen = le32_to_cpu(inode->i_namelen);
    431 	char name[F2FS_NAME_LEN + 1] = {0};
    432 	char path[1024] = {0};
    433 	char ans[255] = {0};
    434 	int is_encrypted = file_is_encrypt(inode);
    435 	int ret;
    436 
    437 	if (is_encrypted) {
    438 		MSG(force, "File is encrypted\n");
    439 		return;
    440 	}
    441 
    442 	if (!S_ISREG(imode) || namelen == 0 || namelen > F2FS_NAME_LEN) {
    443 		MSG(force, "Not a regular file or wrong name info\n\n");
    444 		return;
    445 	}
    446 	if (force)
    447 		goto dump;
    448 
    449 	printf("Do you want to dump this file into ./lost_found/? [Y/N] ");
    450 	ret = scanf("%s", ans);
    451 	ASSERT(ret >= 0);
    452 
    453 	if (!strcasecmp(ans, "y")) {
    454 dump:
    455 		ret = system("mkdir -p ./lost_found");
    456 		ASSERT(ret >= 0);
    457 
    458 		/* make a file */
    459 		strncpy(name, (const char *)inode->i_name, namelen);
    460 		name[namelen] = 0;
    461 		sprintf(path, "./lost_found/%s", name);
    462 
    463 		c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
    464 		ASSERT(c.dump_fd >= 0);
    465 
    466 		/* dump file's data */
    467 		dump_inode_blk(sbi, ni->ino, node_blk);
    468 
    469 		/* adjust file size */
    470 		ret = ftruncate(c.dump_fd, le32_to_cpu(inode->i_size));
    471 		ASSERT(ret >= 0);
    472 
    473 		close(c.dump_fd);
    474 	}
    475 }
    476 
    477 void dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force)
    478 {
    479 	struct node_info ni;
    480 	struct f2fs_node *node_blk;
    481 
    482 	get_node_info(sbi, nid, &ni);
    483 
    484 	node_blk = calloc(BLOCK_SZ, 1);
    485 	dev_read_block(node_blk, ni.blk_addr);
    486 
    487 	DBG(1, "Node ID               [0x%x]\n", nid);
    488 	DBG(1, "nat_entry.block_addr  [0x%x]\n", ni.blk_addr);
    489 	DBG(1, "nat_entry.version     [0x%x]\n", ni.version);
    490 	DBG(1, "nat_entry.ino         [0x%x]\n", ni.ino);
    491 
    492 	if (ni.blk_addr == 0x0)
    493 		MSG(force, "Invalid nat entry\n\n");
    494 
    495 	DBG(1, "node_blk.footer.ino [0x%x]\n", le32_to_cpu(node_blk->footer.ino));
    496 	DBG(1, "node_blk.footer.nid [0x%x]\n", le32_to_cpu(node_blk->footer.nid));
    497 
    498 	if (le32_to_cpu(node_blk->footer.ino) == ni.ino &&
    499 			le32_to_cpu(node_blk->footer.nid) == ni.nid &&
    500 			ni.ino == ni.nid) {
    501 		print_node_info(sbi, node_blk, force);
    502 		dump_file(sbi, &ni, node_blk, force);
    503 	} else {
    504 		print_node_info(sbi, node_blk, force);
    505 		MSG(force, "Invalid (i)node block\n\n");
    506 	}
    507 
    508 	free(node_blk);
    509 }
    510 
    511 static void dump_node_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
    512 {
    513 	struct f2fs_node *node_blk;
    514 	int ret;
    515 
    516 	node_blk = calloc(BLOCK_SZ, 1);
    517 	ASSERT(node_blk);
    518 
    519 	ret = dev_read_block(node_blk, blk_addr);
    520 	ASSERT(ret >= 0);
    521 
    522 	if (c.dbg_lv > 0)
    523 		print_node_info(sbi, node_blk, 0);
    524 	else
    525 		print_inode_info(sbi, node_blk, 1);
    526 
    527 	free(node_blk);
    528 }
    529 
    530 static void dump_data_offset(u32 blk_addr, int ofs_in_node)
    531 {
    532 	struct f2fs_node *node_blk;
    533 	unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4;
    534 	unsigned int bidx = 0;
    535 	unsigned int node_ofs;
    536 	int ret;
    537 
    538 	node_blk = calloc(BLOCK_SZ, 1);
    539 	ASSERT(node_blk);
    540 
    541 	ret = dev_read_block(node_blk, blk_addr);
    542 	ASSERT(ret >= 0);
    543 
    544 	node_ofs = ofs_of_node(node_blk);
    545 
    546 	if (node_ofs == 0)
    547 		goto got_it;
    548 
    549 	if (node_ofs > 0 && node_ofs <= 2) {
    550 		bidx = node_ofs - 1;
    551 	} else if (node_ofs <= indirect_blks) {
    552 		int dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1);
    553 		bidx = node_ofs - 2 - dec;
    554 	} else {
    555 		int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1);
    556 		bidx = node_ofs - 5 - dec;
    557 	}
    558 	bidx = bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE(&node_blk->i);
    559 got_it:
    560 	bidx +=  ofs_in_node;
    561 
    562 	setlocale(LC_ALL, "");
    563 	MSG(0, " - Data offset       : 0x%x (4KB), %'u (bytes)\n",
    564 				bidx, bidx * 4096);
    565 	free(node_blk);
    566 }
    567 
    568 static void dump_node_offset(u32 blk_addr)
    569 {
    570 	struct f2fs_node *node_blk;
    571 	int ret;
    572 
    573 	node_blk = calloc(BLOCK_SZ, 1);
    574 	ASSERT(node_blk);
    575 
    576 	ret = dev_read_block(node_blk, blk_addr);
    577 	ASSERT(ret >= 0);
    578 
    579 	MSG(0, " - Node offset       : 0x%x\n", ofs_of_node(node_blk));
    580 	free(node_blk);
    581 }
    582 
    583 int dump_info_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
    584 {
    585 	nid_t nid;
    586 	int type;
    587 	struct f2fs_summary sum_entry;
    588 	struct node_info ni, ino_ni;
    589 	struct seg_entry *se;
    590 	u32 offset;
    591 	int ret = 0;
    592 
    593 	MSG(0, "\n== Dump data from block address ==\n\n");
    594 
    595 	if (blk_addr < SM_I(sbi)->seg0_blkaddr) {
    596 		MSG(0, "\nFS Reserved Area for SEG #0: ");
    597 		ret = -EINVAL;
    598 	} else if (blk_addr < SIT_I(sbi)->sit_base_addr) {
    599 		MSG(0, "\nFS Metadata Area: ");
    600 		ret = -EINVAL;
    601 	} else if (blk_addr < NM_I(sbi)->nat_blkaddr) {
    602 		MSG(0, "\nFS SIT Area: ");
    603 		ret = -EINVAL;
    604 	} else if (blk_addr < SM_I(sbi)->ssa_blkaddr) {
    605 		MSG(0, "\nFS NAT Area: ");
    606 		ret = -EINVAL;
    607 	} else if (blk_addr < SM_I(sbi)->main_blkaddr) {
    608 		MSG(0, "\nFS SSA Area: ");
    609 		ret = -EINVAL;
    610 	} else if (blk_addr > __end_block_addr(sbi)) {
    611 		MSG(0, "\nOut of address space: ");
    612 		ret = -EINVAL;
    613 	}
    614 
    615 	if (ret) {
    616 		MSG(0, "User data is from 0x%x to 0x%x\n\n",
    617 			SM_I(sbi)->main_blkaddr,
    618 			__end_block_addr(sbi));
    619 		return ret;
    620 	}
    621 
    622 	se = get_seg_entry(sbi, GET_SEGNO(sbi, blk_addr));
    623 	offset = OFFSET_IN_SEG(sbi, blk_addr);
    624 
    625 	if (f2fs_test_bit(offset, (const char *)se->cur_valid_map) == 0) {
    626 		MSG(0, "\nblkaddr is not valid\n");
    627 	}
    628 
    629 	type = get_sum_entry(sbi, blk_addr, &sum_entry);
    630 	nid = le32_to_cpu(sum_entry.nid);
    631 
    632 	get_node_info(sbi, nid, &ni);
    633 
    634 	DBG(1, "Note: blkaddr = main_blkaddr + segno * 512 + offset\n");
    635 	DBG(1, "Block_addr            [0x%x]\n", blk_addr);
    636 	DBG(1, " - Segno              [0x%x]\n", GET_SEGNO(sbi, blk_addr));
    637 	DBG(1, " - Offset             [0x%x]\n", OFFSET_IN_SEG(sbi, blk_addr));
    638 	DBG(1, "SUM.nid               [0x%x]\n", nid);
    639 	DBG(1, "SUM.type              [%s]\n", type >= 0 ?
    640 						seg_type_name[type] :
    641 						"Broken");
    642 	DBG(1, "SUM.version           [%d]\n", sum_entry.version);
    643 	DBG(1, "SUM.ofs_in_node       [0x%x]\n", sum_entry.ofs_in_node);
    644 	DBG(1, "NAT.blkaddr           [0x%x]\n", ni.blk_addr);
    645 	DBG(1, "NAT.ino               [0x%x]\n", ni.ino);
    646 
    647 	get_node_info(sbi, ni.ino, &ino_ni);
    648 
    649 	/* inode block address */
    650 	if (ni.blk_addr == NULL_ADDR || ino_ni.blk_addr == NULL_ADDR) {
    651 		MSG(0, "FS Userdata Area: Obsolete block from 0x%x\n",
    652 			blk_addr);
    653 		return -EINVAL;
    654 	}
    655 
    656 	/* print inode */
    657 	if (c.dbg_lv > 0)
    658 		dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
    659 
    660 	if (type == SEG_TYPE_CUR_DATA || type == SEG_TYPE_DATA) {
    661 		MSG(0, "FS Userdata Area: Data block from 0x%x\n", blk_addr);
    662 		MSG(0, " - Direct node block : id = 0x%x from 0x%x\n",
    663 					nid, ni.blk_addr);
    664 		MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
    665 					ni.ino, ino_ni.blk_addr);
    666 		dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
    667 		dump_data_offset(ni.blk_addr,
    668 			le16_to_cpu(sum_entry.ofs_in_node));
    669 	} else {
    670 		MSG(0, "FS Userdata Area: Node block from 0x%x\n", blk_addr);
    671 		if (ni.ino == ni.nid) {
    672 			MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
    673 					ni.ino, ino_ni.blk_addr);
    674 			dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
    675 		} else {
    676 			MSG(0, " - Node block        : id = 0x%x from 0x%x\n",
    677 					nid, ni.blk_addr);
    678 			MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
    679 					ni.ino, ino_ni.blk_addr);
    680 			dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
    681 			dump_node_offset(ni.blk_addr);
    682 		}
    683 	}
    684 
    685 	return 0;
    686 }
    687