f2fs_format.c revision e69e4378500b836863dfb7f6e88e39935f23ae80
1/** 2 * f2fs_format.c 3 * 4 * Copyright (c) 2012 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#define _LARGEFILE64_SOURCE 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <fcntl.h> 16#include <string.h> 17#include <unistd.h> 18#include <sys/stat.h> 19#include <sys/mount.h> 20#include <time.h> 21#include <linux/fs.h> 22#include <uuid/uuid.h> 23 24#include "f2fs_fs.h" 25 26extern struct f2fs_configuration config; 27struct f2fs_super_block super_block; 28 29static void mkfs_usage() 30{ 31 MSG(0, "\nUsage: mkfs.f2fs [options] device\n"); 32 MSG(0, "[options]:\n"); 33 MSG(0, " -a heap-based allocation [default:1]\n"); 34 MSG(0, " -d debug level [default:0]\n"); 35 MSG(0, " -e [extension list] e.g. \"mp3,gif,mov\"\n"); 36 MSG(0, " -l label\n"); 37 MSG(0, " -o overprovision ratio [default:5]\n"); 38 MSG(0, " -s # of segments per section [default:1]\n"); 39 MSG(0, " -z # of sections per zone [default:1]\n"); 40 exit(1); 41} 42 43static void f2fs_parse_options(int argc, char *argv[]) 44{ 45 static const char *option_string = "a:d:e:l:o:s:z:"; 46 int32_t option=0; 47 48 while ((option = getopt(argc,argv,option_string)) != EOF) { 49 switch (option) { 50 case 'a': 51 config.heap = atoi(optarg); 52 if (config.heap == 0) 53 MSG(0, "Info: Disable heap-based policy\n"); 54 break; 55 case 'd': 56 config.dbg_lv = atoi(optarg); 57 MSG(0, "Info: Debug level = %d\n", config.dbg_lv); 58 break; 59 case 'e': 60 config.extension_list = strdup(optarg); 61 MSG(0, "Info: Add new extension list\n"); 62 break; 63 case 'l': /*v: volume label */ 64 if (strlen(optarg) > 512) { 65 MSG(0, "Error: Volume Label should be less than\ 66 512 characters\n"); 67 mkfs_usage(); 68 } 69 sprintf((char *)config.vol_label, "%s", optarg); 70 MSG(0, "Info: Label = %s\n", config.vol_label); 71 break; 72 case 'o': 73 config.overprovision = atoi(optarg); 74 MSG(0, "Info: Overprovision ratio = %u%%\n", 75 atoi(optarg)); 76 break; 77 case 's': 78 config.segs_per_sec = atoi(optarg); 79 MSG(0, "Info: Segments per section = %d\n", 80 atoi(optarg)); 81 break; 82 case 'z': 83 config.secs_per_zone = atoi(optarg); 84 MSG(0, "Info: Sections per zone = %d\n", atoi(optarg)); 85 break; 86 default: 87 MSG(0, "\tError: Unknown option %c\n",option); 88 mkfs_usage(); 89 break; 90 } 91 } 92 93 if ((optind + 1) != argc) { 94 MSG(0, "\tError: Device not specified\n"); 95 mkfs_usage(); 96 } 97 98 config.reserved_segments = 99 (2 * (100 / config.overprovision + 1) + 6) 100 * config.segs_per_sec; 101 config.device_name = argv[optind]; 102} 103 104const char *media_ext_lists[] = { 105 "jpg", 106 "gif", 107 "png", 108 "avi", 109 "divx", 110 "mp4", 111 "mp3", 112 "3gp", 113 "wmv", 114 "wma", 115 "mpeg", 116 "mkv", 117 "mov", 118 "asx", 119 "asf", 120 "wmx", 121 "svi", 122 "wvx", 123 "wm", 124 "mpg", 125 "mpe", 126 "rm", 127 "ogg", 128 NULL 129}; 130 131static void configure_extension_list(void) 132{ 133 const char **extlist = media_ext_lists; 134 char *ext_str = config.extension_list; 135 char *ue; 136 int name_len; 137 int i = 0; 138 139 super_block.extension_count = 0; 140 memset(super_block.extension_list, 0, 141 sizeof(super_block.extension_list)); 142 143 while (*extlist) { 144 name_len = strlen(*extlist); 145 memcpy(super_block.extension_list[i++], *extlist, name_len); 146 extlist++; 147 } 148 super_block.extension_count = i - 1; 149 150 if (!ext_str) 151 return; 152 153 /* add user ext list */ 154 ue = strtok(ext_str, ","); 155 while (ue != NULL) { 156 name_len = strlen(ue); 157 memcpy(super_block.extension_list[i++], ue, name_len); 158 ue = strtok(NULL, ","); 159 if (i > F2FS_MAX_EXTENSION) 160 break; 161 } 162 163 super_block.extension_count = i - 1; 164 165 free(config.extension_list); 166} 167 168static int f2fs_prepare_super_block(void) 169{ 170 u_int32_t blk_size_bytes; 171 u_int32_t log_sectorsize, log_sectors_per_block; 172 u_int32_t log_blocksize, log_blks_per_seg; 173 u_int32_t segment_size_bytes, zone_size_bytes; 174 u_int32_t sit_segments; 175 u_int32_t blocks_for_sit, blocks_for_nat, blocks_for_ssa; 176 u_int32_t total_valid_blks_available; 177 u_int64_t zone_align_start_offset, diff, total_meta_segments; 178 u_int32_t sit_bitmap_size, max_nat_bitmap_size, max_nat_segments; 179 u_int32_t total_zones; 180 181 super_block.magic = cpu_to_le32(F2FS_SUPER_MAGIC); 182 super_block.major_ver = cpu_to_le16(F2FS_MAJOR_VERSION); 183 super_block.minor_ver = cpu_to_le16(F2FS_MINOR_VERSION); 184 185 log_sectorsize = log_base_2(config.sector_size); 186 log_sectors_per_block = log_base_2(config.sectors_per_blk); 187 log_blocksize = log_sectorsize + log_sectors_per_block; 188 log_blks_per_seg = log_base_2(config.blks_per_seg); 189 190 super_block.log_sectorsize = cpu_to_le32(log_sectorsize); 191 192 if (log_sectorsize < 0) { 193 MSG(1, "\tError: Failed to get the sector size: %u!\n", 194 config.sector_size); 195 return -1; 196 } 197 198 super_block.log_sectors_per_block = cpu_to_le32(log_sectors_per_block); 199 200 if (log_sectors_per_block < 0) { 201 MSG(1, "\tError: Failed to get sectors per block: %u!\n", 202 config.sectors_per_blk); 203 return -1; 204 } 205 206 super_block.log_blocksize = cpu_to_le32(log_blocksize); 207 super_block.log_blocks_per_seg = cpu_to_le32(log_blks_per_seg); 208 209 if (log_blks_per_seg < 0) { 210 MSG(1, "\tError: Failed to get block per segment: %u!\n", 211 config.blks_per_seg); 212 return -1; 213 } 214 215 super_block.segs_per_sec = cpu_to_le32(config.segs_per_sec); 216 super_block.secs_per_zone = cpu_to_le32(config.secs_per_zone); 217 blk_size_bytes = 1 << log_blocksize; 218 segment_size_bytes = blk_size_bytes * config.blks_per_seg; 219 zone_size_bytes = 220 blk_size_bytes * config.secs_per_zone * 221 config.segs_per_sec * config.blks_per_seg; 222 223 super_block.checksum_offset = 0; 224 225 super_block.block_count = cpu_to_le64( 226 (config.total_sectors * DEFAULT_SECTOR_SIZE) / 227 blk_size_bytes); 228 229 zone_align_start_offset = 230 (config.start_sector * DEFAULT_SECTOR_SIZE + 231 2 * F2FS_BLKSIZE + zone_size_bytes - 1) / 232 zone_size_bytes * zone_size_bytes - 233 config.start_sector * DEFAULT_SECTOR_SIZE; 234 235 if (config.start_sector % DEFAULT_SECTORS_PER_BLOCK) { 236 MSG(1, "\tWARN: Align start sector number to the page unit\n"); 237 MSG(1, "\ti.e., start sector: %d, ofs:%d (sects/page: %d)\n", 238 config.start_sector, 239 config.start_sector % DEFAULT_SECTORS_PER_BLOCK, 240 DEFAULT_SECTORS_PER_BLOCK); 241 } 242 243 super_block.segment_count = cpu_to_le32( 244 ((config.total_sectors * DEFAULT_SECTOR_SIZE) - 245 zone_align_start_offset) / segment_size_bytes); 246 247 super_block.segment0_blkaddr = 248 cpu_to_le32(zone_align_start_offset / blk_size_bytes); 249 super_block.cp_blkaddr = super_block.segment0_blkaddr; 250 251 MSG(0, "Info: zone aligned segment0 blkaddr: %u\n", 252 le32_to_cpu(super_block.segment0_blkaddr)); 253 254 super_block.segment_count_ckpt = 255 cpu_to_le32(F2FS_NUMBER_OF_CHECKPOINT_PACK); 256 257 super_block.sit_blkaddr = cpu_to_le32( 258 le32_to_cpu(super_block.segment0_blkaddr) + 259 (le32_to_cpu(super_block.segment_count_ckpt) * 260 (1 << log_blks_per_seg))); 261 262 blocks_for_sit = (le32_to_cpu(super_block.segment_count) + 263 SIT_ENTRY_PER_BLOCK - 1) / SIT_ENTRY_PER_BLOCK; 264 265 sit_segments = (blocks_for_sit + config.blks_per_seg - 1) 266 / config.blks_per_seg; 267 268 super_block.segment_count_sit = cpu_to_le32(sit_segments * 2); 269 270 super_block.nat_blkaddr = cpu_to_le32( 271 le32_to_cpu(super_block.sit_blkaddr) + 272 (le32_to_cpu(super_block.segment_count_sit) * 273 config.blks_per_seg)); 274 275 total_valid_blks_available = (le32_to_cpu(super_block.segment_count) - 276 (le32_to_cpu(super_block.segment_count_ckpt) + 277 le32_to_cpu(super_block.segment_count_sit))) * 278 config.blks_per_seg; 279 280 blocks_for_nat = (total_valid_blks_available + NAT_ENTRY_PER_BLOCK - 1) 281 / NAT_ENTRY_PER_BLOCK; 282 283 super_block.segment_count_nat = cpu_to_le32( 284 (blocks_for_nat + config.blks_per_seg - 1) / 285 config.blks_per_seg); 286 /* 287 * The number of node segments should not be exceeded a "Threshold". 288 * This number resizes NAT bitmap area in a CP page. 289 * So the threshold is determined not to overflow one CP page 290 */ 291 sit_bitmap_size = ((le32_to_cpu(super_block.segment_count_sit) / 2) << 292 log_blks_per_seg) / 8; 293 max_nat_bitmap_size = 4096 - sizeof(struct f2fs_checkpoint) + 1 - 294 sit_bitmap_size; 295 max_nat_segments = (max_nat_bitmap_size * 8) >> log_blks_per_seg; 296 297 if (le32_to_cpu(super_block.segment_count_nat) > max_nat_segments) 298 super_block.segment_count_nat = cpu_to_le32(max_nat_segments); 299 300 super_block.segment_count_nat = cpu_to_le32( 301 le32_to_cpu(super_block.segment_count_nat) * 2); 302 303 super_block.ssa_blkaddr = cpu_to_le32( 304 le32_to_cpu(super_block.nat_blkaddr) + 305 le32_to_cpu(super_block.segment_count_nat) * 306 config.blks_per_seg); 307 308 total_valid_blks_available = (le32_to_cpu(super_block.segment_count) - 309 (le32_to_cpu(super_block.segment_count_ckpt) + 310 le32_to_cpu(super_block.segment_count_sit) + 311 le32_to_cpu(super_block.segment_count_nat))) * 312 config.blks_per_seg; 313 314 blocks_for_ssa = total_valid_blks_available / 315 config.blks_per_seg + 1; 316 317 super_block.segment_count_ssa = cpu_to_le32( 318 (blocks_for_ssa + config.blks_per_seg - 1) / 319 config.blks_per_seg); 320 321 total_meta_segments = le32_to_cpu(super_block.segment_count_ckpt) + 322 le32_to_cpu(super_block.segment_count_sit) + 323 le32_to_cpu(super_block.segment_count_nat) + 324 le32_to_cpu(super_block.segment_count_ssa); 325 diff = total_meta_segments % (config.segs_per_sec * 326 config.secs_per_zone); 327 if (diff) 328 super_block.segment_count_ssa = cpu_to_le32( 329 le32_to_cpu(super_block.segment_count_ssa) + 330 (config.segs_per_sec * config.secs_per_zone - 331 diff)); 332 333 super_block.main_blkaddr = cpu_to_le32( 334 le32_to_cpu(super_block.ssa_blkaddr) + 335 (le32_to_cpu(super_block.segment_count_ssa) * 336 config.blks_per_seg)); 337 338 super_block.segment_count_main = cpu_to_le32( 339 le32_to_cpu(super_block.segment_count) - 340 (le32_to_cpu(super_block.segment_count_ckpt) 341 + le32_to_cpu(super_block.segment_count_sit) + 342 le32_to_cpu(super_block.segment_count_nat) + 343 le32_to_cpu(super_block.segment_count_ssa))); 344 345 super_block.section_count = cpu_to_le32( 346 le32_to_cpu(super_block.segment_count_main) 347 / config.segs_per_sec); 348 349 super_block.segment_count_main = cpu_to_le32( 350 le32_to_cpu(super_block.section_count) * 351 config.segs_per_sec); 352 353 if ((le32_to_cpu(super_block.segment_count_main) - 2) < 354 config.reserved_segments) { 355 MSG(1, "\tError: Device size is not sufficient for F2FS volume,\ 356 more segment needed =%u", 357 config.reserved_segments - 358 (le32_to_cpu(super_block.segment_count_main) - 2)); 359 return -1; 360 } 361 362 uuid_generate(super_block.uuid); 363 364 ASCIIToUNICODE(super_block.volume_name, config.vol_label); 365 366 super_block.node_ino = cpu_to_le32(1); 367 super_block.meta_ino = cpu_to_le32(2); 368 super_block.root_ino = cpu_to_le32(3); 369 370 total_zones = ((le32_to_cpu(super_block.segment_count_main) - 1) / 371 config.segs_per_sec) / 372 config.secs_per_zone; 373 if (total_zones <= 6) { 374 MSG(1, "\tError: %d zones: Need more zones \ 375 by shrinking zone size\n", total_zones); 376 return -1; 377 } 378 379 if (config.heap) { 380 config.cur_seg[CURSEG_HOT_NODE] = (total_zones - 1) * 381 config.segs_per_sec * 382 config.secs_per_zone + 383 ((config.secs_per_zone - 1) * 384 config.segs_per_sec); 385 config.cur_seg[CURSEG_WARM_NODE] = 386 config.cur_seg[CURSEG_HOT_NODE] - 387 config.segs_per_sec * 388 config.secs_per_zone; 389 config.cur_seg[CURSEG_COLD_NODE] = 390 config.cur_seg[CURSEG_WARM_NODE] - 391 config.segs_per_sec * 392 config.secs_per_zone; 393 config.cur_seg[CURSEG_HOT_DATA] = 394 config.cur_seg[CURSEG_COLD_NODE] - 395 config.segs_per_sec * 396 config.secs_per_zone; 397 config.cur_seg[CURSEG_COLD_DATA] = 0; 398 config.cur_seg[CURSEG_WARM_DATA] = 399 config.cur_seg[CURSEG_COLD_DATA] + 400 config.segs_per_sec * 401 config.secs_per_zone; 402 } else { 403 config.cur_seg[CURSEG_HOT_NODE] = 0; 404 config.cur_seg[CURSEG_WARM_NODE] = 405 config.cur_seg[CURSEG_HOT_NODE] + 406 config.segs_per_sec * 407 config.secs_per_zone; 408 config.cur_seg[CURSEG_COLD_NODE] = 409 config.cur_seg[CURSEG_WARM_NODE] + 410 config.segs_per_sec * 411 config.secs_per_zone; 412 config.cur_seg[CURSEG_HOT_DATA] = 413 config.cur_seg[CURSEG_COLD_NODE] + 414 config.segs_per_sec * 415 config.secs_per_zone; 416 config.cur_seg[CURSEG_COLD_DATA] = 417 config.cur_seg[CURSEG_HOT_DATA] + 418 config.segs_per_sec * 419 config.secs_per_zone; 420 config.cur_seg[CURSEG_WARM_DATA] = 421 config.cur_seg[CURSEG_COLD_DATA] + 422 config.segs_per_sec * 423 config.secs_per_zone; 424 } 425 426 configure_extension_list(); 427 428 return 0; 429} 430 431static int f2fs_init_sit_area(void) 432{ 433 u_int32_t blk_size, seg_size; 434 u_int32_t index = 0; 435 u_int64_t sit_seg_addr = 0; 436 u_int8_t *zero_buf = NULL; 437 438 blk_size = 1 << le32_to_cpu(super_block.log_blocksize); 439 seg_size = (1 << le32_to_cpu(super_block.log_blocks_per_seg)) * 440 blk_size; 441 442 zero_buf = calloc(sizeof(u_int8_t), seg_size); 443 if(zero_buf == NULL) { 444 MSG(1, "\tError: Calloc Failed for sit_zero_buf!!!\n"); 445 return -1; 446 } 447 448 sit_seg_addr = le32_to_cpu(super_block.sit_blkaddr); 449 sit_seg_addr *= blk_size; 450 451 for (index = 0; 452 index < (le32_to_cpu(super_block.segment_count_sit) / 2); 453 index++) { 454 if (dev_write(config.fd, zero_buf, sit_seg_addr, seg_size)) { 455 MSG(1, "\tError: While zeroing out the sit area \ 456 on disk!!!\n"); 457 return -1; 458 } 459 sit_seg_addr += seg_size; 460 } 461 462 free(zero_buf); 463 return 0 ; 464} 465 466static int f2fs_init_nat_area(void) 467{ 468 u_int32_t blk_size, seg_size; 469 u_int32_t index = 0; 470 u_int64_t nat_seg_addr = 0; 471 u_int8_t *nat_buf = NULL; 472 473 blk_size = 1 << le32_to_cpu(super_block.log_blocksize); 474 seg_size = (1 << le32_to_cpu(super_block.log_blocks_per_seg)) * 475 blk_size; 476 477 nat_buf = calloc(sizeof(u_int8_t), seg_size); 478 if (nat_buf == NULL) { 479 MSG(1, "\tError: Calloc Failed for nat_zero_blk!!!\n"); 480 return -1; 481 } 482 483 nat_seg_addr = le32_to_cpu(super_block.nat_blkaddr); 484 nat_seg_addr *= blk_size; 485 486 for (index = 0; 487 index < (le32_to_cpu(super_block.segment_count_nat) / 2); 488 index++) { 489 if (dev_write(config.fd, nat_buf, nat_seg_addr, seg_size)) { 490 MSG(1, "\tError: While zeroing out the nat area \ 491 on disk!!!\n"); 492 return -1; 493 } 494 nat_seg_addr = nat_seg_addr + (2 * seg_size); 495 } 496 497 free(nat_buf); 498 return 0 ; 499} 500 501static int f2fs_write_check_point_pack(void) 502{ 503 struct f2fs_checkpoint *ckp = NULL; 504 struct f2fs_summary_block *sum = NULL; 505 u_int32_t blk_size_bytes; 506 u_int64_t cp_seg_blk_offset = 0; 507 u_int32_t crc = 0; 508 int i; 509 510 ckp = calloc(F2FS_BLKSIZE, 1); 511 if (ckp == NULL) { 512 MSG(1, "\tError: Calloc Failed for f2fs_checkpoint!!!\n"); 513 return -1; 514 } 515 516 sum = calloc(F2FS_BLKSIZE, 1); 517 if (sum == NULL) { 518 MSG(1, "\tError: Calloc Failed for summay_node!!!\n"); 519 return -1; 520 } 521 522 /* 1. cp page 1 of checkpoint pack 1 */ 523 ckp->checkpoint_ver = 1; 524 ckp->cur_node_segno[0] = 525 cpu_to_le32(config.cur_seg[CURSEG_HOT_NODE]); 526 ckp->cur_node_segno[1] = 527 cpu_to_le32(config.cur_seg[CURSEG_WARM_NODE]); 528 ckp->cur_node_segno[2] = 529 cpu_to_le32(config.cur_seg[CURSEG_COLD_NODE]); 530 ckp->cur_data_segno[0] = 531 cpu_to_le32(config.cur_seg[CURSEG_HOT_DATA]); 532 ckp->cur_data_segno[1] = 533 cpu_to_le32(config.cur_seg[CURSEG_WARM_DATA]); 534 ckp->cur_data_segno[2] = 535 cpu_to_le32(config.cur_seg[CURSEG_COLD_DATA]); 536 for (i = 3; i < MAX_ACTIVE_NODE_LOGS; i++) { 537 ckp->cur_node_segno[i] = 0xffffffff; 538 ckp->cur_data_segno[i] = 0xffffffff; 539 } 540 541 ckp->cur_node_blkoff[0] = cpu_to_le16(1); 542 ckp->cur_data_blkoff[0] = cpu_to_le16(1); 543 ckp->valid_block_count = cpu_to_le64(2); 544 ckp->rsvd_segment_count = cpu_to_le32(config.reserved_segments); 545 ckp->overprov_segment_count = cpu_to_le32( 546 (le32_to_cpu(super_block.segment_count_main) - 547 le32_to_cpu(ckp->rsvd_segment_count)) * 548 config.overprovision / 100); 549 ckp->overprov_segment_count = cpu_to_le32( 550 le32_to_cpu(ckp->overprov_segment_count) + 551 le32_to_cpu(ckp->rsvd_segment_count)); 552 553 /* main segments - reserved segments - (node + data segments) */ 554 ckp->free_segment_count = cpu_to_le32( 555 le32_to_cpu(super_block.segment_count_main) - 6); 556 ckp->user_block_count = cpu_to_le64( 557 ((le32_to_cpu(ckp->free_segment_count) + 6 - 558 le32_to_cpu(ckp->overprov_segment_count)) * 559 config.blks_per_seg)); 560 ckp->cp_pack_total_block_count = cpu_to_le32(8); 561 ckp->ckpt_flags |= CP_UMOUNT_FLAG; 562 ckp->cp_pack_start_sum = cpu_to_le32(1); 563 ckp->valid_node_count = cpu_to_le32(1); 564 ckp->valid_inode_count = cpu_to_le32(1); 565 ckp->next_free_nid = cpu_to_le32( 566 le32_to_cpu(super_block.root_ino) + 1); 567 568 ckp->sit_ver_bitmap_bytesize = cpu_to_le32( 569 ((le32_to_cpu(super_block.segment_count_sit) / 2) << 570 le32_to_cpu(super_block.log_blocks_per_seg)) / 8); 571 572 ckp->nat_ver_bitmap_bytesize = cpu_to_le32( 573 ((le32_to_cpu(super_block.segment_count_nat) / 2) << 574 le32_to_cpu(super_block.log_blocks_per_seg)) / 8); 575 576 ckp->checksum_offset = cpu_to_le32(4092); 577 578 crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, ckp, 579 le32_to_cpu(ckp->checksum_offset)); 580 *((u_int32_t *)((unsigned char *)ckp + 581 le32_to_cpu(ckp->checksum_offset))) = crc; 582 583 blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize); 584 cp_seg_blk_offset = le32_to_cpu(super_block.segment0_blkaddr); 585 cp_seg_blk_offset *= blk_size_bytes; 586 587 if (dev_write(config.fd, ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) { 588 MSG(1, "\tError: While writing the ckp to disk!!!\n"); 589 return -1; 590 } 591 592 /* 2. Prepare and write Segment summary for data blocks */ 593 memset(sum, 0, sizeof(struct f2fs_summary_block)); 594 SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA); 595 596 sum->entries[0].nid = super_block.root_ino; 597 sum->entries[0].ofs_in_node = 0; 598 599 cp_seg_blk_offset += blk_size_bytes; 600 if (dev_write(config.fd, sum, cp_seg_blk_offset, F2FS_BLKSIZE)) { 601 MSG(1, "\tError: While writing the sum_blk to disk!!!\n"); 602 return -1; 603 } 604 605 /* 3. Fill segment summary for data block to zero. */ 606 memset(sum, 0, sizeof(struct f2fs_summary_block)); 607 SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA); 608 609 cp_seg_blk_offset += blk_size_bytes; 610 if (dev_write(config.fd, sum, cp_seg_blk_offset, F2FS_BLKSIZE)) { 611 MSG(1, "\tError: While writing the sum_blk to disk!!!\n"); 612 return -1; 613 } 614 615 /* 4. Fill segment summary for data block to zero. */ 616 memset(sum, 0, sizeof(struct f2fs_summary_block)); 617 SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA); 618 619 /* inode sit for root */ 620 sum->n_sits = cpu_to_le16(6); 621 sum->sit_j.entries[0].segno = ckp->cur_node_segno[0]; 622 sum->sit_j.entries[0].se.vblocks = cpu_to_le16((CURSEG_HOT_NODE << 10) | 1); 623 f2fs_set_bit(0, sum->sit_j.entries[0].se.valid_map); 624 sum->sit_j.entries[1].segno = ckp->cur_node_segno[1]; 625 sum->sit_j.entries[1].se.vblocks = cpu_to_le16((CURSEG_WARM_NODE << 10)); 626 sum->sit_j.entries[2].segno = ckp->cur_node_segno[2]; 627 sum->sit_j.entries[2].se.vblocks = cpu_to_le16((CURSEG_COLD_NODE << 10)); 628 629 /* data sit for root */ 630 sum->sit_j.entries[3].segno = ckp->cur_data_segno[0]; 631 sum->sit_j.entries[3].se.vblocks = cpu_to_le16((CURSEG_HOT_DATA << 10) | 1); 632 f2fs_set_bit(0, sum->sit_j.entries[3].se.valid_map); 633 sum->sit_j.entries[4].segno = ckp->cur_data_segno[1]; 634 sum->sit_j.entries[4].se.vblocks = cpu_to_le16((CURSEG_WARM_DATA << 10)); 635 sum->sit_j.entries[5].segno = ckp->cur_data_segno[2]; 636 sum->sit_j.entries[5].se.vblocks = cpu_to_le16((CURSEG_COLD_DATA << 10)); 637 638 cp_seg_blk_offset += blk_size_bytes; 639 if (dev_write(config.fd, sum, cp_seg_blk_offset, F2FS_BLKSIZE)) { 640 MSG(1, "\tError: While writing the sum_blk to disk!!!\n"); 641 return -1; 642 } 643 644 /* 5. Prepare and write Segment summary for node blocks */ 645 memset(sum, 0, sizeof(struct f2fs_summary_block)); 646 SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE); 647 648 sum->entries[0].nid = super_block.root_ino; 649 sum->entries[0].ofs_in_node = 0; 650 651 cp_seg_blk_offset += blk_size_bytes; 652 if (dev_write(config.fd, sum, cp_seg_blk_offset, F2FS_BLKSIZE)) { 653 MSG(1, "\tError: While writing the sum_blk to disk!!!\n"); 654 return -1; 655 } 656 657 /* 6. Fill segment summary for data block to zero. */ 658 memset(sum, 0, sizeof(struct f2fs_summary_block)); 659 SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE); 660 661 cp_seg_blk_offset += blk_size_bytes; 662 if (dev_write(config.fd, sum, cp_seg_blk_offset, F2FS_BLKSIZE)) { 663 MSG(1, "\tError: While writing the sum_blk to disk!!!\n"); 664 return -1; 665 } 666 667 /* 7. Fill segment summary for data block to zero. */ 668 memset(sum, 0, sizeof(struct f2fs_summary_block)); 669 SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE); 670 cp_seg_blk_offset += blk_size_bytes; 671 if (dev_write(config.fd, sum, cp_seg_blk_offset, F2FS_BLKSIZE)) { 672 MSG(1, "\tError: While writing the sum_blk to disk!!!\n"); 673 return -1; 674 } 675 676 /* 8. cp page2 */ 677 cp_seg_blk_offset += blk_size_bytes; 678 if (dev_write(config.fd, ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) { 679 MSG(1, "\tError: While writing the ckp to disk!!!\n"); 680 return -1; 681 } 682 683 /* 9. cp page 1 of check point pack 2 684 * Initiatialize other checkpoint pack with version zero 685 */ 686 ckp->checkpoint_ver = 0; 687 688 crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, ckp, 689 le32_to_cpu(ckp->checksum_offset)); 690 *((u_int32_t *)((unsigned char *)ckp + 691 le32_to_cpu(ckp->checksum_offset))) = crc; 692 693 cp_seg_blk_offset = (le32_to_cpu(super_block.segment0_blkaddr) + 694 config.blks_per_seg) * 695 blk_size_bytes; 696 if (dev_write(config.fd, ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) { 697 MSG(1, "\tError: While writing the ckp to disk!!!\n"); 698 return -1; 699 } 700 701 free(sum) ; 702 free(ckp) ; 703 return 0; 704} 705 706static int f2fs_write_super_block(void) 707{ 708 int index; 709 u_int8_t *zero_buff; 710 711 zero_buff = calloc(F2FS_BLKSIZE, 1); 712 713 memcpy(zero_buff + F2FS_SUPER_OFFSET, &super_block, 714 sizeof(super_block)); 715 for (index = 0; index < 2; index++) { 716 if (dev_write(config.fd, zero_buff, 717 index * F2FS_BLKSIZE, F2FS_BLKSIZE)) { 718 MSG(1, "\tError: While while writing supe_blk \ 719 on disk!!! index : %d\n", index); 720 return -1; 721 } 722 } 723 724 free(zero_buff); 725 return 0; 726} 727 728static int f2fs_write_root_inode(void) 729{ 730 struct f2fs_node *raw_node = NULL; 731 u_int64_t blk_size_bytes, data_blk_nor; 732 u_int64_t main_area_node_seg_blk_offset = 0; 733 734 raw_node = calloc(F2FS_BLKSIZE, 1); 735 if (raw_node == NULL) { 736 MSG(1, "\tError: Calloc Failed for raw_node!!!\n"); 737 return -1; 738 } 739 740 raw_node->footer.nid = super_block.root_ino; 741 raw_node->footer.ino = super_block.root_ino; 742 raw_node->footer.cp_ver = cpu_to_le64(1); 743 raw_node->footer.next_blkaddr = cpu_to_le32( 744 le32_to_cpu(super_block.main_blkaddr) + 745 config.cur_seg[CURSEG_HOT_NODE] * 746 config.blks_per_seg + 1); 747 748 raw_node->i.i_mode = cpu_to_le16(0x41ed); 749 raw_node->i.i_links = cpu_to_le32(2); 750 raw_node->i.i_uid = cpu_to_le32(getuid()); 751 raw_node->i.i_gid = cpu_to_le32(getgid()); 752 753 blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize); 754 raw_node->i.i_size = cpu_to_le64(1 * blk_size_bytes); /* dentry */ 755 raw_node->i.i_blocks = cpu_to_le64(2); 756 757 raw_node->i.i_atime = cpu_to_le32(time(NULL)); 758 raw_node->i.i_atime_nsec = 0; 759 raw_node->i.i_ctime = cpu_to_le32(time(NULL)); 760 raw_node->i.i_ctime_nsec = 0; 761 raw_node->i.i_mtime = cpu_to_le32(time(NULL)); 762 raw_node->i.i_mtime_nsec = 0; 763 raw_node->i.i_generation = 0; 764 raw_node->i.i_xattr_nid = 0; 765 raw_node->i.i_flags = 0; 766 raw_node->i.i_current_depth = cpu_to_le32(1); 767 768 data_blk_nor = le32_to_cpu(super_block.main_blkaddr) + 769 config.cur_seg[CURSEG_HOT_DATA] * config.blks_per_seg; 770 raw_node->i.i_addr[0] = cpu_to_le32(data_blk_nor); 771 772 raw_node->i.i_ext.fofs = 0; 773 raw_node->i.i_ext.blk_addr = cpu_to_le32(data_blk_nor); 774 raw_node->i.i_ext.len = cpu_to_le32(1); 775 776 main_area_node_seg_blk_offset = le32_to_cpu(super_block.main_blkaddr); 777 main_area_node_seg_blk_offset += config.cur_seg[CURSEG_HOT_NODE] * 778 config.blks_per_seg; 779 main_area_node_seg_blk_offset *= blk_size_bytes; 780 781 if (dev_write(config.fd, raw_node, 782 main_area_node_seg_blk_offset, F2FS_BLKSIZE)) { 783 MSG(1, "\tError: While writing the raw_node to disk!!!\n"); 784 return -1; 785 } 786 787 memset(raw_node, 0xff, sizeof(struct f2fs_node)); 788 789 if (dev_write(config.fd, raw_node, 790 main_area_node_seg_blk_offset + F2FS_BLKSIZE, 791 F2FS_BLKSIZE)) { 792 MSG(1, "\tError: While writing the raw_node to disk!!!\n"); 793 return -1; 794 } 795 free(raw_node); 796 return 0; 797} 798 799static int f2fs_update_nat_root(void) 800{ 801 struct f2fs_nat_block *nat_blk = NULL; 802 u_int64_t blk_size_bytes, nat_seg_blk_offset = 0; 803 804 nat_blk = calloc(F2FS_BLKSIZE, 1); 805 if(nat_blk == NULL) { 806 MSG(1, "\tError: Calloc Failed for nat_blk!!!\n"); 807 return -1; 808 } 809 810 /* update root */ 811 nat_blk->entries[super_block.root_ino].block_addr = cpu_to_le32( 812 le32_to_cpu(super_block.main_blkaddr) + 813 config.cur_seg[CURSEG_HOT_NODE] * config.blks_per_seg); 814 nat_blk->entries[super_block.root_ino].ino = super_block.root_ino; 815 816 /* update node nat */ 817 nat_blk->entries[super_block.node_ino].block_addr = cpu_to_le32(1); 818 nat_blk->entries[super_block.node_ino].ino = super_block.node_ino; 819 820 /* update meta nat */ 821 nat_blk->entries[super_block.meta_ino].block_addr = cpu_to_le32(1); 822 nat_blk->entries[super_block.meta_ino].ino = super_block.meta_ino; 823 824 blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize); 825 nat_seg_blk_offset = le32_to_cpu(super_block.nat_blkaddr); 826 nat_seg_blk_offset *= blk_size_bytes; 827 828 if (dev_write(config.fd, nat_blk, nat_seg_blk_offset, F2FS_BLKSIZE)) { 829 MSG(1, "\tError: While writing the nat_blk set0 to disk!\n"); 830 return -1; 831 } 832 833 free(nat_blk); 834 return 0; 835} 836 837static int f2fs_add_default_dentry_root(void) 838{ 839 struct f2fs_dentry_block *dent_blk = NULL; 840 u_int64_t blk_size_bytes, data_blk_offset = 0; 841 842 dent_blk = calloc(F2FS_BLKSIZE, 1); 843 if(dent_blk == NULL) { 844 MSG(1, "\tError: Calloc Failed for dent_blk!!!\n"); 845 return -1; 846 } 847 848 dent_blk->dentry[0].hash_code = 0; 849 dent_blk->dentry[0].ino = super_block.root_ino; 850 dent_blk->dentry[0].name_len = cpu_to_le16(1); 851 dent_blk->dentry[0].file_type = F2FS_FT_DIR; 852 memcpy(dent_blk->filename[0], ".", 1); 853 854 dent_blk->dentry[1].hash_code = 0; 855 dent_blk->dentry[1].ino = super_block.root_ino; 856 dent_blk->dentry[1].name_len = cpu_to_le16(2); 857 dent_blk->dentry[1].file_type = F2FS_FT_DIR; 858 memcpy(dent_blk->filename[1], "..", 2); 859 860 /* bitmap for . and .. */ 861 dent_blk->dentry_bitmap[0] = (1 << 1) | (1 << 0); 862 blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize); 863 data_blk_offset = le32_to_cpu(super_block.main_blkaddr); 864 data_blk_offset += config.cur_seg[CURSEG_HOT_DATA] * 865 config.blks_per_seg; 866 data_blk_offset *= blk_size_bytes; 867 868 if (dev_write(config.fd, dent_blk, data_blk_offset, F2FS_BLKSIZE)) { 869 MSG(1, "\tError: While writing the dentry_blk to disk!!!\n"); 870 return -1; 871 } 872 873 free(dent_blk); 874 return 0; 875} 876 877static int f2fs_create_root_dir(void) 878{ 879 int err = 0; 880 881 err = f2fs_write_root_inode(); 882 if (err < 0) { 883 MSG(1, "\tError: Failed to write root inode!!!\n"); 884 goto exit; 885 } 886 887 err = f2fs_update_nat_root(); 888 if (err < 0) { 889 MSG(1, "\tError: Failed to update NAT for root!!!\n"); 890 goto exit; 891 } 892 893 err = f2fs_add_default_dentry_root(); 894 if (err < 0) { 895 MSG(1, "\tError: Failed to add default dentries for root!!!\n"); 896 goto exit; 897 } 898exit: 899 if (err) 900 MSG(1, "\tError: Could not create the root directory!!!\n"); 901 902 return err; 903} 904 905int f2fs_trim_device() 906{ 907 unsigned long long range[2]; 908 struct stat stat_buf; 909 910 range[0] = 0; 911 range[1] = config.total_sectors * DEFAULT_SECTOR_SIZE; 912 913 if (fstat(config.fd, &stat_buf) < 0 ) { 914 MSG(1, "\tError: Failed to get the device stat!!!\n"); 915 return -1; 916 } 917 918 if (S_ISREG(stat_buf.st_mode)) 919 return 0; 920 else if (S_ISBLK(stat_buf.st_mode)) { 921 if (ioctl(config.fd, BLKDISCARD, &range) < 0) 922 MSG(0, "Info: This device doesn't support TRIM\n"); 923 } else 924 return -1; 925 return 0; 926} 927 928static int f2fs_format_device(void) 929{ 930 int err = 0; 931 932 err= f2fs_prepare_super_block(); 933 if (err < 0) { 934 MSG(0, "\tError: Failed to prepare a super block!!!\n"); 935 goto exit; 936 } 937 938 err = f2fs_trim_device(); 939 if (err < 0) { 940 MSG(0, "\tError: Failed to trim whole device!!!\n"); 941 goto exit; 942 } 943 944 err = f2fs_init_sit_area(); 945 if (err < 0) { 946 MSG(0, "\tError: Failed to Initialise the SIT AREA!!!\n"); 947 goto exit; 948 } 949 950 err = f2fs_init_nat_area(); 951 if (err < 0) { 952 MSG(0, "\tError: Failed to Initialise the NAT AREA!!!\n"); 953 goto exit; 954 } 955 956 err = f2fs_create_root_dir(); 957 if (err < 0) { 958 MSG(0, "\tError: Failed to create the root directory!!!\n"); 959 goto exit; 960 } 961 962 err = f2fs_write_check_point_pack(); 963 if (err < 0) { 964 MSG(0, "\tError: Failed to write the check point pack!!!\n"); 965 goto exit; 966 } 967 968 err = f2fs_write_super_block(); 969 if (err < 0) { 970 MSG(0, "\tError: Failed to write the Super Block!!!\n"); 971 goto exit; 972 } 973exit: 974 if (err) 975 MSG(0, "\tError: Could not format the device!!!\n"); 976 977 /* 978 * We should call fsync() to flush out all the dirty pages 979 * in the block device page cache. 980 */ 981 if (fsync(config.fd) < 0) 982 MSG(0, "\tError: Could not conduct fsync!!!\n"); 983 984 if (close(config.fd) < 0) 985 MSG(0, "\tError: Failed to close device file!!!\n"); 986 987 return err; 988} 989 990int main(int argc, char *argv[]) 991{ 992 MSG(0, "\n\tF2FS-tools: mkfs.f2fs Ver: %s (%s)\n\n", 993 F2FS_TOOLS_VERSION, 994 F2FS_TOOLS_DATE); 995 f2fs_init_configuration(&config); 996 997 f2fs_parse_options(argc, argv); 998 999 if (f2fs_dev_is_mounted(&config) < 0) 1000 return -1; 1001 1002 if (f2fs_get_device_info(&config) < 0) 1003 return -1; 1004 1005 if (f2fs_format_device() < 0) 1006 return -1; 1007 1008 MSG(0, "Info: format successful\n"); 1009 1010 return 0; 1011} 1012