OSDN Git Service

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