• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
nat_dump(struct f2fs_sb_info * sbi)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 
sit_dump(struct f2fs_sb_info * sbi,unsigned int start_sit,unsigned int end_sit)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 
ssa_dump(struct f2fs_sb_info * sbi,int start_ssa,int end_ssa)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 
dump_data_blk(struct f2fs_sb_info * sbi,__u64 offset,u32 blkaddr)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 
dump_node_blk(struct f2fs_sb_info * sbi,int ntype,u32 nid,u64 * ofs)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
dump_xattr(struct f2fs_sb_info * sbi,struct f2fs_node * node_blk)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
dump_xattr(struct f2fs_sb_info * UNUSED (sbi),struct f2fs_node * UNUSED (node_blk))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 
dump_inode_blk(struct f2fs_sb_info * sbi,u32 nid,struct f2fs_node * node_blk)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 
dump_file(struct f2fs_sb_info * sbi,struct node_info * ni,struct f2fs_node * node_blk,int force)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 
dump_node(struct f2fs_sb_info * sbi,nid_t nid,int force)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 
dump_node_from_blkaddr(struct f2fs_sb_info * sbi,u32 blk_addr)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 
dump_data_offset(u32 blk_addr,int ofs_in_node)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 
dump_node_offset(u32 blk_addr)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 
dump_info_from_blkaddr(struct f2fs_sb_info * sbi,u32 blk_addr)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