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