15e5c12b0Sopenharmony_ci/**
25e5c12b0Sopenharmony_ci * f2fs_format_utils.c
35e5c12b0Sopenharmony_ci *
45e5c12b0Sopenharmony_ci * Copyright (c) 2014 Samsung Electronics Co., Ltd.
55e5c12b0Sopenharmony_ci *             http://www.samsung.com/
65e5c12b0Sopenharmony_ci *
75e5c12b0Sopenharmony_ci * Dual licensed under the GPL or LGPL version 2 licenses.
85e5c12b0Sopenharmony_ci */
95e5c12b0Sopenharmony_ci#ifndef _LARGEFILE_SOURCE
105e5c12b0Sopenharmony_ci#define _LARGEFILE_SOURCE
115e5c12b0Sopenharmony_ci#endif
125e5c12b0Sopenharmony_ci#ifndef _LARGEFILE64_SOURCE
135e5c12b0Sopenharmony_ci#define _LARGEFILE64_SOURCE
145e5c12b0Sopenharmony_ci#endif
155e5c12b0Sopenharmony_ci#ifndef _GNU_SOURCE
165e5c12b0Sopenharmony_ci#define _GNU_SOURCE
175e5c12b0Sopenharmony_ci#endif
185e5c12b0Sopenharmony_ci
195e5c12b0Sopenharmony_ci#ifndef _FILE_OFFSET_BITS
205e5c12b0Sopenharmony_ci#define _FILE_OFFSET_BITS 64
215e5c12b0Sopenharmony_ci#endif
225e5c12b0Sopenharmony_ci
235e5c12b0Sopenharmony_ci#include <f2fs_fs.h>
245e5c12b0Sopenharmony_ci
255e5c12b0Sopenharmony_ci#include <stdio.h>
265e5c12b0Sopenharmony_ci#include <unistd.h>
275e5c12b0Sopenharmony_ci#include <stdlib.h>
285e5c12b0Sopenharmony_ci#include <stdbool.h>
295e5c12b0Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H
305e5c12b0Sopenharmony_ci#include <sys/ioctl.h>
315e5c12b0Sopenharmony_ci#endif
325e5c12b0Sopenharmony_ci#include <sys/stat.h>
335e5c12b0Sopenharmony_ci#include <fcntl.h>
345e5c12b0Sopenharmony_ci
355e5c12b0Sopenharmony_ci#ifdef HAVE_LINUX_FS_H
365e5c12b0Sopenharmony_ci#include <linux/fs.h>
375e5c12b0Sopenharmony_ci#endif
385e5c12b0Sopenharmony_ci#ifdef HAVE_LINUX_FALLOC_H
395e5c12b0Sopenharmony_ci#include <linux/falloc.h>
405e5c12b0Sopenharmony_ci#endif
415e5c12b0Sopenharmony_ci
425e5c12b0Sopenharmony_ci#ifdef __linux__
435e5c12b0Sopenharmony_ci#ifndef BLKDISCARD
445e5c12b0Sopenharmony_ci#define BLKDISCARD	_IO(0x12,119)
455e5c12b0Sopenharmony_ci#endif
465e5c12b0Sopenharmony_ci#ifndef BLKSECDISCARD
475e5c12b0Sopenharmony_ci#define BLKSECDISCARD	_IO(0x12,125)
485e5c12b0Sopenharmony_ci#endif
495e5c12b0Sopenharmony_ci#endif
505e5c12b0Sopenharmony_ci
515e5c12b0Sopenharmony_ci#if defined(FALLOC_FL_PUNCH_HOLE) || defined(BLKDISCARD) || \
525e5c12b0Sopenharmony_ci	defined(BLKSECDISCARD)
535e5c12b0Sopenharmony_cistatic int trim_device(int i)
545e5c12b0Sopenharmony_ci{
555e5c12b0Sopenharmony_ci	unsigned long long range[2];
565e5c12b0Sopenharmony_ci	struct stat *stat_buf;
575e5c12b0Sopenharmony_ci	struct device_info *dev = c.devices + i;
585e5c12b0Sopenharmony_ci	uint64_t bytes = dev->total_sectors * dev->sector_size;
595e5c12b0Sopenharmony_ci	int fd = dev->fd;
605e5c12b0Sopenharmony_ci
615e5c12b0Sopenharmony_ci	stat_buf = malloc(sizeof(struct stat));
625e5c12b0Sopenharmony_ci	if (stat_buf == NULL) {
635e5c12b0Sopenharmony_ci		MSG(1, "\tError: Malloc Failed for trim_stat_buf!!!\n");
645e5c12b0Sopenharmony_ci		return -1;
655e5c12b0Sopenharmony_ci	}
665e5c12b0Sopenharmony_ci
675e5c12b0Sopenharmony_ci	if (fstat(fd, stat_buf) < 0 ) {
685e5c12b0Sopenharmony_ci		MSG(1, "\tError: Failed to get the device stat!!!\n");
695e5c12b0Sopenharmony_ci		free(stat_buf);
705e5c12b0Sopenharmony_ci		return -1;
715e5c12b0Sopenharmony_ci	}
725e5c12b0Sopenharmony_ci
735e5c12b0Sopenharmony_ci	range[0] = 0;
745e5c12b0Sopenharmony_ci	range[1] = bytes;
755e5c12b0Sopenharmony_ci
765e5c12b0Sopenharmony_ci#if defined(WITH_BLKDISCARD) && defined(BLKDISCARD)
775e5c12b0Sopenharmony_ci	MSG(0, "Info: [%s] Discarding device\n", dev->path);
785e5c12b0Sopenharmony_ci	if (S_ISREG(stat_buf->st_mode)) {
795e5c12b0Sopenharmony_ci#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE)
805e5c12b0Sopenharmony_ci		if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
815e5c12b0Sopenharmony_ci				range[0], range[1]) < 0) {
825e5c12b0Sopenharmony_ci			MSG(0, "Info: fallocate(PUNCH_HOLE|KEEP_SIZE) is failed\n");
835e5c12b0Sopenharmony_ci		}
845e5c12b0Sopenharmony_ci#endif
855e5c12b0Sopenharmony_ci		free(stat_buf);
865e5c12b0Sopenharmony_ci		return 0;
875e5c12b0Sopenharmony_ci	} else if (S_ISBLK(stat_buf->st_mode)) {
885e5c12b0Sopenharmony_ci		if (dev->zoned_model != F2FS_ZONED_NONE) {
895e5c12b0Sopenharmony_ci			free(stat_buf);
905e5c12b0Sopenharmony_ci			return f2fs_reset_zones(i);
915e5c12b0Sopenharmony_ci		}
925e5c12b0Sopenharmony_ci#ifdef BLKSECDISCARD
935e5c12b0Sopenharmony_ci		if (ioctl(fd, BLKSECDISCARD, &range) < 0) {
945e5c12b0Sopenharmony_ci			MSG(0, "Info: This device doesn't support BLKSECDISCARD\n");
955e5c12b0Sopenharmony_ci		} else {
965e5c12b0Sopenharmony_ci			MSG(0, "Info: Secure Discarded %lu MB\n",
975e5c12b0Sopenharmony_ci					(unsigned long)stat_buf->st_size >> 20);
985e5c12b0Sopenharmony_ci			free(stat_buf);
995e5c12b0Sopenharmony_ci			return 0;
1005e5c12b0Sopenharmony_ci		}
1015e5c12b0Sopenharmony_ci#endif
1025e5c12b0Sopenharmony_ci		if (ioctl(fd, BLKDISCARD, &range) < 0) {
1035e5c12b0Sopenharmony_ci			MSG(0, "Info: This device doesn't support BLKDISCARD\n");
1045e5c12b0Sopenharmony_ci		} else {
1055e5c12b0Sopenharmony_ci			MSG(0, "Info: Discarded %llu MB\n", range[1] >> 20);
1065e5c12b0Sopenharmony_ci		}
1075e5c12b0Sopenharmony_ci	} else {
1085e5c12b0Sopenharmony_ci		free(stat_buf);
1095e5c12b0Sopenharmony_ci		return -1;
1105e5c12b0Sopenharmony_ci	}
1115e5c12b0Sopenharmony_ci#endif
1125e5c12b0Sopenharmony_ci	free(stat_buf);
1135e5c12b0Sopenharmony_ci	return 0;
1145e5c12b0Sopenharmony_ci}
1155e5c12b0Sopenharmony_ci#else
1165e5c12b0Sopenharmony_cistatic int trim_device(int UNUSED(i))
1175e5c12b0Sopenharmony_ci{
1185e5c12b0Sopenharmony_ci	return 0;
1195e5c12b0Sopenharmony_ci}
1205e5c12b0Sopenharmony_ci#endif
1215e5c12b0Sopenharmony_ci
1225e5c12b0Sopenharmony_ci#ifdef WITH_ANDROID
1235e5c12b0Sopenharmony_cistatic bool is_wiped_device(int i)
1245e5c12b0Sopenharmony_ci{
1255e5c12b0Sopenharmony_ci	struct device_info *dev = c.devices + i;
1265e5c12b0Sopenharmony_ci	int fd = dev->fd;
1275e5c12b0Sopenharmony_ci	char *buf, *zero_buf;
1285e5c12b0Sopenharmony_ci	bool wiped = true;
1295e5c12b0Sopenharmony_ci	int nblocks = 4096;	/* 16MB size */
1305e5c12b0Sopenharmony_ci	int j;
1315e5c12b0Sopenharmony_ci
1325e5c12b0Sopenharmony_ci	/* let's trim the other devices except the first device */
1335e5c12b0Sopenharmony_ci	if (i > 0)
1345e5c12b0Sopenharmony_ci		return false;
1355e5c12b0Sopenharmony_ci
1365e5c12b0Sopenharmony_ci	buf = malloc(F2FS_BLKSIZE);
1375e5c12b0Sopenharmony_ci	if (buf == NULL) {
1385e5c12b0Sopenharmony_ci		MSG(1, "\tError: Malloc Failed for buf!!!\n");
1395e5c12b0Sopenharmony_ci		return false;
1405e5c12b0Sopenharmony_ci	}
1415e5c12b0Sopenharmony_ci	zero_buf = calloc(1, F2FS_BLKSIZE);
1425e5c12b0Sopenharmony_ci	if (zero_buf == NULL) {
1435e5c12b0Sopenharmony_ci		MSG(1, "\tError: Calloc Failed for zero buf!!!\n");
1445e5c12b0Sopenharmony_ci		free(buf);
1455e5c12b0Sopenharmony_ci		return false;
1465e5c12b0Sopenharmony_ci	}
1475e5c12b0Sopenharmony_ci
1485e5c12b0Sopenharmony_ci	if (lseek(fd, 0, SEEK_SET) < 0) {
1495e5c12b0Sopenharmony_ci		free(zero_buf);
1505e5c12b0Sopenharmony_ci		free(buf);
1515e5c12b0Sopenharmony_ci		return false;
1525e5c12b0Sopenharmony_ci	}
1535e5c12b0Sopenharmony_ci
1545e5c12b0Sopenharmony_ci	/* check first n blocks */
1555e5c12b0Sopenharmony_ci	for (j = 0; j < nblocks; j++) {
1565e5c12b0Sopenharmony_ci		if (read(fd, buf, F2FS_BLKSIZE) != F2FS_BLKSIZE ||
1575e5c12b0Sopenharmony_ci				memcmp(buf, zero_buf, F2FS_BLKSIZE)) {
1585e5c12b0Sopenharmony_ci			wiped = false;
1595e5c12b0Sopenharmony_ci			break;
1605e5c12b0Sopenharmony_ci		}
1615e5c12b0Sopenharmony_ci	}
1625e5c12b0Sopenharmony_ci	free(zero_buf);
1635e5c12b0Sopenharmony_ci	free(buf);
1645e5c12b0Sopenharmony_ci
1655e5c12b0Sopenharmony_ci	if (wiped)
1665e5c12b0Sopenharmony_ci		MSG(0, "Info: Found all zeros in first %d blocks\n", nblocks);
1675e5c12b0Sopenharmony_ci	return wiped;
1685e5c12b0Sopenharmony_ci}
1695e5c12b0Sopenharmony_ci#else
1705e5c12b0Sopenharmony_cistatic bool is_wiped_device(int UNUSED(i))
1715e5c12b0Sopenharmony_ci{
1725e5c12b0Sopenharmony_ci	return false;
1735e5c12b0Sopenharmony_ci}
1745e5c12b0Sopenharmony_ci#endif
1755e5c12b0Sopenharmony_ci
1765e5c12b0Sopenharmony_ciint f2fs_trim_devices(void)
1775e5c12b0Sopenharmony_ci{
1785e5c12b0Sopenharmony_ci	int i;
1795e5c12b0Sopenharmony_ci
1805e5c12b0Sopenharmony_ci	for (i = 0; i < c.ndevs; i++) {
1815e5c12b0Sopenharmony_ci		if (!is_wiped_device(i) && trim_device(i))
1825e5c12b0Sopenharmony_ci			return -1;
1835e5c12b0Sopenharmony_ci	}
1845e5c12b0Sopenharmony_ci	c.trimmed = 1;
1855e5c12b0Sopenharmony_ci	return 0;
1865e5c12b0Sopenharmony_ci}
187