f2fs_format.c revision b155ea8e18a2de5a5d09d3c969cc6fd79a04cb1d
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	"apk",	/* for android system */
134	NULL
135};
136
137static void configure_extension_list(void)
138{
139	const char **extlist = media_ext_lists;
140	char *ext_str = config.extension_list;
141	char *ue;
142	int name_len;
143	int i = 0;
144
145	super_block.extension_count = 0;
146	memset(super_block.extension_list, 0,
147			sizeof(super_block.extension_list));
148
149	while (*extlist) {
150		name_len = strlen(*extlist);
151		memcpy(super_block.extension_list[i++], *extlist, name_len);
152		extlist++;
153	}
154	super_block.extension_count = i - 1;
155
156	if (!ext_str)
157		return;
158
159	/* add user ext list */
160	ue = strtok(ext_str, ",");
161	while (ue != NULL) {
162		name_len = strlen(ue);
163		memcpy(super_block.extension_list[i++], ue, name_len);
164		ue = strtok(NULL, ",");
165		if (i > F2FS_MAX_EXTENSION)
166			break;
167	}
168
169	super_block.extension_count = i - 1;
170
171	free(config.extension_list);
172}
173
174static int f2fs_prepare_super_block(void)
175{
176	u_int32_t blk_size_bytes;
177	u_int32_t log_sectorsize, log_sectors_per_block;
178	u_int32_t log_blocksize, log_blks_per_seg;
179	u_int32_t segment_size_bytes, zone_size_bytes;
180	u_int32_t sit_segments;
181	u_int32_t blocks_for_sit, blocks_for_nat, blocks_for_ssa;
182	u_int32_t total_valid_blks_available;
183	u_int64_t zone_align_start_offset, diff, total_meta_segments;
184	u_int32_t sit_bitmap_size, max_nat_bitmap_size, max_nat_segments;
185	u_int32_t total_zones;
186
187	super_block.magic = cpu_to_le32(F2FS_SUPER_MAGIC);
188	super_block.major_ver = cpu_to_le16(F2FS_MAJOR_VERSION);
189	super_block.minor_ver = cpu_to_le16(F2FS_MINOR_VERSION);
190
191	log_sectorsize = log_base_2(config.sector_size);
192	log_sectors_per_block = log_base_2(config.sectors_per_blk);
193	log_blocksize = log_sectorsize + log_sectors_per_block;
194	log_blks_per_seg = log_base_2(config.blks_per_seg);
195
196	super_block.log_sectorsize = cpu_to_le32(log_sectorsize);
197
198	if (log_sectorsize < 0) {
199		MSG(1, "\tError: Failed to get the sector size: %u!\n",
200				config.sector_size);
201		return -1;
202	}
203
204	super_block.log_sectors_per_block = cpu_to_le32(log_sectors_per_block);
205
206	if (log_sectors_per_block < 0) {
207		MSG(1, "\tError: Failed to get sectors per block: %u!\n",
208				config.sectors_per_blk);
209		return -1;
210	}
211
212	super_block.log_blocksize = cpu_to_le32(log_blocksize);
213	super_block.log_blocks_per_seg = cpu_to_le32(log_blks_per_seg);
214
215	if (log_blks_per_seg < 0) {
216		MSG(1, "\tError: Failed to get block per segment: %u!\n",
217				config.blks_per_seg);
218		return -1;
219	}
220
221	super_block.segs_per_sec = cpu_to_le32(config.segs_per_sec);
222	super_block.secs_per_zone = cpu_to_le32(config.secs_per_zone);
223	blk_size_bytes = 1 << log_blocksize;
224	segment_size_bytes = blk_size_bytes * config.blks_per_seg;
225	zone_size_bytes =
226		blk_size_bytes * config.secs_per_zone *
227		config.segs_per_sec * config.blks_per_seg;
228
229	super_block.checksum_offset = 0;
230
231	super_block.block_count = cpu_to_le64(
232		(config.total_sectors * DEFAULT_SECTOR_SIZE) /
233			blk_size_bytes);
234
235	zone_align_start_offset =
236		(config.start_sector * DEFAULT_SECTOR_SIZE +
237		2 * F2FS_BLKSIZE + zone_size_bytes - 1) /
238		zone_size_bytes * zone_size_bytes -
239		config.start_sector * DEFAULT_SECTOR_SIZE;
240
241	if (config.start_sector % DEFAULT_SECTORS_PER_BLOCK) {
242		MSG(1, "\tWARN: Align start sector number to the page unit\n");
243		MSG(1, "\ti.e., start sector: %d, ofs:%d (sects/page: %d)\n",
244				config.start_sector,
245				config.start_sector % DEFAULT_SECTORS_PER_BLOCK,
246				DEFAULT_SECTORS_PER_BLOCK);
247	}
248
249	super_block.segment_count = cpu_to_le32(
250		((config.total_sectors * DEFAULT_SECTOR_SIZE) -
251		zone_align_start_offset) / segment_size_bytes);
252
253	super_block.segment0_blkaddr =
254		cpu_to_le32(zone_align_start_offset / blk_size_bytes);
255	super_block.cp_blkaddr = super_block.segment0_blkaddr;
256
257	MSG(0, "Info: zone aligned segment0 blkaddr: %u\n",
258				le32_to_cpu(super_block.segment0_blkaddr));
259
260	super_block.segment_count_ckpt =
261				cpu_to_le32(F2FS_NUMBER_OF_CHECKPOINT_PACK);
262
263	super_block.sit_blkaddr = cpu_to_le32(
264		le32_to_cpu(super_block.segment0_blkaddr) +
265		(le32_to_cpu(super_block.segment_count_ckpt) *
266		(1 << log_blks_per_seg)));
267
268	blocks_for_sit = (le32_to_cpu(super_block.segment_count) +
269			SIT_ENTRY_PER_BLOCK - 1) / SIT_ENTRY_PER_BLOCK;
270
271	sit_segments = (blocks_for_sit + config.blks_per_seg - 1)
272			/ config.blks_per_seg;
273
274	super_block.segment_count_sit = cpu_to_le32(sit_segments * 2);
275
276	super_block.nat_blkaddr = cpu_to_le32(
277			le32_to_cpu(super_block.sit_blkaddr) +
278			(le32_to_cpu(super_block.segment_count_sit) *
279			 config.blks_per_seg));
280
281	total_valid_blks_available = (le32_to_cpu(super_block.segment_count) -
282			(le32_to_cpu(super_block.segment_count_ckpt) +
283			 le32_to_cpu(super_block.segment_count_sit))) *
284			config.blks_per_seg;
285
286	blocks_for_nat = (total_valid_blks_available + NAT_ENTRY_PER_BLOCK - 1)
287				/ NAT_ENTRY_PER_BLOCK;
288
289	super_block.segment_count_nat = cpu_to_le32(
290				(blocks_for_nat + config.blks_per_seg - 1) /
291				config.blks_per_seg);
292	/*
293	 * The number of node segments should not be exceeded a "Threshold".
294	 * This number resizes NAT bitmap area in a CP page.
295	 * So the threshold is determined not to overflow one CP page
296	 */
297	sit_bitmap_size = ((le32_to_cpu(super_block.segment_count_sit) / 2) <<
298				log_blks_per_seg) / 8;
299	max_nat_bitmap_size = 4096 - sizeof(struct f2fs_checkpoint) + 1 -
300			sit_bitmap_size;
301	max_nat_segments = (max_nat_bitmap_size * 8) >> log_blks_per_seg;
302
303	if (le32_to_cpu(super_block.segment_count_nat) > max_nat_segments)
304		super_block.segment_count_nat = cpu_to_le32(max_nat_segments);
305
306	super_block.segment_count_nat = cpu_to_le32(
307			le32_to_cpu(super_block.segment_count_nat) * 2);
308
309	super_block.ssa_blkaddr = cpu_to_le32(
310			le32_to_cpu(super_block.nat_blkaddr) +
311			le32_to_cpu(super_block.segment_count_nat) *
312			config.blks_per_seg);
313
314	total_valid_blks_available = (le32_to_cpu(super_block.segment_count) -
315			(le32_to_cpu(super_block.segment_count_ckpt) +
316			le32_to_cpu(super_block.segment_count_sit) +
317			le32_to_cpu(super_block.segment_count_nat))) *
318			config.blks_per_seg;
319
320	blocks_for_ssa = total_valid_blks_available /
321				config.blks_per_seg + 1;
322
323	super_block.segment_count_ssa = cpu_to_le32(
324			(blocks_for_ssa + config.blks_per_seg - 1) /
325			config.blks_per_seg);
326
327	total_meta_segments = le32_to_cpu(super_block.segment_count_ckpt) +
328		le32_to_cpu(super_block.segment_count_sit) +
329		le32_to_cpu(super_block.segment_count_nat) +
330		le32_to_cpu(super_block.segment_count_ssa);
331	diff = total_meta_segments % (config.segs_per_sec *
332						config.secs_per_zone);
333	if (diff)
334		super_block.segment_count_ssa = cpu_to_le32(
335			le32_to_cpu(super_block.segment_count_ssa) +
336			(config.segs_per_sec * config.secs_per_zone -
337			 diff));
338
339	super_block.main_blkaddr = cpu_to_le32(
340			le32_to_cpu(super_block.ssa_blkaddr) +
341			(le32_to_cpu(super_block.segment_count_ssa) *
342			 config.blks_per_seg));
343
344	super_block.segment_count_main = cpu_to_le32(
345			le32_to_cpu(super_block.segment_count) -
346			(le32_to_cpu(super_block.segment_count_ckpt)
347			 + le32_to_cpu(super_block.segment_count_sit) +
348			 le32_to_cpu(super_block.segment_count_nat) +
349			 le32_to_cpu(super_block.segment_count_ssa)));
350
351	super_block.section_count = cpu_to_le32(
352			le32_to_cpu(super_block.segment_count_main)
353			/ config.segs_per_sec);
354
355	super_block.segment_count_main = cpu_to_le32(
356			le32_to_cpu(super_block.section_count) *
357			config.segs_per_sec);
358
359	if ((le32_to_cpu(super_block.segment_count_main) - 2) <
360					config.reserved_segments) {
361		MSG(1, "\tError: Device size is not sufficient for F2FS volume,\
362			more segment needed =%u",
363			config.reserved_segments -
364			(le32_to_cpu(super_block.segment_count_main) - 2));
365		return -1;
366	}
367
368	uuid_generate(super_block.uuid);
369
370	ASCIIToUNICODE(super_block.volume_name, (u_int8_t *)config.vol_label);
371
372	super_block.node_ino = cpu_to_le32(1);
373	super_block.meta_ino = cpu_to_le32(2);
374	super_block.root_ino = cpu_to_le32(3);
375
376	total_zones = le32_to_cpu(super_block.segment_count_main) /
377			(config.segs_per_sec * 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	MSG(0, "Info: Discarding device\n");
921	if (S_ISREG(stat_buf.st_mode))
922		return 0;
923	else if (S_ISBLK(stat_buf.st_mode)) {
924		if (ioctl(config.fd, BLKDISCARD, &range) < 0)
925			MSG(0, "Info: This device doesn't support TRIM\n");
926	} else
927		return -1;
928	return 0;
929}
930
931static int f2fs_format_device(void)
932{
933	int err = 0;
934
935	err= f2fs_prepare_super_block();
936	if (err < 0) {
937		MSG(0, "\tError: Failed to prepare a super block!!!\n");
938		goto exit;
939	}
940
941	err = f2fs_trim_device();
942	if (err < 0) {
943		MSG(0, "\tError: Failed to trim whole device!!!\n");
944		goto exit;
945	}
946
947	err = f2fs_init_sit_area();
948	if (err < 0) {
949		MSG(0, "\tError: Failed to Initialise the SIT AREA!!!\n");
950		goto exit;
951	}
952
953	err = f2fs_init_nat_area();
954	if (err < 0) {
955		MSG(0, "\tError: Failed to Initialise the NAT AREA!!!\n");
956		goto exit;
957	}
958
959	err = f2fs_create_root_dir();
960	if (err < 0) {
961		MSG(0, "\tError: Failed to create the root directory!!!\n");
962		goto exit;
963	}
964
965	err = f2fs_write_check_point_pack();
966	if (err < 0) {
967		MSG(0, "\tError: Failed to write the check point pack!!!\n");
968		goto exit;
969	}
970
971	err = f2fs_write_super_block();
972	if (err < 0) {
973		MSG(0, "\tError: Failed to write the Super Block!!!\n");
974		goto exit;
975	}
976exit:
977	if (err)
978		MSG(0, "\tError: Could not format the device!!!\n");
979
980	/*
981	 * We should call fsync() to flush out all the dirty pages
982	 * in the block device page cache.
983	 */
984	if (fsync(config.fd) < 0)
985		MSG(0, "\tError: Could not conduct fsync!!!\n");
986
987	if (close(config.fd) < 0)
988		MSG(0, "\tError: Failed to close device file!!!\n");
989
990	return err;
991}
992
993int main(int argc, char *argv[])
994{
995	MSG(0, "\n\tF2FS-tools: mkfs.f2fs Ver: %s (%s)\n\n",
996				F2FS_TOOLS_VERSION,
997				F2FS_TOOLS_DATE);
998	f2fs_init_configuration(&config);
999
1000	f2fs_parse_options(argc, argv);
1001
1002	if (f2fs_dev_is_umounted(&config) < 0)
1003		return -1;
1004
1005	if (f2fs_get_device_info(&config) < 0)
1006		return -1;
1007
1008	if (f2fs_format_device() < 0)
1009		return -1;
1010
1011	MSG(0, "Info: format successful\n");
1012
1013	return 0;
1014}
1015