1/** 2 * f2fs_format_utils.c 3 * 4 * Copyright (c) 2014 Samsung Electronics Co., Ltd. 5 * http://www.samsung.com/ 6 * 7 * Dual licensed under the GPL or LGPL version 2 licenses. 8 */ 9#ifndef _LARGEFILE_SOURCE 10#define _LARGEFILE_SOURCE 11#endif 12#ifndef _LARGEFILE64_SOURCE 13#define _LARGEFILE64_SOURCE 14#endif 15#ifndef _GNU_SOURCE 16#define _GNU_SOURCE 17#endif 18 19#ifndef _FILE_OFFSET_BITS 20#define _FILE_OFFSET_BITS 64 21#endif 22 23#include <f2fs_fs.h> 24 25#include <stdio.h> 26#include <unistd.h> 27#include <stdlib.h> 28#include <stdbool.h> 29#ifdef HAVE_SYS_IOCTL_H 30#include <sys/ioctl.h> 31#endif 32#include <sys/stat.h> 33#include <fcntl.h> 34 35#ifdef HAVE_LINUX_FS_H 36#include <linux/fs.h> 37#endif 38#ifdef HAVE_LINUX_FALLOC_H 39#include <linux/falloc.h> 40#endif 41 42#ifdef __linux__ 43#ifndef BLKDISCARD 44#define BLKDISCARD _IO(0x12,119) 45#endif 46#ifndef BLKSECDISCARD 47#define BLKSECDISCARD _IO(0x12,125) 48#endif 49#endif 50 51#if defined(FALLOC_FL_PUNCH_HOLE) || defined(BLKDISCARD) || \ 52 defined(BLKSECDISCARD) 53static int trim_device(int i) 54{ 55 unsigned long long range[2]; 56 struct stat *stat_buf; 57 struct device_info *dev = c.devices + i; 58 uint64_t bytes = dev->total_sectors * dev->sector_size; 59 int fd = dev->fd; 60 61 stat_buf = malloc(sizeof(struct stat)); 62 if (stat_buf == NULL) { 63 MSG(1, "\tError: Malloc Failed for trim_stat_buf!!!\n"); 64 return -1; 65 } 66 67 if (fstat(fd, stat_buf) < 0 ) { 68 MSG(1, "\tError: Failed to get the device stat!!!\n"); 69 free(stat_buf); 70 return -1; 71 } 72 73 range[0] = 0; 74 range[1] = bytes; 75 76#if defined(WITH_BLKDISCARD) && defined(BLKDISCARD) 77 MSG(0, "Info: [%s] Discarding device\n", dev->path); 78 if (S_ISREG(stat_buf->st_mode)) { 79#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE) 80 if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 81 range[0], range[1]) < 0) { 82 MSG(0, "Info: fallocate(PUNCH_HOLE|KEEP_SIZE) is failed\n"); 83 } 84#endif 85 free(stat_buf); 86 return 0; 87 } else if (S_ISBLK(stat_buf->st_mode)) { 88 if (dev->zoned_model != F2FS_ZONED_NONE) { 89 free(stat_buf); 90 return f2fs_reset_zones(i); 91 } 92#ifdef BLKSECDISCARD 93 if (ioctl(fd, BLKSECDISCARD, &range) < 0) { 94 MSG(0, "Info: This device doesn't support BLKSECDISCARD\n"); 95 } else { 96 MSG(0, "Info: Secure Discarded %lu MB\n", 97 (unsigned long)stat_buf->st_size >> 20); 98 free(stat_buf); 99 return 0; 100 } 101#endif 102 if (ioctl(fd, BLKDISCARD, &range) < 0) { 103 MSG(0, "Info: This device doesn't support BLKDISCARD\n"); 104 } else { 105 MSG(0, "Info: Discarded %llu MB\n", range[1] >> 20); 106 } 107 } else { 108 free(stat_buf); 109 return -1; 110 } 111#endif 112 free(stat_buf); 113 return 0; 114} 115#else 116static int trim_device(int UNUSED(i)) 117{ 118 return 0; 119} 120#endif 121 122#ifdef WITH_ANDROID 123static bool is_wiped_device(int i) 124{ 125 struct device_info *dev = c.devices + i; 126 int fd = dev->fd; 127 char *buf, *zero_buf; 128 bool wiped = true; 129 int nblocks = 4096; /* 16MB size */ 130 int j; 131 132 /* let's trim the other devices except the first device */ 133 if (i > 0) 134 return false; 135 136 buf = malloc(F2FS_BLKSIZE); 137 if (buf == NULL) { 138 MSG(1, "\tError: Malloc Failed for buf!!!\n"); 139 return false; 140 } 141 zero_buf = calloc(1, F2FS_BLKSIZE); 142 if (zero_buf == NULL) { 143 MSG(1, "\tError: Calloc Failed for zero buf!!!\n"); 144 free(buf); 145 return false; 146 } 147 148 if (lseek(fd, 0, SEEK_SET) < 0) { 149 free(zero_buf); 150 free(buf); 151 return false; 152 } 153 154 /* check first n blocks */ 155 for (j = 0; j < nblocks; j++) { 156 if (read(fd, buf, F2FS_BLKSIZE) != F2FS_BLKSIZE || 157 memcmp(buf, zero_buf, F2FS_BLKSIZE)) { 158 wiped = false; 159 break; 160 } 161 } 162 free(zero_buf); 163 free(buf); 164 165 if (wiped) 166 MSG(0, "Info: Found all zeros in first %d blocks\n", nblocks); 167 return wiped; 168} 169#else 170static bool is_wiped_device(int UNUSED(i)) 171{ 172 return false; 173} 174#endif 175 176int f2fs_trim_devices(void) 177{ 178 int i; 179 180 for (i = 0; i < c.ndevs; i++) { 181 if (!is_wiped_device(i) && trim_device(i)) 182 return -1; 183 } 184 c.trimmed = 1; 185 return 0; 186} 187