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