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