1 /**
2 * libf2fs.c
3 *
4 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com/
6 *
7 * Dual licensed under the GPL or LGPL version 2 licenses.
8 */
9 #define _LARGEFILE64_SOURCE
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <mntent.h>
18 #include <time.h>
19 #include <sys/stat.h>
20 #include <sys/mount.h>
21 #include <sys/ioctl.h>
22 #ifndef WITH_ANDROID
23 #include <scsi/sg.h>
24 #endif
25 #include <linux/hdreg.h>
26 #include <linux/limits.h>
27
28 #include <f2fs_fs.h>
29
30 #ifndef WITH_ANDROID
31 /* SCSI command for standard inquiry*/
32 #define MODELINQUIRY 0x12,0x00,0x00,0x00,0x4A,0x00
33 #endif
34
35 #ifndef _WIN32 /* O_BINARY is windows-specific flag */
36 #define O_BINARY 0
37 #endif
38
39 /*
40 * UTF conversion codes are Copied from exfat tools.
41 */
utf8_to_wchar(const char * input,wchar_t * wc,size_t insize)42 static const char *utf8_to_wchar(const char *input, wchar_t *wc,
43 size_t insize)
44 {
45 if ((input[0] & 0x80) == 0 && insize >= 1) {
46 *wc = (wchar_t) input[0];
47 return input + 1;
48 }
49 if ((input[0] & 0xe0) == 0xc0 && insize >= 2) {
50 *wc = (((wchar_t) input[0] & 0x1f) << 6) |
51 ((wchar_t) input[1] & 0x3f);
52 return input + 2;
53 }
54 if ((input[0] & 0xf0) == 0xe0 && insize >= 3) {
55 *wc = (((wchar_t) input[0] & 0x0f) << 12) |
56 (((wchar_t) input[1] & 0x3f) << 6) |
57 ((wchar_t) input[2] & 0x3f);
58 return input + 3;
59 }
60 if ((input[0] & 0xf8) == 0xf0 && insize >= 4) {
61 *wc = (((wchar_t) input[0] & 0x07) << 18) |
62 (((wchar_t) input[1] & 0x3f) << 12) |
63 (((wchar_t) input[2] & 0x3f) << 6) |
64 ((wchar_t) input[3] & 0x3f);
65 return input + 4;
66 }
67 if ((input[0] & 0xfc) == 0xf8 && insize >= 5) {
68 *wc = (((wchar_t) input[0] & 0x03) << 24) |
69 (((wchar_t) input[1] & 0x3f) << 18) |
70 (((wchar_t) input[2] & 0x3f) << 12) |
71 (((wchar_t) input[3] & 0x3f) << 6) |
72 ((wchar_t) input[4] & 0x3f);
73 return input + 5;
74 }
75 if ((input[0] & 0xfe) == 0xfc && insize >= 6) {
76 *wc = (((wchar_t) input[0] & 0x01) << 30) |
77 (((wchar_t) input[1] & 0x3f) << 24) |
78 (((wchar_t) input[2] & 0x3f) << 18) |
79 (((wchar_t) input[3] & 0x3f) << 12) |
80 (((wchar_t) input[4] & 0x3f) << 6) |
81 ((wchar_t) input[5] & 0x3f);
82 return input + 6;
83 }
84 return NULL;
85 }
86
wchar_to_utf16(u_int16_t * output,wchar_t wc,size_t outsize)87 static u_int16_t *wchar_to_utf16(u_int16_t *output, wchar_t wc, size_t outsize)
88 {
89 if (wc <= 0xffff) {
90 if (outsize == 0)
91 return NULL;
92 output[0] = cpu_to_le16(wc);
93 return output + 1;
94 }
95 if (outsize < 2)
96 return NULL;
97 wc -= 0x10000;
98 output[0] = cpu_to_le16(0xd800 | ((wc >> 10) & 0x3ff));
99 output[1] = cpu_to_le16(0xdc00 | (wc & 0x3ff));
100 return output + 2;
101 }
102
utf8_to_utf16(u_int16_t * output,const char * input,size_t outsize,size_t insize)103 int utf8_to_utf16(u_int16_t *output, const char *input, size_t outsize,
104 size_t insize)
105 {
106 const char *inp = input;
107 u_int16_t *outp = output;
108 wchar_t wc;
109
110 while ((size_t)(inp - input) < insize && *inp) {
111 inp = utf8_to_wchar(inp, &wc, insize - (inp - input));
112 if (inp == NULL) {
113 DBG(0, "illegal UTF-8 sequence\n");
114 return -EILSEQ;
115 }
116 outp = wchar_to_utf16(outp, wc, outsize - (outp - output));
117 if (outp == NULL) {
118 DBG(0, "name is too long\n");
119 return -ENAMETOOLONG;
120 }
121 }
122 *outp = cpu_to_le16(0);
123 return 0;
124 }
125
utf16_to_wchar(const u_int16_t * input,wchar_t * wc,size_t insize)126 static const u_int16_t *utf16_to_wchar(const u_int16_t *input, wchar_t *wc,
127 size_t insize)
128 {
129 if ((le16_to_cpu(input[0]) & 0xfc00) == 0xd800) {
130 if (insize < 2 || (le16_to_cpu(input[1]) & 0xfc00) != 0xdc00)
131 return NULL;
132 *wc = ((wchar_t) (le16_to_cpu(input[0]) & 0x3ff) << 10);
133 *wc |= (le16_to_cpu(input[1]) & 0x3ff);
134 *wc += 0x10000;
135 return input + 2;
136 } else {
137 *wc = le16_to_cpu(*input);
138 return input + 1;
139 }
140 }
141
wchar_to_utf8(char * output,wchar_t wc,size_t outsize)142 static char *wchar_to_utf8(char *output, wchar_t wc, size_t outsize)
143 {
144 if (wc <= 0x7f) {
145 if (outsize < 1)
146 return NULL;
147 *output++ = (char) wc;
148 } else if (wc <= 0x7ff) {
149 if (outsize < 2)
150 return NULL;
151 *output++ = 0xc0 | (wc >> 6);
152 *output++ = 0x80 | (wc & 0x3f);
153 } else if (wc <= 0xffff) {
154 if (outsize < 3)
155 return NULL;
156 *output++ = 0xe0 | (wc >> 12);
157 *output++ = 0x80 | ((wc >> 6) & 0x3f);
158 *output++ = 0x80 | (wc & 0x3f);
159 } else if (wc <= 0x1fffff) {
160 if (outsize < 4)
161 return NULL;
162 *output++ = 0xf0 | (wc >> 18);
163 *output++ = 0x80 | ((wc >> 12) & 0x3f);
164 *output++ = 0x80 | ((wc >> 6) & 0x3f);
165 *output++ = 0x80 | (wc & 0x3f);
166 } else if (wc <= 0x3ffffff) {
167 if (outsize < 5)
168 return NULL;
169 *output++ = 0xf8 | (wc >> 24);
170 *output++ = 0x80 | ((wc >> 18) & 0x3f);
171 *output++ = 0x80 | ((wc >> 12) & 0x3f);
172 *output++ = 0x80 | ((wc >> 6) & 0x3f);
173 *output++ = 0x80 | (wc & 0x3f);
174 } else if (wc <= 0x7fffffff) {
175 if (outsize < 6)
176 return NULL;
177 *output++ = 0xfc | (wc >> 30);
178 *output++ = 0x80 | ((wc >> 24) & 0x3f);
179 *output++ = 0x80 | ((wc >> 18) & 0x3f);
180 *output++ = 0x80 | ((wc >> 12) & 0x3f);
181 *output++ = 0x80 | ((wc >> 6) & 0x3f);
182 *output++ = 0x80 | (wc & 0x3f);
183 } else
184 return NULL;
185
186 return output;
187 }
188
utf16_to_utf8(char * output,const u_int16_t * input,size_t outsize,size_t insize)189 int utf16_to_utf8(char *output, const u_int16_t *input, size_t outsize,
190 size_t insize)
191 {
192 const u_int16_t *inp = input;
193 char *outp = output;
194 wchar_t wc;
195
196 while ((size_t)(inp - input) < insize && le16_to_cpu(*inp)) {
197 inp = utf16_to_wchar(inp, &wc, insize - (inp - input));
198 if (inp == NULL) {
199 DBG(0, "illegal UTF-16 sequence\n");
200 return -EILSEQ;
201 }
202 outp = wchar_to_utf8(outp, wc, outsize - (outp - output));
203 if (outp == NULL) {
204 DBG(0, "name is too long\n");
205 return -ENAMETOOLONG;
206 }
207 }
208 *outp = '\0';
209 return 0;
210 }
211
log_base_2(u_int32_t num)212 int log_base_2(u_int32_t num)
213 {
214 int ret = 0;
215 if (num <= 0 || (num & (num - 1)) != 0)
216 return -1;
217
218 while (num >>= 1)
219 ret++;
220 return ret;
221 }
222
223 /*
224 * f2fs bit operations
225 */
226 static const int bits_in_byte[256] = {
227 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
228 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
229 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
230 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
231 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
232 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
233 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
234 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
235 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
236 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
237 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
238 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
239 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
240 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
241 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
242 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
243 };
244
get_bits_in_byte(unsigned char n)245 int get_bits_in_byte(unsigned char n)
246 {
247 return bits_in_byte[n];
248 }
249
test_and_set_bit_le(u32 nr,u8 * addr)250 int test_and_set_bit_le(u32 nr, u8 *addr)
251 {
252 int mask, retval;
253
254 addr += nr >> 3;
255 mask = 1 << ((nr & 0x07));
256 retval = mask & *addr;
257 *addr |= mask;
258 return retval;
259 }
260
test_and_clear_bit_le(u32 nr,u8 * addr)261 int test_and_clear_bit_le(u32 nr, u8 *addr)
262 {
263 int mask, retval;
264
265 addr += nr >> 3;
266 mask = 1 << ((nr & 0x07));
267 retval = mask & *addr;
268 *addr &= ~mask;
269 return retval;
270 }
271
test_bit_le(u32 nr,const u8 * addr)272 int test_bit_le(u32 nr, const u8 *addr)
273 {
274 return ((1 << (nr & 7)) & (addr[nr >> 3]));
275 }
276
f2fs_test_bit(unsigned int nr,const char * p)277 int f2fs_test_bit(unsigned int nr, const char *p)
278 {
279 int mask;
280 char *addr = (char *)p;
281
282 addr += (nr >> 3);
283 mask = 1 << (7 - (nr & 0x07));
284 return (mask & *addr) != 0;
285 }
286
f2fs_set_bit(unsigned int nr,char * addr)287 int f2fs_set_bit(unsigned int nr, char *addr)
288 {
289 int mask;
290 int ret;
291
292 addr += (nr >> 3);
293 mask = 1 << (7 - (nr & 0x07));
294 ret = mask & *addr;
295 *addr |= mask;
296 return ret;
297 }
298
f2fs_clear_bit(unsigned int nr,char * addr)299 int f2fs_clear_bit(unsigned int nr, char *addr)
300 {
301 int mask;
302 int ret;
303
304 addr += (nr >> 3);
305 mask = 1 << (7 - (nr & 0x07));
306 ret = mask & *addr;
307 *addr &= ~mask;
308 return ret;
309 }
310
__ffs(u8 word)311 static inline u64 __ffs(u8 word)
312 {
313 int num = 0;
314
315 if ((word & 0xf) == 0) {
316 num += 4;
317 word >>= 4;
318 }
319 if ((word & 0x3) == 0) {
320 num += 2;
321 word >>= 2;
322 }
323 if ((word & 0x1) == 0)
324 num += 1;
325 return num;
326 }
327
328 /* Copied from linux/lib/find_bit.c */
329 #define BITMAP_FIRST_BYTE_MASK(start) (0xff << ((start) & (BITS_PER_BYTE - 1)))
330
_find_next_bit_le(const u8 * addr,u64 nbits,u64 start,char invert)331 static u64 _find_next_bit_le(const u8 *addr, u64 nbits, u64 start, char invert)
332 {
333 u8 tmp;
334
335 if (!nbits || start >= nbits)
336 return nbits;
337
338 tmp = addr[start / BITS_PER_BYTE] ^ invert;
339
340 /* Handle 1st word. */
341 tmp &= BITMAP_FIRST_BYTE_MASK(start);
342 start = round_down(start, BITS_PER_BYTE);
343
344 while (!tmp) {
345 start += BITS_PER_BYTE;
346 if (start >= nbits)
347 return nbits;
348
349 tmp = addr[start / BITS_PER_BYTE] ^ invert;
350 }
351
352 return min(start + __ffs(tmp), nbits);
353 }
354
find_next_bit_le(const u8 * addr,u64 size,u64 offset)355 u64 find_next_bit_le(const u8 *addr, u64 size, u64 offset)
356 {
357 return _find_next_bit_le(addr, size, offset, 0);
358 }
359
360
find_next_zero_bit_le(const u8 * addr,u64 size,u64 offset)361 u64 find_next_zero_bit_le(const u8 *addr, u64 size, u64 offset)
362 {
363 return _find_next_bit_le(addr, size, offset, 0xff);
364 }
365
366 /*
367 * Hashing code adapted from ext3
368 */
369 #define DELTA 0x9E3779B9
370
TEA_transform(unsigned int buf[4],unsigned int const in[])371 static void TEA_transform(unsigned int buf[4], unsigned int const in[])
372 {
373 __u32 sum = 0;
374 __u32 b0 = buf[0], b1 = buf[1];
375 __u32 a = in[0], b = in[1], c = in[2], d = in[3];
376 int n = 16;
377
378 do {
379 sum += DELTA;
380 b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
381 b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
382 } while (--n);
383
384 buf[0] += b0;
385 buf[1] += b1;
386
387 }
388
str2hashbuf(const unsigned char * msg,int len,unsigned int * buf,int num)389 static void str2hashbuf(const unsigned char *msg, int len,
390 unsigned int *buf, int num)
391 {
392 unsigned pad, val;
393 int i;
394
395 pad = (__u32)len | ((__u32)len << 8);
396 pad |= pad << 16;
397
398 val = pad;
399 if (len > num * 4)
400 len = num * 4;
401 for (i = 0; i < len; i++) {
402 if ((i % 4) == 0)
403 val = pad;
404 val = msg[i] + (val << 8);
405 if ((i % 4) == 3) {
406 *buf++ = val;
407 val = pad;
408 num--;
409 }
410 }
411 if (--num >= 0)
412 *buf++ = val;
413 while (--num >= 0)
414 *buf++ = pad;
415
416 }
417
418 /**
419 * Return hash value of directory entry
420 * @param name dentry name
421 * @param len name lenth
422 * @return return on success hash value, errno on failure
423 */
f2fs_dentry_hash(const unsigned char * name,int len)424 f2fs_hash_t f2fs_dentry_hash(const unsigned char *name, int len)
425 {
426 __u32 hash;
427 f2fs_hash_t f2fs_hash;
428 const unsigned char *p;
429 __u32 in[8], buf[4];
430
431 /* special hash codes for special dentries */
432 if ((len <= 2) && (name[0] == '.') &&
433 (name[1] == '.' || name[1] == '\0'))
434 return 0;
435
436 /* Initialize the default seed for the hash checksum functions */
437 buf[0] = 0x67452301;
438 buf[1] = 0xefcdab89;
439 buf[2] = 0x98badcfe;
440 buf[3] = 0x10325476;
441
442 p = name;
443 while (1) {
444 str2hashbuf(p, len, in, 4);
445 TEA_transform(buf, in);
446 p += 16;
447 if (len <= 16)
448 break;
449 len -= 16;
450 }
451 hash = buf[0];
452
453 f2fs_hash = cpu_to_le32(hash & ~F2FS_HASH_COL_BIT);
454 return f2fs_hash;
455 }
456
addrs_per_inode(struct f2fs_inode * i)457 unsigned int addrs_per_inode(struct f2fs_inode *i)
458 {
459 if (i->i_inline & F2FS_INLINE_XATTR)
460 return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS;
461 return DEF_ADDRS_PER_INODE;
462 }
463
464 /*
465 * CRC32
466 */
467 #define CRCPOLY_LE 0xedb88320
468
f2fs_cal_crc32(u_int32_t crc,void * buf,int len)469 u_int32_t f2fs_cal_crc32(u_int32_t crc, void *buf, int len)
470 {
471 int i;
472 unsigned char *p = (unsigned char *)buf;
473 while (len--) {
474 crc ^= *p++;
475 for (i = 0; i < 8; i++)
476 crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
477 }
478 return crc;
479 }
480
f2fs_crc_valid(u_int32_t blk_crc,void * buf,int len)481 int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len)
482 {
483 u_int32_t cal_crc = 0;
484
485 cal_crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, buf, len);
486
487 if (cal_crc != blk_crc) {
488 DBG(0,"CRC validation failed: cal_crc = %u, "
489 "blk_crc = %u buff_size = 0x%x\n",
490 cal_crc, blk_crc, len);
491 return -1;
492 }
493 return 0;
494 }
495
496 /*
497 * try to identify the root device
498 */
get_rootdev()499 const char *get_rootdev()
500 {
501 struct stat sb;
502 int fd, ret;
503 char buf[32];
504 char *uevent, *ptr;
505
506 static char rootdev[PATH_MAX + 1];
507
508 if (stat("/", &sb) == -1)
509 return NULL;
510
511 snprintf(buf, 32, "/sys/dev/block/%u:%u/uevent",
512 major(sb.st_dev), minor(sb.st_dev));
513
514 fd = open(buf, O_RDONLY);
515
516 if (fd < 0)
517 return NULL;
518
519 ret = lseek(fd, (off_t)0, SEEK_END);
520 (void)lseek(fd, (off_t)0, SEEK_SET);
521
522 if (ret == -1) {
523 close(fd);
524 return NULL;
525 }
526
527 uevent = malloc(ret + 1);
528 uevent[ret] = '\0';
529
530 ret = read(fd, uevent, ret);
531 close(fd);
532
533 ptr = strstr(uevent, "DEVNAME");
534 if (!ptr)
535 return NULL;
536
537 ret = sscanf(ptr, "DEVNAME=%s\n", buf);
538 snprintf(rootdev, PATH_MAX + 1, "/dev/%s", buf);
539
540 return rootdev;
541 }
542
543 /*
544 * device information
545 */
f2fs_init_configuration(void)546 void f2fs_init_configuration(void)
547 {
548 int i;
549
550 c.ndevs = 1;
551 c.total_sectors = 0;
552 c.sector_size = 0;
553 c.sectors_per_blk = DEFAULT_SECTORS_PER_BLOCK;
554 c.blks_per_seg = DEFAULT_BLOCKS_PER_SEGMENT;
555 c.rootdev_name = get_rootdev();
556 c.wanted_total_sectors = -1;
557 c.zoned_mode = 0;
558 c.zoned_model = 0;
559 c.zone_blocks = 0;
560
561 for (i = 0; i < MAX_DEVICES; i++) {
562 memset(&c.devices[i], 0, sizeof(struct device_info));
563 c.devices[i].fd = -1;
564 c.devices[i].sector_size = DEFAULT_SECTOR_SIZE;
565 c.devices[i].end_blkaddr = -1;
566 c.devices[i].zoned_model = F2FS_ZONED_NONE;
567 }
568
569 /* calculated by overprovision ratio */
570 c.reserved_segments = 0;
571 c.overprovision = 0;
572 c.segs_per_sec = 1;
573 c.secs_per_zone = 1;
574 c.segs_per_zone = 1;
575 c.heap = 0;
576 c.vol_label = "";
577 c.trim = 1;
578 c.trimmed = 0;
579 c.ro = 0;
580 c.kd = -1;
581 }
582
is_mounted(const char * mpt,const char * device)583 static int is_mounted(const char *mpt, const char *device)
584 {
585 FILE *file = NULL;
586 struct mntent *mnt = NULL;
587
588 file = setmntent(mpt, "r");
589 if (file == NULL)
590 return 0;
591
592 while ((mnt = getmntent(file)) != NULL) {
593 if (!strcmp(device, mnt->mnt_fsname)) {
594 #ifdef MNTOPT_RO
595 if (hasmntopt(mnt, MNTOPT_RO))
596 c.ro = 1;
597 #endif
598 break;
599 }
600 }
601 endmntent(file);
602 return mnt ? 1 : 0;
603 }
604
f2fs_dev_is_umounted(char * path)605 int f2fs_dev_is_umounted(char *path)
606 {
607 struct stat st_buf;
608 int is_rootdev = 0;
609 int ret = 0;
610
611 if (c.rootdev_name && !strcmp(path, c.rootdev_name))
612 is_rootdev = 1;
613
614 /*
615 * try with /proc/mounts fist to detect RDONLY.
616 * f2fs_stop_checkpoint makes RO in /proc/mounts while RW in /etc/mtab.
617 */
618 ret = is_mounted("/proc/mounts", path);
619 if (ret) {
620 MSG(0, "Info: Mounted device!\n");
621 return -1;
622 }
623
624 ret = is_mounted(MOUNTED, path);
625 if (ret) {
626 MSG(0, "Info: Mounted device!\n");
627 return -1;
628 }
629
630 /*
631 * If we are supposed to operate on the root device, then
632 * also check the mounts for '/dev/root', which sometimes
633 * functions as an alias for the root device.
634 */
635 if (is_rootdev) {
636 ret = is_mounted("/proc/mounts", "/dev/root");
637 if (ret) {
638 MSG(0, "Info: Mounted device!\n");
639 return -1;
640 }
641 }
642
643 /*
644 * If f2fs is umounted with -l, the process can still use
645 * the file system. In this case, we should not format.
646 */
647 if (stat(path, &st_buf) == 0 && S_ISBLK(st_buf.st_mode)) {
648 int fd = open(path, O_RDONLY | O_EXCL);
649
650 if (fd >= 0) {
651 close(fd);
652 } else if (errno == EBUSY) {
653 MSG(0, "\tError: In use by the system!\n");
654 return -1;
655 }
656 }
657 return 0;
658 }
659
f2fs_devs_are_umounted(void)660 int f2fs_devs_are_umounted(void)
661 {
662 int i;
663
664 for (i = 0; i < c.ndevs; i++)
665 if (f2fs_dev_is_umounted((char *)c.devices[i].path))
666 return -1;
667 return 0;
668 }
669
get_kernel_version(__u8 * version)670 void get_kernel_version(__u8 *version)
671 {
672 int i;
673 for (i = 0; i < VERSION_LEN; i++) {
674 if (version[i] == '\n')
675 break;
676 }
677 memset(version + i, 0, VERSION_LEN + 1 - i);
678 }
679
get_device_info(int i)680 int get_device_info(int i)
681 {
682 int32_t fd = 0;
683 uint32_t sector_size;
684 #ifndef BLKGETSIZE64
685 uint32_t total_sectors;
686 #endif
687 struct stat stat_buf;
688 struct hd_geometry geom;
689 #ifndef WITH_ANDROID
690 sg_io_hdr_t io_hdr;
691 unsigned char reply_buffer[96] = {0};
692 unsigned char model_inq[6] = {MODELINQUIRY};
693 #endif
694 struct device_info *dev = c.devices + i;
695
696 if (c.sparse_mode) {
697 fd = open((char *)dev->path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
698 } else {
699 fd = open((char *)dev->path, O_RDWR);
700 }
701 if (fd < 0) {
702 MSG(0, "\tError: Failed to open the device!\n");
703 return -1;
704 }
705
706 dev->fd = fd;
707
708 if (c.kd == -1) {
709 c.kd = open("/proc/version", O_RDONLY);
710 if (c.kd < 0) {
711 MSG(0, "\tInfo: No support kernel version!\n");
712 c.kd = -2;
713 }
714 }
715
716 if (fstat(fd, &stat_buf) < 0 ) {
717 MSG(0, "\tError: Failed to get the device stat!\n");
718 return -1;
719 }
720
721 if (c.sparse_mode) {
722 dev->total_sectors = c.device_size / dev->sector_size;
723 } else if (S_ISREG(stat_buf.st_mode)) {
724 dev->total_sectors = stat_buf.st_size / dev->sector_size;
725 } else if (S_ISBLK(stat_buf.st_mode)) {
726 if (ioctl(fd, BLKSSZGET, §or_size) < 0)
727 MSG(0, "\tError: Using the default sector size\n");
728 else if (dev->sector_size < sector_size)
729 dev->sector_size = sector_size;
730 #ifdef BLKGETSIZE64
731 if (ioctl(fd, BLKGETSIZE64, &dev->total_sectors) < 0) {
732 MSG(0, "\tError: Cannot get the device size\n");
733 return -1;
734 }
735 #else
736 if (ioctl(fd, BLKGETSIZE, &total_sectors) < 0) {
737 MSG(0, "\tError: Cannot get the device size\n");
738 return -1;
739 }
740 dev->total_sectors = total_sectors;
741 #endif
742 dev->total_sectors /= dev->sector_size;
743
744 if (i == 0) {
745 if (ioctl(fd, HDIO_GETGEO, &geom) < 0)
746 c.start_sector = 0;
747 else
748 c.start_sector = geom.start;
749 }
750
751 #ifndef WITH_ANDROID
752 /* Send INQUIRY command */
753 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
754 io_hdr.interface_id = 'S';
755 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
756 io_hdr.dxfer_len = sizeof(reply_buffer);
757 io_hdr.dxferp = reply_buffer;
758 io_hdr.cmd_len = sizeof(model_inq);
759 io_hdr.cmdp = model_inq;
760 io_hdr.timeout = 1000;
761
762 if (!ioctl(fd, SG_IO, &io_hdr)) {
763 int i = 16;
764
765 MSG(0, "Info: [%s] Disk Model: ",
766 dev->path);
767 while (reply_buffer[i] != '`' && i < 80)
768 printf("%c", reply_buffer[i++]);
769 printf("\n");
770 }
771 #endif
772 } else {
773 MSG(0, "\tError: Volume type is not supported!!!\n");
774 return -1;
775 }
776
777 if (!c.sector_size) {
778 c.sector_size = dev->sector_size;
779 c.sectors_per_blk = F2FS_BLKSIZE / c.sector_size;
780 } else if (c.sector_size != c.devices[i].sector_size) {
781 MSG(0, "\tError: Different sector sizes!!!\n");
782 return -1;
783 }
784
785 #ifndef WITH_ANDROID
786 if (S_ISBLK(stat_buf.st_mode))
787 f2fs_get_zoned_model(i);
788
789 if (dev->zoned_model != F2FS_ZONED_NONE) {
790 if (dev->zoned_model == F2FS_ZONED_HM)
791 c.zoned_model = F2FS_ZONED_HM;
792
793 if (f2fs_get_zone_blocks(i)) {
794 MSG(0, "\tError: Failed to get number of blocks per zone\n");
795 return -1;
796 }
797
798 if (f2fs_check_zones(i)) {
799 MSG(0, "\tError: Failed to check zone configuration\n");
800 return -1;
801 }
802 MSG(0, "Info: Host-%s zoned block device:\n",
803 (dev->zoned_model == F2FS_ZONED_HA) ?
804 "aware" : "managed");
805 MSG(0, " %u zones, %u randomly writeable zones\n",
806 dev->nr_zones, dev->nr_rnd_zones);
807 MSG(0, " %lu blocks per zone\n",
808 dev->zone_blocks);
809 }
810 #endif
811 c.total_sectors += dev->total_sectors;
812 return 0;
813 }
814
f2fs_get_device_info(void)815 int f2fs_get_device_info(void)
816 {
817 int i;
818
819 for (i = 0; i < c.ndevs; i++)
820 if (get_device_info(i))
821 return -1;
822
823 if (c.wanted_total_sectors < c.total_sectors) {
824 MSG(0, "Info: total device sectors = %"PRIu64" (in %u bytes)\n",
825 c.total_sectors, c.sector_size);
826 c.total_sectors = c.wanted_total_sectors;
827 c.devices[0].total_sectors = c.total_sectors;
828 }
829 if (c.total_sectors * c.sector_size >
830 (u_int64_t)F2FS_MAX_SEGMENT * 2 * 1024 * 1024) {
831 MSG(0, "\tError: F2FS can support 16TB at most!!!\n");
832 return -1;
833 }
834
835 for (i = 0; i < c.ndevs; i++) {
836 if (c.devices[i].zoned_model != F2FS_ZONED_NONE) {
837 if (c.zone_blocks &&
838 c.zone_blocks != c.devices[i].zone_blocks) {
839 MSG(0, "\tError: not support different zone sizes!!!\n");
840 return -1;
841 }
842 c.zone_blocks = c.devices[i].zone_blocks;
843 }
844 }
845
846 /*
847 * Align sections to the device zone size
848 * and align F2FS zones to the device zones.
849 */
850 if (c.zone_blocks) {
851 c.segs_per_sec = c.zone_blocks / DEFAULT_BLOCKS_PER_SEGMENT;
852 c.secs_per_zone = 1;
853 } else {
854 c.zoned_mode = 0;
855 }
856
857 c.segs_per_zone = c.segs_per_sec * c.secs_per_zone;
858
859 MSG(0, "Info: Segments per section = %d\n", c.segs_per_sec);
860 MSG(0, "Info: Sections per zone = %d\n", c.secs_per_zone);
861 MSG(0, "Info: sector size = %u\n", c.sector_size);
862 MSG(0, "Info: total sectors = %"PRIu64" (%"PRIu64" MB)\n",
863 c.total_sectors, (c.total_sectors *
864 (c.sector_size >> 9)) >> 11);
865 return 0;
866 }
867