1 #define _LARGEFILE64_SOURCE
3 #define LOG_TAG "f2fs_sparseblock"
6 #include <cutils/log.h>
9 #include <linux/types.h>
11 #include "f2fs_sparseblock.h"
14 #define D_DISP_u32(ptr, member) \
16 SLOGD("%-30s" "\t\t[0x%#08x : %u]\n", \
17 #member, le32_to_cpu((ptr)->member), le32_to_cpu((ptr)->member) ); \
20 #define D_DISP_u64(ptr, member) \
22 SLOGD("%-30s" "\t\t[0x%#016llx : %llu]\n", \
23 #member, le64_to_cpu((ptr)->member), le64_to_cpu((ptr)->member) ); \
26 #define segno_in_journal(sum, i) (sum->sit_j.entries[i].segno)
28 #define sit_in_journal(sum, i) (sum->sit_j.entries[i].se)
30 static void dbg_print_raw_sb_info(struct f2fs_super_block *sb)
33 SLOGD("+--------------------------------------------------------+\n");
34 SLOGD("| Super block |\n");
35 SLOGD("+--------------------------------------------------------+\n");
37 D_DISP_u32(sb, magic);
38 D_DISP_u32(sb, major_ver);
39 D_DISP_u32(sb, minor_ver);
40 D_DISP_u32(sb, log_sectorsize);
41 D_DISP_u32(sb, log_sectors_per_block);
43 D_DISP_u32(sb, log_blocksize);
44 D_DISP_u32(sb, log_blocks_per_seg);
45 D_DISP_u32(sb, segs_per_sec);
46 D_DISP_u32(sb, secs_per_zone);
47 D_DISP_u32(sb, checksum_offset);
48 D_DISP_u64(sb, block_count);
50 D_DISP_u32(sb, section_count);
51 D_DISP_u32(sb, segment_count);
52 D_DISP_u32(sb, segment_count_ckpt);
53 D_DISP_u32(sb, segment_count_sit);
54 D_DISP_u32(sb, segment_count_nat);
56 D_DISP_u32(sb, segment_count_ssa);
57 D_DISP_u32(sb, segment_count_main);
58 D_DISP_u32(sb, segment0_blkaddr);
60 D_DISP_u32(sb, cp_blkaddr);
61 D_DISP_u32(sb, sit_blkaddr);
62 D_DISP_u32(sb, nat_blkaddr);
63 D_DISP_u32(sb, ssa_blkaddr);
64 D_DISP_u32(sb, main_blkaddr);
66 D_DISP_u32(sb, root_ino);
67 D_DISP_u32(sb, node_ino);
68 D_DISP_u32(sb, meta_ino);
69 D_DISP_u32(sb, cp_payload);
72 static void dbg_print_raw_ckpt_struct(struct f2fs_checkpoint *cp)
75 SLOGD("+--------------------------------------------------------+\n");
76 SLOGD("| Checkpoint |\n");
77 SLOGD("+--------------------------------------------------------+\n");
79 D_DISP_u64(cp, checkpoint_ver);
80 D_DISP_u64(cp, user_block_count);
81 D_DISP_u64(cp, valid_block_count);
82 D_DISP_u32(cp, rsvd_segment_count);
83 D_DISP_u32(cp, overprov_segment_count);
84 D_DISP_u32(cp, free_segment_count);
86 D_DISP_u32(cp, alloc_type[CURSEG_HOT_NODE]);
87 D_DISP_u32(cp, alloc_type[CURSEG_WARM_NODE]);
88 D_DISP_u32(cp, alloc_type[CURSEG_COLD_NODE]);
89 D_DISP_u32(cp, cur_node_segno[0]);
90 D_DISP_u32(cp, cur_node_segno[1]);
91 D_DISP_u32(cp, cur_node_segno[2]);
93 D_DISP_u32(cp, cur_node_blkoff[0]);
94 D_DISP_u32(cp, cur_node_blkoff[1]);
95 D_DISP_u32(cp, cur_node_blkoff[2]);
98 D_DISP_u32(cp, alloc_type[CURSEG_HOT_DATA]);
99 D_DISP_u32(cp, alloc_type[CURSEG_WARM_DATA]);
100 D_DISP_u32(cp, alloc_type[CURSEG_COLD_DATA]);
101 D_DISP_u32(cp, cur_data_segno[0]);
102 D_DISP_u32(cp, cur_data_segno[1]);
103 D_DISP_u32(cp, cur_data_segno[2]);
105 D_DISP_u32(cp, cur_data_blkoff[0]);
106 D_DISP_u32(cp, cur_data_blkoff[1]);
107 D_DISP_u32(cp, cur_data_blkoff[2]);
109 D_DISP_u32(cp, ckpt_flags);
110 D_DISP_u32(cp, cp_pack_total_block_count);
111 D_DISP_u32(cp, cp_pack_start_sum);
112 D_DISP_u32(cp, valid_node_count);
113 D_DISP_u32(cp, valid_inode_count);
114 D_DISP_u32(cp, next_free_nid);
115 D_DISP_u32(cp, sit_ver_bitmap_bytesize);
116 D_DISP_u32(cp, nat_ver_bitmap_bytesize);
117 D_DISP_u32(cp, checksum_offset);
118 D_DISP_u64(cp, elapsed_time);
120 D_DISP_u32(cp, sit_nat_version_bitmap[0]);
124 static void dbg_print_info_struct(struct f2fs_info *info)
127 SLOGD("+--------------------------------------------------------+\n");
128 SLOGD("| F2FS_INFO |\n");
129 SLOGD("+--------------------------------------------------------+\n");
130 SLOGD("blocks_per_segment: %"PRIu64, info->blocks_per_segment);
131 SLOGD("block_size: %d", info->block_size);
132 SLOGD("sit_bmp loc: %p", info->sit_bmp);
133 SLOGD("sit_bmp_size: %d", info->sit_bmp_size);
134 SLOGD("blocks_per_sit: %"PRIu64, info->blocks_per_sit);
135 SLOGD("sit_blocks loc: %p", info->sit_blocks);
136 SLOGD("sit_sums loc: %p", info->sit_sums);
137 SLOGD("sit_sums num: %d", le16_to_cpu(info->sit_sums->n_sits));
139 for(i = 0; i < (le16_to_cpu(info->sit_sums->n_sits)); i++) {
140 SLOGD("entry %d in journal entries is for segment %d",i, le32_to_cpu(segno_in_journal(info->sit_sums, i)));
143 SLOGD("cp_blkaddr: %"PRIu64, info->cp_blkaddr);
144 SLOGD("cp_valid_cp_blkaddr: %"PRIu64, info->cp_valid_cp_blkaddr);
145 SLOGD("sit_blkaddr: %"PRIu64, info->sit_blkaddr);
146 SLOGD("nat_blkaddr: %"PRIu64, info->nat_blkaddr);
147 SLOGD("ssa_blkaddr: %"PRIu64, info->ssa_blkaddr);
148 SLOGD("main_blkaddr: %"PRIu64, info->main_blkaddr);
149 SLOGD("total_user_used: %"PRIu64, info->total_user_used);
150 SLOGD("total_blocks: %"PRIu64, info->total_blocks);
156 static int read_structure(int fd, unsigned long long start, void *buf, ssize_t len)
160 ret = lseek64(fd, start, SEEK_SET);
162 SLOGE("failed to seek\n");
166 ret = read(fd, buf, len);
168 SLOGE("failed to read\n");
172 SLOGE("failed to read all\n");
178 static int read_structure_blk(int fd, unsigned long long start_blk, void *buf, size_t len)
180 return read_structure(fd, F2FS_BLKSIZE*start_blk, buf, F2FS_BLKSIZE * len);
183 static int read_f2fs_sb(int fd, struct f2fs_super_block *sb)
186 rc = read_structure(fd, F2FS_SUPER_OFFSET, sb, sizeof(*sb));
187 if (le32_to_cpu(sb->magic) != F2FS_SUPER_MAGIC) {
188 SLOGE("Not a valid F2FS super block. Magic:%#08x != %#08x",
189 le32_to_cpu(sb->magic), F2FS_SUPER_MAGIC);
195 unsigned int get_f2fs_filesystem_size_sec(char *dev)
198 if ((fd = open(dev, O_RDONLY)) < 0) {
199 SLOGE("Cannot open device to get filesystem size ");
202 struct f2fs_super_block sb;
203 if(read_f2fs_sb(fd, &sb))
205 return (unsigned int)(le64_to_cpu(sb.block_count)*F2FS_BLKSIZE/DEFAULT_SECTOR_SIZE);
208 static struct f2fs_checkpoint *validate_checkpoint(block_t cp_addr,
209 unsigned long long *version, int fd)
211 unsigned char *cp_block_1, *cp_block_2;
212 struct f2fs_checkpoint *cp_block, *cp_ret;
213 u64 cp1_version = 0, cp2_version = 0;
215 cp_block_1 = malloc(F2FS_BLKSIZE);
219 /* Read the 1st cp block in this CP pack */
220 if (read_structure_blk(fd, cp_addr, cp_block_1, 1))
223 /* get the version number */
224 cp_block = (struct f2fs_checkpoint *)cp_block_1;
226 cp1_version = le64_to_cpu(cp_block->checkpoint_ver);
228 cp_block_2 = malloc(F2FS_BLKSIZE);
232 /* Read the 2nd cp block in this CP pack */
233 cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
234 if (read_structure_blk(fd, cp_addr, cp_block_2, 1)) {
238 cp_block = (struct f2fs_checkpoint *)cp_block_2;
240 cp2_version = le64_to_cpu(cp_block->checkpoint_ver);
242 if (cp2_version == cp1_version) {
243 *version = cp2_version;
245 return (struct f2fs_checkpoint *)cp_block_1;
248 /* There must be something wrong with this checkpoint */
256 int get_valid_checkpoint_info(int fd, struct f2fs_super_block *sb, struct f2fs_checkpoint **cp, struct f2fs_info *info)
258 struct f2fs_checkpoint *cp_block;
260 struct f2fs_checkpoint *cp1, *cp2, *cur_cp;
262 unsigned long blk_size;// = 1<<le32_to_cpu(info->sb->log_blocksize);
263 unsigned long long cp1_version = 0, cp2_version = 0;
264 unsigned long long cp1_start_blk_no;
265 unsigned long long cp2_start_blk_no;
268 blk_size = 1U<<le32_to_cpu(sb->log_blocksize);
271 * Find valid cp by reading both packs and finding most recent one.
273 cp1_start_blk_no = le32_to_cpu(sb->cp_blkaddr);
274 cp1 = validate_checkpoint(cp1_start_blk_no, &cp1_version, fd);
276 /* The second checkpoint pack should start at the next segment */
277 cp2_start_blk_no = cp1_start_blk_no + (1 << le32_to_cpu(sb->log_blocks_per_seg));
278 cp2 = validate_checkpoint(cp2_start_blk_no, &cp2_version, fd);
281 if (ver_after(cp2_version, cp1_version)) {
283 info->cp_valid_cp_blkaddr = cp2_start_blk_no;
287 info->cp_valid_cp_blkaddr = cp1_start_blk_no;
292 info->cp_valid_cp_blkaddr = cp1_start_blk_no;
295 info->cp_valid_cp_blkaddr = cp2_start_blk_no;
305 SLOGE("Valid Checkpoint not found!!");
309 static int gather_sit_info(int fd, struct f2fs_info *info)
311 u64 num_segments = (info->total_blocks - info->main_blkaddr
312 + info->blocks_per_segment - 1) / info->blocks_per_segment;
313 u64 num_sit_blocks = (num_segments + SIT_ENTRY_PER_BLOCK - 1) / SIT_ENTRY_PER_BLOCK;
316 info->sit_blocks = malloc(num_sit_blocks * sizeof(struct f2fs_sit_block));
317 if (!info->sit_blocks)
320 for(sit_block = 0; sit_block<num_sit_blocks; sit_block++) {
321 off64_t address = info->sit_blkaddr + sit_block;
323 if (f2fs_test_bit(sit_block, info->sit_bmp))
324 address += info->blocks_per_sit;
326 SLOGD("Reading cache block starting at block %"PRIu64, address);
327 if (read_structure(fd, address * F2FS_BLKSIZE, &info->sit_blocks[sit_block], sizeof(struct f2fs_sit_block))) {
328 SLOGE("Could not read sit block at block %"PRIu64, address);
329 free(info->sit_blocks);
336 static inline int is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
338 unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
339 return !!(ckpt_flags & f);
342 static inline u64 sum_blk_addr(struct f2fs_checkpoint *cp, struct f2fs_info *info, int base, int type)
344 return info->cp_valid_cp_blkaddr + le32_to_cpu(cp->cp_pack_total_block_count)
348 static int get_sit_summary(int fd, struct f2fs_info *info, struct f2fs_checkpoint *cp)
350 char buffer[F2FS_BLKSIZE];
352 info->sit_sums = calloc(1, sizeof(struct f2fs_summary_block));
356 /* CURSEG_COLD_DATA where the journaled SIT entries are. */
357 if (is_set_ckpt_flags(cp, CP_COMPACT_SUM_FLAG)) {
358 if (read_structure_blk(fd, info->cp_valid_cp_blkaddr + le32_to_cpu(cp->cp_pack_start_sum), buffer, 1))
360 memcpy(&info->sit_sums->n_sits, &buffer[SUM_JOURNAL_SIZE], SUM_JOURNAL_SIZE);
363 if (is_set_ckpt_flags(cp, CP_UMOUNT_FLAG))
364 blk_addr = sum_blk_addr(cp, info, NR_CURSEG_TYPE, CURSEG_COLD_DATA);
366 blk_addr = sum_blk_addr(cp, info, NR_CURSEG_DATA_TYPE, CURSEG_COLD_DATA);
368 if (read_structure_blk(fd, blk_addr, buffer, 1))
371 memcpy(info->sit_sums, buffer, sizeof(struct f2fs_summary_block));
376 struct f2fs_info *generate_f2fs_info(int fd)
378 struct f2fs_super_block *sb = NULL;
379 struct f2fs_checkpoint *cp = NULL;
380 struct f2fs_info *info;
382 info = calloc(1, sizeof(*info));
384 SLOGE("Out of memory!");
388 sb = malloc(sizeof(*sb));
390 SLOGE("Out of memory!");
394 if (read_f2fs_sb(fd, sb)) {
395 SLOGE("Failed to read superblock");
400 dbg_print_raw_sb_info(sb);
402 info->cp_blkaddr = le32_to_cpu(sb->cp_blkaddr);
403 info->sit_blkaddr = le32_to_cpu(sb->sit_blkaddr);
404 info->nat_blkaddr = le32_to_cpu(sb->nat_blkaddr);
405 info->ssa_blkaddr = le32_to_cpu(sb->ssa_blkaddr);
406 info->main_blkaddr = le32_to_cpu(sb->main_blkaddr);
407 info->block_size = F2FS_BLKSIZE;
408 info->total_blocks = sb->block_count;
409 info->blocks_per_sit = (le32_to_cpu(sb->segment_count_sit) >> 1) << le32_to_cpu(sb->log_blocks_per_seg);
410 info->blocks_per_segment = 1U << le32_to_cpu(sb->log_blocks_per_seg);
412 if (get_valid_checkpoint_info(fd, sb, &cp, info))
414 dbg_print_raw_ckpt_struct(cp);
416 info->total_user_used = le32_to_cpu(cp->valid_block_count);
418 u32 bmp_size = le32_to_cpu(cp->sit_ver_bitmap_bytesize);
420 /* get sit validity bitmap */
421 info->sit_bmp = malloc(bmp_size);
423 SLOGE("Out of memory!");
427 info->sit_bmp_size = bmp_size;
428 if (read_structure(fd, info->cp_valid_cp_blkaddr * F2FS_BLKSIZE
429 + offsetof(struct f2fs_checkpoint, sit_nat_version_bitmap),
430 info->sit_bmp, bmp_size)) {
431 SLOGE("Error getting SIT validity bitmap");
435 if (gather_sit_info(fd , info)) {
436 SLOGE("Error getting SIT information");
439 if (get_sit_summary(fd, info, cp)) {
440 SLOGE("Error getting SIT entries in summary area");
443 dbg_print_info_struct(info);
448 free_f2fs_info(info);
452 void free_f2fs_info(struct f2fs_info *info)
455 free(info->sit_blocks);
456 info->sit_blocks = NULL;
459 info->sit_bmp = NULL;
461 free(info->sit_sums);
462 info->sit_sums = NULL;
467 u64 get_num_blocks_used(struct f2fs_info *info)
469 return info->main_blkaddr + info->total_user_used;
472 int f2fs_test_bit(unsigned int nr, const char *p)
475 char *addr = (char *)p;
478 mask = 1 << (7 - (nr & 0x07));
479 return (mask & *addr) != 0;
482 int run_on_used_blocks(u64 startblock, struct f2fs_info *info, int (*func)(u64 pos, void *data), void *data) {
483 struct f2fs_sit_block sit_block_cache;
484 struct f2fs_sit_entry * sit_entry;
485 u64 sit_block_num_cur = 0, segnum = 0, block_offset;
487 unsigned int used, found, started = 0, i;
489 for (block=startblock; block<info->total_blocks; block++) {
490 /* TODO: Save only relevant portions of metadata */
491 if (block < info->main_blkaddr) {
492 if (func(block, data)) {
498 segnum = (block - info->main_blkaddr)/info->blocks_per_segment;
500 /* check the SIT entries in the journal */
502 for(i = 0; i < le16_to_cpu(info->sit_sums->n_sits); i++) {
503 if (le32_to_cpu(segno_in_journal(info->sit_sums, i)) == segnum) {
504 sit_entry = &sit_in_journal(info->sit_sums, i);
510 /* get SIT entry from SIT section */
512 sit_block_num_cur = segnum/SIT_ENTRY_PER_BLOCK;
513 sit_entry = &info->sit_blocks[sit_block_num_cur].entries[segnum % SIT_ENTRY_PER_BLOCK];
516 block_offset = (block - info->main_blkaddr) % info->blocks_per_segment;
518 used = f2fs_test_bit(block_offset, (char *)sit_entry->valid_map);
520 if (func(block, data))
535 struct f2fs_info *info;
540 * This is a simple test program. It performs a block to block copy of a
541 * filesystem, replacing blocks identified as unused with 0's.
544 int copy_used(u64 pos, void *data)
546 struct privdata *d = data;
548 int pdone = (pos*100)/d->info->total_blocks;
549 if (pdone > d->done) {
551 printf("Done with %d percent\n", d->done);
556 if(read_structure_blk(d->infd, (unsigned long long)pos, d->buf, 1)) {
557 printf("Error reading!!!\n");
562 ret = lseek64(d->outfd, pos*F2FS_BLKSIZE, SEEK_SET);
564 SLOGE("failed to seek\n");
568 ret = write(d->outfd, d->buf, F2FS_BLKSIZE);
570 SLOGE("failed to write\n");
573 if (ret != F2FS_BLKSIZE) {
574 SLOGE("failed to read all\n");
580 int main(int argc, char **argv)
583 printf("Usage: %s fs_file_in fs_file_out\n", argv[0]);
588 if ((infd = open(in, O_RDONLY)) < 0) {
589 SLOGE("Cannot open device");
592 if ((outfd = open(out, O_WRONLY|O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
593 SLOGE("Cannot open output");
601 struct f2fs_info *info = generate_f2fs_info(infd);
603 printf("Failed to generate info!");
606 char *buf = malloc(F2FS_BLKSIZE);
607 char *zbuf = calloc(1, F2FS_BLKSIZE);
612 int expected_count = get_num_blocks_used(info);
613 run_on_used_blocks(0, info, ©_used, &d);
614 printf("Copied %d blocks. Expected to copy %d\n", d.count, expected_count);
615 ftruncate64(outfd, info->total_blocks * F2FS_BLKSIZE);
616 free_f2fs_info(info);