blob: 988c85446d89879f7fd0abc7bf5ef99b84015011 [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 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#define _LARGEFILE64_SOURCE
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
Jaegeuk Kim2c877a82013-08-02 17:03:10 +090016#include <errno.h>
Jaegeuk Kime69e4372013-01-25 17:20:16 +090017#include <unistd.h>
18#include <fcntl.h>
19#include <mntent.h>
20#include <time.h>
21#include <sys/stat.h>
22#include <sys/mount.h>
23#include <sys/ioctl.h>
24#include <linux/hdreg.h>
25#include <linux/fs.h>
26
Changman Lee7f35b542013-07-04 17:11:32 +090027#include <f2fs_fs.h>
Jaegeuk Kime69e4372013-01-25 17:20:16 +090028
29struct f2fs_configuration config;
30
31void ASCIIToUNICODE(u_int16_t *out_buf, u_int8_t *in_buf)
32{
33 u_int8_t *pchTempPtr = in_buf;
34 u_int16_t *pwTempPtr = out_buf;
35
36 while (*pchTempPtr != '\0') {
37 *pwTempPtr = (u_int16_t)*pchTempPtr;
38 pchTempPtr++;
39 pwTempPtr++;
40 }
41 *pwTempPtr = '\0';
42 return;
43}
44
45int log_base_2(u_int32_t num)
46{
47 int ret = 0;
48 if (num <= 0 || (num & (num - 1)) != 0)
49 return -1;
50
51 while (num >>= 1)
52 ret++;
53 return ret;
54}
55
56/*
57 * f2fs bit operations
58 */
Changman Lee7f35b542013-07-04 17:11:32 +090059static const int bits_in_byte[256] = {
60 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
61 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
62 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
63 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
64 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
65 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
66 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
67 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
68 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
69 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
70 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
71 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
72 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
73 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
74 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
75 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
76};
77
78int get_bits_in_byte(unsigned char n)
79{
80 return bits_in_byte[n];
81}
82
83int set_bit(unsigned int nr,void * addr)
84{
85 int mask, retval;
86 unsigned char *ADDR = (unsigned char *) addr;
87
88 ADDR += nr >> 3;
89 mask = 1 << ((nr & 0x07));
90 retval = mask & *ADDR;
91 *ADDR |= mask;
92 return retval;
93}
94
95int clear_bit(unsigned int nr, void * addr)
96{
97 int mask, retval;
98 unsigned char *ADDR = (unsigned char *) addr;
99
100 ADDR += nr >> 3;
101 mask = 1 << ((nr & 0x07));
102 retval = mask & *ADDR;
103 *ADDR &= ~mask;
104 return retval;
105}
106
107int test_bit(unsigned int nr, const void * addr)
108{
109 const __u32 *p = (const __u32 *)addr;
110
111 nr = nr ^ 0;
112
113 return ((1 << (nr & 31)) & (p[nr >> 5])) != 0;
114}
115
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900116int f2fs_test_bit(unsigned int nr, const char *p)
117{
118 int mask;
119 char *addr = (char *)p;
120
121 addr += (nr >> 3);
122 mask = 1 << (7 - (nr & 0x07));
123 return (mask & *addr) != 0;
124}
125
Changman Lee7f35b542013-07-04 17:11:32 +0900126int f2fs_set_bit(unsigned int nr, char *addr)
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900127{
128 int mask;
129 int ret;
130
131 addr += (nr >> 3);
132 mask = 1 << (7 - (nr & 0x07));
133 ret = mask & *addr;
134 *addr |= mask;
135 return ret;
136}
137
138int f2fs_clear_bit(unsigned int nr, char *addr)
139{
140 int mask;
141 int ret;
142
143 addr += (nr >> 3);
144 mask = 1 << (7 - (nr & 0x07));
145 ret = mask & *addr;
146 *addr &= ~mask;
147 return ret;
148}
149
Changman Lee57baa232013-07-30 16:39:06 +0900150static inline unsigned long __ffs(unsigned long word)
151{
152 int num = 0;
153
154#if BITS_PER_LONG == 64
155 if ((word & 0xffffffff) == 0) {
156 num += 32;
157 word >>= 32;
158 }
159#endif
160 if ((word & 0xffff) == 0) {
161 num += 16;
162 word >>= 16;
163 }
164 if ((word & 0xff) == 0) {
165 num += 8;
166 word >>= 8;
167 }
168 if ((word & 0xf) == 0) {
169 num += 4;
170 word >>= 4;
171 }
172 if ((word & 0x3) == 0) {
173 num += 2;
174 word >>= 2;
175 }
176 if ((word & 0x1) == 0)
177 num += 1;
178 return num;
179}
180
181unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
182 unsigned long offset)
183{
184 const unsigned long *p = addr + BIT_WORD(offset);
185 unsigned long result = offset & ~(BITS_PER_LONG-1);
186 unsigned long tmp;
187
188 if (offset >= size)
189 return size;
190 size -= result;
191 offset %= BITS_PER_LONG;
192 if (offset) {
193 tmp = *(p++);
194 tmp &= (~0UL << offset);
195 if (size < BITS_PER_LONG)
196 goto found_first;
197 if (tmp)
198 goto found_middle;
199 size -= BITS_PER_LONG;
200 result += BITS_PER_LONG;
201 }
202 while (size & ~(BITS_PER_LONG-1)) {
203 if ((tmp = *(p++)))
204 goto found_middle;
205 result += BITS_PER_LONG;
206 size -= BITS_PER_LONG;
207 }
208 if (!size)
209 return result;
210 tmp = *p;
211
212found_first:
213 tmp &= (~0UL >> (BITS_PER_LONG - size));
214 if (tmp == 0UL) /* Are any bits set? */
215 return result + size; /* Nope. */
216found_middle:
217 return result + __ffs(tmp);
218}
219
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900220/*
Changman Lee7f35b542013-07-04 17:11:32 +0900221 * Hashing code adapted from ext3
222 */
223#define DELTA 0x9E3779B9
224
225static void TEA_transform(unsigned int buf[4], unsigned int const in[])
226{
227 __u32 sum = 0;
228 __u32 b0 = buf[0], b1 = buf[1];
229 __u32 a = in[0], b = in[1], c = in[2], d = in[3];
230 int n = 16;
231
232 do {
233 sum += DELTA;
234 b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
235 b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
236 } while (--n);
237
238 buf[0] += b0;
239 buf[1] += b1;
240
241}
242
243static void str2hashbuf(const char *msg, int len, unsigned int *buf, int num)
244{
245 unsigned pad, val;
246 int i;
247
248 pad = (__u32)len | ((__u32)len << 8);
249 pad |= pad << 16;
250
251 val = pad;
252 if (len > num * 4)
253 len = num * 4;
254 for (i = 0; i < len; i++) {
255 if ((i % 4) == 0)
256 val = pad;
257 val = msg[i] + (val << 8);
258 if ((i % 4) == 3) {
259 *buf++ = val;
260 val = pad;
261 num--;
262 }
263 }
264 if (--num >= 0)
265 *buf++ = val;
266 while (--num >= 0)
267 *buf++ = pad;
268
269}
270
271/**
272 * Return hash value of directory entry
273 * @param name dentry name
274 * @param len name lenth
275 * @return return on success hash value, errno on failure
276 */
277f2fs_hash_t f2fs_dentry_hash(const char *name, int len)
278{
279 __u32 hash;
280 f2fs_hash_t f2fs_hash;
281 const char *p;
282 __u32 in[8], buf[4];
283
284 /* special hash codes for special dentries */
285 if (name[0] == '.') {
286 if (name[1] == '\0') {
287 f2fs_hash = F2FS_DOT_HASH;
288 goto exit;
289 }
290 if (name[1] == '.' && name[2] == '\0') {
291 f2fs_hash = F2FS_DDOT_HASH;
292 goto exit;
293 }
294 }
295
296 /* Initialize the default seed for the hash checksum functions */
297 buf[0] = 0x67452301;
298 buf[1] = 0xefcdab89;
299 buf[2] = 0x98badcfe;
300 buf[3] = 0x10325476;
301
302 p = name;
303 while (len > 0) {
304 str2hashbuf(p, len, in, 4);
305 TEA_transform(buf, in);
306 len -= 16;
307 p += 16;
308 }
309 hash = buf[0];
310
311 f2fs_hash = hash;
312exit:
313 f2fs_hash &= ~F2FS_HASH_COL_BIT;
314
315 return f2fs_hash;
316}
317
Jaegeuk Kimcd1e4702013-08-20 18:05:56 +0900318unsigned int addrs_per_inode(struct f2fs_inode *i)
319{
320 if (i->i_inline & F2FS_INLINE_XATTR)
321 return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS;
322 return DEF_ADDRS_PER_INODE;
323}
324
Changman Lee7f35b542013-07-04 17:11:32 +0900325/*
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900326 * CRC32
327 */
328#define CRCPOLY_LE 0xedb88320
329
330u_int32_t f2fs_cal_crc32(u_int32_t crc, void *buf, int len)
331{
332 int i;
333 unsigned char *p = (unsigned char *)buf;
334 while (len--) {
335 crc ^= *p++;
336 for (i = 0; i < 8; i++)
337 crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
338 }
339 return crc;
340}
341
Jaegeuk Kim5043dff2013-02-12 11:03:24 +0900342int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len)
343{
344 u_int32_t cal_crc = 0;
345
346 cal_crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, buf, len);
347
348 if (cal_crc != blk_crc) {
349 DBG(0,"CRC validation failed: cal_crc = %u \
350 blk_crc = %u buff_size = 0x%x",
351 cal_crc, blk_crc, len);
352 return -1;
353 }
354 return 0;
355}
356
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900357/*
358 * device information
359 */
360void f2fs_init_configuration(struct f2fs_configuration *c)
361{
362 c->sector_size = DEFAULT_SECTOR_SIZE;
363 c->sectors_per_blk = DEFAULT_SECTORS_PER_BLOCK;
364 c->blks_per_seg = DEFAULT_BLOCKS_PER_SEGMENT;
365
366 /* calculated by overprovision ratio */
367 c->reserved_segments = 48;
368 c->overprovision = 5;
369 c->segs_per_sec = 1;
370 c->secs_per_zone = 1;
371 c->heap = 1;
Mike Fleetwood9799d632013-04-02 23:15:20 +0100372 c->vol_label = "";
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900373 c->device_name = NULL;
374}
375
Jaegeuk Kim2c877a82013-08-02 17:03:10 +0900376static int is_mounted(const char *mpt, const char *device)
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900377{
378 FILE *file = NULL;
379 struct mntent *mnt = NULL;
380
Jaegeuk Kim2c877a82013-08-02 17:03:10 +0900381 file = setmntent(mpt, "r");
382 if (file == NULL)
383 return 0;
384
385 while ((mnt = getmntent(file)) != NULL) {
386 if (!strcmp(device, mnt->mnt_fsname))
387 break;
388 }
389 endmntent(file);
390 return mnt ? 1 : 0;
391}
392
393int f2fs_dev_is_umounted(struct f2fs_configuration *c)
394{
395 struct stat st_buf;
396 int ret = 0;
397
398 ret = is_mounted(MOUNTED, c->device_name);
399 if (ret) {
400 MSG(0, "\tError: Not available on mounted device!\n");
401 return -1;
Namjae Jeon8d3802b2013-03-31 11:51:29 +0900402 }
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900403
Jaegeuk Kim2c877a82013-08-02 17:03:10 +0900404 /*
405 * if failed due to /etc/mtab file not present
406 * try with /proc/mounts.
407 */
408 ret = is_mounted("/proc/mounts", c->device_name);
409 if (ret) {
410 MSG(0, "\tError: Not available on mounted device!\n");
411 return -1;
412 }
413
414 /*
415 * If f2fs is umounted with -l, the process can still use
416 * the file system. In this case, we should not format.
417 */
418 if (stat(c->device_name, &st_buf) == 0 && S_ISBLK(st_buf.st_mode)) {
419 int fd = open(c->device_name, O_RDONLY | O_EXCL);
420
421 if (fd >= 0) {
422 close(fd);
423 } else if (errno == EBUSY) {
424 MSG(0, "\tError: In use by the system!\n");
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900425 return -1;
426 }
427 }
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900428 return 0;
429}
430
431int f2fs_get_device_info(struct f2fs_configuration *c)
432{
433 int32_t fd = 0;
434 int32_t sector_size;
435 struct stat stat_buf;
436 struct hd_geometry geom;
437
438 fd = open(c->device_name, O_RDWR);
439 if (fd < 0) {
440 MSG(0, "\tError: Failed to open the device!\n");
441 return -1;
442 }
443 c->fd = fd;
444
445 if (fstat(fd, &stat_buf) < 0 ) {
446 MSG(0, "\tError: Failed to get the device stat!\n");
447 return -1;
448 }
449
450 if (S_ISREG(stat_buf.st_mode)) {
451 c->total_sectors = stat_buf.st_size / c->sector_size;
452 } else if (S_ISBLK(stat_buf.st_mode)) {
453 if (ioctl(fd, BLKSSZGET, &sector_size) < 0) {
454 MSG(0, "\tError: Using the default sector size\n");
455 } else {
456 if (c->sector_size < sector_size) {
457 MSG(0, "\tError: Cannot set the sector size to:"
458 " %d as the device does not support"
459 "\nSetting the sector size to : %d\n",
460 c->sector_size, sector_size);
461 c->sector_size = sector_size;
462 c->sectors_per_blk = PAGE_SIZE / sector_size;
463 }
464 }
465
466 if (ioctl(fd, BLKGETSIZE, &c->total_sectors) < 0) {
467 MSG(0, "\tError: Cannot get the device size\n");
468 return -1;
469 }
470
471 if (ioctl(fd, HDIO_GETGEO, &geom) < 0)
472 c->start_sector = 0;
473 else
474 c->start_sector = geom.start;
475 } else {
476 MSG(0, "\tError: Volume type is not supported!!!\n");
477 return -1;
478 }
479
480 MSG(0, "Info: sector size = %u\n", c->sector_size);
481 MSG(0, "Info: total sectors = %"PRIu64" (in 512bytes)\n",
482 c->total_sectors);
483 if (c->total_sectors <
484 (F2FS_MIN_VOLUME_SIZE / DEFAULT_SECTOR_SIZE)) {
485 MSG(0, "Error: Min volume size supported is %d\n",
486 F2FS_MIN_VOLUME_SIZE);
487 return -1;
488 }
489
490 return 0;
491}
492
493/*
494 * IO interfaces
495 */
Jaegeuk Kim5043dff2013-02-12 11:03:24 +0900496int dev_read(void *buf, __u64 offset, size_t len)
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900497{
Jaegeuk Kim5043dff2013-02-12 11:03:24 +0900498 if (lseek64(config.fd, (off64_t)offset, SEEK_SET) < 0)
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900499 return -1;
Jaegeuk Kim5043dff2013-02-12 11:03:24 +0900500 if (read(config.fd, buf, len) < 0)
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900501 return -1;
502 return 0;
503}
504
Jaegeuk Kim5043dff2013-02-12 11:03:24 +0900505int dev_write(void *buf, __u64 offset, size_t len)
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900506{
Jaegeuk Kim5043dff2013-02-12 11:03:24 +0900507 if (lseek64(config.fd, (off64_t)offset, SEEK_SET) < 0)
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900508 return -1;
Jaegeuk Kim5043dff2013-02-12 11:03:24 +0900509 if (write(config.fd, buf, len) < 0)
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900510 return -1;
511 return 0;
512}
513
Jaegeuk Kim5043dff2013-02-12 11:03:24 +0900514int dev_read_block(void *buf, __u64 blk_addr)
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900515{
Jaegeuk Kim5043dff2013-02-12 11:03:24 +0900516 return dev_read(buf, blk_addr * F2FS_BLKSIZE, F2FS_BLKSIZE);
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900517}
518
Jaegeuk Kim5043dff2013-02-12 11:03:24 +0900519int dev_read_blocks(void *buf, __u64 addr, __u32 nr_blks)
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900520{
Jaegeuk Kim5043dff2013-02-12 11:03:24 +0900521 return dev_read(buf, addr * F2FS_BLKSIZE, nr_blks * F2FS_BLKSIZE);
Jaegeuk Kime69e4372013-01-25 17:20:16 +0900522}