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