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