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, &copy_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