dump.c revision b3a4f9457718eb1aecb85d082f9e6f737ce3af86
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
17const 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
24void 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
65void 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
118static 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
138static 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	int i, ret;
144	u32 idx, skip = 0;
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	ret = get_node_info(sbi, nid, &ni);
166	ASSERT(ret >= 0);
167
168	node_blk = calloc(BLOCK_SZ, 1);
169	dev_read_block(node_blk, ni.blk_addr);
170
171	for (i = 0; i < idx; i++, (*ofs)++) {
172		switch (ntype) {
173		case TYPE_DIRECT_NODE:
174			dump_data_blk(*ofs * F2FS_BLKSIZE,
175					le32_to_cpu(node_blk->dn.addr[i]));
176			break;
177		case TYPE_INDIRECT_NODE:
178			dump_node_blk(sbi, TYPE_DIRECT_NODE,
179					le32_to_cpu(node_blk->in.nid[i]), ofs);
180			break;
181		case TYPE_DOUBLE_INDIRECT_NODE:
182			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
183					le32_to_cpu(node_blk->in.nid[i]), ofs);
184			break;
185		}
186	}
187	free(node_blk);
188}
189
190static void dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
191					struct f2fs_node *node_blk)
192{
193	u32 i = 0;
194	u64 ofs = 0;
195
196	/* TODO: need to dump xattr */
197
198	if((node_blk->i.i_inline & F2FS_INLINE_DATA)){
199		DBG(3, "ino[0x%x] has inline data!\n", nid);
200		/* recover from inline data */
201		dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
202							0, MAX_INLINE_DATA);
203		return;
204	}
205
206	/* check data blocks in inode */
207	for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
208		dump_data_blk(ofs * F2FS_BLKSIZE,
209				le32_to_cpu(node_blk->i.i_addr[i]));
210
211	/* check node blocks in inode */
212	for (i = 0; i < 5; i++) {
213		if (i == 0 || i == 1)
214			dump_node_blk(sbi, TYPE_DIRECT_NODE,
215					node_blk->i.i_nid[i], &ofs);
216		else if (i == 2 || i == 3)
217			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
218					node_blk->i.i_nid[i], &ofs);
219		else if (i == 4)
220			dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
221					node_blk->i.i_nid[i], &ofs);
222		else
223			ASSERT(0);
224	}
225}
226
227void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
228					struct f2fs_node *node_blk)
229{
230	struct f2fs_inode *inode = &node_blk->i;
231	u32 imode = le32_to_cpu(inode->i_mode);
232	char name[255] = {0};
233	char path[1024] = {0};
234	char ans[255] = {0};
235	int ret;
236
237	if (!S_ISREG(imode)) {
238		MSG(0, "Not a regular file\n\n");
239		return;
240	}
241
242	printf("Do you want to dump this file into ./lost_found/? [Y/N] ");
243	ret = scanf("%s", ans);
244	ASSERT(ret >= 0);
245
246	if (!strcasecmp(ans, "y")) {
247		ret = system("mkdir -p ./lost_found");
248		ASSERT(ret >= 0);
249
250		/* make a file */
251		strncpy(name, (const char *)inode->i_name,
252					le32_to_cpu(inode->i_namelen));
253		name[le32_to_cpu(inode->i_namelen)] = 0;
254		sprintf(path, "./lost_found/%s", name);
255
256		config.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
257		ASSERT(config.dump_fd >= 0);
258
259		/* dump file's data */
260		dump_inode_blk(sbi, ni->ino, node_blk);
261
262		/* adjust file size */
263		ret = ftruncate(config.dump_fd, le32_to_cpu(inode->i_size));
264		ASSERT(ret >= 0);
265
266		close(config.dump_fd);
267	}
268}
269
270int dump_node(struct f2fs_sb_info *sbi, nid_t nid)
271{
272	struct node_info ni;
273	struct f2fs_node *node_blk;
274	int ret;
275
276	ret = get_node_info(sbi, nid, &ni);
277	ASSERT(ret >= 0);
278
279	node_blk = calloc(BLOCK_SZ, 1);
280	dev_read_block(node_blk, ni.blk_addr);
281
282	DBG(1, "Node ID               [0x%x]\n", nid);
283	DBG(1, "nat_entry.block_addr  [0x%x]\n", ni.blk_addr);
284	DBG(1, "nat_entry.version     [0x%x]\n", ni.version);
285	DBG(1, "nat_entry.ino         [0x%x]\n", ni.ino);
286
287	if (ni.blk_addr == 0x0) {
288		MSG(0, "Invalid nat entry\n\n");
289	}
290
291	DBG(1, "node_blk.footer.ino [0x%x]\n", le32_to_cpu(node_blk->footer.ino));
292	DBG(1, "node_blk.footer.nid [0x%x]\n", le32_to_cpu(node_blk->footer.nid));
293
294	if (le32_to_cpu(node_blk->footer.ino) == ni.ino &&
295			le32_to_cpu(node_blk->footer.nid) == ni.nid) {
296		print_node_info(node_blk);
297		dump_file(sbi, &ni, node_blk);
298	} else {
299		MSG(0, "Invalid node block\n\n");
300	}
301
302	free(node_blk);
303	return 0;
304}
305
306int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
307{
308	nid_t ino, nid;
309	int type, ret;
310	struct f2fs_summary sum_entry;
311	struct node_info ni;
312	struct f2fs_node *node_blk;
313
314	type = get_sum_entry(sbi, blk_addr, &sum_entry);
315	nid = le32_to_cpu(sum_entry.nid);
316
317	ret = get_node_info(sbi, nid, &ni);
318	ASSERT(ret >= 0);
319
320	DBG(1, "Note: blkaddr = main_blkaddr + segno * 512 + offset\n");
321	DBG(1, "Block_addr            [0x%x]\n", blk_addr);
322	DBG(1, " - Segno              [0x%x]\n", GET_SEGNO(sbi, blk_addr));
323	DBG(1, " - Offset             [0x%x]\n", OFFSET_IN_SEG(sbi, blk_addr));
324	DBG(1, "SUM.nid               [0x%x]\n", nid);
325	DBG(1, "SUM.type              [%s]\n", seg_type_name[type]);
326	DBG(1, "SUM.version           [%d]\n", sum_entry.version);
327	DBG(1, "SUM.ofs_in_node       [%d]\n", sum_entry.ofs_in_node);
328	DBG(1, "NAT.blkaddr           [0x%x]\n", ni.blk_addr);
329	DBG(1, "NAT.ino               [0x%x]\n", ni.ino);
330
331	node_blk = calloc(BLOCK_SZ, 1);
332
333read_node_blk:
334	dev_read_block(node_blk, blk_addr);
335
336	ino = le32_to_cpu(node_blk->footer.ino);
337	nid = le32_to_cpu(node_blk->footer.nid);
338
339	if (ino == nid) {
340		print_node_info(node_blk);
341	} else {
342		ret = get_node_info(sbi, ino, &ni);
343		goto read_node_blk;
344	}
345
346	free(node_blk);
347	return ino;
348}
349