Changman Lee | 7f35b54 | 2013-07-04 17:11:32 +0900 | [diff] [blame^] | 1 | /** |
| 2 | * mount.c |
| 3 | * |
| 4 | * Copyright (c) 2013 Samsung Electronics Co., Ltd. |
| 5 | * http://www.samsung.com/ |
| 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License version 2 as |
| 9 | * published by the Free Software Foundation. |
| 10 | */ |
| 11 | #include "fsck.h" |
| 12 | |
| 13 | void print_inode_info(struct f2fs_inode *inode) |
| 14 | { |
| 15 | int i = 0; |
| 16 | int namelen = le32_to_cpu(inode->i_namelen); |
| 17 | |
| 18 | DISP_u32(inode, i_mode); |
| 19 | DISP_u32(inode, i_uid); |
| 20 | DISP_u32(inode, i_gid); |
| 21 | DISP_u32(inode, i_links); |
| 22 | DISP_u64(inode, i_size); |
| 23 | DISP_u64(inode, i_blocks); |
| 24 | |
| 25 | DISP_u64(inode, i_atime); |
| 26 | DISP_u32(inode, i_atime_nsec); |
| 27 | DISP_u64(inode, i_ctime); |
| 28 | DISP_u32(inode, i_ctime_nsec); |
| 29 | DISP_u64(inode, i_mtime); |
| 30 | DISP_u32(inode, i_mtime_nsec); |
| 31 | |
| 32 | DISP_u32(inode, i_generation); |
| 33 | DISP_u32(inode, i_current_depth); |
| 34 | DISP_u32(inode, i_xattr_nid); |
| 35 | DISP_u32(inode, i_flags); |
| 36 | DISP_u32(inode, i_pino); |
| 37 | |
| 38 | if (namelen) { |
| 39 | DISP_u32(inode, i_namelen); |
| 40 | inode->i_name[namelen] = '\0'; |
| 41 | DISP_utf(inode, i_name); |
| 42 | } |
| 43 | |
| 44 | printf("i_ext: fofs:%x blkaddr:%x len:%x\n", |
| 45 | inode->i_ext.fofs, |
| 46 | inode->i_ext.blk_addr, |
| 47 | inode->i_ext.len); |
| 48 | |
| 49 | DISP_u32(inode, i_addr[0]); /* Pointers to data blocks */ |
| 50 | DISP_u32(inode, i_addr[1]); /* Pointers to data blocks */ |
| 51 | DISP_u32(inode, i_addr[2]); /* Pointers to data blocks */ |
| 52 | DISP_u32(inode, i_addr[3]); /* Pointers to data blocks */ |
| 53 | |
| 54 | for (i = 4; i < ADDRS_PER_INODE; i++) { |
| 55 | if (inode->i_addr[i] != 0x0) { |
| 56 | printf("i_addr[0x%x] points data block\r\t\t\t\t[0x%4x]\n", |
| 57 | i, inode->i_addr[i]); |
| 58 | break; |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | DISP_u32(inode, i_nid[0]); /* direct */ |
| 63 | DISP_u32(inode, i_nid[1]); /* direct */ |
| 64 | DISP_u32(inode, i_nid[2]); /* indirect */ |
| 65 | DISP_u32(inode, i_nid[3]); /* indirect */ |
| 66 | DISP_u32(inode, i_nid[4]); /* double indirect */ |
| 67 | |
| 68 | printf("\n"); |
| 69 | } |
| 70 | |
| 71 | void print_node_info(struct f2fs_node *node_block) |
| 72 | { |
| 73 | nid_t ino = le32_to_cpu(node_block->footer.ino); |
| 74 | nid_t nid = le32_to_cpu(node_block->footer.nid); |
| 75 | /* Is this inode? */ |
| 76 | if (ino == nid) { |
| 77 | DBG(0, "Node ID [0x%x:%u] is inode\n", nid, nid); |
| 78 | print_inode_info(&node_block->i); |
| 79 | } else { |
| 80 | DBG(0, "Node ID [0x%x:%u] is direct node or indirect node.\n", nid, nid); |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | void print_raw_sb_info(struct f2fs_sb_info *sbi) |
| 85 | { |
| 86 | struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); |
| 87 | printf("\n"); |
| 88 | printf("+--------------------------------------------------------+\n"); |
| 89 | printf("| Super block |\n"); |
| 90 | printf("+--------------------------------------------------------+\n"); |
| 91 | |
| 92 | DISP_u32(sb, magic); |
| 93 | DISP_u32(sb, major_ver); |
| 94 | DISP_u32(sb, minor_ver); |
| 95 | DISP_u32(sb, log_sectorsize); |
| 96 | DISP_u32(sb, log_sectors_per_block); |
| 97 | |
| 98 | DISP_u32(sb, log_blocksize); |
| 99 | DISP_u32(sb, log_blocks_per_seg); |
| 100 | DISP_u32(sb, segs_per_sec); |
| 101 | DISP_u32(sb, secs_per_zone); |
| 102 | DISP_u32(sb, checksum_offset); |
| 103 | DISP_u64(sb, block_count); |
| 104 | |
| 105 | DISP_u32(sb, section_count); |
| 106 | DISP_u32(sb, segment_count); |
| 107 | DISP_u32(sb, segment_count_ckpt); |
| 108 | DISP_u32(sb, segment_count_sit); |
| 109 | DISP_u32(sb, segment_count_nat); |
| 110 | |
| 111 | DISP_u32(sb, segment_count_ssa); |
| 112 | DISP_u32(sb, segment_count_main); |
| 113 | DISP_u32(sb, segment0_blkaddr); |
| 114 | |
| 115 | DISP_u32(sb, cp_blkaddr); |
| 116 | DISP_u32(sb, sit_blkaddr); |
| 117 | DISP_u32(sb, nat_blkaddr); |
| 118 | DISP_u32(sb, ssa_blkaddr); |
| 119 | DISP_u32(sb, main_blkaddr); |
| 120 | |
| 121 | DISP_u32(sb, root_ino); |
| 122 | DISP_u32(sb, node_ino); |
| 123 | DISP_u32(sb, meta_ino); |
| 124 | printf("\n"); |
| 125 | } |
| 126 | |
| 127 | void print_ckpt_info(struct f2fs_sb_info *sbi) |
| 128 | { |
| 129 | struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); |
| 130 | |
| 131 | printf("\n"); |
| 132 | printf("+--------------------------------------------------------+\n"); |
| 133 | printf("| Checkpoint |\n"); |
| 134 | printf("+--------------------------------------------------------+\n"); |
| 135 | |
| 136 | DISP_u64(cp, checkpoint_ver); |
| 137 | DISP_u64(cp, user_block_count); |
| 138 | DISP_u64(cp, valid_block_count); |
| 139 | DISP_u32(cp, rsvd_segment_count); |
| 140 | DISP_u32(cp, overprov_segment_count); |
| 141 | DISP_u32(cp, free_segment_count); |
| 142 | |
| 143 | DISP_u32(cp, alloc_type[CURSEG_HOT_NODE]); |
| 144 | DISP_u32(cp, alloc_type[CURSEG_WARM_NODE]); |
| 145 | DISP_u32(cp, alloc_type[CURSEG_COLD_NODE]); |
| 146 | DISP_u32(cp, cur_node_segno[0]); |
| 147 | DISP_u32(cp, cur_node_segno[1]); |
| 148 | DISP_u32(cp, cur_node_segno[2]); |
| 149 | |
| 150 | DISP_u32(cp, cur_node_blkoff[0]); |
| 151 | DISP_u32(cp, cur_node_blkoff[1]); |
| 152 | DISP_u32(cp, cur_node_blkoff[2]); |
| 153 | |
| 154 | |
| 155 | DISP_u32(cp, alloc_type[CURSEG_HOT_DATA]); |
| 156 | DISP_u32(cp, alloc_type[CURSEG_WARM_DATA]); |
| 157 | DISP_u32(cp, alloc_type[CURSEG_COLD_DATA]); |
| 158 | DISP_u32(cp, cur_data_segno[0]); |
| 159 | DISP_u32(cp, cur_data_segno[1]); |
| 160 | DISP_u32(cp, cur_data_segno[2]); |
| 161 | |
| 162 | DISP_u32(cp, cur_data_blkoff[0]); |
| 163 | DISP_u32(cp, cur_data_blkoff[1]); |
| 164 | DISP_u32(cp, cur_data_blkoff[2]); |
| 165 | |
| 166 | DISP_u32(cp, ckpt_flags); |
| 167 | DISP_u32(cp, cp_pack_total_block_count); |
| 168 | DISP_u32(cp, cp_pack_start_sum); |
| 169 | DISP_u32(cp, valid_node_count); |
| 170 | DISP_u32(cp, valid_inode_count); |
| 171 | DISP_u32(cp, next_free_nid); |
| 172 | DISP_u32(cp, sit_ver_bitmap_bytesize); |
| 173 | DISP_u32(cp, nat_ver_bitmap_bytesize); |
| 174 | DISP_u32(cp, checksum_offset); |
| 175 | DISP_u64(cp, elapsed_time); |
| 176 | |
| 177 | DISP_u32(cp, sit_nat_version_bitmap[0]); |
| 178 | printf("\n\n"); |
| 179 | } |
| 180 | |
| 181 | int sanity_check_raw_super(struct f2fs_super_block *raw_super) |
| 182 | { |
| 183 | unsigned int blocksize; |
| 184 | |
| 185 | if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) { |
| 186 | return -1; |
| 187 | } |
| 188 | |
| 189 | if (F2FS_BLKSIZE != PAGE_CACHE_SIZE) { |
| 190 | return -1; |
| 191 | } |
| 192 | |
| 193 | blocksize = 1 << le32_to_cpu(raw_super->log_blocksize); |
| 194 | if (F2FS_BLKSIZE != blocksize) { |
| 195 | return -1; |
| 196 | } |
| 197 | |
| 198 | if (F2FS_LOG_SECTOR_SIZE != le32_to_cpu(raw_super->log_sectorsize)) { |
| 199 | return -1; |
| 200 | } |
| 201 | |
| 202 | if (F2FS_LOG_SECTORS_PER_BLOCK != le32_to_cpu(raw_super->log_sectors_per_block)) { |
| 203 | return -1; |
| 204 | } |
| 205 | |
| 206 | return 0; |
| 207 | } |
| 208 | |
| 209 | int validate_super_block(struct f2fs_sb_info *sbi, int block) |
| 210 | { |
| 211 | u64 offset = (block + 1) * F2FS_SUPER_OFFSET; |
| 212 | sbi->raw_super = malloc(sizeof(struct f2fs_super_block)); |
| 213 | |
| 214 | if (dev_read(sbi->raw_super, offset, sizeof(struct f2fs_super_block))) |
| 215 | return -1; |
| 216 | |
| 217 | if (!sanity_check_raw_super(sbi->raw_super)) |
| 218 | return 0; |
| 219 | |
| 220 | free(sbi->raw_super); |
| 221 | MSG(0, "\tCan't find a valid F2FS filesystem in %d superblock\n", block); |
| 222 | |
| 223 | return -EINVAL; |
| 224 | } |
| 225 | |
| 226 | int init_sb_info(struct f2fs_sb_info *sbi) |
| 227 | { |
| 228 | struct f2fs_super_block *raw_super = sbi->raw_super; |
| 229 | |
| 230 | sbi->log_sectors_per_block = |
| 231 | le32_to_cpu(raw_super->log_sectors_per_block); |
| 232 | sbi->log_blocksize = le32_to_cpu(raw_super->log_blocksize); |
| 233 | sbi->blocksize = 1 << sbi->log_blocksize; |
| 234 | sbi->log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); |
| 235 | sbi->blocks_per_seg = 1 << sbi->log_blocks_per_seg; |
| 236 | sbi->segs_per_sec = le32_to_cpu(raw_super->segs_per_sec); |
| 237 | sbi->secs_per_zone = le32_to_cpu(raw_super->secs_per_zone); |
| 238 | sbi->total_sections = le32_to_cpu(raw_super->section_count); |
| 239 | sbi->total_node_count = |
| 240 | (le32_to_cpu(raw_super->segment_count_nat) / 2) |
| 241 | * sbi->blocks_per_seg * NAT_ENTRY_PER_BLOCK; |
| 242 | sbi->root_ino_num = le32_to_cpu(raw_super->root_ino); |
| 243 | sbi->node_ino_num = le32_to_cpu(raw_super->node_ino); |
| 244 | sbi->meta_ino_num = le32_to_cpu(raw_super->meta_ino); |
| 245 | sbi->cur_victim_sec = NULL_SEGNO; |
| 246 | return 0; |
| 247 | } |
| 248 | |
| 249 | void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr, unsigned long long *version) |
| 250 | { |
| 251 | void *cp_page_1, *cp_page_2; |
| 252 | struct f2fs_checkpoint *cp_block; |
| 253 | unsigned long blk_size = sbi->blocksize; |
| 254 | unsigned long long cur_version = 0, pre_version = 0; |
| 255 | unsigned int crc = 0; |
| 256 | size_t crc_offset; |
| 257 | |
| 258 | /* Read the 1st cp block in this CP pack */ |
| 259 | cp_page_1 = malloc(PAGE_SIZE); |
| 260 | if (dev_read_block(cp_page_1, cp_addr) < 0) |
| 261 | return NULL; |
| 262 | |
| 263 | cp_block = (struct f2fs_checkpoint *)cp_page_1; |
| 264 | crc_offset = le32_to_cpu(cp_block->checksum_offset); |
| 265 | if (crc_offset >= blk_size) |
| 266 | goto invalid_cp1; |
| 267 | |
| 268 | crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset); |
| 269 | if (f2fs_crc_valid(crc, cp_block, crc_offset)) |
| 270 | goto invalid_cp1; |
| 271 | |
| 272 | pre_version = le64_to_cpu(cp_block->checkpoint_ver); |
| 273 | |
| 274 | /* Read the 2nd cp block in this CP pack */ |
| 275 | cp_page_2 = malloc(PAGE_SIZE); |
| 276 | cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1; |
| 277 | if (dev_read_block(cp_page_2, cp_addr) < 0) |
| 278 | goto invalid_cp2; |
| 279 | |
| 280 | cp_block = (struct f2fs_checkpoint *)cp_page_2; |
| 281 | crc_offset = le32_to_cpu(cp_block->checksum_offset); |
| 282 | if (crc_offset >= blk_size) |
| 283 | goto invalid_cp2; |
| 284 | |
| 285 | crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset); |
| 286 | if (f2fs_crc_valid(crc, cp_block, crc_offset)) |
| 287 | goto invalid_cp1; |
| 288 | |
| 289 | cur_version = le64_to_cpu(cp_block->checkpoint_ver); |
| 290 | |
| 291 | if (cur_version == pre_version) { |
| 292 | *version = cur_version; |
| 293 | free(cp_page_2); |
| 294 | return cp_page_1; |
| 295 | } |
| 296 | |
| 297 | invalid_cp2: |
| 298 | free(cp_page_2); |
| 299 | invalid_cp1: |
| 300 | free(cp_page_1); |
| 301 | return NULL; |
| 302 | } |
| 303 | |
| 304 | int get_valid_checkpoint(struct f2fs_sb_info *sbi) |
| 305 | { |
| 306 | struct f2fs_super_block *raw_sb = sbi->raw_super; |
| 307 | void *cp1, *cp2, *cur_page; |
| 308 | unsigned long blk_size = sbi->blocksize; |
| 309 | unsigned long long cp1_version = 0, cp2_version = 0; |
| 310 | unsigned long long cp_start_blk_no; |
| 311 | |
| 312 | sbi->ckpt = malloc(blk_size); |
| 313 | if (!sbi->ckpt) |
| 314 | return -ENOMEM; |
| 315 | /* |
| 316 | * Finding out valid cp block involves read both |
| 317 | * sets( cp pack1 and cp pack 2) |
| 318 | */ |
| 319 | cp_start_blk_no = le32_to_cpu(raw_sb->cp_blkaddr); |
| 320 | cp1 = validate_checkpoint(sbi, cp_start_blk_no, &cp1_version); |
| 321 | |
| 322 | /* The second checkpoint pack should start at the next segment */ |
| 323 | cp_start_blk_no += 1 << le32_to_cpu(raw_sb->log_blocks_per_seg); |
| 324 | cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version); |
| 325 | |
| 326 | if (cp1 && cp2) { |
| 327 | if (ver_after(cp2_version, cp1_version)) |
| 328 | cur_page = cp2; |
| 329 | else |
| 330 | cur_page = cp1; |
| 331 | } else if (cp1) { |
| 332 | cur_page = cp1; |
| 333 | } else if (cp2) { |
| 334 | cur_page = cp2; |
| 335 | } else { |
| 336 | free(cp1); |
| 337 | free(cp2); |
| 338 | goto fail_no_cp; |
| 339 | } |
| 340 | |
| 341 | memcpy(sbi->ckpt, cur_page, blk_size); |
| 342 | |
| 343 | free(cp1); |
| 344 | free(cp2); |
| 345 | return 0; |
| 346 | |
| 347 | fail_no_cp: |
| 348 | free(sbi->ckpt); |
| 349 | return -EINVAL; |
| 350 | } |
| 351 | |
| 352 | int sanity_check_ckpt(struct f2fs_sb_info *sbi) |
| 353 | { |
| 354 | unsigned int total, fsmeta; |
| 355 | struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); |
| 356 | struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); |
| 357 | |
| 358 | total = le32_to_cpu(raw_super->segment_count); |
| 359 | fsmeta = le32_to_cpu(raw_super->segment_count_ckpt); |
| 360 | fsmeta += le32_to_cpu(raw_super->segment_count_sit); |
| 361 | fsmeta += le32_to_cpu(raw_super->segment_count_nat); |
| 362 | fsmeta += le32_to_cpu(ckpt->rsvd_segment_count); |
| 363 | fsmeta += le32_to_cpu(raw_super->segment_count_ssa); |
| 364 | |
| 365 | if (fsmeta >= total) |
| 366 | return 1; |
| 367 | |
| 368 | return 0; |
| 369 | } |
| 370 | |
| 371 | int init_node_manager(struct f2fs_sb_info *sbi) |
| 372 | { |
| 373 | struct f2fs_super_block *sb_raw = F2FS_RAW_SUPER(sbi); |
| 374 | struct f2fs_nm_info *nm_i = NM_I(sbi); |
| 375 | unsigned char *version_bitmap; |
| 376 | unsigned int nat_segs, nat_blocks; |
| 377 | |
| 378 | nm_i->nat_blkaddr = le32_to_cpu(sb_raw->nat_blkaddr); |
| 379 | |
| 380 | /* segment_count_nat includes pair segment so divide to 2. */ |
| 381 | nat_segs = le32_to_cpu(sb_raw->segment_count_nat) >> 1; |
| 382 | nat_blocks = nat_segs << le32_to_cpu(sb_raw->log_blocks_per_seg); |
| 383 | nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks; |
| 384 | nm_i->fcnt = 0; |
| 385 | nm_i->nat_cnt = 0; |
| 386 | nm_i->init_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid); |
| 387 | nm_i->next_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid); |
| 388 | |
| 389 | nm_i->bitmap_size = __bitmap_size(sbi, NAT_BITMAP); |
| 390 | |
| 391 | nm_i->nat_bitmap = malloc(nm_i->bitmap_size); |
| 392 | if (!nm_i->nat_bitmap) |
| 393 | return -ENOMEM; |
| 394 | version_bitmap = __bitmap_ptr(sbi, NAT_BITMAP); |
| 395 | if (!version_bitmap) |
| 396 | return -EFAULT; |
| 397 | |
| 398 | /* copy version bitmap */ |
| 399 | memcpy(nm_i->nat_bitmap, version_bitmap, nm_i->bitmap_size); |
| 400 | return 0; |
| 401 | } |
| 402 | |
| 403 | int build_node_manager(struct f2fs_sb_info *sbi) |
| 404 | { |
| 405 | int err; |
| 406 | sbi->nm_info = malloc(sizeof(struct f2fs_nm_info)); |
| 407 | if (!sbi->nm_info) |
| 408 | return -ENOMEM; |
| 409 | |
| 410 | err = init_node_manager(sbi); |
| 411 | if (err) |
| 412 | return err; |
| 413 | |
| 414 | return 0; |
| 415 | } |
| 416 | |
| 417 | int build_sit_info(struct f2fs_sb_info *sbi) |
| 418 | { |
| 419 | struct f2fs_super_block *raw_sb = F2FS_RAW_SUPER(sbi); |
| 420 | struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); |
| 421 | struct sit_info *sit_i; |
| 422 | unsigned int sit_segs, start; |
| 423 | char *src_bitmap, *dst_bitmap; |
| 424 | unsigned int bitmap_size; |
| 425 | |
| 426 | sit_i = malloc(sizeof(struct sit_info)); |
| 427 | if (!sit_i) |
| 428 | return -ENOMEM; |
| 429 | |
| 430 | SM_I(sbi)->sit_info = sit_i; |
| 431 | |
| 432 | sit_i->sentries = calloc(TOTAL_SEGS(sbi) * sizeof(struct seg_entry), 1); |
| 433 | |
| 434 | for (start = 0; start < TOTAL_SEGS(sbi); start++) { |
| 435 | sit_i->sentries[start].cur_valid_map |
| 436 | = calloc(SIT_VBLOCK_MAP_SIZE, 1); |
| 437 | sit_i->sentries[start].ckpt_valid_map |
| 438 | = calloc(SIT_VBLOCK_MAP_SIZE, 1); |
| 439 | if (!sit_i->sentries[start].cur_valid_map |
| 440 | || !sit_i->sentries[start].ckpt_valid_map) |
| 441 | return -ENOMEM; |
| 442 | } |
| 443 | |
| 444 | sit_segs = le32_to_cpu(raw_sb->segment_count_sit) >> 1; |
| 445 | bitmap_size = __bitmap_size(sbi, SIT_BITMAP); |
| 446 | src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP); |
| 447 | |
| 448 | dst_bitmap = malloc(bitmap_size); |
| 449 | memcpy(dst_bitmap, src_bitmap, bitmap_size); |
| 450 | |
| 451 | sit_i->sit_base_addr = le32_to_cpu(raw_sb->sit_blkaddr); |
| 452 | sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg; |
| 453 | sit_i->written_valid_blocks = le64_to_cpu(ckpt->valid_block_count); |
| 454 | sit_i->sit_bitmap = dst_bitmap; |
| 455 | sit_i->bitmap_size = bitmap_size; |
| 456 | sit_i->dirty_sentries = 0; |
| 457 | sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK; |
| 458 | sit_i->elapsed_time = le64_to_cpu(ckpt->elapsed_time); |
| 459 | return 0; |
| 460 | } |
| 461 | |
| 462 | void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) |
| 463 | { |
| 464 | struct curseg_info *curseg = CURSEG_I(sbi, type); |
| 465 | |
| 466 | curseg->segno = curseg->next_segno; |
| 467 | curseg->zone = GET_ZONENO_FROM_SEGNO(sbi, curseg->segno); |
| 468 | curseg->next_blkoff = 0; |
| 469 | curseg->next_segno = NULL_SEGNO; |
| 470 | |
| 471 | } |
| 472 | |
| 473 | int read_compacted_summaries(struct f2fs_sb_info *sbi) |
| 474 | { |
| 475 | struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); |
| 476 | struct curseg_info *curseg; |
| 477 | block_t start; |
| 478 | char *kaddr; |
| 479 | unsigned int i, j, offset; |
| 480 | |
| 481 | start = start_sum_block(sbi); |
| 482 | |
| 483 | kaddr = (char *)malloc(PAGE_SIZE); |
| 484 | dev_read_block(kaddr, start++); |
| 485 | |
| 486 | curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); |
| 487 | memcpy(&curseg->sum_blk->n_nats, kaddr, SUM_JOURNAL_SIZE); |
| 488 | |
| 489 | curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); |
| 490 | memcpy(&curseg->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE); |
| 491 | |
| 492 | offset = 2 * SUM_JOURNAL_SIZE; |
| 493 | for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { |
| 494 | unsigned short blk_off; |
| 495 | unsigned int segno; |
| 496 | |
| 497 | curseg = CURSEG_I(sbi, i); |
| 498 | segno = le32_to_cpu(ckpt->cur_data_segno[i]); |
| 499 | blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]); |
| 500 | curseg->next_segno = segno; |
| 501 | reset_curseg(sbi, i, 0); |
| 502 | curseg->alloc_type = ckpt->alloc_type[i]; |
| 503 | curseg->next_blkoff = blk_off; |
| 504 | |
| 505 | if (curseg->alloc_type == SSR) |
| 506 | blk_off = sbi->blocks_per_seg; |
| 507 | |
| 508 | for (j = 0; j < blk_off; j++) { |
| 509 | struct f2fs_summary *s; |
| 510 | s = (struct f2fs_summary *)(kaddr + offset); |
| 511 | curseg->sum_blk->entries[j] = *s; |
| 512 | offset += SUMMARY_SIZE; |
| 513 | if (offset + SUMMARY_SIZE <= PAGE_CACHE_SIZE - SUM_FOOTER_SIZE) |
| 514 | continue; |
| 515 | memset(kaddr, 0, PAGE_SIZE); |
| 516 | dev_read_block(kaddr, start++); |
| 517 | offset = 0; |
| 518 | } |
| 519 | } |
| 520 | |
| 521 | free(kaddr); |
| 522 | return 0; |
| 523 | } |
| 524 | |
| 525 | int restore_node_summary(struct f2fs_sb_info *sbi, |
| 526 | unsigned int segno, struct f2fs_summary_block *sum_blk) |
| 527 | { |
| 528 | struct f2fs_node *node_blk; |
| 529 | struct f2fs_summary *sum_entry; |
| 530 | void *page; |
| 531 | block_t addr; |
| 532 | int i; |
| 533 | |
| 534 | page = malloc(PAGE_SIZE); |
| 535 | if (!page) |
| 536 | return -ENOMEM; |
| 537 | |
| 538 | /* scan the node segment */ |
| 539 | addr = START_BLOCK(sbi, segno); |
| 540 | sum_entry = &sum_blk->entries[0]; |
| 541 | |
| 542 | for (i = 0; i < sbi->blocks_per_seg; i++, sum_entry++) { |
| 543 | if (dev_read_block(page, addr)) |
| 544 | goto out; |
| 545 | |
| 546 | node_blk = (struct f2fs_node *)page; |
| 547 | sum_entry->nid = node_blk->footer.nid; |
| 548 | /* do not change original value */ |
| 549 | #if 0 |
| 550 | sum_entry->version = 0; |
| 551 | sum_entry->ofs_in_node = 0; |
| 552 | #endif |
| 553 | addr++; |
| 554 | |
| 555 | } |
| 556 | out: |
| 557 | free(page); |
| 558 | return 0; |
| 559 | } |
| 560 | |
| 561 | int read_normal_summaries(struct f2fs_sb_info *sbi, int type) |
| 562 | { |
| 563 | struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); |
| 564 | struct f2fs_summary_block *sum_blk; |
| 565 | struct curseg_info *curseg; |
| 566 | unsigned short blk_off; |
| 567 | unsigned int segno = 0; |
| 568 | block_t blk_addr = 0; |
| 569 | |
| 570 | if (IS_DATASEG(type)) { |
| 571 | segno = le32_to_cpu(ckpt->cur_data_segno[type]); |
| 572 | blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - CURSEG_HOT_DATA]); |
| 573 | |
| 574 | if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) |
| 575 | blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type); |
| 576 | else |
| 577 | blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type); |
| 578 | } else { |
| 579 | segno = le32_to_cpu(ckpt->cur_node_segno[type - CURSEG_HOT_NODE]); |
| 580 | blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type - CURSEG_HOT_NODE]); |
| 581 | |
| 582 | if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) |
| 583 | blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, type - CURSEG_HOT_NODE); |
| 584 | else |
| 585 | blk_addr = GET_SUM_BLKADDR(sbi, segno); |
| 586 | } |
| 587 | |
| 588 | sum_blk = (struct f2fs_summary_block *)malloc(PAGE_SIZE); |
| 589 | dev_read_block(sum_blk, blk_addr); |
| 590 | |
| 591 | if (IS_NODESEG(type)) { |
| 592 | if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) { |
| 593 | struct f2fs_summary *sum_entry = &sum_blk->entries[0]; |
| 594 | int i; |
| 595 | for (i = 0; i < sbi->blocks_per_seg; i++, sum_entry++) { |
| 596 | /* do not change original value */ |
| 597 | #if 0 |
| 598 | sum_entry->version = 0; |
| 599 | sum_entry->ofs_in_node = 0; |
| 600 | #endif |
| 601 | } |
| 602 | } else { |
| 603 | if (restore_node_summary(sbi, segno, sum_blk)) { |
| 604 | free(sum_blk); |
| 605 | return -EINVAL; |
| 606 | } |
| 607 | } |
| 608 | } |
| 609 | |
| 610 | curseg = CURSEG_I(sbi, type); |
| 611 | memcpy(curseg->sum_blk, sum_blk, PAGE_CACHE_SIZE); |
| 612 | curseg->next_segno = segno; |
| 613 | reset_curseg(sbi, type, 0); |
| 614 | curseg->alloc_type = ckpt->alloc_type[type]; |
| 615 | curseg->next_blkoff = blk_off; |
| 616 | free(sum_blk); |
| 617 | |
| 618 | return 0; |
| 619 | } |
| 620 | |
| 621 | int restore_curseg_summaries(struct f2fs_sb_info *sbi) |
| 622 | { |
| 623 | int type = CURSEG_HOT_DATA; |
| 624 | |
| 625 | if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) { |
| 626 | if (read_compacted_summaries(sbi)) |
| 627 | return -EINVAL; |
| 628 | type = CURSEG_HOT_NODE; |
| 629 | } |
| 630 | |
| 631 | for (; type <= CURSEG_COLD_NODE; type++) { |
| 632 | if (read_normal_summaries(sbi, type)) |
| 633 | return -EINVAL; |
| 634 | } |
| 635 | return 0; |
| 636 | } |
| 637 | |
| 638 | int build_curseg(struct f2fs_sb_info *sbi) |
| 639 | { |
| 640 | struct curseg_info *array; |
| 641 | int i; |
| 642 | |
| 643 | array = malloc(sizeof(*array) * NR_CURSEG_TYPE); |
| 644 | |
| 645 | SM_I(sbi)->curseg_array = array; |
| 646 | |
| 647 | for (i = 0; i < NR_CURSEG_TYPE; i++) { |
| 648 | array[i].sum_blk = malloc(PAGE_CACHE_SIZE); |
| 649 | if (!array[i].sum_blk) |
| 650 | return -ENOMEM; |
| 651 | array[i].segno = NULL_SEGNO; |
| 652 | array[i].next_blkoff = 0; |
| 653 | } |
| 654 | return restore_curseg_summaries(sbi); |
| 655 | } |
| 656 | |
| 657 | inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) |
| 658 | { |
| 659 | unsigned int end_segno = SM_I(sbi)->segment_count - 1; |
| 660 | ASSERT(segno <= end_segno); |
| 661 | } |
| 662 | |
| 663 | struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *sbi, unsigned int segno) |
| 664 | { |
| 665 | struct sit_info *sit_i = SIT_I(sbi); |
| 666 | unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno); |
| 667 | block_t blk_addr = sit_i->sit_base_addr + offset; |
| 668 | struct f2fs_sit_block *sit_blk = calloc(BLOCK_SZ, 1); |
| 669 | |
| 670 | check_seg_range(sbi, segno); |
| 671 | |
| 672 | /* calculate sit block address */ |
| 673 | if (f2fs_test_bit(offset, sit_i->sit_bitmap)) |
| 674 | blk_addr += sit_i->sit_blocks; |
| 675 | |
| 676 | dev_read_block(sit_blk, blk_addr); |
| 677 | |
| 678 | return sit_blk; |
| 679 | } |
| 680 | |
| 681 | void check_block_count(struct f2fs_sb_info *sbi, |
| 682 | int segno, struct f2fs_sit_entry *raw_sit) |
| 683 | { |
| 684 | struct f2fs_sm_info *sm_info = SM_I(sbi); |
| 685 | unsigned int end_segno = sm_info->segment_count - 1; |
| 686 | int valid_blocks = 0; |
| 687 | int i; |
| 688 | |
| 689 | /* check segment usage */ |
| 690 | ASSERT(GET_SIT_VBLOCKS(raw_sit) <= sbi->blocks_per_seg); |
| 691 | |
| 692 | /* check boundary of a given segment number */ |
| 693 | ASSERT(segno <= end_segno); |
| 694 | |
| 695 | /* check bitmap with valid block count */ |
| 696 | for (i = 0; i < sbi->blocks_per_seg; i++) |
| 697 | if (f2fs_test_bit(i, (char *)raw_sit->valid_map)) |
| 698 | valid_blocks++; |
| 699 | ASSERT(GET_SIT_VBLOCKS(raw_sit) == valid_blocks); |
| 700 | } |
| 701 | |
| 702 | void seg_info_from_raw_sit(struct seg_entry *se, |
| 703 | struct f2fs_sit_entry *raw_sit) |
| 704 | { |
| 705 | se->valid_blocks = GET_SIT_VBLOCKS(raw_sit); |
| 706 | se->ckpt_valid_blocks = GET_SIT_VBLOCKS(raw_sit); |
| 707 | memcpy(se->cur_valid_map, raw_sit->valid_map, SIT_VBLOCK_MAP_SIZE); |
| 708 | memcpy(se->ckpt_valid_map, raw_sit->valid_map, SIT_VBLOCK_MAP_SIZE); |
| 709 | se->type = GET_SIT_TYPE(raw_sit); |
| 710 | se->mtime = le64_to_cpu(raw_sit->mtime); |
| 711 | } |
| 712 | |
| 713 | struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi, |
| 714 | unsigned int segno) |
| 715 | { |
| 716 | struct sit_info *sit_i = SIT_I(sbi); |
| 717 | return &sit_i->sentries[segno]; |
| 718 | } |
| 719 | |
| 720 | int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summary_block *sum_blk) |
| 721 | { |
| 722 | struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); |
| 723 | struct curseg_info *curseg; |
| 724 | int type, ret; |
| 725 | u64 ssa_blk; |
| 726 | |
| 727 | ssa_blk = GET_SUM_BLKADDR(sbi, segno); |
| 728 | for (type = 0; type < NR_CURSEG_NODE_TYPE; type++) { |
| 729 | if (segno == ckpt->cur_node_segno[type]) { |
| 730 | curseg = CURSEG_I(sbi, type); |
| 731 | memcpy(sum_blk, curseg->sum_blk, BLOCK_SZ); |
| 732 | return SEG_TYPE_CUR_NODE; /* current node seg was not stored */ |
| 733 | } |
| 734 | } |
| 735 | |
| 736 | for (type = 0; type < NR_CURSEG_DATA_TYPE; type++) { |
| 737 | if (segno == ckpt->cur_data_segno[type]) { |
| 738 | curseg = CURSEG_I(sbi, type); |
| 739 | memcpy(sum_blk, curseg->sum_blk, BLOCK_SZ); |
| 740 | ASSERT(!IS_SUM_NODE_SEG(sum_blk->footer)); |
| 741 | DBG(2, "segno [0x%x] is current data seg[0x%x]\n", segno, type); |
| 742 | return SEG_TYPE_CUR_DATA; /* current data seg was not stored */ |
| 743 | } |
| 744 | } |
| 745 | |
| 746 | ret = dev_read_block(sum_blk, ssa_blk); |
| 747 | ASSERT(ret >= 0); |
| 748 | |
| 749 | if (IS_SUM_NODE_SEG(sum_blk->footer)) |
| 750 | return SEG_TYPE_NODE; |
| 751 | else |
| 752 | return SEG_TYPE_DATA; |
| 753 | |
| 754 | } |
| 755 | |
| 756 | int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, struct f2fs_summary *sum_entry) |
| 757 | { |
| 758 | struct f2fs_summary_block *sum_blk; |
| 759 | u32 segno, offset; |
| 760 | int ret; |
| 761 | |
| 762 | segno = GET_SEGNO(sbi, blk_addr); |
| 763 | offset = OFFSET_IN_SEG(sbi, blk_addr); |
| 764 | |
| 765 | sum_blk = calloc(BLOCK_SZ, 1); |
| 766 | |
| 767 | ret = get_sum_block(sbi, segno, sum_blk); |
| 768 | |
| 769 | memcpy(sum_entry, &(sum_blk->entries[offset]), sizeof(struct f2fs_summary)); |
| 770 | |
| 771 | free(sum_blk); |
| 772 | return ret; |
| 773 | } |
| 774 | |
| 775 | int get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, struct f2fs_nat_entry *raw_nat) |
| 776 | { |
| 777 | struct f2fs_fsck *fsck = F2FS_FSCK(sbi); |
| 778 | struct f2fs_nm_info *nm_i = NM_I(sbi); |
| 779 | struct f2fs_nat_block *nat_block; |
| 780 | pgoff_t block_off; |
| 781 | pgoff_t block_addr; |
| 782 | int seg_off, entry_off; |
| 783 | int ret; |
| 784 | |
| 785 | if (nid / NAT_ENTRY_PER_BLOCK > (fsck->nat_area_bitmap_sz * 8)) { |
| 786 | DBG(0, "\n"); |
| 787 | return -EINVAL; |
| 788 | } |
| 789 | |
| 790 | if (lookup_nat_in_journal(sbi, nid, raw_nat) >= 0) |
| 791 | return 0; |
| 792 | |
| 793 | nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1); |
| 794 | |
| 795 | block_off = nid / NAT_ENTRY_PER_BLOCK; |
| 796 | entry_off = nid % NAT_ENTRY_PER_BLOCK; |
| 797 | |
| 798 | seg_off = block_off >> sbi->log_blocks_per_seg; |
| 799 | block_addr = (pgoff_t)(nm_i->nat_blkaddr + |
| 800 | (seg_off << sbi->log_blocks_per_seg << 1) + |
| 801 | (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); |
| 802 | |
| 803 | if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) |
| 804 | block_addr += sbi->blocks_per_seg; |
| 805 | |
| 806 | ret = dev_read_block(nat_block, block_addr); |
| 807 | ASSERT(ret >= 0); |
| 808 | |
| 809 | memcpy(raw_nat, &nat_block->entries[entry_off], sizeof(struct f2fs_nat_entry)); |
| 810 | free(nat_block); |
| 811 | |
| 812 | return 0; |
| 813 | } |
| 814 | |
| 815 | int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) |
| 816 | { |
| 817 | struct f2fs_nat_entry raw_nat; |
| 818 | int ret; |
| 819 | |
| 820 | ret = get_nat_entry(sbi, nid, &raw_nat); |
| 821 | ni->nid = nid; |
| 822 | node_info_from_raw_nat(ni, &raw_nat); |
| 823 | return ret; |
| 824 | } |
| 825 | |
| 826 | void build_sit_entries(struct f2fs_sb_info *sbi) |
| 827 | { |
| 828 | struct sit_info *sit_i = SIT_I(sbi); |
| 829 | struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); |
| 830 | struct f2fs_summary_block *sum = curseg->sum_blk; |
| 831 | unsigned int segno; |
| 832 | |
| 833 | for (segno = 0; segno < TOTAL_SEGS(sbi); segno++) { |
| 834 | struct seg_entry *se = &sit_i->sentries[segno]; |
| 835 | struct f2fs_sit_block *sit_blk; |
| 836 | struct f2fs_sit_entry sit; |
| 837 | int i; |
| 838 | |
| 839 | for (i = 0; i < sits_in_cursum(sum); i++) { |
| 840 | if (le32_to_cpu(segno_in_journal(sum, i)) == segno) { |
| 841 | sit = sit_in_journal(sum, i); |
| 842 | goto got_it; |
| 843 | } |
| 844 | } |
| 845 | sit_blk = get_current_sit_page(sbi, segno); |
| 846 | sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno)]; |
| 847 | free(sit_blk); |
| 848 | got_it: |
| 849 | check_block_count(sbi, segno, &sit); |
| 850 | seg_info_from_raw_sit(se, &sit); |
| 851 | } |
| 852 | |
| 853 | } |
| 854 | |
| 855 | int build_segment_manager(struct f2fs_sb_info *sbi) |
| 856 | { |
| 857 | struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); |
| 858 | struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); |
| 859 | struct f2fs_sm_info *sm_info; |
| 860 | |
| 861 | sm_info = malloc(sizeof(struct f2fs_sm_info)); |
| 862 | if (!sm_info) |
| 863 | return -ENOMEM; |
| 864 | |
| 865 | /* init sm info */ |
| 866 | sbi->sm_info = sm_info; |
| 867 | sm_info->seg0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr); |
| 868 | sm_info->main_blkaddr = le32_to_cpu(raw_super->main_blkaddr); |
| 869 | sm_info->segment_count = le32_to_cpu(raw_super->segment_count); |
| 870 | sm_info->reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count); |
| 871 | sm_info->ovp_segments = le32_to_cpu(ckpt->overprov_segment_count); |
| 872 | sm_info->main_segments = le32_to_cpu(raw_super->segment_count_main); |
| 873 | sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr); |
| 874 | |
| 875 | build_sit_info(sbi); |
| 876 | |
| 877 | build_curseg(sbi); |
| 878 | |
| 879 | build_sit_entries(sbi); |
| 880 | |
| 881 | return 0; |
| 882 | } |
| 883 | |
| 884 | int build_sit_area_bitmap(struct f2fs_sb_info *sbi) |
| 885 | { |
| 886 | struct f2fs_fsck *fsck = F2FS_FSCK(sbi); |
| 887 | struct f2fs_sm_info *sm_i = SM_I(sbi); |
| 888 | int segno = 0, j = 0; |
| 889 | char *ptr = NULL; |
| 890 | |
| 891 | u32 sum_vblocks = 0; |
| 892 | u32 free_segs = 0; |
| 893 | u32 vblocks = 0; |
| 894 | |
| 895 | struct seg_entry *se; |
| 896 | |
| 897 | fsck->sit_area_bitmap_sz = sm_i->main_segments * SIT_VBLOCK_MAP_SIZE; |
| 898 | fsck->sit_area_bitmap = calloc(1, fsck->sit_area_bitmap_sz); |
| 899 | ptr = fsck->sit_area_bitmap; |
| 900 | |
| 901 | ASSERT(fsck->sit_area_bitmap_sz == fsck->main_area_bitmap_sz); |
| 902 | |
| 903 | for (segno = 0; segno < sm_i->main_segments; segno++) { |
| 904 | se = get_seg_entry(sbi, segno); |
| 905 | |
| 906 | memcpy(ptr, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE); |
| 907 | ptr += SIT_VBLOCK_MAP_SIZE; |
| 908 | |
| 909 | vblocks = 0; |
| 910 | for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++) { |
| 911 | vblocks += get_bits_in_byte(se->cur_valid_map[j]); |
| 912 | } |
| 913 | ASSERT(vblocks == se->valid_blocks); |
| 914 | |
| 915 | if (se->valid_blocks == 0x0) { |
| 916 | |
| 917 | if (sbi->ckpt->cur_node_segno[0] == segno || |
| 918 | sbi->ckpt->cur_data_segno[0] == segno || |
| 919 | sbi->ckpt->cur_node_segno[1] == segno || |
| 920 | sbi->ckpt->cur_data_segno[1] == segno || |
| 921 | sbi->ckpt->cur_node_segno[2] == segno || |
| 922 | sbi->ckpt->cur_data_segno[2] == segno) { |
| 923 | continue; |
| 924 | } else { |
| 925 | free_segs++; |
| 926 | } |
| 927 | |
| 928 | } else { |
| 929 | ASSERT(se->valid_blocks <= 512); |
| 930 | sum_vblocks += se->valid_blocks; |
| 931 | } |
| 932 | } |
| 933 | |
| 934 | fsck->chk.sit_valid_blocks = sum_vblocks; |
| 935 | fsck->chk.sit_free_segs = free_segs; |
| 936 | |
| 937 | DBG(0, "Blocks [0x%x] Free Segs [0x%x]\n", sum_vblocks, free_segs); |
| 938 | return 0; |
| 939 | } |
| 940 | |
| 941 | int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_entry *raw_nat) |
| 942 | { |
| 943 | struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); |
| 944 | struct f2fs_summary_block *sum = curseg->sum_blk; |
| 945 | int i = 0; |
| 946 | |
| 947 | for (i = 0; i < nats_in_cursum(sum); i++) { |
| 948 | if (le32_to_cpu(nid_in_journal(sum, i)) == nid) { |
| 949 | memcpy(raw_nat, &nat_in_journal(sum, i), sizeof(struct f2fs_nat_entry)); |
| 950 | DBG(3, "==> Found nid [0x%x] in nat cache\n", nid); |
| 951 | return i; |
| 952 | } |
| 953 | } |
| 954 | return -1; |
| 955 | } |
| 956 | |
| 957 | void build_nat_area_bitmap(struct f2fs_sb_info *sbi) |
| 958 | { |
| 959 | struct f2fs_fsck *fsck = F2FS_FSCK(sbi); |
| 960 | struct f2fs_super_block *raw_sb = F2FS_RAW_SUPER(sbi); |
| 961 | struct f2fs_nm_info *nm_i = NM_I(sbi); |
| 962 | struct f2fs_nat_block *nat_block; |
| 963 | u32 nid, nr_nat_blks; |
| 964 | |
| 965 | pgoff_t block_off; |
| 966 | pgoff_t block_addr; |
| 967 | int seg_off; |
| 968 | int ret, i; |
| 969 | |
| 970 | |
| 971 | nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1); |
| 972 | |
| 973 | /* Alloc & build nat entry bitmap */ |
| 974 | nr_nat_blks = (le32_to_cpu(raw_sb->segment_count_nat) / 2) << sbi->log_blocks_per_seg; |
| 975 | |
| 976 | fsck->nr_nat_entries = nr_nat_blks * NAT_ENTRY_PER_BLOCK; |
| 977 | fsck->nat_area_bitmap_sz = (fsck->nr_nat_entries + 7) / 8; |
| 978 | fsck->nat_area_bitmap = calloc(fsck->nat_area_bitmap_sz, 1); |
| 979 | ASSERT(fsck->nat_area_bitmap != NULL); |
| 980 | |
| 981 | for (block_off = 0; block_off < nr_nat_blks; block_off++) { |
| 982 | |
| 983 | seg_off = block_off >> sbi->log_blocks_per_seg; |
| 984 | block_addr = (pgoff_t)(nm_i->nat_blkaddr + |
| 985 | (seg_off << sbi->log_blocks_per_seg << 1) + |
| 986 | (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); |
| 987 | |
| 988 | if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) |
| 989 | block_addr += sbi->blocks_per_seg; |
| 990 | |
| 991 | ret = dev_read_block(nat_block, block_addr); |
| 992 | ASSERT(ret >= 0); |
| 993 | |
| 994 | nid = block_off * NAT_ENTRY_PER_BLOCK; |
| 995 | for (i = 0; i < NAT_ENTRY_PER_BLOCK; i++) { |
| 996 | struct f2fs_nat_entry raw_nat; |
| 997 | struct node_info ni; |
| 998 | ni.nid = nid + i; |
| 999 | |
| 1000 | if ((nid + i) == F2FS_NODE_INO(sbi) || (nid + i) == F2FS_META_INO(sbi)) { |
| 1001 | ASSERT(nat_block->entries[i].block_addr != 0x0); |
| 1002 | continue; |
| 1003 | } |
| 1004 | |
| 1005 | if (lookup_nat_in_journal(sbi, nid + i, &raw_nat) >= 0) { |
| 1006 | node_info_from_raw_nat(&ni, &raw_nat); |
| 1007 | if (ni.blk_addr != 0x0) { |
| 1008 | f2fs_set_bit(nid + i, fsck->nat_area_bitmap); |
| 1009 | fsck->chk.valid_nat_entry_cnt++; |
| 1010 | DBG(3, "nid[0x%x] in nat cache\n", nid + i); |
| 1011 | } |
| 1012 | } else { |
| 1013 | node_info_from_raw_nat(&ni, &nat_block->entries[i]); |
| 1014 | if (ni.blk_addr != 0) { |
| 1015 | ASSERT(nid + i != 0x0); |
| 1016 | |
| 1017 | DBG(3, "nid[0x%8x] in nat entry [0x%16x] [0x%8x]\n", |
| 1018 | nid + i, |
| 1019 | ni.blk_addr, |
| 1020 | ni.ino); |
| 1021 | |
| 1022 | f2fs_set_bit(nid + i, fsck->nat_area_bitmap); |
| 1023 | fsck->chk.valid_nat_entry_cnt++; |
| 1024 | } |
| 1025 | } |
| 1026 | } |
| 1027 | } |
| 1028 | free(nat_block); |
| 1029 | |
| 1030 | DBG(0, "valid nat entries (block_addr != 0x0) [0x%8x : %u]\n", |
| 1031 | fsck->chk.valid_nat_entry_cnt, fsck->chk.valid_nat_entry_cnt); |
| 1032 | |
| 1033 | } |
| 1034 | |
| 1035 | int f2fs_do_mount(struct f2fs_sb_info *sbi) |
| 1036 | { |
| 1037 | int ret; |
| 1038 | sbi->active_logs = NR_CURSEG_TYPE; |
| 1039 | ret = validate_super_block(sbi, 0); |
| 1040 | if (ret) { |
| 1041 | ret = validate_super_block(sbi, 1); |
| 1042 | if (ret) |
| 1043 | return -1; |
| 1044 | } |
| 1045 | |
| 1046 | print_raw_sb_info(sbi); |
| 1047 | |
| 1048 | init_sb_info(sbi); |
| 1049 | |
| 1050 | ret = get_valid_checkpoint(sbi); |
| 1051 | if (ret) { |
| 1052 | ERR_MSG("Can't find valid checkpoint\n"); |
| 1053 | return -1; |
| 1054 | } |
| 1055 | |
| 1056 | if (sanity_check_ckpt(sbi)) { |
| 1057 | ERR_MSG("Checkpoint is polluted\n"); |
| 1058 | return -1; |
| 1059 | } |
| 1060 | |
| 1061 | print_ckpt_info(sbi); |
| 1062 | |
| 1063 | sbi->total_valid_node_count = le32_to_cpu(sbi->ckpt->valid_node_count); |
| 1064 | sbi->total_valid_inode_count = le32_to_cpu(sbi->ckpt->valid_inode_count); |
| 1065 | sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count); |
| 1066 | sbi->total_valid_block_count = le64_to_cpu(sbi->ckpt->valid_block_count); |
| 1067 | sbi->last_valid_block_count = sbi->total_valid_block_count; |
| 1068 | sbi->alloc_valid_block_count = 0; |
| 1069 | |
| 1070 | if (build_segment_manager(sbi)) { |
| 1071 | ERR_MSG("build_segment_manager failed\n"); |
| 1072 | return -1; |
| 1073 | } |
| 1074 | |
| 1075 | if (build_node_manager(sbi)) { |
| 1076 | ERR_MSG("build_segment_manager failed\n"); |
| 1077 | return -1; |
| 1078 | } |
| 1079 | |
| 1080 | return ret; |
| 1081 | } |
| 1082 | |
| 1083 | void f2fs_do_umount(struct f2fs_sb_info *sbi) |
| 1084 | { |
| 1085 | struct sit_info *sit_i = SIT_I(sbi); |
| 1086 | struct f2fs_sm_info *sm_i = SM_I(sbi); |
| 1087 | struct f2fs_nm_info *nm_i = NM_I(sbi); |
| 1088 | int i; |
| 1089 | |
| 1090 | /* free nm_info */ |
| 1091 | free(nm_i->nat_bitmap); |
| 1092 | free(sbi->nm_info); |
| 1093 | |
| 1094 | /* free sit_info */ |
| 1095 | for (i = 0; i < TOTAL_SEGS(sbi); i++) { |
| 1096 | free(sit_i->sentries[i].cur_valid_map); |
| 1097 | free(sit_i->sentries[i].ckpt_valid_map); |
| 1098 | } |
| 1099 | free(sit_i->sit_bitmap); |
| 1100 | free(sm_i->sit_info); |
| 1101 | |
| 1102 | /* free sm_info */ |
| 1103 | for (i = 0; i < NR_CURSEG_TYPE; i++) |
| 1104 | free(sm_i->curseg_array[i].sum_blk); |
| 1105 | |
| 1106 | free(sm_i->curseg_array); |
| 1107 | free(sbi->sm_info); |
| 1108 | |
| 1109 | free(sbi->ckpt); |
| 1110 | free(sbi->raw_super); |
| 1111 | } |