f2fs_sparseblock.c revision 02e662508d7c6b96df94154b2fdf9c8f2c348690
1#define _LARGEFILE64_SOURCE 2 3#define LOG_TAG "f2fs_sparseblock" 4 5 6#include <cutils/log.h> 7#include <fcntl.h> 8#include <f2fs_fs.h> 9#include <linux/types.h> 10#include <sys/stat.h> 11#include "f2fs_sparseblock.h" 12 13 14#define D_DISP_u32(ptr, member) \ 15 do { \ 16 SLOGD("%-30s" "\t\t[0x%#08x : %u]\n", \ 17 #member, le32_to_cpu((ptr)->member), le32_to_cpu((ptr)->member) ); \ 18 } while (0); 19 20#define D_DISP_u64(ptr, member) \ 21 do { \ 22 SLOGD("%-30s" "\t\t[0x%#016llx : %llu]\n", \ 23 #member, le64_to_cpu((ptr)->member), le64_to_cpu((ptr)->member) ); \ 24 } while (0); 25 26static void dbg_print_raw_sb_info(struct f2fs_super_block *sb) 27{ 28 SLOGD("\n"); 29 SLOGD("+--------------------------------------------------------+\n"); 30 SLOGD("| Super block |\n"); 31 SLOGD("+--------------------------------------------------------+\n"); 32 33 D_DISP_u32(sb, magic); 34 D_DISP_u32(sb, major_ver); 35 D_DISP_u32(sb, minor_ver); 36 D_DISP_u32(sb, log_sectorsize); 37 D_DISP_u32(sb, log_sectors_per_block); 38 39 D_DISP_u32(sb, log_blocksize); 40 D_DISP_u32(sb, log_blocks_per_seg); 41 D_DISP_u32(sb, segs_per_sec); 42 D_DISP_u32(sb, secs_per_zone); 43 D_DISP_u32(sb, checksum_offset); 44 D_DISP_u64(sb, block_count); 45 46 D_DISP_u32(sb, section_count); 47 D_DISP_u32(sb, segment_count); 48 D_DISP_u32(sb, segment_count_ckpt); 49 D_DISP_u32(sb, segment_count_sit); 50 D_DISP_u32(sb, segment_count_nat); 51 52 D_DISP_u32(sb, segment_count_ssa); 53 D_DISP_u32(sb, segment_count_main); 54 D_DISP_u32(sb, segment0_blkaddr); 55 56 D_DISP_u32(sb, cp_blkaddr); 57 D_DISP_u32(sb, sit_blkaddr); 58 D_DISP_u32(sb, nat_blkaddr); 59 D_DISP_u32(sb, ssa_blkaddr); 60 D_DISP_u32(sb, main_blkaddr); 61 62 D_DISP_u32(sb, root_ino); 63 D_DISP_u32(sb, node_ino); 64 D_DISP_u32(sb, meta_ino); 65 D_DISP_u32(sb, cp_payload); 66 SLOGD("\n"); 67} 68static void dbg_print_raw_ckpt_struct(struct f2fs_checkpoint *cp) 69{ 70 SLOGD("\n"); 71 SLOGD("+--------------------------------------------------------+\n"); 72 SLOGD("| Checkpoint |\n"); 73 SLOGD("+--------------------------------------------------------+\n"); 74 75 D_DISP_u64(cp, checkpoint_ver); 76 D_DISP_u64(cp, user_block_count); 77 D_DISP_u64(cp, valid_block_count); 78 D_DISP_u32(cp, rsvd_segment_count); 79 D_DISP_u32(cp, overprov_segment_count); 80 D_DISP_u32(cp, free_segment_count); 81 82 D_DISP_u32(cp, alloc_type[CURSEG_HOT_NODE]); 83 D_DISP_u32(cp, alloc_type[CURSEG_WARM_NODE]); 84 D_DISP_u32(cp, alloc_type[CURSEG_COLD_NODE]); 85 D_DISP_u32(cp, cur_node_segno[0]); 86 D_DISP_u32(cp, cur_node_segno[1]); 87 D_DISP_u32(cp, cur_node_segno[2]); 88 89 D_DISP_u32(cp, cur_node_blkoff[0]); 90 D_DISP_u32(cp, cur_node_blkoff[1]); 91 D_DISP_u32(cp, cur_node_blkoff[2]); 92 93 94 D_DISP_u32(cp, alloc_type[CURSEG_HOT_DATA]); 95 D_DISP_u32(cp, alloc_type[CURSEG_WARM_DATA]); 96 D_DISP_u32(cp, alloc_type[CURSEG_COLD_DATA]); 97 D_DISP_u32(cp, cur_data_segno[0]); 98 D_DISP_u32(cp, cur_data_segno[1]); 99 D_DISP_u32(cp, cur_data_segno[2]); 100 101 D_DISP_u32(cp, cur_data_blkoff[0]); 102 D_DISP_u32(cp, cur_data_blkoff[1]); 103 D_DISP_u32(cp, cur_data_blkoff[2]); 104 105 D_DISP_u32(cp, ckpt_flags); 106 D_DISP_u32(cp, cp_pack_total_block_count); 107 D_DISP_u32(cp, cp_pack_start_sum); 108 D_DISP_u32(cp, valid_node_count); 109 D_DISP_u32(cp, valid_inode_count); 110 D_DISP_u32(cp, next_free_nid); 111 D_DISP_u32(cp, sit_ver_bitmap_bytesize); 112 D_DISP_u32(cp, nat_ver_bitmap_bytesize); 113 D_DISP_u32(cp, checksum_offset); 114 D_DISP_u64(cp, elapsed_time); 115 116 D_DISP_u32(cp, sit_nat_version_bitmap[0]); 117 SLOGD("\n\n"); 118} 119 120static void dbg_print_info_struct(struct f2fs_info *info) 121{ 122 SLOGD("\n"); 123 SLOGD("+--------------------------------------------------------+\n"); 124 SLOGD("| F2FS_INFO |\n"); 125 SLOGD("+--------------------------------------------------------+\n"); 126 SLOGD("blocks_per_segment: %"PRIu64, info->blocks_per_segment); 127 SLOGD("block_size: %d", info->block_size); 128 SLOGD("sit_bmp loc: %p", info->sit_bmp); 129 SLOGD("sit_bmp_size: %d", info->sit_bmp_size); 130 SLOGD("blocks_per_sit: %"PRIu64, info->blocks_per_sit); 131 SLOGD("sit_blocks loc: %p", info->sit_blocks); 132 SLOGD("sit_sums loc: %p", info->sit_sums); 133 SLOGD("cp_blkaddr: %"PRIu64, info->cp_blkaddr); 134 SLOGD("cp_valid_cp_blkaddr: %"PRIu64, info->cp_valid_cp_blkaddr); 135 SLOGD("sit_blkaddr: %"PRIu64, info->sit_blkaddr); 136 SLOGD("nat_blkaddr: %"PRIu64, info->nat_blkaddr); 137 SLOGD("ssa_blkaddr: %"PRIu64, info->ssa_blkaddr); 138 SLOGD("main_blkaddr: %"PRIu64, info->main_blkaddr); 139 SLOGD("total_user_used: %"PRIu64, info->total_user_used); 140 SLOGD("total_blocks: %"PRIu64, info->total_blocks); 141 SLOGD("\n\n"); 142} 143 144 145/* read blocks */ 146static int read_structure(int fd, unsigned long long start, void *buf, ssize_t len) 147{ 148 off64_t ret; 149 150 ret = lseek64(fd, start, SEEK_SET); 151 if (ret < 0) { 152 SLOGE("failed to seek\n"); 153 return ret; 154 } 155 156 ret = read(fd, buf, len); 157 if (ret < 0) { 158 SLOGE("failed to read\n"); 159 return ret; 160 } 161 if (ret != len) { 162 SLOGE("failed to read all\n"); 163 return -1; 164 } 165 return 0; 166} 167 168static int read_structure_blk(int fd, unsigned long long start_blk, void *buf, size_t len) 169{ 170 return read_structure(fd, F2FS_BLKSIZE*start_blk, buf, F2FS_BLKSIZE * len); 171} 172 173static int read_f2fs_sb(int fd, struct f2fs_super_block *sb) 174{ 175 int rc; 176 rc = read_structure(fd, F2FS_SUPER_OFFSET, sb, sizeof(*sb)); 177 if (le32_to_cpu(sb->magic) != F2FS_SUPER_MAGIC) { 178 SLOGE("Not a valid F2FS super block. Magic:%#08x != %#08x", 179 le32_to_cpu(sb->magic), F2FS_SUPER_MAGIC); 180 return -1; 181 } 182 return 0; 183} 184 185unsigned int get_f2fs_filesystem_size_sec(char *dev) 186{ 187 int fd; 188 if ((fd = open(dev, O_RDONLY)) < 0) { 189 SLOGE("Cannot open device to get filesystem size "); 190 return 0; 191 } 192 struct f2fs_super_block sb; 193 if(read_f2fs_sb(fd, &sb)) 194 return 0; 195 return (unsigned int)(le64_to_cpu(sb.block_count)*F2FS_BLKSIZE/DEFAULT_SECTOR_SIZE); 196} 197 198static struct f2fs_checkpoint *validate_checkpoint(block_t cp_addr, 199 unsigned long long *version, int fd) 200{ 201 unsigned char *cp_block_1, *cp_block_2; 202 struct f2fs_checkpoint *cp_block, *cp_ret; 203 u64 cp1_version = 0, cp2_version = 0; 204 205 cp_block_1 = malloc(F2FS_BLKSIZE); 206 if (!cp_block_1) 207 return NULL; 208 209 /* Read the 1st cp block in this CP pack */ 210 if (read_structure_blk(fd, cp_addr, cp_block_1, 1)) 211 goto invalid_cp1; 212 213 /* get the version number */ 214 cp_block = (struct f2fs_checkpoint *)cp_block_1; 215 216 cp1_version = le64_to_cpu(cp_block->checkpoint_ver); 217 218 cp_block_2 = malloc(F2FS_BLKSIZE); 219 if (!cp_block_2) { 220 goto invalid_cp1; 221 } 222 /* Read the 2nd cp block in this CP pack */ 223 cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1; 224 if (read_structure_blk(fd, cp_addr, cp_block_2, 1)) { 225 goto invalid_cp2; 226 } 227 228 cp_block = (struct f2fs_checkpoint *)cp_block_2; 229 230 cp2_version = le64_to_cpu(cp_block->checkpoint_ver); 231 232 if (cp2_version == cp1_version) { 233 *version = cp2_version; 234 free(cp_block_2); 235 return (struct f2fs_checkpoint *)cp_block_1; 236 } 237 238 /* There must be something wrong with this checkpoint */ 239invalid_cp2: 240 free(cp_block_2); 241invalid_cp1: 242 free(cp_block_1); 243 return NULL; 244} 245 246int get_valid_checkpoint_info(int fd, struct f2fs_super_block *sb, struct f2fs_checkpoint **cp, struct f2fs_info *info) 247{ 248 struct f2fs_checkpoint *cp_block; 249 250 struct f2fs_checkpoint *cp1, *cp2, *cur_cp; 251 int cur_cp_no; 252 unsigned long blk_size;// = 1<<le32_to_cpu(info->sb->log_blocksize); 253 unsigned long long cp1_version = 0, cp2_version = 0; 254 unsigned long long cp1_start_blk_no; 255 unsigned long long cp2_start_blk_no; 256 u32 bmp_size; 257 258 blk_size = 1U<<le32_to_cpu(sb->log_blocksize); 259 260 /* 261 * Find valid cp by reading both packs and finding most recent one. 262 */ 263 cp1_start_blk_no = le32_to_cpu(sb->cp_blkaddr); 264 cp1 = validate_checkpoint(cp1_start_blk_no, &cp1_version, fd); 265 266 /* The second checkpoint pack should start at the next segment */ 267 cp2_start_blk_no = cp1_start_blk_no + (1 << le32_to_cpu(sb->log_blocks_per_seg)); 268 cp2 = validate_checkpoint(cp2_start_blk_no, &cp2_version, fd); 269 270 if (cp1 && cp2) { 271 if (ver_after(cp2_version, cp1_version)) { 272 cur_cp = cp2; 273 info->cp_valid_cp_blkaddr = cp2_start_blk_no; 274 free(cp1); 275 } else { 276 cur_cp = cp1; 277 info->cp_valid_cp_blkaddr = cp1_start_blk_no; 278 free(cp2); 279 } 280 } else if (cp1) { 281 cur_cp = cp1; 282 info->cp_valid_cp_blkaddr = cp1_start_blk_no; 283 } else if (cp2) { 284 cur_cp = cp2; 285 info->cp_valid_cp_blkaddr = cp2_start_blk_no; 286 } else { 287 goto fail_no_cp; 288 } 289 290 *cp = cur_cp; 291 292 return 0; 293 294fail_no_cp: 295 SLOGE("Valid Checkpoint not found!!"); 296 return -EINVAL; 297} 298 299static int gather_sit_info(int fd, struct f2fs_info *info) 300{ 301 u64 num_segments = (info->total_blocks - info->main_blkaddr 302 + info->blocks_per_segment - 1) / info->blocks_per_segment; 303 u64 num_sit_blocks = (num_segments + SIT_ENTRY_PER_BLOCK - 1) / SIT_ENTRY_PER_BLOCK; 304 u64 sit_block; 305 306 info->sit_blocks = malloc(num_sit_blocks * sizeof(struct f2fs_sit_block)); 307 if (!info->sit_blocks) 308 return -1; 309 310 for(sit_block = 0; sit_block<num_sit_blocks; sit_block++) { 311 off64_t address = info->sit_blkaddr + sit_block; 312 313 if (f2fs_test_bit(sit_block, info->sit_bmp)) 314 address += info->blocks_per_sit; 315 316 SLOGD("Reading cache block starting at block %"PRIu64, address); 317 if (read_structure(fd, address * F2FS_BLKSIZE, &info->sit_blocks[sit_block], sizeof(struct f2fs_sit_block))) { 318 SLOGE("Could not read sit block at block %"PRIu64, address); 319 free(info->sit_blocks); 320 return -1; 321 } 322 } 323 return 0; 324} 325 326static int get_sit_summary(int fd, struct f2fs_info *info, struct f2fs_checkpoint *cp) 327{ 328 char buffer[4096]; 329 read_structure_blk(fd, info->cp_valid_cp_blkaddr + le32_to_cpu(cp->cp_pack_start_sum), &buffer, 1); 330 info->sit_sums = calloc(1, sizeof(struct f2fs_summary_block)); 331 if (!info->sit_sums) 332 return -1; 333 memcpy(&info->sit_sums->n_sits, &buffer[SUM_JOURNAL_SIZE], SUM_JOURNAL_SIZE); 334 return 0; 335} 336 337struct f2fs_info *generate_f2fs_info(int fd) 338{ 339 struct f2fs_super_block *sb = NULL; 340 struct f2fs_checkpoint *cp = NULL; 341 struct f2fs_info *info; 342 343 info = calloc(1, sizeof(*info)); 344 if (!info) { 345 SLOGE("Out of memory!"); 346 return NULL; 347 } 348 349 sb = malloc(sizeof(*sb)); 350 if(!sb) { 351 SLOGE("Out of memory!"); 352 free(info); 353 return NULL; 354 } 355 if (read_f2fs_sb(fd, sb)) { 356 SLOGE("Failed to read superblock"); 357 free(info); 358 free(sb); 359 return NULL; 360 } 361 dbg_print_raw_sb_info(sb); 362 363 info->cp_blkaddr = le32_to_cpu(sb->cp_blkaddr); 364 info->sit_blkaddr = le32_to_cpu(sb->sit_blkaddr); 365 info->nat_blkaddr = le32_to_cpu(sb->nat_blkaddr); 366 info->ssa_blkaddr = le32_to_cpu(sb->ssa_blkaddr); 367 info->main_blkaddr = le32_to_cpu(sb->main_blkaddr); 368 info->block_size = F2FS_BLKSIZE; 369 info->total_blocks = sb->block_count; 370 info->blocks_per_sit = (le32_to_cpu(sb->segment_count_sit) >> 1) << le32_to_cpu(sb->log_blocks_per_seg); 371 info->blocks_per_segment = 1U << le32_to_cpu(sb->log_blocks_per_seg); 372 373 if (get_valid_checkpoint_info(fd, sb, &cp, info)) 374 goto error; 375 dbg_print_raw_ckpt_struct(cp); 376 377 info->total_user_used = le32_to_cpu(cp->valid_block_count); 378 379 u32 bmp_size = le32_to_cpu(cp->sit_ver_bitmap_bytesize); 380 381 /* get sit validity bitmap */ 382 info->sit_bmp = malloc(bmp_size); 383 if(!info->sit_bmp) { 384 SLOGE("Out of memory!"); 385 goto error; 386 } 387 388 info->sit_bmp_size = bmp_size; 389 if (read_structure(fd, info->cp_valid_cp_blkaddr * F2FS_BLKSIZE 390 + offsetof(struct f2fs_checkpoint, sit_nat_version_bitmap), 391 info->sit_bmp, bmp_size)) { 392 SLOGE("Error getting SIT validity bitmap"); 393 goto error; 394 } 395 396 if (gather_sit_info(fd , info)) { 397 SLOGE("Error getting SIT information"); 398 goto error; 399 } 400 if (get_sit_summary(fd, info, cp)) { 401 SLOGE("Error getting SIT entries in summary area"); 402 goto error; 403 } 404 dbg_print_info_struct(info); 405 return info; 406error: 407 free(sb); 408 free(cp); 409 free_f2fs_info(info); 410 return NULL; 411} 412 413void free_f2fs_info(struct f2fs_info *info) 414{ 415 if (info) { 416 free(info->sit_blocks); 417 info->sit_blocks = NULL; 418 419 free(info->sit_bmp); 420 info->sit_bmp = NULL; 421 422 free(info->sit_sums); 423 info->sit_sums = NULL; 424 } 425 free(info); 426} 427 428u64 get_num_blocks_used(struct f2fs_info *info) 429{ 430 return info->main_blkaddr + info->total_user_used; 431} 432 433int f2fs_test_bit(unsigned int nr, const char *p) 434{ 435 int mask; 436 char *addr = (char *)p; 437 438 addr += (nr >> 3); 439 mask = 1 << (7 - (nr & 0x07)); 440 return (mask & *addr) != 0; 441} 442 443#define segno_in_journal(sum, i) (sum->sit_j.entries[i].segno) 444 445#define sit_in_journal(sum, i) (sum->sit_j.entries[i].se) 446 447int run_on_used_blocks(u64 startblock, struct f2fs_info *info, int (*func)(u64 pos, void *data), void *data) { 448 struct f2fs_sit_block sit_block_cache; 449 struct f2fs_sit_entry * sit_entry, *sit_entry1, *sit_entry2; 450 u64 sit_block_num_cur = 0, segnum=0, block_offset; 451 u64 block; 452 unsigned int used, found, started = 0, i; 453 454 for (block=startblock; block<info->total_blocks; block++) { 455 /* TODO: Save only relevant portions of metadata */ 456 if (block < info->main_blkaddr) { 457 if (func(block, data)) { 458 SLOGI("func error"); 459 return -1; 460 } 461 } else { 462 /* Main Section */ 463 segnum = (block - info->main_blkaddr)/info->blocks_per_segment; 464 465 /* check the SIT entries in the journal */ 466 found=0; 467 for(i = 0; i<SIT_JOURNAL_ENTRIES; i++) { 468 if (le32_to_cpu(segno_in_journal(info->sit_sums, i)) == segnum) { 469 sit_entry = &sit_in_journal(info->sit_sums, i); 470 found = 1; 471 break; 472 } 473 } 474 475 /* get SIT entry from SIT section */ 476 if (!found) { 477 sit_block_num_cur = segnum/SIT_ENTRY_PER_BLOCK; 478 sit_entry = &info->sit_blocks[sit_block_num_cur].entries[segnum % SIT_ENTRY_PER_BLOCK]; 479 } 480 481 block_offset = (block - info->main_blkaddr) % info->blocks_per_segment; 482 483 if (block_offset == 0 && GET_SIT_VBLOCKS(sit_entry) == 0) { 484 block += info->blocks_per_segment; 485 continue; 486 } 487 488 used = f2fs_test_bit(block_offset, (char *)sit_entry->valid_map); 489 if(used) 490 if (func(block, data)) 491 return -1; 492 } 493 } 494 return 0; 495} 496 497struct privdata 498{ 499 int count; 500 int infd; 501 int outfd; 502 char* buf; 503 char *zbuf; 504 int done; 505 struct f2fs_info *info; 506}; 507 508 509/* 510 * This is a simple test program. It performs a block to block copy of a 511 * filesystem, replacing blocks identified as unused with 0's. 512 */ 513 514int copy_used(u64 pos, void *data) 515{ 516 struct privdata *d = data; 517 char *buf; 518 int pdone = (pos*100)/d->info->total_blocks; 519 if (pdone > d->done) { 520 d->done = pdone; 521 printf("Done with %d percent\n", d->done); 522 } 523 524 d->count++; 525 buf = d->buf; 526 if(read_structure_blk(d->infd, (unsigned long long)pos, d->buf, 1)) { 527 printf("Error reading!!!\n"); 528 return -1; 529 } 530 531 off64_t ret; 532 ret = lseek64(d->outfd, pos*F2FS_BLKSIZE, SEEK_SET); 533 if (ret < 0) { 534 SLOGE("failed to seek\n"); 535 return ret; 536 } 537 538 ret = write(d->outfd, d->buf, F2FS_BLKSIZE); 539 if (ret < 0) { 540 SLOGE("failed to write\n"); 541 return ret; 542 } 543 if (ret != F2FS_BLKSIZE) { 544 SLOGE("failed to read all\n"); 545 return -1; 546 } 547 return 0; 548} 549 550int main(int argc, char **argv) 551{ 552 if (argc != 3) 553 printf("Usage: %s fs_file_in fs_file_out\n", argv[0]); 554 char *in = argv[1]; 555 char *out = argv[2]; 556 int infd, outfd; 557 558 if ((infd = open(in, O_RDONLY)) < 0) { 559 SLOGE("Cannot open device"); 560 return 0; 561 } 562 if ((outfd = open(out, O_WRONLY|O_CREAT, S_IRUSR | S_IWUSR)) < 0) { 563 SLOGE("Cannot open output"); 564 return 0; 565 } 566 567 struct privdata d; 568 d.infd = infd; 569 d.outfd = outfd; 570 d.count = 0; 571 struct f2fs_info *info = generate_f2fs_info(infd); 572 if (!info) { 573 printf("Failed to generate info!"); 574 return -1; 575 } 576 char *buf = malloc(F2FS_BLKSIZE); 577 char *zbuf = calloc(1, F2FS_BLKSIZE); 578 d.buf = buf; 579 d.zbuf = zbuf; 580 d.done = 0; 581 d.info = info; 582 int expected_count = get_num_blocks_used(info); 583 run_on_used_blocks(0, info, ©_used, &d); 584 printf("Copied %d blocks. Expected to copy %d\n", d.count, expected_count); 585 ftruncate64(outfd, info->total_blocks * F2FS_BLKSIZE); 586 free_f2fs_info(info); 587 free(buf); 588 free(zbuf); 589 close(infd); 590 close(outfd); 591 return 0; 592} 593