blob: 0eb1477b6d7ab63c5ec3ff538139b8b840130590 [file] [log] [blame]
Jaegeuk Kime69e4372013-01-25 17:20:16 +09001/**
2 * libf2fs.c
3 *
4 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com/
6 *
Jaegeuk Kim0fbdf6c2014-04-07 12:10:59 +09007 * Dual licensed under the GPL or LGPL version 2 licenses.
Jaegeuk Kime69e4372013-01-25 17:20:16 +09008 */
9#define _LARGEFILE64_SOURCE
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
Jaegeuk Kim2c877a82013-08-02 17:03:10 +090014#include <errno.h>
Jaegeuk Kime69e4372013-01-25 17:20:16 +090015#include <unistd.h>
16#include <fcntl.h>
Keith Mok45f6df22015-09-03 11:34:33 -070017#ifdef __linux__
Jaegeuk Kime69e4372013-01-25 17:20:16 +090018#include <mntent.h>
Keith Mok45f6df22015-09-03 11:34:33 -070019#include <linux/hdreg.h>
20#endif
Jaegeuk Kime69e4372013-01-25 17:20:16 +090021#include <time.h>
22#include <sys/stat.h>
23#include <sys/mount.h>
24#include <sys/ioctl.h>
Jaegeuk Kime69e4372013-01-25 17:20:16 +090025
Changman Lee7f35b542013-07-04 17:11:32 +090026#include <f2fs_fs.h>
Jaegeuk Kime69e4372013-01-25 17:20:16 +090027
Greg Wallaceb8f37de2016-01-02 17:01:27 -050028#ifdef __ANDROID__
29char *hasmntopt (const struct mntent *mnt, const char *opt) {
30 const size_t optlen = strlen (opt);
31 char *rest = mnt->mnt_opts, *p;
32
33 while ((p = strstr (rest, opt)) != NULL) {
34 if ((p == rest || p[-1] == ',')
35 && (p[optlen] == '\0' || p[optlen] == '=' || p[optlen] == ','))
36 return p;
37
38 rest = strchr (p, ',');
39 if (rest == NULL)
40 break;
41 ++rest;
42 }
43 return NULL;
44}
45#endif
46
Jaegeuk Kim77b8e792015-12-14 14:29:41 -080047/*
48 * UTF conversion codes are Copied from exfat tools.
49 */
50static const char *utf8_to_wchar(const char *input, wchar_t *wc,
51 size_t insize)
Jaegeuk Kime69e4372013-01-25 17:20:16 +090052{
Jaegeuk Kim77b8e792015-12-14 14:29:41 -080053 if ((input[0] & 0x80) == 0 && insize >= 1) {
54 *wc = (wchar_t) input[0];
55 return input + 1;
Jaegeuk Kime69e4372013-01-25 17:20:16 +090056 }
Jaegeuk Kim77b8e792015-12-14 14:29:41 -080057 if ((input[0] & 0xe0) == 0xc0 && insize >= 2) {
58 *wc = (((wchar_t) input[0] & 0x1f) << 6) |
59 ((wchar_t) input[1] & 0x3f);
60 return input + 2;
61 }
62 if ((input[0] & 0xf0) == 0xe0 && insize >= 3) {
63 *wc = (((wchar_t) input[0] & 0x0f) << 12) |
64 (((wchar_t) input[1] & 0x3f) << 6) |
65 ((wchar_t) input[2] & 0x3f);
66 return input + 3;
67 }
68 if ((input[0] & 0xf8) == 0xf0 && insize >= 4) {
69 *wc = (((wchar_t) input[0] & 0x07) << 18) |
70 (((wchar_t) input[1] & 0x3f) << 12) |
71 (((wchar_t) input[2] & 0x3f) << 6) |
72 ((wchar_t) input[3] & 0x3f);
73 return input + 4;
74 }
75 if ((input[0] & 0xfc) == 0xf8 && insize >= 5) {
76 *wc = (((wchar_t) input[0] & 0x03) << 24) |
77 (((wchar_t) input[1] & 0x3f) << 18) |
78 (((wchar_t) input[2] & 0x3f) << 12) |
79 (((wchar_t) input[3] & 0x3f) << 6) |
80 ((wchar_t) input[4] & 0x3f);
81 return input + 5;
82 }
83 if ((input[0] & 0xfe) == 0xfc && insize >= 6) {
84 *wc = (((wchar_t) input[0] & 0x01) << 30) |
85 (((wchar_t) input[1] & 0x3f) << 24) |
86 (((wchar_t) input[2] & 0x3f) << 18) |
87 (((wchar_t) input[3] & 0x3f) << 12) |
88 (((wchar_t) input[4] & 0x3f) << 6) |
89 ((wchar_t) input[5] & 0x3f);
90 return input + 6;
91 }
92 return NULL;
93}
94
95static u_int16_t *wchar_to_utf16(u_int16_t *output, wchar_t wc, size_t outsize)
96{
97 if (wc <= 0xffff) {
98 if (outsize == 0)
99 return NULL;
100 output[0] = cpu_to_le16(wc);
101 return output + 1;
102 }
103 if (outsize < 2)
104 return NULL;
105 wc -= 0x10000;
106 output[0] = cpu_to_le16(0xd800 | ((wc >> 10) & 0x3ff));
107 output[1] = cpu_to_le16(0xdc00 | (wc & 0x3ff));
108 return output + 2;
109}
110
111int utf8_to_utf16(u_int16_t *output, const char *input, size_t outsize,
112 size_t insize)
113{
114 const char *inp = input;
115 u_int16_t *outp = output;
116 wchar_t wc;
117
Jaegeuk Kim3aa929b2016-01-13 11:51:33 -0800118 while ((size_t)(inp - input) < insize && *inp) {
Jaegeuk Kim77b8e792015-12-14 14:29:41 -0800119 inp = utf8_to_wchar(inp, &wc, insize - (inp - input));
120 if (inp == NULL) {
121 DBG(0, "illegal UTF-8 sequence\n");
122 return -EILSEQ;
123 }
124 outp = wchar_to_utf16(outp, wc, outsize - (outp - output));
125 if (outp == NULL) {
126 DBG(0, "name is too long\n");
127 return -ENAMETOOLONG;
128 }
129 }
130 *outp = cpu_to_le16(0);
131 return 0;
132}
133
134static const u_int16_t *utf16_to_wchar(const u_int16_t *input, wchar_t *wc,
135 size_t insize)
136{
137 if ((le16_to_cpu(input[0]) & 0xfc00) == 0xd800) {
138 if (insize < 2 || (le16_to_cpu(input[1]) & 0xfc00) != 0xdc00)
139 return NULL;
140 *wc = ((wchar_t) (le16_to_cpu(input[0]) & 0x3ff) << 10);
141 *wc |= (le16_to_cpu(input[1]) & 0x3ff);
142 *wc += 0x10000;
143 return input + 2;
144 } else {
145 *wc = le16_to_cpu(*input);
146 return input + 1;
147 }
148}
149
150static char *wchar_to_utf8(char *output, wchar_t wc, size_t outsize)
151{
152 if (wc <= 0x7f) {
153 if (outsize < 1)
154 return NULL;
155 *output++ = (char) wc;
156 } else if (wc <= 0x7ff) {
157 if (outsize < 2)
158 return NULL;
159 *output++ = 0xc0 | (wc >> 6);
160 *output++ = 0x80 | (wc & 0x3f);
161 } else if (wc <= 0xffff) {
162 if (outsize < 3)
163 return NULL;
164 *output++ = 0xe0 | (wc >> 12);
165 *output++ = 0x80 | ((wc >> 6) & 0x3f);
166 *output++ = 0x80 | (wc & 0x3f);
167 } else if (wc <= 0x1fffff) {
168 if (outsize < 4)
169 return NULL;
170 *output++ = 0xf0 | (wc >> 18);
171 *output++ = 0x80 | ((wc >> 12) & 0x3f);
172 *output++ = 0x80 | ((wc >> 6) & 0x3f);
173 *output++ = 0x80 | (wc & 0x3f);
174 } else if (wc <= 0x3ffffff) {
175 if (outsize < 5)
176 return NULL;
177 *output++ = 0xf8 | (wc >> 24);
178 *output++ = 0x80 | ((wc >> 18) & 0x3f);
179 *output++ = 0x80 | ((wc >> 12) & 0x3f);
180 *output++ = 0x80 | ((wc >> 6) & 0x3f);
181 *output++ = 0x80 | (wc & 0x3f);
182 } else if (wc <= 0x7fffffff) {
183 if (outsize < 6)
184 return NULL;
185 *output++ = 0xfc | (wc >> 30);
186 *output++ = 0x80 | ((wc >> 24) & 0x3f);
187 *output++ = 0x80 | ((wc >> 18) & 0x3f);
188 *output++ = 0x80 | ((wc >> 12) & 0x3f);
189 *output++ = 0x80 | ((wc >> 6) & 0x3f);
190 *output++ = 0x80 | (wc & 0x3f);
191 } else
192 return NULL;
193
194 return output;
195}
196
197int utf16_to_utf8(char *output, const u_int16_t *input, size_t outsize,
198 size_t insize)
199{
200 const u_int16_t *inp = input;
201 char *outp = output;
202 wchar_t wc;
203
Jaegeuk Kim3aa929b2016-01-13 11:51:33 -0800204 while ((size_t)(inp - input) < insize && le16_to_cpu(*inp)) {
Jaegeuk Kim77b8e792015-12-14 14:29:41 -0800205 inp = utf16_to_wchar(inp, &wc, insize - (inp - input));
206 if (inp == NULL) {
207 DBG(0, "illegal UTF-16 sequence\n");
208 return -EILSEQ;
209 }
210 outp = wchar_to_utf8(outp, wc, outsize - (outp - output));
211 if (outp == NULL) {
212 DBG(0, "name is too long\n");
213 return -ENAMETOOLONG;
214 }
215 }
216 *outp = '\0';
217 return 0;
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900218}
219
220int log_base_2(u_int32_t num)
221{
222 int ret = 0;
223 if (num <= 0 || (num & (num - 1)) != 0)
224 return -1;
225
226 while (num >>= 1)
227 ret++;
228 return ret;
229}
230
231/*
232 * f2fs bit operations
233 */
Changman Lee7f35b542013-07-04 17:11:32 +0900234static const int bits_in_byte[256] = {
235 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
236 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
237 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
238 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
239 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
240 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
241 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
242 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
243 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
244 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
245 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
246 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
247 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
248 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
249 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
250 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
251};
252
253int get_bits_in_byte(unsigned char n)
254{
255 return bits_in_byte[n];
256}
257
Jaegeuk Kim94a04b12015-12-15 11:13:25 -0800258int test_and_set_bit_le(u32 nr, u8 *addr)
Changman Lee7f35b542013-07-04 17:11:32 +0900259{
Jaegeuk Kim0cb56c82015-12-09 11:44:31 -0800260 int mask, retval;
Changman Lee7f35b542013-07-04 17:11:32 +0900261
Jaegeuk Kim44557422015-12-15 10:10:15 -0800262 addr += nr >> 3;
Changman Lee7f35b542013-07-04 17:11:32 +0900263 mask = 1 << ((nr & 0x07));
Jaegeuk Kim44557422015-12-15 10:10:15 -0800264 retval = mask & *addr;
265 *addr |= mask;
Changman Lee7f35b542013-07-04 17:11:32 +0900266 return retval;
267}
268
Jaegeuk Kim94a04b12015-12-15 11:13:25 -0800269int test_and_clear_bit_le(u32 nr, u8 *addr)
Changman Lee7f35b542013-07-04 17:11:32 +0900270{
Jaegeuk Kim0cb56c82015-12-09 11:44:31 -0800271 int mask, retval;
Changman Lee7f35b542013-07-04 17:11:32 +0900272
Jaegeuk Kim44557422015-12-15 10:10:15 -0800273 addr += nr >> 3;
Changman Lee7f35b542013-07-04 17:11:32 +0900274 mask = 1 << ((nr & 0x07));
Jaegeuk Kim44557422015-12-15 10:10:15 -0800275 retval = mask & *addr;
276 *addr &= ~mask;
Changman Lee7f35b542013-07-04 17:11:32 +0900277 return retval;
278}
279
Jaegeuk Kim94a04b12015-12-15 11:13:25 -0800280int test_bit_le(u32 nr, const u8 *addr)
Changman Lee7f35b542013-07-04 17:11:32 +0900281{
Jaegeuk Kim44557422015-12-15 10:10:15 -0800282 return ((1 << (nr & 7)) & (addr[nr >> 3]));
Changman Lee7f35b542013-07-04 17:11:32 +0900283}
284
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900285int f2fs_test_bit(unsigned int nr, const char *p)
286{
287 int mask;
288 char *addr = (char *)p;
289
290 addr += (nr >> 3);
291 mask = 1 << (7 - (nr & 0x07));
292 return (mask & *addr) != 0;
293}
294
Changman Lee7f35b542013-07-04 17:11:32 +0900295int f2fs_set_bit(unsigned int nr, char *addr)
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900296{
297 int mask;
298 int ret;
299
300 addr += (nr >> 3);
301 mask = 1 << (7 - (nr & 0x07));
302 ret = mask & *addr;
303 *addr |= mask;
304 return ret;
305}
306
307int f2fs_clear_bit(unsigned int nr, char *addr)
308{
309 int mask;
310 int ret;
311
312 addr += (nr >> 3);
313 mask = 1 << (7 - (nr & 0x07));
314 ret = mask & *addr;
315 *addr &= ~mask;
316 return ret;
317}
318
Jaegeuk Kim94a04b12015-12-15 11:13:25 -0800319static inline u64 __ffs(u8 word)
Changman Lee57baa232013-07-30 16:39:06 +0900320{
321 int num = 0;
322
Changman Lee57baa232013-07-30 16:39:06 +0900323 if ((word & 0xf) == 0) {
324 num += 4;
325 word >>= 4;
326 }
327 if ((word & 0x3) == 0) {
328 num += 2;
329 word >>= 2;
330 }
331 if ((word & 0x1) == 0)
332 num += 1;
333 return num;
334}
335
Jaegeuk Kim0cb56c82015-12-09 11:44:31 -0800336/* Copied from linux/lib/find_bit.c */
337#define BITMAP_FIRST_BYTE_MASK(start) (0xff << ((start) & (BITS_PER_BYTE - 1)))
338
Jaegeuk Kim94a04b12015-12-15 11:13:25 -0800339static u64 _find_next_bit_le(const u8 *addr, u64 nbits, u64 start, char invert)
Changman Lee57baa232013-07-30 16:39:06 +0900340{
Jaegeuk Kim94a04b12015-12-15 11:13:25 -0800341 u8 tmp;
Changman Lee57baa232013-07-30 16:39:06 +0900342
Jaegeuk Kim0cb56c82015-12-09 11:44:31 -0800343 if (!nbits || start >= nbits)
344 return nbits;
Changman Lee57baa232013-07-30 16:39:06 +0900345
Jaegeuk Kim0cb56c82015-12-09 11:44:31 -0800346 tmp = addr[start / BITS_PER_BYTE] ^ invert;
347
348 /* Handle 1st word. */
349 tmp &= BITMAP_FIRST_BYTE_MASK(start);
350 start = round_down(start, BITS_PER_BYTE);
351
352 while (!tmp) {
353 start += BITS_PER_BYTE;
354 if (start >= nbits)
355 return nbits;
356
357 tmp = addr[start / BITS_PER_BYTE] ^ invert;
358 }
359
360 return min(start + __ffs(tmp), nbits);
361}
362
Jaegeuk Kim94a04b12015-12-15 11:13:25 -0800363u64 find_next_bit_le(const u8 *addr, u64 size, u64 offset)
Jaegeuk Kim0cb56c82015-12-09 11:44:31 -0800364{
365 return _find_next_bit_le(addr, size, offset, 0);
366}
367
368
Jaegeuk Kim94a04b12015-12-15 11:13:25 -0800369u64 find_next_zero_bit_le(const u8 *addr, u64 size, u64 offset)
Jaegeuk Kim0cb56c82015-12-09 11:44:31 -0800370{
371 return _find_next_bit_le(addr, size, offset, 0xff);
Changman Lee57baa232013-07-30 16:39:06 +0900372}
373
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900374/*
Changman Lee7f35b542013-07-04 17:11:32 +0900375 * Hashing code adapted from ext3
376 */
377#define DELTA 0x9E3779B9
378
379static void TEA_transform(unsigned int buf[4], unsigned int const in[])
380{
381 __u32 sum = 0;
382 __u32 b0 = buf[0], b1 = buf[1];
383 __u32 a = in[0], b = in[1], c = in[2], d = in[3];
384 int n = 16;
385
386 do {
387 sum += DELTA;
388 b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
389 b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
390 } while (--n);
391
392 buf[0] += b0;
393 buf[1] += b1;
394
395}
396
Jaegeuk Kim347fe812014-08-26 16:28:12 -0700397static void str2hashbuf(const unsigned char *msg, int len,
398 unsigned int *buf, int num)
Changman Lee7f35b542013-07-04 17:11:32 +0900399{
400 unsigned pad, val;
401 int i;
402
403 pad = (__u32)len | ((__u32)len << 8);
404 pad |= pad << 16;
405
406 val = pad;
407 if (len > num * 4)
408 len = num * 4;
409 for (i = 0; i < len; i++) {
410 if ((i % 4) == 0)
411 val = pad;
412 val = msg[i] + (val << 8);
413 if ((i % 4) == 3) {
414 *buf++ = val;
415 val = pad;
416 num--;
417 }
418 }
419 if (--num >= 0)
420 *buf++ = val;
421 while (--num >= 0)
422 *buf++ = pad;
423
424}
425
426/**
427 * Return hash value of directory entry
428 * @param name dentry name
429 * @param len name lenth
430 * @return return on success hash value, errno on failure
431 */
Jaegeuk Kim347fe812014-08-26 16:28:12 -0700432f2fs_hash_t f2fs_dentry_hash(const unsigned char *name, int len)
Changman Lee7f35b542013-07-04 17:11:32 +0900433{
434 __u32 hash;
435 f2fs_hash_t f2fs_hash;
Jaegeuk Kim347fe812014-08-26 16:28:12 -0700436 const unsigned char *p;
Changman Lee7f35b542013-07-04 17:11:32 +0900437 __u32 in[8], buf[4];
438
439 /* special hash codes for special dentries */
Jaegeuk Kim347fe812014-08-26 16:28:12 -0700440 if ((len <= 2) && (name[0] == '.') &&
441 (name[1] == '.' || name[1] == '\0'))
442 return 0;
Changman Lee7f35b542013-07-04 17:11:32 +0900443
444 /* Initialize the default seed for the hash checksum functions */
445 buf[0] = 0x67452301;
446 buf[1] = 0xefcdab89;
447 buf[2] = 0x98badcfe;
448 buf[3] = 0x10325476;
449
450 p = name;
Jaegeuk Kim347fe812014-08-26 16:28:12 -0700451 while (1) {
Changman Lee7f35b542013-07-04 17:11:32 +0900452 str2hashbuf(p, len, in, 4);
453 TEA_transform(buf, in);
Changman Lee7f35b542013-07-04 17:11:32 +0900454 p += 16;
Jaegeuk Kim347fe812014-08-26 16:28:12 -0700455 if (len <= 16)
456 break;
457 len -= 16;
Changman Lee7f35b542013-07-04 17:11:32 +0900458 }
459 hash = buf[0];
460
Jaegeuk Kim347fe812014-08-26 16:28:12 -0700461 f2fs_hash = cpu_to_le32(hash & ~F2FS_HASH_COL_BIT);
Changman Lee7f35b542013-07-04 17:11:32 +0900462 return f2fs_hash;
463}
464
Jaegeuk Kimcd1e4702013-08-20 18:05:56 +0900465unsigned int addrs_per_inode(struct f2fs_inode *i)
466{
467 if (i->i_inline & F2FS_INLINE_XATTR)
468 return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS;
469 return DEF_ADDRS_PER_INODE;
470}
471
Changman Lee7f35b542013-07-04 17:11:32 +0900472/*
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900473 * CRC32
474 */
475#define CRCPOLY_LE 0xedb88320
476
477u_int32_t f2fs_cal_crc32(u_int32_t crc, void *buf, int len)
478{
479 int i;
480 unsigned char *p = (unsigned char *)buf;
481 while (len--) {
482 crc ^= *p++;
483 for (i = 0; i < 8; i++)
484 crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
485 }
486 return crc;
487}
488
Jaegeuk Kim5043dff2013-02-12 11:03:24 +0900489int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len)
490{
491 u_int32_t cal_crc = 0;
492
493 cal_crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, buf, len);
494
495 if (cal_crc != blk_crc) {
Changman Leefd9816f2014-05-12 22:03:46 +0900496 DBG(0,"CRC validation failed: cal_crc = %u, "
497 "blk_crc = %u buff_size = 0x%x\n",
Jaegeuk Kim5043dff2013-02-12 11:03:24 +0900498 cal_crc, blk_crc, len);
499 return -1;
500 }
501 return 0;
502}
503
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900504/*
505 * device information
506 */
507void f2fs_init_configuration(struct f2fs_configuration *c)
508{
JP Abgrall94f92852014-06-11 21:55:38 -0700509 c->total_sectors = 0;
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900510 c->sector_size = DEFAULT_SECTOR_SIZE;
511 c->sectors_per_blk = DEFAULT_SECTORS_PER_BLOCK;
512 c->blks_per_seg = DEFAULT_BLOCKS_PER_SEGMENT;
513
514 /* calculated by overprovision ratio */
Jaegeuk Kim5ddd5f82015-08-10 15:45:10 -0700515 c->reserved_segments = 0;
516 c->overprovision = 0;
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900517 c->segs_per_sec = 1;
518 c->secs_per_zone = 1;
Changman Lee060292e2014-11-17 14:03:41 +0900519 c->segs_per_zone = 1;
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900520 c->heap = 1;
Mike Fleetwood9799d632013-04-02 23:15:20 +0100521 c->vol_label = "";
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900522 c->device_name = NULL;
Changman Leeb155ea82013-08-31 08:41:31 +0900523 c->trim = 1;
qemx13bf53b3a2015-10-19 13:05:55 -0700524 c->bytes_reserved = 0;
Jaegeuk Kim378a8352015-11-22 10:53:07 +0800525 c->ro = 0;
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900526}
527
Jaegeuk Kim3aa929b2016-01-13 11:51:33 -0800528static int is_mounted(const char *mpt, const char *device)
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900529{
Keith Mok45f6df22015-09-03 11:34:33 -0700530#ifdef __linux__
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900531 FILE *file = NULL;
532 struct mntent *mnt = NULL;
533
Jaegeuk Kim2c877a82013-08-02 17:03:10 +0900534 file = setmntent(mpt, "r");
535 if (file == NULL)
536 return 0;
537
538 while ((mnt = getmntent(file)) != NULL) {
Jaegeuk Kim378a8352015-11-22 10:53:07 +0800539 if (!strcmp(device, mnt->mnt_fsname)) {
Jaegeuk Kim3aa929b2016-01-13 11:51:33 -0800540#ifdef MNTOPT_RO
Jaegeuk Kim378a8352015-11-22 10:53:07 +0800541 if (hasmntopt(mnt, MNTOPT_RO))
Greg Wallaceb8f37de2016-01-02 17:01:27 -0500542#else
543 if (hasmntopt(mnt, "ro"))
Jaegeuk Kim3aa929b2016-01-13 11:51:33 -0800544#endif
Greg Wallaceb8f37de2016-01-02 17:01:27 -0500545 config.ro = 1;
Jaegeuk Kim2c877a82013-08-02 17:03:10 +0900546 break;
Jaegeuk Kim378a8352015-11-22 10:53:07 +0800547 }
Jaegeuk Kim2c877a82013-08-02 17:03:10 +0900548 }
549 endmntent(file);
550 return mnt ? 1 : 0;
Keith Mok45f6df22015-09-03 11:34:33 -0700551#else
552 /* TODO */
553 return 0;
554#endif
Jaegeuk Kim2c877a82013-08-02 17:03:10 +0900555}
556
557int f2fs_dev_is_umounted(struct f2fs_configuration *c)
558{
559 struct stat st_buf;
560 int ret = 0;
561
Jaegeuk Kim596a94a2016-02-18 17:37:14 -0800562 /*
563 * try with /proc/mounts fist to detect RDONLY.
564 * f2fs_stop_checkpoint makes RO in /proc/mounts while RW in /etc/mtab.
565 */
566 ret = is_mounted("/proc/mounts", c->device_name);
567 if (ret) {
568 MSG(0, "Info: Mounted device!\n");
569 return -1;
570 }
571
Keith Mok45f6df22015-09-03 11:34:33 -0700572#ifdef __linux__
Jaegeuk Kim3aa929b2016-01-13 11:51:33 -0800573 ret = is_mounted(MOUNTED, c->device_name);
Jaegeuk Kim2c877a82013-08-02 17:03:10 +0900574 if (ret) {
Jaegeuk Kim378a8352015-11-22 10:53:07 +0800575 MSG(0, "Info: Mounted device!\n");
Jaegeuk Kim2c877a82013-08-02 17:03:10 +0900576 return -1;
Namjae Jeon8d3802b2013-03-31 11:51:29 +0900577 }
Keith Mok45f6df22015-09-03 11:34:33 -0700578#endif
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900579
Jaegeuk Kim2c877a82013-08-02 17:03:10 +0900580 /*
Jaegeuk Kim2c877a82013-08-02 17:03:10 +0900581 * If f2fs is umounted with -l, the process can still use
582 * the file system. In this case, we should not format.
583 */
584 if (stat(c->device_name, &st_buf) == 0 && S_ISBLK(st_buf.st_mode)) {
585 int fd = open(c->device_name, O_RDONLY | O_EXCL);
586
587 if (fd >= 0) {
588 close(fd);
589 } else if (errno == EBUSY) {
590 MSG(0, "\tError: In use by the system!\n");
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900591 return -1;
592 }
593 }
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900594 return 0;
595}
596
Jaegeuk Kimc07795e2014-11-06 19:34:40 -0800597void get_kernel_version(__u8 *version)
598{
599 int i;
600 for (i = 0; i < VERSION_LEN; i++) {
601 if (version[i] == '\n')
602 break;
603 }
604 memset(version + i, 0, VERSION_LEN + 1 - i);
605}
606
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900607int f2fs_get_device_info(struct f2fs_configuration *c)
608{
609 int32_t fd = 0;
JP Abgrall3c85e732014-05-13 17:02:55 -0700610 uint32_t sector_size;
joerg jungermann290d0402014-09-25 22:05:12 -0700611#ifndef BLKGETSIZE64
612 uint32_t total_sectors;
613#endif
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900614 struct stat stat_buf;
Keith Mok45f6df22015-09-03 11:34:33 -0700615#ifdef __linux__
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900616 struct hd_geometry geom;
Keith Mok45f6df22015-09-03 11:34:33 -0700617#endif
JP Abgrall94f92852014-06-11 21:55:38 -0700618 u_int64_t wanted_total_sectors = c->total_sectors;
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900619
620 fd = open(c->device_name, O_RDWR);
621 if (fd < 0) {
622 MSG(0, "\tError: Failed to open the device!\n");
623 return -1;
624 }
625 c->fd = fd;
626
Jaegeuk Kimc07795e2014-11-06 19:34:40 -0800627 c->kd = open("/proc/version", O_RDONLY);
628 if (c->kd < 0)
629 MSG(0, "\tInfo: No support kernel version!\n");
630
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900631 if (fstat(fd, &stat_buf) < 0 ) {
632 MSG(0, "\tError: Failed to get the device stat!\n");
633 return -1;
634 }
635
636 if (S_ISREG(stat_buf.st_mode)) {
qemx13bf53b3a2015-10-19 13:05:55 -0700637 if (c->bytes_reserved >= stat_buf.st_size) {
638 MSG(0, "\n\Error: reserved bytes (%u) is bigger than the device size (%u bytes)\n",
639 (unsigned int) c->bytes_reserved,
640 (unsigned int) stat_buf.st_size);
641 return -1;
642 }
643
644 c->total_sectors = (stat_buf.st_size - c->bytes_reserved) / c->sector_size;
645
646 if (c->bytes_reserved) {
647 MSG(0, "Info: Reserved %u bytes ", (unsigned int) c->bytes_reserved);
648 MSG(0, "from device of size %u sectors\n",
649 (unsigned int) (stat_buf.st_size / c->sector_size));
650 }
Keith Mok45f6df22015-09-03 11:34:33 -0700651#ifdef __linux__
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900652 } else if (S_ISBLK(stat_buf.st_mode)) {
653 if (ioctl(fd, BLKSSZGET, &sector_size) < 0) {
654 MSG(0, "\tError: Using the default sector size\n");
655 } else {
656 if (c->sector_size < sector_size) {
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900657 c->sector_size = sector_size;
658 c->sectors_per_blk = PAGE_SIZE / sector_size;
659 }
660 }
661
joerg jungermann290d0402014-09-25 22:05:12 -0700662#ifdef BLKGETSIZE64
663 if (ioctl(fd, BLKGETSIZE64, &c->total_sectors) < 0) {
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900664 MSG(0, "\tError: Cannot get the device size\n");
665 return -1;
666 }
joerg jungermann290d0402014-09-25 22:05:12 -0700667 c->total_sectors /= c->sector_size;
668#else
669 if (ioctl(fd, BLKGETSIZE, &total_sectors) < 0) {
670 MSG(0, "\tError: Cannot get the device size\n");
671 return -1;
672 }
673 total_sectors /= c->sector_size;
674 c->total_sectors = total_sectors;
675#endif
qemx13bf53b3a2015-10-19 13:05:55 -0700676
677 if (c->bytes_reserved) {
678 unsigned int reserved_sectors;
679
680 reserved_sectors = c->bytes_reserved / c->sector_size;
681 if (c->bytes_reserved % c->sector_size) {reserved_sectors++;}
682
683 if(reserved_sectors >= c->total_sectors) {
684 MSG(0, "\n\Error: reserved bytes (%u sectors) is bigger than the device size (%u sectors)\n",
685 (unsigned int) reserved_sectors,
686 (unsigned int) c->total_sectors);
687 return -1;
688 }
689
690 MSG(0, "\n");
691 MSG(0, "Info: Reserved %u sectors ", (unsigned int) reserved_sectors);
692 MSG(0, "from device of size %u sectors\n",
693 (unsigned int) c->total_sectors);
694
695 c->total_sectors -= reserved_sectors;
696 }
697
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900698 if (ioctl(fd, HDIO_GETGEO, &geom) < 0)
699 c->start_sector = 0;
700 else
701 c->start_sector = geom.start;
Keith Mok45f6df22015-09-03 11:34:33 -0700702#endif
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900703 } else {
704 MSG(0, "\tError: Volume type is not supported!!!\n");
705 return -1;
706 }
JP Abgrall94f92852014-06-11 21:55:38 -0700707 if (wanted_total_sectors && wanted_total_sectors < c->total_sectors) {
Chao Yu29ab4d82015-02-05 17:36:39 +0800708 MSG(0, "Info: total device sectors = %"PRIu64" (in %u bytes)\n",
709 c->total_sectors, c->sector_size);
JP Abgrall94f92852014-06-11 21:55:38 -0700710 c->total_sectors = wanted_total_sectors;
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900711
JP Abgrall94f92852014-06-11 21:55:38 -0700712 }
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900713 MSG(0, "Info: sector size = %u\n", c->sector_size);
Jaegeuk Kimeb38acb2015-03-20 16:41:59 -0700714 MSG(0, "Info: total sectors = %"PRIu64" (%"PRIu64" MB)\n",
Jaegeuk Kima093b0f2015-12-07 15:50:26 -0800715 c->total_sectors, (c->total_sectors *
716 (c->sector_size >> 9)) >> 11);
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900717 return 0;
718}
719