f2fs_format.c revision c5bf205a4d7a4e8efad80849bf016e4299935734
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 = cpu_to_le64(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 = cpu_to_le32(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(CHECKSUM_OFFSET);
582
583	crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, ckp, CHECKSUM_OFFSET);
584	*((__le32 *)((unsigned char *)ckp + CHECKSUM_OFFSET)) =
585							cpu_to_le32(crc);
586
587	blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize);
588	cp_seg_blk_offset = le32_to_cpu(super_block.segment0_blkaddr);
589	cp_seg_blk_offset *= blk_size_bytes;
590
591	if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
592		MSG(1, "\tError: While writing the ckp to disk!!!\n");
593		return -1;
594	}
595
596	/* 2. Prepare and write Segment summary for data blocks */
597	memset(sum, 0, sizeof(struct f2fs_summary_block));
598	SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
599
600	sum->entries[0].nid = super_block.root_ino;
601	sum->entries[0].ofs_in_node = 0;
602
603	cp_seg_blk_offset += blk_size_bytes;
604	if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
605		MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
606		return -1;
607	}
608
609	/* 3. Fill segment summary for data block to zero. */
610	memset(sum, 0, sizeof(struct f2fs_summary_block));
611	SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
612
613	cp_seg_blk_offset += blk_size_bytes;
614	if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
615		MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
616		return -1;
617	}
618
619	/* 4. Fill segment summary for data block to zero. */
620	memset(sum, 0, sizeof(struct f2fs_summary_block));
621	SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
622
623	/* inode sit for root */
624	sum->n_sits = cpu_to_le16(6);
625	sum->sit_j.entries[0].segno = ckp->cur_node_segno[0];
626	sum->sit_j.entries[0].se.vblocks = cpu_to_le16((CURSEG_HOT_NODE << 10) | 1);
627	f2fs_set_bit(0, sum->sit_j.entries[0].se.valid_map);
628	sum->sit_j.entries[1].segno = ckp->cur_node_segno[1];
629	sum->sit_j.entries[1].se.vblocks = cpu_to_le16((CURSEG_WARM_NODE << 10));
630	sum->sit_j.entries[2].segno = ckp->cur_node_segno[2];
631	sum->sit_j.entries[2].se.vblocks = cpu_to_le16((CURSEG_COLD_NODE << 10));
632
633	/* data sit for root */
634	sum->sit_j.entries[3].segno = ckp->cur_data_segno[0];
635	sum->sit_j.entries[3].se.vblocks = cpu_to_le16((CURSEG_HOT_DATA << 10) | 1);
636	f2fs_set_bit(0, sum->sit_j.entries[3].se.valid_map);
637	sum->sit_j.entries[4].segno = ckp->cur_data_segno[1];
638	sum->sit_j.entries[4].se.vblocks = cpu_to_le16((CURSEG_WARM_DATA << 10));
639	sum->sit_j.entries[5].segno = ckp->cur_data_segno[2];
640	sum->sit_j.entries[5].se.vblocks = cpu_to_le16((CURSEG_COLD_DATA << 10));
641
642	cp_seg_blk_offset += blk_size_bytes;
643	if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
644		MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
645		return -1;
646	}
647
648	/* 5. Prepare and write Segment summary for node blocks */
649	memset(sum, 0, sizeof(struct f2fs_summary_block));
650	SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
651
652	sum->entries[0].nid = super_block.root_ino;
653	sum->entries[0].ofs_in_node = 0;
654
655	cp_seg_blk_offset += blk_size_bytes;
656	if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
657		MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
658		return -1;
659	}
660
661	/* 6. Fill segment summary for data block to zero. */
662	memset(sum, 0, sizeof(struct f2fs_summary_block));
663	SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
664
665	cp_seg_blk_offset += blk_size_bytes;
666	if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
667		MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
668		return -1;
669	}
670
671	/* 7. Fill segment summary for data block to zero. */
672	memset(sum, 0, sizeof(struct f2fs_summary_block));
673	SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
674	cp_seg_blk_offset += blk_size_bytes;
675	if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
676		MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
677		return -1;
678	}
679
680	/* 8. cp page2 */
681	cp_seg_blk_offset += blk_size_bytes;
682	if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
683		MSG(1, "\tError: While writing the ckp to disk!!!\n");
684		return -1;
685	}
686
687	/* 9. cp page 1 of check point pack 2
688	 * Initiatialize other checkpoint pack with version zero
689	 */
690	ckp->checkpoint_ver = 0;
691
692	crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, ckp, CHECKSUM_OFFSET);
693	*((__le32 *)((unsigned char *)ckp + CHECKSUM_OFFSET)) =
694							cpu_to_le32(crc);
695	cp_seg_blk_offset = (le32_to_cpu(super_block.segment0_blkaddr) +
696				config.blks_per_seg) *
697				blk_size_bytes;
698	if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
699		MSG(1, "\tError: While writing the ckp to disk!!!\n");
700		return -1;
701	}
702
703	free(sum) ;
704	free(ckp) ;
705	return	0;
706}
707
708static int f2fs_write_super_block(void)
709{
710	int index;
711	u_int8_t *zero_buff;
712
713	zero_buff = calloc(F2FS_BLKSIZE, 1);
714
715	memcpy(zero_buff + F2FS_SUPER_OFFSET, &super_block,
716						sizeof(super_block));
717	for (index = 0; index < 2; index++) {
718		if (dev_write(zero_buff, index * F2FS_BLKSIZE, F2FS_BLKSIZE)) {
719			MSG(1, "\tError: While while writing supe_blk \
720					on disk!!! index : %d\n", index);
721			return -1;
722		}
723	}
724
725	free(zero_buff);
726	return 0;
727}
728
729static int f2fs_write_root_inode(void)
730{
731	struct f2fs_node *raw_node = NULL;
732	u_int64_t blk_size_bytes, data_blk_nor;
733	u_int64_t main_area_node_seg_blk_offset = 0;
734
735	raw_node = calloc(F2FS_BLKSIZE, 1);
736	if (raw_node == NULL) {
737		MSG(1, "\tError: Calloc Failed for raw_node!!!\n");
738		return -1;
739	}
740
741	raw_node->footer.nid = super_block.root_ino;
742	raw_node->footer.ino = super_block.root_ino;
743	raw_node->footer.cp_ver = cpu_to_le64(1);
744	raw_node->footer.next_blkaddr = cpu_to_le32(
745			le32_to_cpu(super_block.main_blkaddr) +
746			config.cur_seg[CURSEG_HOT_NODE] *
747			config.blks_per_seg + 1);
748
749	raw_node->i.i_mode = cpu_to_le16(0x41ed);
750	raw_node->i.i_links = cpu_to_le32(2);
751	raw_node->i.i_uid = cpu_to_le32(getuid());
752	raw_node->i.i_gid = cpu_to_le32(getgid());
753
754	blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize);
755	raw_node->i.i_size = cpu_to_le64(1 * blk_size_bytes); /* dentry */
756	raw_node->i.i_blocks = cpu_to_le64(2);
757
758	raw_node->i.i_atime = cpu_to_le32(time(NULL));
759	raw_node->i.i_atime_nsec = 0;
760	raw_node->i.i_ctime = cpu_to_le32(time(NULL));
761	raw_node->i.i_ctime_nsec = 0;
762	raw_node->i.i_mtime = cpu_to_le32(time(NULL));
763	raw_node->i.i_mtime_nsec = 0;
764	raw_node->i.i_generation = 0;
765	raw_node->i.i_xattr_nid = 0;
766	raw_node->i.i_flags = 0;
767	raw_node->i.i_current_depth = cpu_to_le32(1);
768
769	data_blk_nor = le32_to_cpu(super_block.main_blkaddr) +
770		config.cur_seg[CURSEG_HOT_DATA] * config.blks_per_seg;
771	raw_node->i.i_addr[0] = cpu_to_le32(data_blk_nor);
772
773	raw_node->i.i_ext.fofs = 0;
774	raw_node->i.i_ext.blk_addr = cpu_to_le32(data_blk_nor);
775	raw_node->i.i_ext.len = cpu_to_le32(1);
776
777	main_area_node_seg_blk_offset = le32_to_cpu(super_block.main_blkaddr);
778	main_area_node_seg_blk_offset += config.cur_seg[CURSEG_HOT_NODE] *
779					config.blks_per_seg;
780        main_area_node_seg_blk_offset *= blk_size_bytes;
781
782	if (dev_write(raw_node, 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	main_area_node_seg_blk_offset += F2FS_BLKSIZE;
790	if (dev_write(raw_node, main_area_node_seg_blk_offset, F2FS_BLKSIZE)) {
791		MSG(1, "\tError: While writing the raw_node to disk!!!\n");
792		return -1;
793	}
794	free(raw_node);
795	return 0;
796}
797
798static int f2fs_update_nat_root(void)
799{
800	struct f2fs_nat_block *nat_blk = NULL;
801	u_int64_t blk_size_bytes, nat_seg_blk_offset = 0;
802
803	nat_blk = calloc(F2FS_BLKSIZE, 1);
804	if(nat_blk == NULL) {
805		MSG(1, "\tError: Calloc Failed for nat_blk!!!\n");
806		return -1;
807	}
808
809	/* update root */
810	nat_blk->entries[le32_to_cpu(super_block.root_ino)].block_addr = cpu_to_le32(
811		le32_to_cpu(super_block.main_blkaddr) +
812		config.cur_seg[CURSEG_HOT_NODE] * config.blks_per_seg);
813	nat_blk->entries[le32_to_cpu(super_block.root_ino)].ino = super_block.root_ino;
814
815	/* update node nat */
816	nat_blk->entries[le32_to_cpu(super_block.node_ino)].block_addr = cpu_to_le32(1);
817	nat_blk->entries[le32_to_cpu(super_block.node_ino)].ino = super_block.node_ino;
818
819	/* update meta nat */
820	nat_blk->entries[le32_to_cpu(super_block.meta_ino)].block_addr = cpu_to_le32(1);
821	nat_blk->entries[le32_to_cpu(super_block.meta_ino)].ino = super_block.meta_ino;
822
823	blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize);
824	nat_seg_blk_offset = le32_to_cpu(super_block.nat_blkaddr);
825	nat_seg_blk_offset *= blk_size_bytes;
826
827	if (dev_write(nat_blk, nat_seg_blk_offset, F2FS_BLKSIZE)) {
828		MSG(1, "\tError: While writing the nat_blk set0 to disk!\n");
829		return -1;
830	}
831
832	free(nat_blk);
833	return 0;
834}
835
836static int f2fs_add_default_dentry_root(void)
837{
838	struct f2fs_dentry_block *dent_blk = NULL;
839	u_int64_t blk_size_bytes, data_blk_offset = 0;
840
841	dent_blk = calloc(F2FS_BLKSIZE, 1);
842	if(dent_blk == NULL) {
843		MSG(1, "\tError: Calloc Failed for dent_blk!!!\n");
844		return -1;
845	}
846
847	dent_blk->dentry[0].hash_code = 0;
848	dent_blk->dentry[0].ino = super_block.root_ino;
849	dent_blk->dentry[0].name_len = cpu_to_le16(1);
850	dent_blk->dentry[0].file_type = F2FS_FT_DIR;
851	memcpy(dent_blk->filename[0], ".", 1);
852
853	dent_blk->dentry[1].hash_code = 0;
854	dent_blk->dentry[1].ino = super_block.root_ino;
855	dent_blk->dentry[1].name_len = cpu_to_le16(2);
856	dent_blk->dentry[1].file_type = F2FS_FT_DIR;
857	memcpy(dent_blk->filename[1], "..", 2);
858
859	/* bitmap for . and .. */
860	dent_blk->dentry_bitmap[0] = (1 << 1) | (1 << 0);
861	blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize);
862	data_blk_offset = le32_to_cpu(super_block.main_blkaddr);
863	data_blk_offset += config.cur_seg[CURSEG_HOT_DATA] *
864				config.blks_per_seg;
865	data_blk_offset *= blk_size_bytes;
866
867	if (dev_write(dent_blk, data_blk_offset, F2FS_BLKSIZE)) {
868		MSG(1, "\tError: While writing the dentry_blk to disk!!!\n");
869		return -1;
870	}
871
872	free(dent_blk);
873	return 0;
874}
875
876static int f2fs_create_root_dir(void)
877{
878	int err = 0;
879
880	err = f2fs_write_root_inode();
881	if (err < 0) {
882		MSG(1, "\tError: Failed to write root inode!!!\n");
883		goto exit;
884	}
885
886	err = f2fs_update_nat_root();
887	if (err < 0) {
888		MSG(1, "\tError: Failed to update NAT for root!!!\n");
889		goto exit;
890	}
891
892	err = f2fs_add_default_dentry_root();
893	if (err < 0) {
894		MSG(1, "\tError: Failed to add default dentries for root!!!\n");
895		goto exit;
896	}
897exit:
898	if (err)
899		MSG(1, "\tError: Could not create the root directory!!!\n");
900
901	return err;
902}
903
904int f2fs_trim_device()
905{
906	unsigned long long range[2];
907	struct stat stat_buf;
908
909	if (!config.trim)
910		return 0;
911
912	range[0] = 0;
913	range[1] = config.total_sectors * DEFAULT_SECTOR_SIZE;
914
915	if (fstat(config.fd, &stat_buf) < 0 ) {
916		MSG(1, "\tError: Failed to get the device stat!!!\n");
917		return -1;
918	}
919
920	if (S_ISREG(stat_buf.st_mode))
921		return 0;
922	else if (S_ISBLK(stat_buf.st_mode)) {
923		if (ioctl(config.fd, BLKDISCARD, &range) < 0)
924			MSG(0, "Info: This device doesn't support TRIM\n");
925	} else
926		return -1;
927	return 0;
928}
929
930static int f2fs_format_device(void)
931{
932	int err = 0;
933
934	err= f2fs_prepare_super_block();
935	if (err < 0) {
936		MSG(0, "\tError: Failed to prepare a super block!!!\n");
937		goto exit;
938	}
939
940	err = f2fs_trim_device();
941	if (err < 0) {
942		MSG(0, "\tError: Failed to trim whole device!!!\n");
943		goto exit;
944	}
945
946	err = f2fs_init_sit_area();
947	if (err < 0) {
948		MSG(0, "\tError: Failed to Initialise the SIT AREA!!!\n");
949		goto exit;
950	}
951
952	err = f2fs_init_nat_area();
953	if (err < 0) {
954		MSG(0, "\tError: Failed to Initialise the NAT AREA!!!\n");
955		goto exit;
956	}
957
958	err = f2fs_create_root_dir();
959	if (err < 0) {
960		MSG(0, "\tError: Failed to create the root directory!!!\n");
961		goto exit;
962	}
963
964	err = f2fs_write_check_point_pack();
965	if (err < 0) {
966		MSG(0, "\tError: Failed to write the check point pack!!!\n");
967		goto exit;
968	}
969
970	err = f2fs_write_super_block();
971	if (err < 0) {
972		MSG(0, "\tError: Failed to write the Super Block!!!\n");
973		goto exit;
974	}
975exit:
976	if (err)
977		MSG(0, "\tError: Could not format the device!!!\n");
978
979	/*
980	 * We should call fsync() to flush out all the dirty pages
981	 * in the block device page cache.
982	 */
983	if (fsync(config.fd) < 0)
984		MSG(0, "\tError: Could not conduct fsync!!!\n");
985
986	if (close(config.fd) < 0)
987		MSG(0, "\tError: Failed to close device file!!!\n");
988
989	return err;
990}
991
992int main(int argc, char *argv[])
993{
994	MSG(0, "\n\tF2FS-tools: mkfs.f2fs Ver: %s (%s)\n\n",
995				F2FS_TOOLS_VERSION,
996				F2FS_TOOLS_DATE);
997	f2fs_init_configuration(&config);
998
999	f2fs_parse_options(argc, argv);
1000
1001	if (f2fs_dev_is_mounted(&config) < 0)
1002		return -1;
1003
1004	if (f2fs_get_device_info(&config) < 0)
1005		return -1;
1006
1007	if (f2fs_format_device() < 0)
1008		return -1;
1009
1010	MSG(0, "Info: format successful\n");
1011
1012	return 0;
1013}
1014