f2fs_sparseblock.c revision b63632828014d3bdac0d689591532fe78bc81bc7
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
26#define segno_in_journal(sum, i)    (sum->sit_j.entries[i].segno)
27
28#define sit_in_journal(sum, i)      (sum->sit_j.entries[i].se)
29
30static void dbg_print_raw_sb_info(struct f2fs_super_block *sb)
31{
32    SLOGD("\n");
33    SLOGD("+--------------------------------------------------------+\n");
34    SLOGD("| Super block                                            |\n");
35    SLOGD("+--------------------------------------------------------+\n");
36
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);
42
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);
49
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);
55
56    D_DISP_u32(sb, segment_count_ssa);
57    D_DISP_u32(sb, segment_count_main);
58    D_DISP_u32(sb, segment0_blkaddr);
59
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);
65
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);
70    SLOGD("\n");
71}
72static void dbg_print_raw_ckpt_struct(struct f2fs_checkpoint *cp)
73{
74    SLOGD("\n");
75    SLOGD("+--------------------------------------------------------+\n");
76    SLOGD("| Checkpoint                                             |\n");
77    SLOGD("+--------------------------------------------------------+\n");
78
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);
85
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]);
92
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]);
96
97
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]);
104
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]);
108
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);
119
120    D_DISP_u32(cp, sit_nat_version_bitmap[0]);
121    SLOGD("\n\n");
122}
123
124static void dbg_print_info_struct(struct f2fs_info *info)
125{
126    SLOGD("\n");
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));
138    unsigned int i;
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)));
141    }
142
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);
151    SLOGD("\n\n");
152}
153
154
155/* read blocks */
156static int read_structure(int fd, unsigned long long start, void *buf, ssize_t len)
157{
158    off64_t ret;
159
160    ret = lseek64(fd, start, SEEK_SET);
161    if (ret < 0) {
162        SLOGE("failed to seek\n");
163        return ret;
164    }
165
166    ret = read(fd, buf, len);
167    if (ret < 0) {
168        SLOGE("failed to read\n");
169        return ret;
170    }
171    if (ret != len) {
172        SLOGE("failed to read all\n");
173        return -1;
174    }
175    return 0;
176}
177
178static int read_structure_blk(int fd, unsigned long long start_blk, void *buf, size_t len)
179{
180    return read_structure(fd, F2FS_BLKSIZE*start_blk, buf, F2FS_BLKSIZE * len);
181}
182
183static int read_f2fs_sb(int fd, struct f2fs_super_block *sb)
184{
185    int rc;
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);
190        return -1;
191    }
192    return 0;
193}
194
195unsigned int get_f2fs_filesystem_size_sec(char *dev)
196{
197    int fd;
198    if ((fd = open(dev, O_RDONLY)) < 0) {
199        SLOGE("Cannot open device to get filesystem size ");
200        return 0;
201    }
202    struct f2fs_super_block sb;
203    if(read_f2fs_sb(fd, &sb))
204        return 0;
205    return (unsigned int)(le64_to_cpu(sb.block_count)*F2FS_BLKSIZE/DEFAULT_SECTOR_SIZE);
206}
207
208static struct f2fs_checkpoint *validate_checkpoint(block_t cp_addr,
209                                                   unsigned long long *version, int fd)
210{
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;
214
215    cp_block_1 = malloc(F2FS_BLKSIZE);
216    if (!cp_block_1)
217        return NULL;
218
219    /* Read the 1st cp block in this CP pack */
220    if (read_structure_blk(fd, cp_addr, cp_block_1, 1))
221        goto invalid_cp1;
222
223    /* get the version number */
224    cp_block = (struct f2fs_checkpoint *)cp_block_1;
225
226    cp1_version = le64_to_cpu(cp_block->checkpoint_ver);
227
228    cp_block_2 = malloc(F2FS_BLKSIZE);
229    if (!cp_block_2) {
230        goto invalid_cp1;
231    }
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)) {
235        goto invalid_cp2;
236    }
237
238    cp_block = (struct f2fs_checkpoint *)cp_block_2;
239
240    cp2_version = le64_to_cpu(cp_block->checkpoint_ver);
241
242    if (cp2_version == cp1_version) {
243        *version = cp2_version;
244        free(cp_block_2);
245        return (struct f2fs_checkpoint *)cp_block_1;
246    }
247
248    /* There must be something wrong with this checkpoint */
249invalid_cp2:
250    free(cp_block_2);
251invalid_cp1:
252    free(cp_block_1);
253    return NULL;
254}
255
256int get_valid_checkpoint_info(int fd, struct f2fs_super_block *sb, struct f2fs_checkpoint **cp,  struct f2fs_info *info)
257{
258    struct f2fs_checkpoint *cp_block;
259
260    struct f2fs_checkpoint *cp1, *cp2, *cur_cp;
261    int cur_cp_no;
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;
266    u32 bmp_size;
267
268    blk_size = 1U<<le32_to_cpu(sb->log_blocksize);
269
270    /*
271     * Find valid cp by reading both packs and finding most recent one.
272     */
273    cp1_start_blk_no = le32_to_cpu(sb->cp_blkaddr);
274    cp1 = validate_checkpoint(cp1_start_blk_no, &cp1_version, fd);
275
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);
279
280    if (cp1 && cp2) {
281        if (ver_after(cp2_version, cp1_version)) {
282            cur_cp = cp2;
283            info->cp_valid_cp_blkaddr = cp2_start_blk_no;
284            free(cp1);
285        } else {
286            cur_cp = cp1;
287            info->cp_valid_cp_blkaddr = cp1_start_blk_no;
288            free(cp2);
289        }
290    } else if (cp1) {
291        cur_cp = cp1;
292        info->cp_valid_cp_blkaddr = cp1_start_blk_no;
293    } else if (cp2) {
294        cur_cp = cp2;
295        info->cp_valid_cp_blkaddr = cp2_start_blk_no;
296    } else {
297        goto fail_no_cp;
298    }
299
300    *cp = cur_cp;
301
302    return 0;
303
304fail_no_cp:
305    SLOGE("Valid Checkpoint not found!!");
306    return -EINVAL;
307}
308
309static int gather_sit_info(int fd, struct f2fs_info *info)
310{
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;
314    u64 sit_block;
315
316    info->sit_blocks = malloc(num_sit_blocks * sizeof(struct f2fs_sit_block));
317    if (!info->sit_blocks)
318        return -1;
319
320    for(sit_block = 0; sit_block<num_sit_blocks; sit_block++) {
321        off64_t address = info->sit_blkaddr + sit_block;
322
323        if (f2fs_test_bit(sit_block, info->sit_bmp))
324            address += info->blocks_per_sit;
325
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);
330            return -1;
331        }
332    }
333    return 0;
334}
335
336static inline int is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
337{
338    unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
339    return !!(ckpt_flags & f);
340}
341
342static inline u64 sum_blk_addr(struct f2fs_checkpoint *cp, struct f2fs_info *info, int base, int type)
343{
344    return info->cp_valid_cp_blkaddr + le32_to_cpu(cp->cp_pack_total_block_count)
345                - (base + 1) + type;
346}
347
348static int get_sit_summary(int fd, struct f2fs_info *info, struct f2fs_checkpoint *cp)
349{
350    char buffer[F2FS_BLKSIZE];
351
352    info->sit_sums = calloc(1, sizeof(struct f2fs_summary_block));
353    if (!info->sit_sums)
354        return -1;
355
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))
359            return -1;
360        memcpy(&info->sit_sums->n_sits, &buffer[SUM_JOURNAL_SIZE], SUM_JOURNAL_SIZE);
361    } else {
362        u64 blk_addr;
363        if (is_set_ckpt_flags(cp, CP_UMOUNT_FLAG))
364            blk_addr = sum_blk_addr(cp, info, NR_CURSEG_TYPE, CURSEG_COLD_DATA);
365        else
366            blk_addr = sum_blk_addr(cp, info, NR_CURSEG_DATA_TYPE, CURSEG_COLD_DATA);
367
368        if (read_structure_blk(fd, blk_addr, buffer, 1))
369            return -1;
370
371        memcpy(info->sit_sums, buffer, sizeof(struct f2fs_summary_block));
372    }
373    return 0;
374}
375
376struct f2fs_info *generate_f2fs_info(int fd)
377{
378    struct f2fs_super_block *sb = NULL;
379    struct f2fs_checkpoint *cp = NULL;
380    struct f2fs_info *info;
381
382    info = calloc(1, sizeof(*info));
383    if (!info) {
384        SLOGE("Out of memory!");
385        return NULL;
386    }
387
388    sb = malloc(sizeof(*sb));
389    if(!sb) {
390        SLOGE("Out of memory!");
391        free(info);
392        return NULL;
393    }
394    if (read_f2fs_sb(fd, sb)) {
395        SLOGE("Failed to read superblock");
396        free(info);
397        free(sb);
398        return NULL;
399    }
400    dbg_print_raw_sb_info(sb);
401
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);
411
412    if (get_valid_checkpoint_info(fd, sb, &cp, info))
413        goto error;
414    dbg_print_raw_ckpt_struct(cp);
415
416    info->total_user_used = le32_to_cpu(cp->valid_block_count);
417
418    u32 bmp_size = le32_to_cpu(cp->sit_ver_bitmap_bytesize);
419
420    /* get sit validity bitmap */
421    info->sit_bmp = malloc(bmp_size);
422    if(!info->sit_bmp) {
423        SLOGE("Out of memory!");
424        goto error;
425    }
426
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");
432        goto error;
433    }
434
435    if (gather_sit_info(fd , info)) {
436        SLOGE("Error getting SIT information");
437        goto error;
438    }
439    if (get_sit_summary(fd, info, cp)) {
440        SLOGE("Error getting SIT entries in summary area");
441        goto error;
442    }
443    dbg_print_info_struct(info);
444    return info;
445error:
446    free(sb);
447    free(cp);
448    free_f2fs_info(info);
449    return NULL;
450}
451
452void free_f2fs_info(struct f2fs_info *info)
453{
454    if (info) {
455        free(info->sit_blocks);
456        info->sit_blocks = NULL;
457
458        free(info->sit_bmp);
459        info->sit_bmp = NULL;
460
461        free(info->sit_sums);
462        info->sit_sums = NULL;
463    }
464    free(info);
465}
466
467u64 get_num_blocks_used(struct f2fs_info *info)
468{
469    return info->main_blkaddr + info->total_user_used;
470}
471
472int f2fs_test_bit(unsigned int nr, const char *p)
473{
474    int mask;
475    char *addr = (char *)p;
476
477    addr += (nr >> 3);
478    mask = 1 << (7 - (nr & 0x07));
479    return (mask & *addr) != 0;
480}
481
482int 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;
486    u64 block;
487    unsigned int used, found, started = 0, i;
488
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)) {
493                SLOGI("func error");
494                return -1;
495            }
496        } else {
497            /* Main Section */
498            segnum = (block - info->main_blkaddr)/info->blocks_per_segment;
499
500            /* check the SIT entries in the journal */
501            found = 0;
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);
505                    found = 1;
506                    break;
507                }
508            }
509
510            /* get SIT entry from SIT section */
511            if (!found) {
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];
514            }
515
516            block_offset = (block - info->main_blkaddr) % info->blocks_per_segment;
517
518            used = f2fs_test_bit(block_offset, (char *)sit_entry->valid_map);
519            if(used)
520                if (func(block, data))
521                    return -1;
522        }
523    }
524    return 0;
525}
526
527struct privdata
528{
529    int count;
530    int infd;
531    int outfd;
532    char* buf;
533    char *zbuf;
534    int done;
535    struct f2fs_info *info;
536};
537
538
539/*
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.
542 */
543
544int copy_used(u64 pos, void *data)
545{
546    struct privdata *d = data;
547    char *buf;
548    int pdone = (pos*100)/d->info->total_blocks;
549    if (pdone > d->done) {
550        d->done = pdone;
551        printf("Done with %d percent\n", d->done);
552    }
553
554    d->count++;
555    buf = d->buf;
556    if(read_structure_blk(d->infd, (unsigned long long)pos, d->buf, 1)) {
557        printf("Error reading!!!\n");
558        return -1;
559    }
560
561    off64_t ret;
562    ret = lseek64(d->outfd, pos*F2FS_BLKSIZE, SEEK_SET);
563    if (ret < 0) {
564        SLOGE("failed to seek\n");
565        return ret;
566    }
567
568    ret = write(d->outfd, d->buf, F2FS_BLKSIZE);
569    if (ret < 0) {
570        SLOGE("failed to write\n");
571        return ret;
572    }
573    if (ret != F2FS_BLKSIZE) {
574        SLOGE("failed to read all\n");
575        return -1;
576    }
577    return 0;
578}
579
580int main(int argc, char **argv)
581{
582    if (argc != 3)
583        printf("Usage: %s fs_file_in fs_file_out\n", argv[0]);
584    char *in = argv[1];
585    char *out = argv[2];
586    int infd, outfd;
587
588    if ((infd = open(in, O_RDONLY)) < 0) {
589        SLOGE("Cannot open device");
590        return 0;
591    }
592    if ((outfd = open(out, O_WRONLY|O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
593        SLOGE("Cannot open output");
594        return 0;
595    }
596
597    struct privdata d;
598    d.infd = infd;
599    d.outfd = outfd;
600    d.count = 0;
601    struct f2fs_info *info = generate_f2fs_info(infd);
602    if (!info) {
603        printf("Failed to generate info!");
604        return -1;
605    }
606    char *buf = malloc(F2FS_BLKSIZE);
607    char *zbuf = calloc(1, F2FS_BLKSIZE);
608    d.buf = buf;
609    d.zbuf = zbuf;
610    d.done = 0;
611    d.info = info;
612    int expected_count = get_num_blocks_used(info);
613    run_on_used_blocks(0, info, &copy_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);
617    free(buf);
618    free(zbuf);
619    close(infd);
620    close(outfd);
621    return 0;
622}
623