f2fs_format.c revision bbf6e62360d8eae415dc7d19325b7d70079db0e1
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 <inttypes.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <fcntl.h>
17#include <string.h>
18#include <unistd.h>
19#include <errno.h>
20#include <mntent.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <sys/ioctl.h>
24#include <sys/mount.h>
25#include <linux/hdreg.h>
26#include <time.h>
27#include <linux/fs.h>
28#include <uuid/uuid.h>
29
30#include "f2fs_format.h"
31
32struct f2fs_global_parameters f2fs_params;
33struct f2fs_super_block super_block;
34
35/**
36 * @brief     	This function will change a given string from ASCII to UNICODE
37 * @param	out_buf Output UNICODE string
38 * @param	in_buf Input ASCII string
39 * @return	None
40 */
41void ASCIIToUNICODE(u_int16_t *out_buf, u_int8_t *in_buf)
42{
43	u_int8_t *pchTempPtr = in_buf;
44	u_int16_t *pwTempPtr = out_buf;
45
46	while (*pchTempPtr != '\0') {
47		/* Copy the string elements character by character
48		 * to the output string with typecasting the source.
49		 */
50		*pwTempPtr = (u_int16_t)*pchTempPtr;
51		pchTempPtr++;
52		pwTempPtr++;
53	}
54	*pwTempPtr = '\0';
55	return;
56}
57
58/**
59 * @brief     	This function will ntitlize f2fs global paramenters
60 * @param	None
61 * @return	None
62 */
63static void f2fs_init_global_parameters(void)
64{
65	f2fs_params.sector_size = DEFAULT_SECTOR_SIZE;
66	f2fs_params.sectors_per_blk = DEFAULT_SECTORS_PER_BLOCK;
67	f2fs_params.blks_per_seg = DEFAULT_BLOCKS_PER_SEGMENT;
68	f2fs_params.reserved_segments = 20; /* calculated by overprovision ratio */
69	f2fs_params.overprovision = 5;
70	f2fs_params.segs_per_sec = 1;
71	f2fs_params.secs_per_zone = 1;
72	f2fs_params.heap = 1;
73	memset(f2fs_params.vol_label, 0, sizeof(f2fs_params.vol_label));
74
75	f2fs_params.vol_label[0] = 'F';
76	f2fs_params.vol_label[1] = '2';
77	f2fs_params.vol_label[2] = 'F';
78	f2fs_params.vol_label[3] = 'S';
79	f2fs_params.vol_label[4] = '\0';
80	f2fs_params.device_name = NULL;
81}
82
83static inline int f2fs_set_bit(unsigned int nr, unsigned char *addr)
84{
85	int mask;
86	int ret;
87
88	addr += (nr >> 3);
89	mask = 1 << (7 - (nr & 0x07));
90	ret = mask & *addr;
91	*addr |= mask;
92	return ret;
93}
94
95/**
96 * @brief     	This function calculates log base 2 of given number
97 * @param	num an integer number
98 * @return	an int log base 2 of given number
99 */
100static int8_t log_base_2(u_int32_t num)
101{
102	int8_t ret = 0;
103
104	if (num <= 0 || (num & (num - 1)) != 0) {
105		return -1;
106	}
107
108	while (num >>= 1) {
109		ret++;
110	}
111
112	return ret;
113}
114
115/**
116 * @brief     	This function shows error if user gives wrong parameters
117 * @param	None
118 * @return	None
119 */
120static void f2fs_usage(void)
121{
122	fprintf(stderr, "Usage: f2fs_format [options] device\n");
123	fprintf(stderr, "[options]\n");
124	fprintf(stderr, "-l label\n");
125	fprintf(stderr, "-a heap-based allocation [default:1]\n");
126	fprintf(stderr, "-o overprovision ratio [default:5]\n");
127	fprintf(stderr, "-s # of segments per section [default:1]\n");
128	fprintf(stderr, "-z # of sections per zone [default:1]\n");
129	fprintf(stderr, "-e [extension list] e.g. \"mp3,gif,mov\"\n");
130	exit(1);
131}
132
133/**
134 * @brief     	This function calculates log base 2 of given number
135 * @param	argc number of arguments
136 * @param	argv an array of arguments
137 * @return	None
138 */
139static void f2fs_parse_options(int argc, char *argv[])
140{
141	static const char *option_string = "l:o:z:a:s:e:";
142	int32_t option=0;
143
144	while ((option = getopt(argc,argv,option_string)) != EOF) {
145		switch (option) {
146		case 'l':		/*v: volume label */
147			if (strlen(optarg) > 512) {
148				printf("Error: Volume Label should be less than \
149						512 characters\n");
150				f2fs_usage();
151			}
152			sprintf((char *)f2fs_params.vol_label, "%s", optarg);
153			break;
154		case 'o':
155			f2fs_params.overprovision = atoi(optarg);
156			printf("Info: Overprovision ratio = %u%%\n", atoi(optarg));
157			break;
158		case 's':
159			f2fs_params.segs_per_sec = atoi(optarg);
160			printf("Info: segments per section = %d\n", atoi(optarg));
161			break;
162		case 'a':
163			f2fs_params.heap = atoi(optarg);
164			if (f2fs_params.heap == 0)
165				printf("Info: Allocate without heap-based policy\n");
166			break;
167		case 'z':
168			f2fs_params.secs_per_zone = atoi(optarg);
169			printf("Info: sections per zone = %d\n", atoi(optarg));
170			break;
171		case 'e':
172			f2fs_params.extension_list = strdup(optarg);
173			break;
174		default:
175			printf("Error: Unknown option %c\n",option);
176			f2fs_usage();
177			break;
178		}
179	}
180
181	if ((optind + 1) != argc) {
182		printf("Error: Device not specified\n");
183		f2fs_usage();
184	}
185
186	f2fs_params.reserved_segments  =
187			(100 / f2fs_params.overprovision + 5)
188			* f2fs_params.segs_per_sec;
189	f2fs_params.device_name = argv[optind];
190}
191
192/**
193 * @brief     	Routine to  check if the device is already mounted
194 * @param	None
195 * @return	0 if device is not mounted
196 * 		-1 if already mounted
197 */
198static int8_t f2fs_is_device_mounted()
199{
200	FILE *file;
201	struct mntent *mnt; /* mntent structure to retrieve mount info */
202
203	if ((file = setmntent(MOUNTED, "r")) == NULL)
204		return 0;
205
206	while ((mnt = getmntent(file)) != NULL) {
207		if (!strcmp(f2fs_params.device_name, mnt->mnt_fsname)) {
208			printf("Error: %s is already mounted\n",
209					f2fs_params.device_name);
210			return -1;
211		}
212	}
213	endmntent(file);
214	return 0;
215}
216
217/**
218 * @brief     	Get device info - sector size, number of sectors etc
219 * @param	None
220 * @return	0 if successfully got device info
221 */
222static int8_t f2fs_get_device_info()
223{
224	int32_t fd = 0;
225	int32_t sector_size;
226	struct stat stat_buf;
227	struct hd_geometry geom;
228
229	fd = open(f2fs_params.device_name, O_RDWR);
230	if (fd < 0) {
231		printf("\n\tError: Failed to open the device!!!\n");
232		return -1;
233	}
234	f2fs_params.fd = fd;
235
236	if (fstat(fd, &stat_buf) < 0 ) {
237		printf("\n\tError: Failed to get the device stat!!!\n");
238		return -1;
239	}
240
241	if (S_ISREG(stat_buf.st_mode)) {
242		f2fs_params.total_sectors = stat_buf.st_size /
243			f2fs_params.sector_size;
244	}
245	else if (S_ISBLK(stat_buf.st_mode)) {
246		if (ioctl(fd, BLKSSZGET, &sector_size) < 0 )
247			printf("\n\tError: Cannot get the sector size!!! \
248					Using the default Sector Size\n");
249		else {
250			if (f2fs_params.sector_size < sector_size) {
251				printf("\n\tError: Cannot set the sector size to: %d"
252					" as the device does not support"
253					"\nSetting the sector size to : %d\n",
254					f2fs_params.sector_size, sector_size);
255				f2fs_params.sector_size = sector_size;
256				f2fs_params.sectors_per_blk = PAGE_SIZE / sector_size;
257			}
258		}
259
260		if (ioctl(fd, BLKGETSIZE, &f2fs_params.total_sectors) < 0) {
261			printf("\n\tError: Cannot get the device size\n");
262			return -1;
263		}
264
265		if (ioctl(fd, HDIO_GETGEO, &geom) < 0) {
266			printf("\n\tError: Cannot get the device geometry\n");
267			return -1;
268		}
269		f2fs_params.start_sector = geom.start;
270	}
271	else {
272		printf("\n\n\tError: Volume type is not supported!!!\n");
273		return -1;
274	}
275
276	printf("Info: sector size = %u\n", f2fs_params.sector_size);
277	printf("Info: total sectors = %"PRIu64" (in 512bytes)\n",
278					f2fs_params.total_sectors);
279	if (f2fs_params.total_sectors <
280			(F2FS_MIN_VOLUME_SIZE / DEFAULT_SECTOR_SIZE)) {
281		printf("Error: Min volume size supported is %d\n",
282				F2FS_MIN_VOLUME_SIZE);
283		return -1;
284	}
285
286	return 0;
287}
288
289const char *media_ext_lists[] = {
290	"jpg",
291	"gif",
292	"png",
293	"avi",
294	"divx",
295	"mp4",
296	"mp3",
297	"3gp",
298	"wmv",
299	"wma",
300	"mpeg",
301	"mkv",
302	"mov",
303	"asx",
304	"asf",
305	"wmx",
306	"svi",
307	"wvx",
308	"wm",
309	"mpg",
310	"mpe",
311	"rm",
312	"ogg",
313	NULL
314};
315
316static void configure_extension_list(void)
317{
318	const char **extlist = media_ext_lists;
319	char *ext_str = f2fs_params.extension_list;
320	char *ue;
321	int name_len;
322	int i = 0;
323
324	super_block.extension_count = 0;
325	memset(super_block.extension_list, 0,
326			sizeof(super_block.extension_list));
327
328	while (*extlist) {
329		name_len = strlen(*extlist);
330		memcpy(super_block.extension_list[i++], *extlist, name_len);
331		extlist++;
332	}
333	super_block.extension_count = i - 1;
334
335	if (!ext_str)
336		return;
337
338	/* add user ext list */
339	ue = strtok(ext_str, ",");
340	while (ue != NULL) {
341		name_len = strlen(ue);
342		memcpy(super_block.extension_list[i++], ue, name_len);
343		ue = strtok(NULL, ",");
344		if (i > F2FS_MAX_EXTENSION)
345			break;
346	}
347
348	super_block.extension_count = i - 1;
349
350	free(f2fs_params.extension_list);
351}
352
353
354/**
355 * @brief     	It writes buffer to disk or storage meant to be formatted
356 *		with F2FS.
357 * @param	fd File descriptor for device
358 * @param	buf buffer to be written
359 * @param	offset where to bw written on the device
360 * @param	length length of the device
361 * @return	0 if success
362 */
363static int writetodisk(int32_t fd, void *buf, u_int64_t offset, size_t length)
364{
365	if (lseek64(fd, offset, SEEK_SET) < 0) {
366		printf("\n\tError: While lseek to the derised location!!!\n");
367		return -1;
368	}
369
370	if (write(fd, buf, length) < 0) {
371		printf("\n\tError: While writing data to the disk!!! Error Num : \
372				%d\n", errno);
373		return -1;
374	}
375
376	return 0;
377}
378
379/**
380 * @brief     	It initialize F2FS super block
381 * @param	None
382 * @return	None
383 */
384static int f2fs_prepare_super_block(void)
385{
386	u_int32_t blk_size_bytes;
387	u_int32_t log_sectorsize, log_sectors_per_block;
388	u_int32_t log_blocksize, log_blks_per_seg;
389	u_int32_t segment_size_bytes, zone_size_bytes;
390	u_int32_t sit_segments;
391	u_int32_t blocks_for_sit, blocks_for_nat, blocks_for_ssa;
392	u_int32_t total_valid_blks_available;
393	u_int64_t zone_align_start_offset, diff, total_meta_segments;
394	u_int32_t sit_bitmap_size, max_nat_bitmap_size, max_nat_segments;
395	u_int32_t total_zones;
396
397	super_block.magic = cpu_to_le32(F2FS_SUPER_MAGIC);
398	super_block.major_ver = cpu_to_le16(F2FS_MAJOR_VERSION);
399	super_block.minor_ver = cpu_to_le16(F2FS_MINOR_VERSION);
400
401	log_sectorsize = log_base_2(f2fs_params.sector_size);
402	log_sectors_per_block = log_base_2(f2fs_params.sectors_per_blk);
403	log_blocksize = log_sectorsize + log_sectors_per_block;
404	log_blks_per_seg = log_base_2(f2fs_params.blks_per_seg);
405
406	super_block.log_sectorsize = cpu_to_le32(log_sectorsize);
407
408	if (log_sectorsize < 0) {
409		printf("\n\tError: Failed to get the sector size: %u!\n",
410				f2fs_params.sector_size);
411		return -1;
412	}
413
414	super_block.log_sectors_per_block = cpu_to_le32(log_sectors_per_block);
415
416	if (log_sectors_per_block < 0) {
417		printf("\n\tError: Failed to get sectors per block: %u!\n",
418				f2fs_params.sectors_per_blk);
419		return -1;
420	}
421
422	super_block.log_blocksize = cpu_to_le32(log_blocksize);
423	super_block.log_blocks_per_seg = cpu_to_le32(log_blks_per_seg);
424
425	if (log_blks_per_seg < 0) {
426		printf("\n\tError: Failed to get block per segment: %u!\n",
427				f2fs_params.blks_per_seg);
428		return -1;
429	}
430
431	super_block.segs_per_sec = cpu_to_le32(f2fs_params.segs_per_sec);
432	super_block.secs_per_zone = cpu_to_le32(f2fs_params.secs_per_zone);
433	blk_size_bytes = 1 << log_blocksize;
434	segment_size_bytes = blk_size_bytes * f2fs_params.blks_per_seg;
435	zone_size_bytes =
436		blk_size_bytes * f2fs_params.secs_per_zone *
437		f2fs_params.segs_per_sec * f2fs_params.blks_per_seg;
438
439	super_block.checksum_offset = 0;
440
441	super_block.block_count = cpu_to_le64(
442		(f2fs_params.total_sectors * DEFAULT_SECTOR_SIZE) /
443			blk_size_bytes);
444
445	zone_align_start_offset =
446		(f2fs_params.start_sector * DEFAULT_SECTOR_SIZE +
447		2 * F2FS_BLKSIZE + zone_size_bytes - 1) /
448		zone_size_bytes * zone_size_bytes -
449		f2fs_params.start_sector * DEFAULT_SECTOR_SIZE;
450
451	if (f2fs_params.start_sector % DEFAULT_SECTORS_PER_BLOCK) {
452		printf("WARN: Align start sector number in a unit of pages\n");
453		printf("\ti.e., start sector: %d, ofs:%d (sectors per page: %d)\n",
454				f2fs_params.start_sector,
455				f2fs_params.start_sector % DEFAULT_SECTORS_PER_BLOCK,
456				DEFAULT_SECTORS_PER_BLOCK);
457	}
458
459	super_block.segment_count = cpu_to_le32(
460		((f2fs_params.total_sectors * DEFAULT_SECTOR_SIZE) -
461		zone_align_start_offset) / segment_size_bytes);
462
463	super_block.segment0_blkaddr =
464		cpu_to_le32(zone_align_start_offset / blk_size_bytes);
465	super_block.cp_blkaddr = super_block.segment0_blkaddr;
466
467	printf("Info: zone aligned segment0 blkaddr: %u\n",
468				le32_to_cpu(super_block.segment0_blkaddr));
469
470	super_block.segment_count_ckpt =
471				cpu_to_le32(F2FS_NUMBER_OF_CHECKPOINT_PACK);
472
473	super_block.sit_blkaddr = cpu_to_le32(
474		le32_to_cpu(super_block.segment0_blkaddr) +
475		(le32_to_cpu(super_block.segment_count_ckpt) *
476		(1 << log_blks_per_seg)));
477
478	blocks_for_sit = (le32_to_cpu(super_block.segment_count) +
479			SIT_ENTRY_PER_BLOCK - 1) / SIT_ENTRY_PER_BLOCK;
480
481	sit_segments = (blocks_for_sit + f2fs_params.blks_per_seg - 1)
482			/ f2fs_params.blks_per_seg;
483
484	super_block.segment_count_sit = cpu_to_le32(sit_segments * 2);
485
486	super_block.nat_blkaddr = cpu_to_le32(
487			le32_to_cpu(super_block.sit_blkaddr) +
488			(le32_to_cpu(super_block.segment_count_sit) *
489			 f2fs_params.blks_per_seg));
490
491	total_valid_blks_available = (le32_to_cpu(super_block.segment_count) -
492			(le32_to_cpu(super_block.segment_count_ckpt) +
493			 le32_to_cpu(super_block.segment_count_sit))) *
494			f2fs_params.blks_per_seg;
495
496	blocks_for_nat = (total_valid_blks_available + NAT_ENTRY_PER_BLOCK - 1)
497				/ NAT_ENTRY_PER_BLOCK;
498
499	super_block.segment_count_nat = cpu_to_le32(
500				(blocks_for_nat + f2fs_params.blks_per_seg - 1) /
501				f2fs_params.blks_per_seg);
502	/*
503	 * The number of node segments should not be exceeded a "Threshold".
504	 * This number resizes NAT bitmap area in a CP page.
505	 * So the threshold is determined not to overflow one CP page
506	 */
507	sit_bitmap_size = ((le32_to_cpu(super_block.segment_count_sit) / 2) <<
508				log_blks_per_seg) / 8;
509	max_nat_bitmap_size = 4096 - sizeof(struct f2fs_checkpoint) + 1 -
510			sit_bitmap_size;
511	max_nat_segments = (max_nat_bitmap_size * 8) >> log_blks_per_seg;
512
513	if (le32_to_cpu(super_block.segment_count_nat) > max_nat_segments)
514		super_block.segment_count_nat = cpu_to_le32(max_nat_segments);
515
516	super_block.segment_count_nat = cpu_to_le32(
517			le32_to_cpu(super_block.segment_count_nat) * 2);
518
519	super_block.ssa_blkaddr = cpu_to_le32(
520			le32_to_cpu(super_block.nat_blkaddr) +
521			le32_to_cpu(super_block.segment_count_nat) *
522			f2fs_params.blks_per_seg);
523
524	total_valid_blks_available = (le32_to_cpu(super_block.segment_count) -
525			(le32_to_cpu(super_block.segment_count_ckpt) +
526			le32_to_cpu(super_block.segment_count_sit) +
527			le32_to_cpu(super_block.segment_count_nat))) *
528			f2fs_params.blks_per_seg;
529
530	blocks_for_ssa = total_valid_blks_available /
531				f2fs_params.blks_per_seg + 1;
532
533	super_block.segment_count_ssa = cpu_to_le32(
534			(blocks_for_ssa + f2fs_params.blks_per_seg - 1) /
535			f2fs_params.blks_per_seg);
536
537	total_meta_segments = le32_to_cpu(super_block.segment_count_ckpt) +
538		le32_to_cpu(super_block.segment_count_sit) +
539		le32_to_cpu(super_block.segment_count_nat) +
540		le32_to_cpu(super_block.segment_count_ssa);
541	diff = total_meta_segments % (f2fs_params.segs_per_sec *
542						f2fs_params.secs_per_zone);
543	if (diff)
544		super_block.segment_count_ssa = cpu_to_le32(
545			le32_to_cpu(super_block.segment_count_ssa) +
546			(f2fs_params.segs_per_sec * f2fs_params.secs_per_zone -
547			 diff));
548
549	super_block.main_blkaddr = cpu_to_le32(
550			le32_to_cpu(super_block.ssa_blkaddr) +
551			(le32_to_cpu(super_block.segment_count_ssa) *
552			 f2fs_params.blks_per_seg));
553
554	super_block.segment_count_main = cpu_to_le32(
555			le32_to_cpu(super_block.segment_count) -
556			(le32_to_cpu(super_block.segment_count_ckpt)
557			 + le32_to_cpu(super_block.segment_count_sit) +
558			 le32_to_cpu(super_block.segment_count_nat) +
559			 le32_to_cpu(super_block.segment_count_ssa)));
560
561	super_block.section_count = cpu_to_le32(
562			le32_to_cpu(super_block.segment_count_main)
563			/ f2fs_params.segs_per_sec);
564
565	super_block.segment_count_main = cpu_to_le32(
566			le32_to_cpu(super_block.section_count) *
567			f2fs_params.segs_per_sec);
568
569	if ((le32_to_cpu(super_block.segment_count_main) - 2) <
570					f2fs_params.reserved_segments) {
571		printf("Error: Device size is not sufficient for F2FS volume, \
572			more segment needed =%u",
573			f2fs_params.reserved_segments -
574			(le32_to_cpu(super_block.segment_count_main) - 2));
575		return -1;
576	}
577
578	uuid_generate(super_block.uuid);
579
580	ASCIIToUNICODE(super_block.volume_name, f2fs_params.vol_label);
581
582	super_block.node_ino = cpu_to_le32(1);
583	super_block.meta_ino = cpu_to_le32(2);
584	super_block.root_ino = cpu_to_le32(3);
585
586	total_zones = ((le32_to_cpu(super_block.segment_count_main) - 1) /
587			f2fs_params.segs_per_sec) /
588			f2fs_params.secs_per_zone;
589	if (total_zones <= 6) {
590		printf("\n\tError: %d zones: Need more zones \
591			by shrinking zone size\n", total_zones);
592		return -1;
593	}
594
595	if (f2fs_params.heap) {
596		f2fs_params.cur_seg[CURSEG_HOT_NODE] = (total_zones - 1) *
597					f2fs_params.segs_per_sec *
598					f2fs_params.secs_per_zone +
599					((f2fs_params.secs_per_zone - 1) *
600					f2fs_params.segs_per_sec);
601		f2fs_params.cur_seg[CURSEG_WARM_NODE] =
602					f2fs_params.cur_seg[CURSEG_HOT_NODE] -
603					f2fs_params.segs_per_sec *
604					f2fs_params.secs_per_zone;
605		f2fs_params.cur_seg[CURSEG_COLD_NODE] =
606					f2fs_params.cur_seg[CURSEG_WARM_NODE] -
607					f2fs_params.segs_per_sec *
608					f2fs_params.secs_per_zone;
609		f2fs_params.cur_seg[CURSEG_HOT_DATA] =
610					f2fs_params.cur_seg[CURSEG_COLD_NODE] -
611					f2fs_params.segs_per_sec *
612					f2fs_params.secs_per_zone;
613		f2fs_params.cur_seg[CURSEG_COLD_DATA] = 0;
614		f2fs_params.cur_seg[CURSEG_WARM_DATA] =
615					f2fs_params.cur_seg[CURSEG_COLD_DATA] +
616					f2fs_params.segs_per_sec *
617					f2fs_params.secs_per_zone;
618	} else {
619		f2fs_params.cur_seg[CURSEG_HOT_NODE] = 0;
620		f2fs_params.cur_seg[CURSEG_WARM_NODE] =
621					f2fs_params.cur_seg[CURSEG_HOT_NODE] +
622					f2fs_params.segs_per_sec *
623					f2fs_params.secs_per_zone;
624		f2fs_params.cur_seg[CURSEG_COLD_NODE] =
625					f2fs_params.cur_seg[CURSEG_WARM_NODE] +
626					f2fs_params.segs_per_sec *
627					f2fs_params.secs_per_zone;
628		f2fs_params.cur_seg[CURSEG_HOT_DATA] =
629					f2fs_params.cur_seg[CURSEG_COLD_NODE] +
630					f2fs_params.segs_per_sec *
631					f2fs_params.secs_per_zone;
632		f2fs_params.cur_seg[CURSEG_COLD_DATA] =
633					f2fs_params.cur_seg[CURSEG_HOT_DATA] +
634					f2fs_params.segs_per_sec *
635					f2fs_params.secs_per_zone;
636		f2fs_params.cur_seg[CURSEG_WARM_DATA] =
637					f2fs_params.cur_seg[CURSEG_COLD_DATA] +
638					f2fs_params.segs_per_sec *
639					f2fs_params.secs_per_zone;
640	}
641
642	configure_extension_list();
643
644	return 0;
645}
646
647/**
648 * @brief     	It initialize SIT Data structure
649 * @param	None
650 * @return	0 if success
651 */
652static int8_t f2fs_init_sit_area(void)
653{
654	u_int32_t blk_size_bytes;
655	u_int32_t seg_size_bytes;
656	u_int32_t index = 0;
657	u_int64_t sit_seg_blk_offset = 0;
658	u_int8_t *zero_buf = NULL;
659
660	blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize);
661	seg_size_bytes = (1 << le32_to_cpu(super_block.log_blocks_per_seg)) *
662				blk_size_bytes;
663
664	zero_buf = calloc(sizeof(u_int8_t), seg_size_bytes);
665	if(zero_buf == NULL) {
666		printf("\n\tError: Calloc Failed for sit_zero_buf!!!\n");
667		return -1;
668	}
669
670	sit_seg_blk_offset = le32_to_cpu(super_block.sit_blkaddr) *
671						blk_size_bytes;
672
673	for (index = 0;
674		index < (le32_to_cpu(super_block.segment_count_sit) / 2);
675								index++) {
676		if (writetodisk(f2fs_params.fd, zero_buf, sit_seg_blk_offset,
677					seg_size_bytes) < 0) {
678			printf("\n\tError: While zeroing out the sit area \
679					on disk!!!\n");
680			return -1;
681		}
682		sit_seg_blk_offset = sit_seg_blk_offset + seg_size_bytes;
683	}
684
685	free(zero_buf);
686	return 0 ;
687}
688
689/**
690 * @brief     	It initialize NAT Area
691 * @param	None
692 * @return	0 if success
693 */
694static int8_t f2fs_init_nat_area(void)
695{
696	u_int32_t blk_size_bytes;
697	u_int32_t seg_size_bytes;
698	u_int32_t index = 0;
699	u_int64_t nat_seg_blk_offset = 0;
700	u_int8_t *nat_buf = NULL;
701
702	blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize);
703	seg_size_bytes = (1 << le32_to_cpu(super_block.log_blocks_per_seg)) *
704					blk_size_bytes;
705
706	nat_buf = calloc(sizeof(u_int8_t), seg_size_bytes);
707	if (nat_buf == NULL) {
708		printf("\n\tError: Calloc Failed for nat_zero_blk!!!\n");
709		return -1;
710	}
711
712	nat_seg_blk_offset = le32_to_cpu(super_block.nat_blkaddr) *
713							blk_size_bytes;
714
715	for (index = 0;
716		index < (le32_to_cpu(super_block.segment_count_nat) / 2);
717								index++) {
718		if (writetodisk(f2fs_params.fd, nat_buf, nat_seg_blk_offset,
719					seg_size_bytes) < 0) {
720			printf("\n\tError: While zeroing out the nat area \
721					on disk!!!\n");
722			return -1;
723		}
724		nat_seg_blk_offset = nat_seg_blk_offset + (2 * seg_size_bytes);
725	}
726
727	free(nat_buf);
728	return 0 ;
729}
730
731#define CRCPOLY_LE 0xedb88320
732
733unsigned int f2fs_cal_crc32(unsigned int crc, void *buff, unsigned int len)
734{
735	int i;
736	unsigned char *p = (unsigned char *)buff;
737	while (len--) {
738		crc ^= *p++;
739		for (i = 0; i < 8; i++)
740			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
741	}
742	return crc;
743}
744
745/**
746 * @brief     	It writes check poiint pack on Check point Area
747 * @param	None
748 * @return	0 if succes
749 */
750static int8_t f2fs_write_check_point_pack(void)
751{
752	struct f2fs_checkpoint *ckp = NULL;
753	struct f2fs_summary_block *sum = NULL;
754	u_int32_t blk_size_bytes;
755	u_int64_t cp_seg_blk_offset = 0;
756	u_int32_t crc = 0;
757	int i;
758
759	ckp = calloc(F2FS_CP_BLOCK_SIZE, 1);
760	if (ckp == NULL) {
761		printf("\n\tError: Calloc Failed for f2fs_checkpoint!!!\n");
762		return -1;
763	}
764
765	sum = calloc(sizeof(struct f2fs_summary_block), 1);
766	if (sum == NULL) {
767		printf("\n\tError: Calloc Failed for summay_node!!!\n");
768		return -1;
769	}
770
771	/* 1. cp page 1 of checkpoint pack 1 */
772	ckp->checkpoint_ver = 1;
773	ckp->cur_node_segno[0] =
774		cpu_to_le32(f2fs_params.cur_seg[CURSEG_HOT_NODE]);
775	ckp->cur_node_segno[1] =
776		cpu_to_le32(f2fs_params.cur_seg[CURSEG_WARM_NODE]);
777	ckp->cur_node_segno[2] =
778		cpu_to_le32(f2fs_params.cur_seg[CURSEG_COLD_NODE]);
779	ckp->cur_data_segno[0] =
780		cpu_to_le32(f2fs_params.cur_seg[CURSEG_HOT_DATA]);
781	ckp->cur_data_segno[1] =
782		cpu_to_le32(f2fs_params.cur_seg[CURSEG_WARM_DATA]);
783	ckp->cur_data_segno[2] =
784		cpu_to_le32(f2fs_params.cur_seg[CURSEG_COLD_DATA]);
785	for (i = 3; i < MAX_ACTIVE_NODE_LOGS; i++) {
786		ckp->cur_node_segno[i] = 0xffffffff;
787		ckp->cur_data_segno[i] = 0xffffffff;
788	}
789
790	ckp->cur_node_blkoff[0] = cpu_to_le16(1);
791	ckp->cur_data_blkoff[0] = cpu_to_le16(1);
792	ckp->valid_block_count = cpu_to_le64(2);
793	ckp->rsvd_segment_count = cpu_to_le32(f2fs_params.reserved_segments);
794	ckp->overprov_segment_count = cpu_to_le32(
795			(le32_to_cpu(super_block.segment_count_main) -
796			le32_to_cpu(ckp->rsvd_segment_count)) *
797			f2fs_params.overprovision / 100);
798	ckp->overprov_segment_count = cpu_to_le32(
799			le32_to_cpu(ckp->overprov_segment_count) +
800			le32_to_cpu(ckp->rsvd_segment_count));
801
802	/* main segments - reserved segments - (node + data segments) */
803	ckp->free_segment_count = cpu_to_le32(
804			le32_to_cpu(super_block.segment_count_main) - 6);
805	ckp->user_block_count = cpu_to_le64(
806			((le32_to_cpu(ckp->free_segment_count) + 6 -
807			le32_to_cpu(ckp->overprov_segment_count)) *
808			 f2fs_params.blks_per_seg));
809	ckp->cp_pack_total_block_count = cpu_to_le32(8);
810	ckp->ckpt_flags |= CP_UMOUNT_FLAG;
811	ckp->cp_pack_start_sum = cpu_to_le32(1);
812	ckp->valid_node_count = cpu_to_le32(1);
813	ckp->valid_inode_count = cpu_to_le32(1);
814	ckp->next_free_nid = cpu_to_le32(
815			le32_to_cpu(super_block.root_ino) + 1);
816
817	ckp->sit_ver_bitmap_bytesize = cpu_to_le32(
818			((le32_to_cpu(super_block.segment_count_sit) / 2) <<
819			 le32_to_cpu(super_block.log_blocks_per_seg)) / 8);
820
821	ckp->nat_ver_bitmap_bytesize = cpu_to_le32(
822			((le32_to_cpu(super_block.segment_count_nat) / 2) <<
823			 le32_to_cpu(super_block.log_blocks_per_seg)) / 8);
824
825	ckp->checksum_offset = cpu_to_le32(4092);
826
827	crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, ckp,
828					le32_to_cpu(ckp->checksum_offset));
829	*((u_int32_t *)((unsigned char *)ckp +
830				le32_to_cpu(ckp->checksum_offset))) = crc;
831
832	blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize);
833	cp_seg_blk_offset =
834		le32_to_cpu(super_block.segment0_blkaddr) * blk_size_bytes;
835
836	if (writetodisk(f2fs_params.fd, ckp, cp_seg_blk_offset,
837				F2FS_CP_BLOCK_SIZE) < 0) {
838		printf("\n\tError: While writing the ckp to disk!!!\n");
839		return -1;
840	}
841
842	/* 2. Prepare and write Segment summary for data blocks */
843	memset(sum, 0, sizeof(struct f2fs_summary_block));
844	SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
845
846	sum->entries[0].nid = super_block.root_ino;
847	sum->entries[0].ofs_in_node = 0;
848
849	cp_seg_blk_offset += blk_size_bytes;
850	if (writetodisk(f2fs_params.fd, sum, cp_seg_blk_offset,
851				sizeof(struct f2fs_summary_block)) < 0) {
852		printf("\n\tError: While writing the sum_blk to disk!!!\n");
853		return -1;
854	}
855
856	/* 3. Fill segment summary for data block to zero. */
857	memset(sum, 0, sizeof(struct f2fs_summary_block));
858	SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
859
860	cp_seg_blk_offset += blk_size_bytes;
861	if (writetodisk(f2fs_params.fd, sum, cp_seg_blk_offset,
862				sizeof(struct f2fs_summary_block)) < 0) {
863		printf("\n\tError: While writing the sum_blk to disk!!!\n");
864		return -1;
865	}
866
867	/* 4. Fill segment summary for data block to zero. */
868	memset(sum, 0, sizeof(struct f2fs_summary_block));
869	SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
870
871	/* inode sit for root */
872	sum->n_sits = cpu_to_le16(6);
873	sum->sit_j.entries[0].segno = ckp->cur_node_segno[0];
874	sum->sit_j.entries[0].se.vblocks = cpu_to_le16((CURSEG_HOT_NODE << 10) | 1);
875	f2fs_set_bit(0, sum->sit_j.entries[0].se.valid_map);
876	sum->sit_j.entries[1].segno = ckp->cur_node_segno[1];
877	sum->sit_j.entries[1].se.vblocks = cpu_to_le16((CURSEG_WARM_NODE << 10));
878	sum->sit_j.entries[2].segno = ckp->cur_node_segno[2];
879	sum->sit_j.entries[2].se.vblocks = cpu_to_le16((CURSEG_COLD_NODE << 10));
880
881	/* data sit for root */
882	sum->sit_j.entries[3].segno = ckp->cur_data_segno[0];
883	sum->sit_j.entries[3].se.vblocks = cpu_to_le16((CURSEG_HOT_DATA << 10) | 1);
884	f2fs_set_bit(0, sum->sit_j.entries[3].se.valid_map);
885	sum->sit_j.entries[4].segno = ckp->cur_data_segno[1];
886	sum->sit_j.entries[4].se.vblocks = cpu_to_le16((CURSEG_WARM_DATA << 10));
887	sum->sit_j.entries[5].segno = ckp->cur_data_segno[2];
888	sum->sit_j.entries[5].se.vblocks = cpu_to_le16((CURSEG_COLD_DATA << 10));
889
890	cp_seg_blk_offset += blk_size_bytes;
891	if (writetodisk(f2fs_params.fd, sum, cp_seg_blk_offset,
892				sizeof(struct f2fs_summary_block)) < 0) {
893		printf("\n\tError: While writing the sum_blk to disk!!!\n");
894		return -1;
895	}
896
897	/* 5. Prepare and write Segment summary for node blocks */
898	memset(sum, 0, sizeof(struct f2fs_summary_block));
899	SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
900
901	sum->entries[0].nid = super_block.root_ino;
902	sum->entries[0].ofs_in_node = 0;
903
904	cp_seg_blk_offset += blk_size_bytes;
905	if (writetodisk(f2fs_params.fd, sum, cp_seg_blk_offset,
906				sizeof(struct f2fs_summary_block)) < 0) {
907		printf("\n\tError: While writing the sum_blk to disk!!!\n");
908		return -1;
909	}
910
911	/* 6. Fill segment summary for data block to zero. */
912	memset(sum, 0, sizeof(struct f2fs_summary_block));
913	SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
914
915	cp_seg_blk_offset += blk_size_bytes;
916	if (writetodisk(f2fs_params.fd, sum, cp_seg_blk_offset,
917				sizeof(struct f2fs_summary_block)) < 0) {
918		printf("\n\tError: While writing the sum_blk to disk!!!\n");
919		return -1;
920	}
921
922	/* 7. Fill segment summary for data block to zero. */
923	memset(sum, 0, sizeof(struct f2fs_summary_block));
924	SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
925	cp_seg_blk_offset += blk_size_bytes;
926	if (writetodisk(f2fs_params.fd, sum, cp_seg_blk_offset,
927				sizeof(struct f2fs_summary_block)) < 0) {
928		printf("\n\tError: While writing the sum_blk to disk!!!\n");
929		return -1;
930	}
931
932	/* 8. cp page2 */
933	cp_seg_blk_offset += blk_size_bytes;
934	if (writetodisk(f2fs_params.fd, ckp, cp_seg_blk_offset,
935				F2FS_CP_BLOCK_SIZE) < 0) {
936		printf("\n\tError: While writing the ckp to disk!!!\n");
937		return -1;
938	}
939
940	/* 9. cp page 1 of check point pack 2
941	 * Initiatialize other checkpoint pack with version zero
942	 */
943	ckp->checkpoint_ver = 0;
944
945	crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, ckp,
946					le32_to_cpu(ckp->checksum_offset));
947	*((u_int32_t *)((unsigned char *)ckp +
948				le32_to_cpu(ckp->checksum_offset))) = crc;
949
950	cp_seg_blk_offset = (le32_to_cpu(super_block.segment0_blkaddr) +
951				f2fs_params.blks_per_seg) *
952				blk_size_bytes;
953	if (writetodisk(f2fs_params.fd, ckp,
954				cp_seg_blk_offset, F2FS_CP_BLOCK_SIZE) < 0) {
955		printf("\n\tError: While writing the ckp to disk!!!\n");
956		return -1;
957	}
958
959	free(sum) ;
960	free(ckp) ;
961	return	0;
962}
963
964/**
965 * @brief     	It writes super block on device
966 * @param	None
967 * @return	0 if success
968 */
969static int8_t f2fs_write_super_block(void)
970{
971	u_int32_t index = 0;
972	u_int8_t *zero_buff;
973
974	zero_buff = calloc(F2FS_BLKSIZE, 1);
975
976	memcpy(zero_buff + F2FS_SUPER_OFFSET, &super_block,
977						sizeof(super_block));
978
979	for (index = 0; index < 2; index++) {
980		if (writetodisk(f2fs_params.fd, zero_buff,
981				index * F2FS_BLKSIZE, F2FS_BLKSIZE) < 0) {
982			printf("\n\tError: While while writing supe_blk \
983					on disk!!! index : %d\n", index);
984			return -1;
985		}
986	}
987
988	free(zero_buff);
989	return 0;
990}
991
992/**
993 * @brief     	It initializes and writes root inode on device.
994 * @param	None
995 * @return	0 if success
996 */
997static int8_t f2fs_write_root_inode(void)
998{
999	struct f2fs_node *raw_node = NULL;
1000	u_int32_t blk_size_bytes;
1001	u_int64_t data_blk_nor;
1002	u_int64_t main_area_node_seg_blk_offset = 0;
1003
1004	raw_node = calloc(sizeof(struct f2fs_node), 1);
1005	if (raw_node == NULL) {
1006		printf("\n\tError: Calloc Failed for raw_node!!!\n");
1007		return -1;
1008	}
1009
1010	raw_node->footer.nid = super_block.root_ino;
1011	raw_node->footer.ino = super_block.root_ino;
1012	raw_node->footer.cp_ver = cpu_to_le64(1);
1013	raw_node->footer.next_blkaddr = cpu_to_le32(
1014			le32_to_cpu(super_block.main_blkaddr) +
1015			f2fs_params.cur_seg[CURSEG_HOT_NODE] *
1016			f2fs_params.blks_per_seg + 1);
1017
1018	raw_node->i.i_mode = cpu_to_le16(0x41ed);
1019	raw_node->i.i_links = cpu_to_le32(2);
1020	raw_node->i.i_uid = cpu_to_le32(getuid());
1021	raw_node->i.i_gid = cpu_to_le32(getgid());
1022
1023	blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize);
1024	raw_node->i.i_size = cpu_to_le64(1 * blk_size_bytes); /* dentry */
1025	raw_node->i.i_blocks = cpu_to_le64(2);
1026
1027	raw_node->i.i_atime = cpu_to_le32(time(NULL));
1028	raw_node->i.i_atime_nsec = 0;
1029	raw_node->i.i_ctime = cpu_to_le32(time(NULL));
1030	raw_node->i.i_ctime_nsec = 0;
1031	raw_node->i.i_mtime = cpu_to_le32(time(NULL));
1032	raw_node->i.i_mtime_nsec = 0;
1033	raw_node->i.i_generation = 0;
1034	raw_node->i.i_xattr_nid = 0;
1035	raw_node->i.i_flags = 0;
1036	raw_node->i.i_current_depth = cpu_to_le32(1);
1037
1038	data_blk_nor = le32_to_cpu(super_block.main_blkaddr) +
1039		f2fs_params.cur_seg[CURSEG_HOT_DATA] * f2fs_params.blks_per_seg;
1040	raw_node->i.i_addr[0] = cpu_to_le32(data_blk_nor);
1041
1042	raw_node->i.i_ext.fofs = 0;
1043	raw_node->i.i_ext.blk_addr = cpu_to_le32(data_blk_nor);
1044	raw_node->i.i_ext.len = cpu_to_le32(1);
1045
1046	main_area_node_seg_blk_offset = le32_to_cpu(super_block.main_blkaddr);
1047	main_area_node_seg_blk_offset += f2fs_params.cur_seg[CURSEG_HOT_NODE] *
1048					f2fs_params.blks_per_seg;
1049        main_area_node_seg_blk_offset *= blk_size_bytes;
1050
1051	if (writetodisk(f2fs_params.fd, raw_node, main_area_node_seg_blk_offset,
1052				sizeof(struct f2fs_node)) < 0) {
1053		printf("\n\tError: While writing the raw_node to disk!!!\n");
1054		return -1;
1055	}
1056
1057	memset(raw_node, 0xff, sizeof(struct f2fs_node));
1058
1059	if (writetodisk(f2fs_params.fd, raw_node,
1060				main_area_node_seg_blk_offset + 4096,
1061				sizeof(struct f2fs_node)) < 0) {
1062		printf("\n\tError: While writing the raw_node to disk!!!\n");
1063		return -1;
1064	}
1065	free(raw_node);
1066	return 0;
1067}
1068
1069/**
1070 * @brief     	It updates NAT for root Inode
1071 * @param	None
1072 * @return	0 if success
1073 */
1074static int8_t f2fs_update_nat_root(void)
1075{
1076	struct f2fs_nat_block *nat_blk = NULL;
1077	u_int32_t blk_size_bytes;
1078	u_int64_t nat_seg_blk_offset = 0;
1079
1080	nat_blk = calloc(sizeof(struct f2fs_nat_block), 1);
1081	if(nat_blk == NULL) {
1082		printf("\n\tError: Calloc Failed for nat_blk!!!\n");
1083		return -1;
1084	}
1085
1086	/* update root */
1087	nat_blk->entries[super_block.root_ino].block_addr = cpu_to_le32(
1088		le32_to_cpu(super_block.main_blkaddr) +
1089		f2fs_params.cur_seg[CURSEG_HOT_NODE] * f2fs_params.blks_per_seg);
1090	nat_blk->entries[super_block.root_ino].ino = super_block.root_ino;
1091
1092	/* update node nat */
1093	nat_blk->entries[super_block.node_ino].block_addr = cpu_to_le32(1);
1094	nat_blk->entries[super_block.node_ino].ino = super_block.node_ino;
1095
1096	/* update meta nat */
1097	nat_blk->entries[super_block.meta_ino].block_addr = cpu_to_le32(1);
1098	nat_blk->entries[super_block.meta_ino].ino = super_block.meta_ino;
1099
1100	blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize);
1101
1102	nat_seg_blk_offset = le32_to_cpu(super_block.nat_blkaddr) *
1103							blk_size_bytes;
1104
1105	if (writetodisk(f2fs_params.fd, nat_blk, nat_seg_blk_offset,
1106				sizeof(struct f2fs_nat_block)) < 0) {
1107		printf("\n\tError: While writing the nat_blk set0 to disk!!!\n");
1108		return -1;
1109	}
1110
1111	free(nat_blk);
1112	return 0;
1113}
1114
1115/**
1116 * @brief     	It updates default dentries in Root Inode
1117 * @param	None
1118 * @return	0 if success
1119 */
1120static int8_t f2fs_add_default_dentry_root(void)
1121{
1122	struct f2fs_dentry_block *dent_blk = NULL;
1123	u_int32_t blk_size_bytes;
1124	u_int64_t data_blk_offset = 0;
1125
1126	dent_blk = calloc(sizeof(struct f2fs_dentry_block), 1);
1127	if(dent_blk == NULL) {
1128		printf("\n\tError: Calloc Failed for dent_blk!!!\n");
1129		return -1;
1130	}
1131
1132	dent_blk->dentry[0].hash_code = 0;
1133	dent_blk->dentry[0].ino = super_block.root_ino;
1134	dent_blk->dentry[0].name_len = cpu_to_le16(1);
1135	dent_blk->dentry[0].file_type = F2FS_FT_DIR;
1136	memcpy(dent_blk->filename[0], ".", 1);
1137
1138	dent_blk->dentry[1].hash_code = 0;
1139	dent_blk->dentry[1].ino = super_block.root_ino;
1140	dent_blk->dentry[1].name_len = cpu_to_le16(2);
1141	dent_blk->dentry[1].file_type = F2FS_FT_DIR;
1142	memcpy(dent_blk->filename[1], "..", 2);
1143
1144	/* bitmap for . and .. */
1145	dent_blk->dentry_bitmap[0] = (1 << 1) | (1 << 0);
1146	blk_size_bytes = 1 << le32_to_cpu(super_block.log_blocksize);
1147	data_blk_offset = (le32_to_cpu(super_block.main_blkaddr) +
1148			f2fs_params.cur_seg[CURSEG_HOT_DATA] *
1149			f2fs_params.blks_per_seg) * blk_size_bytes;
1150
1151	if (writetodisk(f2fs_params.fd, dent_blk, data_blk_offset,
1152				sizeof(struct f2fs_dentry_block)) < 0) {
1153		printf("\n\tError: While writing the dentry_blk to disk!!!\n");
1154		return -1;
1155	}
1156
1157	free(dent_blk);
1158	return 0;
1159}
1160
1161/**
1162 * @brief     	It creates root directory on device.
1163 * @param	None
1164 * @return	0 if success
1165 */
1166static int8_t f2fs_create_root_dir(void)
1167{
1168	int8_t err = 0;
1169
1170	err = f2fs_write_root_inode();
1171	if (err < 0) {
1172		printf("\n\tError: Failed to write root inode!!!\n");
1173		goto exit;
1174	}
1175
1176	err = f2fs_update_nat_root();
1177	if (err < 0) {
1178		printf("\n\tError: Failed to update NAT for root!!!\n");
1179		goto exit;
1180	}
1181
1182	err = f2fs_add_default_dentry_root();
1183	if (err < 0) {
1184		printf("\n\tError: Failed to add default dentries for root!!!\n");
1185		goto exit;
1186	}
1187exit:
1188	if (err)
1189		printf("\n\tError: Could not create the root directory!!!\n");
1190
1191	return err;
1192}
1193
1194int f2fs_trim_device()
1195{
1196	unsigned long long range[2];
1197	struct stat stat_buf;
1198
1199	range[0] = 0;
1200	range[1] = f2fs_params.total_sectors * DEFAULT_SECTOR_SIZE;
1201
1202	if (fstat(f2fs_params.fd, &stat_buf) < 0 ) {
1203		printf("\n\tError: Failed to get the device stat!!!\n");
1204		return -1;
1205	}
1206
1207	if (S_ISREG(stat_buf.st_mode))
1208		return 0;
1209	else if (S_ISBLK(stat_buf.st_mode)) {
1210		if (ioctl(f2fs_params.fd, BLKDISCARD, &range) < 0)
1211			printf("Info: This device doesn't support TRIM\n");
1212	} else
1213		return -1;
1214	return 0;
1215}
1216
1217/**
1218 * @brief     	It s a routine to fromat device with F2FS on-disk layout
1219 * @param	None
1220 * @return	0 if success
1221 */
1222static int8_t f2fs_format_device(void)
1223{
1224	int8_t err = 0;
1225
1226	err= f2fs_prepare_super_block();
1227	if (err < 0)
1228		goto exit;
1229
1230	err = f2fs_trim_device();
1231	if (err < 0) {
1232		printf("\n\tError: Failed to trim whole device!!!\n");
1233		goto exit;
1234	}
1235
1236	err = f2fs_init_sit_area();
1237	if (err < 0) {
1238		printf("\n\tError: Failed to Initialise the SIT AREA!!!\n");
1239		goto exit;
1240	}
1241
1242	err = f2fs_init_nat_area();
1243	if (err < 0) {
1244		printf("\n\tError: Failed to Initialise the NAT AREA!!!\n");
1245		goto exit;
1246	}
1247
1248	err = f2fs_create_root_dir();
1249	if (err < 0) {
1250		printf("\n\tError: Failed to create the root directory!!!\n");
1251		goto exit;
1252	}
1253
1254	err = f2fs_write_check_point_pack();
1255	if (err < 0) {
1256		printf("\n\tError: Failed to write the check point pack!!!\n");
1257		goto exit;
1258	}
1259
1260	err = f2fs_write_super_block();
1261	if (err < 0) {
1262		printf("\n\tError: Failed to write the Super Block!!!\n");
1263		goto exit;
1264	}
1265exit:
1266	if (err)
1267		printf("\n\tError: Could not format the device!!!\n");
1268
1269	/*
1270	 * We should call fsync() to flush out all the dirty pages
1271	 * in the block device page cache.
1272	 */
1273	if (fsync(f2fs_params.fd) < 0)
1274		printf("\n\tError: Could not conduct fsync!!!\n");
1275
1276	if (close(f2fs_params.fd) < 0)
1277		printf("\n\tError: Failed to close device file!!!\n");
1278
1279	return err;
1280}
1281
1282/**
1283 * @brief     	main function of F2Fs utility
1284 * @param	argc count of argument
1285 * @param	argv array of arguments
1286 * @return	0 if success
1287 */
1288int main(int argc, char *argv[])
1289{
1290	f2fs_init_global_parameters();
1291
1292	f2fs_parse_options(argc, argv);
1293
1294	if (f2fs_is_device_mounted() < 0)
1295		return -1;
1296
1297	if (f2fs_get_device_info() < 0)
1298		return -1;
1299
1300	if (f2fs_format_device() < 0)
1301		return -1;
1302
1303	printf("Info: format successful\n");
1304
1305	return 0;
1306}
1307