1 /**
2 * libf2fs.c
3 *
4 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com/
6 * Copyright (c) 2019 Google Inc.
7 * http://www.google.com/
8 * Copyright (c) 2020 Google Inc.
9 * Robin Hsu <[email protected]>
10 * : add quick-buffer for sload compression support
11 *
12 * Dual licensed under the GPL or LGPL version 2 licenses.
13 */
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #ifdef HAVE_MNTENT_H
21 #include <mntent.h>
22 #endif
23 #include <time.h>
24 #ifdef HAVE_SYS_STAT_H
25 #include <sys/stat.h>
26 #endif
27 #ifdef HAVE_SYS_MOUNT_H
28 #include <sys/mount.h>
29 #endif
30 #ifdef HAVE_SYS_IOCTL_H
31 #include <sys/ioctl.h>
32 #endif
33 #ifdef HAVE_LINUX_HDREG_H
34 #include <linux/hdreg.h>
35 #endif
36
37 #ifndef F_SET_RW_HINT
38 #define F_LINUX_SPECIFIC_BASE 1024
39 #define F_SET_RW_HINT (F_LINUX_SPECIFIC_BASE + 12)
40 #endif
41
42 #include <stdbool.h>
43 #include <assert.h>
44 #include <inttypes.h>
45 #include "f2fs_fs.h"
46
47 struct f2fs_configuration c;
48
49 #ifdef HAVE_SPARSE_SPARSE_H
50 #include <sparse/sparse.h>
51 struct sparse_file *f2fs_sparse_file;
52 static char **blocks;
53 uint64_t blocks_count;
54 static char *zeroed_block;
55 #endif
56
__get_device_fd(__u64 * offset)57 static int __get_device_fd(__u64 *offset)
58 {
59 __u64 blk_addr = *offset >> F2FS_BLKSIZE_BITS;
60 int i;
61
62 for (i = 0; i < c.ndevs; i++) {
63 if (c.devices[i].start_blkaddr <= blk_addr &&
64 c.devices[i].end_blkaddr >= blk_addr) {
65 *offset -=
66 c.devices[i].start_blkaddr << F2FS_BLKSIZE_BITS;
67 return c.devices[i].fd;
68 }
69 }
70 return -1;
71 }
72
73 /* ---------- dev_cache, Least Used First (LUF) policy ------------------- */
74 /*
75 * Least used block will be the first victim to be replaced when max hash
76 * collision exceeds
77 */
78 static bool *dcache_valid; /* is the cached block valid? */
79 static off_t *dcache_blk; /* which block it cached */
80 static uint64_t *dcache_lastused; /* last used ticks for cache entries */
81 static char *dcache_buf; /* cached block data */
82 static uint64_t dcache_usetick; /* current use tick */
83
84 static uint64_t dcache_raccess;
85 static uint64_t dcache_rhit;
86 static uint64_t dcache_rmiss;
87 static uint64_t dcache_rreplace;
88
89 static bool dcache_exit_registered = false;
90
91 /*
92 * Shadow config:
93 *
94 * Active set of the configurations.
95 * Global configuration 'dcache_config' will be transferred here when
96 * when dcache_init() is called
97 */
98 static dev_cache_config_t dcache_config = {0, 16, 1};
99 static bool dcache_initialized = false;
100
101 #define MIN_NUM_CACHE_ENTRY 1024L
102 #define MAX_MAX_HASH_COLLISION 16
103
104 static long dcache_relocate_offset0[] = {
105 20, -20, 40, -40, 80, -80, 160, -160,
106 320, -320, 640, -640, 1280, -1280, 2560, -2560,
107 };
108 static int dcache_relocate_offset[16];
109
dcache_print_statistics(void)110 static void dcache_print_statistics(void)
111 {
112 long i;
113 long useCnt;
114
115 /* Number of used cache entries */
116 useCnt = 0;
117 for (i = 0; i < dcache_config.num_cache_entry; i++)
118 if (dcache_valid[i])
119 ++useCnt;
120
121 /*
122 * c: number of cache entries
123 * u: used entries
124 * RA: number of read access blocks
125 * CH: cache hit
126 * CM: cache miss
127 * Repl: read cache replaced
128 */
129 printf ("\nc, u, RA, CH, CM, Repl=\n");
130 printf ("%ld %ld %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
131 dcache_config.num_cache_entry,
132 useCnt,
133 dcache_raccess,
134 dcache_rhit,
135 dcache_rmiss,
136 dcache_rreplace);
137 }
138
dcache_release(void)139 void dcache_release(void)
140 {
141 if (!dcache_initialized)
142 return;
143
144 dcache_initialized = false;
145
146 if (c.cache_config.dbg_en)
147 dcache_print_statistics();
148
149 if (dcache_blk != NULL)
150 free(dcache_blk);
151 if (dcache_lastused != NULL)
152 free(dcache_lastused);
153 if (dcache_buf != NULL)
154 free(dcache_buf);
155 if (dcache_valid != NULL)
156 free(dcache_valid);
157 dcache_config.num_cache_entry = 0;
158 dcache_blk = NULL;
159 dcache_lastused = NULL;
160 dcache_buf = NULL;
161 dcache_valid = NULL;
162 }
163
164 // return 0 for success, error code for failure.
dcache_alloc_all(long n)165 static int dcache_alloc_all(long n)
166 {
167 if (n <= 0)
168 return -1;
169 if ((dcache_blk = (off_t *) malloc(sizeof(off_t) * n)) == NULL
170 || (dcache_lastused = (uint64_t *)
171 malloc(sizeof(uint64_t) * n)) == NULL
172 || (dcache_buf = (char *) malloc (F2FS_BLKSIZE * n)) == NULL
173 || (dcache_valid = (bool *) calloc(sizeof(bool) * n, 1)) == NULL)
174 {
175 dcache_release();
176 return -1;
177 }
178 dcache_config.num_cache_entry = n;
179 return 0;
180 }
181
dcache_relocate_init(void)182 static void dcache_relocate_init(void)
183 {
184 int i;
185 int n0 = (sizeof(dcache_relocate_offset0)
186 / sizeof(dcache_relocate_offset0[0]));
187 int n = (sizeof(dcache_relocate_offset)
188 / sizeof(dcache_relocate_offset[0]));
189
190 ASSERT(n == n0);
191 for (i = 0; i < n && i < dcache_config.max_hash_collision; i++) {
192 if (labs(dcache_relocate_offset0[i])
193 > dcache_config.num_cache_entry / 2) {
194 dcache_config.max_hash_collision = i;
195 break;
196 }
197 dcache_relocate_offset[i] =
198 dcache_config.num_cache_entry
199 + dcache_relocate_offset0[i];
200 }
201 }
202
dcache_init(void)203 void dcache_init(void)
204 {
205 long n;
206
207 if (c.cache_config.num_cache_entry <= 0)
208 return;
209
210 /* release previous cache init, if any */
211 dcache_release();
212
213 dcache_blk = NULL;
214 dcache_lastused = NULL;
215 dcache_buf = NULL;
216 dcache_valid = NULL;
217
218 dcache_config = c.cache_config;
219
220 n = max(MIN_NUM_CACHE_ENTRY, dcache_config.num_cache_entry);
221
222 /* halve alloc size until alloc succeed, or min cache reached */
223 while (dcache_alloc_all(n) != 0 && n != MIN_NUM_CACHE_ENTRY)
224 n = max(MIN_NUM_CACHE_ENTRY, n/2);
225
226 /* must be the last: data dependent on num_cache_entry */
227 dcache_relocate_init();
228 dcache_initialized = true;
229
230 if (!dcache_exit_registered) {
231 dcache_exit_registered = true;
232 atexit(dcache_release); /* auto release */
233 }
234
235 dcache_raccess = 0;
236 dcache_rhit = 0;
237 dcache_rmiss = 0;
238 dcache_rreplace = 0;
239 }
240
dcache_addr(long entry)241 static inline char *dcache_addr(long entry)
242 {
243 return dcache_buf + F2FS_BLKSIZE * entry;
244 }
245
246 /* relocate on (n+1)-th collision */
dcache_relocate(long entry,int n)247 static inline long dcache_relocate(long entry, int n)
248 {
249 assert(dcache_config.num_cache_entry != 0);
250 return (entry + dcache_relocate_offset[n]) %
251 dcache_config.num_cache_entry;
252 }
253
dcache_find(__u64 blk)254 static long dcache_find(__u64 blk)
255 {
256 register long n = dcache_config.num_cache_entry;
257 register unsigned m = dcache_config.max_hash_collision;
258 long entry, least_used, target;
259 unsigned try;
260
261 assert(n > 0);
262 target = least_used = entry = blk % n; /* simple modulo hash */
263
264 for (try = 0; try < m; try++) {
265 if (!dcache_valid[target] || dcache_blk[target] == blk)
266 return target; /* found target or empty cache slot */
267 if (dcache_lastused[target] < dcache_lastused[least_used])
268 least_used = target;
269 target = dcache_relocate(entry, try); /* next target */
270 }
271 return least_used; /* max search reached, return least used slot */
272 }
273
274 /* Physical read into cache */
dcache_io_read(long entry,__u64 offset,off_t blk)275 static int dcache_io_read(long entry, __u64 offset, off_t blk)
276 {
277 int fd = __get_device_fd(&offset);
278
279 if (fd < 0)
280 return fd;
281
282 if (lseek(fd, offset, SEEK_SET) < 0) {
283 MSG(0, "\n lseek fail.\n");
284 return -1;
285 }
286 if (read(fd, dcache_buf + entry * F2FS_BLKSIZE, F2FS_BLKSIZE) < 0) {
287 MSG(0, "\n read() fail.\n");
288 return -1;
289 }
290 dcache_lastused[entry] = ++dcache_usetick;
291 dcache_valid[entry] = true;
292 dcache_blk[entry] = blk;
293 return 0;
294 }
295
296 /*
297 * - Note: Read/Write are not symmetric:
298 * For read, we need to do it block by block, due to the cache nature:
299 * some blocks may be cached, and others don't.
300 * For write, since we always do a write-thru, we can join all writes into one,
301 * and write it once at the caller. This function updates the cache for write, but
302 * not the do a physical write. The caller is responsible for the physical write.
303 * - Note: We concentrate read/write together, due to the fact of similar structure to find
304 * the relavant cache entries
305 * - Return values:
306 * 0: success
307 * 1: cache not available (uninitialized)
308 * -1: error
309 */
dcache_update_rw(void * buf,__u64 offset,size_t byte_count,bool is_write)310 static int dcache_update_rw(void *buf, __u64 offset,
311 size_t byte_count, bool is_write)
312 {
313 __u64 blk, start;
314 int addr_in_blk;
315
316 if (!dcache_initialized)
317 dcache_init(); /* auto initialize */
318
319 if (!dcache_initialized)
320 return 1; /* not available */
321
322 blk = offset / F2FS_BLKSIZE;
323 addr_in_blk = offset % F2FS_BLKSIZE;
324 start = blk * F2FS_BLKSIZE;
325
326 while (byte_count != 0) {
327 size_t cur_size = min(byte_count,
328 (size_t)(F2FS_BLKSIZE - addr_in_blk));
329 long entry = dcache_find(blk);
330
331 if (!is_write)
332 ++dcache_raccess;
333
334 if (dcache_valid[entry] && dcache_blk[entry] == blk) {
335 /* cache hit */
336 if (is_write) /* write: update cache */
337 memcpy(dcache_addr(entry) + addr_in_blk,
338 buf, cur_size);
339 else
340 ++dcache_rhit;
341 } else {
342 /* cache miss */
343 if (!is_write) {
344 int err;
345 ++dcache_rmiss;
346 if (dcache_valid[entry])
347 ++dcache_rreplace;
348 /* read: physical I/O read into cache */
349 err = dcache_io_read(entry, start, blk);
350 if (err)
351 return err;
352 }
353 }
354
355 /* read: copy data from cache */
356 /* write: nothing to do, since we don't do physical write. */
357 if (!is_write)
358 memcpy(buf, dcache_addr(entry) + addr_in_blk,
359 cur_size);
360
361 /* next block */
362 ++blk;
363 buf += cur_size;
364 start += F2FS_BLKSIZE;
365 byte_count -= cur_size;
366 addr_in_blk = 0;
367 }
368 return 0;
369 }
370
371 /*
372 * dcache_update_cache() just update cache, won't do physical I/O.
373 * Thus even no error, we need normal non-cache I/O for actual write
374 *
375 * return value: 1: cache not available
376 * 0: success, -1: I/O error
377 */
dcache_update_cache(void * buf,__u64 offset,size_t count)378 int dcache_update_cache(void *buf, __u64 offset, size_t count)
379 {
380 return dcache_update_rw(buf, offset, count, true);
381 }
382
383 /* handles read into cache + read into buffer */
dcache_read(void * buf,__u64 offset,size_t count)384 int dcache_read(void *buf, __u64 offset, size_t count)
385 {
386 return dcache_update_rw(buf, offset, count, false);
387 }
388
389 /*
390 * IO interfaces
391 */
dev_read_version(void * buf,__u64 offset,size_t len)392 int dev_read_version(void *buf, __u64 offset, size_t len)
393 {
394 if (c.sparse_mode)
395 return 0;
396 if (lseek(c.kd, (off_t)offset, SEEK_SET) < 0)
397 return -1;
398 if (read(c.kd, buf, len) < 0)
399 return -1;
400 return 0;
401 }
402
403 #ifdef HAVE_SPARSE_SPARSE_H
sparse_read_blk(__u64 block,int count,void * buf)404 static int sparse_read_blk(__u64 block, int count, void *buf)
405 {
406 int i;
407 char *out = buf;
408 __u64 cur_block;
409
410 for (i = 0; i < count; ++i) {
411 cur_block = block + i;
412 if (blocks[cur_block])
413 memcpy(out + (i * F2FS_BLKSIZE),
414 blocks[cur_block], F2FS_BLKSIZE);
415 else if (blocks)
416 memset(out + (i * F2FS_BLKSIZE), 0, F2FS_BLKSIZE);
417 }
418 return 0;
419 }
420
sparse_write_blk(__u64 block,int count,const void * buf)421 static int sparse_write_blk(__u64 block, int count, const void *buf)
422 {
423 int i;
424 __u64 cur_block;
425 const char *in = buf;
426
427 for (i = 0; i < count; ++i) {
428 cur_block = block + i;
429 if (blocks[cur_block] == zeroed_block)
430 blocks[cur_block] = NULL;
431 if (!blocks[cur_block]) {
432 blocks[cur_block] = calloc(1, F2FS_BLKSIZE);
433 if (!blocks[cur_block])
434 return -ENOMEM;
435 }
436 memcpy(blocks[cur_block], in + (i * F2FS_BLKSIZE),
437 F2FS_BLKSIZE);
438 }
439 return 0;
440 }
441
sparse_write_zeroed_blk(__u64 block,int count)442 static int sparse_write_zeroed_blk(__u64 block, int count)
443 {
444 int i;
445 __u64 cur_block;
446
447 for (i = 0; i < count; ++i) {
448 cur_block = block + i;
449 if (blocks[cur_block])
450 continue;
451 blocks[cur_block] = zeroed_block;
452 }
453 return 0;
454 }
455
456 #ifdef SPARSE_CALLBACK_USES_SIZE_T
sparse_import_segment(void * UNUSED (priv),const void * data,size_t len,unsigned int block,unsigned int nr_blocks)457 static int sparse_import_segment(void *UNUSED(priv), const void *data,
458 size_t len, unsigned int block, unsigned int nr_blocks)
459 #else
460 static int sparse_import_segment(void *UNUSED(priv), const void *data, int len,
461 unsigned int block, unsigned int nr_blocks)
462 #endif
463 {
464 /* Ignore chunk headers, only write the data */
465 if (!nr_blocks || len % F2FS_BLKSIZE)
466 return 0;
467
468 return sparse_write_blk(block, nr_blocks, data);
469 }
470
sparse_merge_blocks(uint64_t start,uint64_t num,int zero)471 static int sparse_merge_blocks(uint64_t start, uint64_t num, int zero)
472 {
473 char *buf;
474 uint64_t i;
475
476 if (zero) {
477 blocks[start] = NULL;
478 return sparse_file_add_fill(f2fs_sparse_file, 0x0,
479 F2FS_BLKSIZE * num, start);
480 }
481
482 buf = calloc(num, F2FS_BLKSIZE);
483 if (!buf) {
484 fprintf(stderr, "failed to alloc %llu\n",
485 (unsigned long long)num * F2FS_BLKSIZE);
486 return -ENOMEM;
487 }
488
489 for (i = 0; i < num; i++) {
490 memcpy(buf + i * F2FS_BLKSIZE, blocks[start + i], F2FS_BLKSIZE);
491 free(blocks[start + i]);
492 blocks[start + i] = NULL;
493 }
494
495 /* free_sparse_blocks will release this buf. */
496 blocks[start] = buf;
497
498 return sparse_file_add_data(f2fs_sparse_file, blocks[start],
499 F2FS_BLKSIZE * num, start);
500 }
501 #else
sparse_read_blk(__u64 UNUSED (block),int UNUSED (count),void * UNUSED (buf))502 static int sparse_read_blk(__u64 UNUSED(block),
503 int UNUSED(count), void *UNUSED(buf))
504 {
505 return 0;
506 }
507
sparse_write_blk(__u64 UNUSED (block),int UNUSED (count),const void * UNUSED (buf))508 static int sparse_write_blk(__u64 UNUSED(block),
509 int UNUSED(count), const void *UNUSED(buf))
510 {
511 return 0;
512 }
513
sparse_write_zeroed_blk(__u64 UNUSED (block),int UNUSED (count))514 static int sparse_write_zeroed_blk(__u64 UNUSED(block), int UNUSED(count))
515 {
516 return 0;
517 }
518 #endif
519
dev_read(void * buf,__u64 offset,size_t len)520 int dev_read(void *buf, __u64 offset, size_t len)
521 {
522 int fd;
523 int err;
524
525 if (c.sparse_mode)
526 return sparse_read_blk(offset / F2FS_BLKSIZE,
527 len / F2FS_BLKSIZE, buf);
528
529 /* err = 1: cache not available, fall back to non-cache R/W */
530 /* err = 0: success, err=-1: I/O error */
531 err = dcache_read(buf, offset, len);
532 if (err <= 0)
533 return err;
534
535 fd = __get_device_fd(&offset);
536 if (fd < 0)
537 return fd;
538 if (lseek(fd, (off_t)offset, SEEK_SET) < 0)
539 return -1;
540 if (read(fd, buf, len) < 0)
541 return -1;
542 return 0;
543 }
544
545 #ifdef POSIX_FADV_WILLNEED
dev_readahead(__u64 offset,size_t len)546 int dev_readahead(__u64 offset, size_t len)
547 #else
548 int dev_readahead(__u64 offset, size_t UNUSED(len))
549 #endif
550 {
551 int fd = __get_device_fd(&offset);
552
553 if (fd < 0)
554 return fd;
555 #ifdef POSIX_FADV_WILLNEED
556 return posix_fadvise(fd, offset, len, POSIX_FADV_WILLNEED);
557 #else
558 return 0;
559 #endif
560 }
561 /*
562 * Copied from fs/f2fs/segment.c
563 */
564 /*
565 * This returns write hints for each segment type. This hints will be
566 * passed down to block layer as below by default.
567 *
568 * User F2FS Block
569 * ---- ---- -----
570 * META WRITE_LIFE_NONE|REQ_META
571 * HOT_NODE WRITE_LIFE_NONE
572 * WARM_NODE WRITE_LIFE_MEDIUM
573 * COLD_NODE WRITE_LIFE_LONG
574 * ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME
575 * extension list " "
576 *
577 * -- buffered io
578 * COLD_DATA WRITE_LIFE_EXTREME
579 * HOT_DATA WRITE_LIFE_SHORT
580 * WARM_DATA WRITE_LIFE_NOT_SET
581 *
582 * -- direct io
583 * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
584 * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
585 * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET
586 * WRITE_LIFE_NONE " WRITE_LIFE_NONE
587 * WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM
588 * WRITE_LIFE_LONG " WRITE_LIFE_LONG
589 */
f2fs_io_type_to_rw_hint(int seg_type)590 enum rw_hint f2fs_io_type_to_rw_hint(int seg_type)
591 {
592 switch (seg_type) {
593 case CURSEG_WARM_DATA:
594 return WRITE_LIFE_NOT_SET;
595 case CURSEG_HOT_DATA:
596 return WRITE_LIFE_SHORT;
597 case CURSEG_COLD_DATA:
598 return WRITE_LIFE_EXTREME;
599 case CURSEG_WARM_NODE:
600 return WRITE_LIFE_MEDIUM;
601 case CURSEG_HOT_NODE:
602 return WRITE_LIFE_NONE;
603 case CURSEG_COLD_NODE:
604 return WRITE_LIFE_LONG;
605 default:
606 return WRITE_LIFE_NONE;
607 }
608 }
609
__dev_write(void * buf,__u64 offset,size_t len,enum rw_hint whint)610 static int __dev_write(void *buf, __u64 offset, size_t len, enum rw_hint whint)
611 {
612 int fd;
613
614 fd = __get_device_fd(&offset);
615 if (fd < 0)
616 return fd;
617
618 if (lseek(fd, (off_t)offset, SEEK_SET) < 0)
619 return -1;
620
621 #if ! defined(__MINGW32__)
622 if (c.need_whint && (c.whint != whint)) {
623 u64 hint = whint;
624 int ret;
625
626 ret = fcntl(fd, F_SET_RW_HINT, &hint);
627 if (ret != -1)
628 c.whint = whint;
629 }
630 #endif
631
632 if (write(fd, buf, len) < 0)
633 return -1;
634
635 c.need_fsync = true;
636
637 return 0;
638 }
639
dev_write(void * buf,__u64 offset,size_t len,enum rw_hint whint)640 int dev_write(void *buf, __u64 offset, size_t len, enum rw_hint whint)
641 {
642 if (c.dry_run)
643 return 0;
644
645 if (c.sparse_mode)
646 return sparse_write_blk(offset / F2FS_BLKSIZE,
647 len / F2FS_BLKSIZE, buf);
648
649 /*
650 * dcache_update_cache() just update cache, won't do I/O.
651 * Thus even no error, we need normal non-cache I/O for actual write
652 */
653 if (dcache_update_cache(buf, offset, len) < 0)
654 return -1;
655
656 return __dev_write(buf, offset, len, whint);
657 }
658
dev_write_block(void * buf,__u64 blk_addr,enum rw_hint whint)659 int dev_write_block(void *buf, __u64 blk_addr, enum rw_hint whint)
660 {
661 return dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE, whint);
662 }
663
dev_write_dump(void * buf,__u64 offset,size_t len)664 int dev_write_dump(void *buf, __u64 offset, size_t len)
665 {
666 if (lseek(c.dump_fd, (off_t)offset, SEEK_SET) < 0)
667 return -1;
668 if (write(c.dump_fd, buf, len) < 0)
669 return -1;
670 return 0;
671 }
672
673 #if !defined(__MINGW32__)
dev_write_symlink(char * buf,size_t len)674 int dev_write_symlink(char *buf, size_t len)
675 {
676 buf[len] = 0;
677 if (symlink(buf, c.dump_symlink))
678 return -1;
679 return 0;
680 }
681 #endif
682
dev_fill(void * buf,__u64 offset,size_t len,enum rw_hint whint)683 int dev_fill(void *buf, __u64 offset, size_t len, enum rw_hint whint)
684 {
685 if (c.sparse_mode)
686 return sparse_write_zeroed_blk(offset / F2FS_BLKSIZE,
687 len / F2FS_BLKSIZE);
688
689 /* Only allow fill to zero */
690 if (*((__u8*)buf))
691 return -1;
692
693 return __dev_write(buf, offset, len, whint);
694 }
695
dev_fill_block(void * buf,__u64 blk_addr,enum rw_hint whint)696 int dev_fill_block(void *buf, __u64 blk_addr, enum rw_hint whint)
697 {
698 return dev_fill(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE, whint);
699 }
700
dev_read_block(void * buf,__u64 blk_addr)701 int dev_read_block(void *buf, __u64 blk_addr)
702 {
703 return dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
704 }
705
dev_reada_block(__u64 blk_addr)706 int dev_reada_block(__u64 blk_addr)
707 {
708 return dev_readahead(blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
709 }
710
f2fs_fsync_device(void)711 int f2fs_fsync_device(void)
712 {
713 #ifdef HAVE_FSYNC
714 int i;
715
716 if (!c.need_fsync)
717 return 0;
718
719 for (i = 0; i < c.ndevs; i++) {
720 if (fsync(c.devices[i].fd) < 0) {
721 MSG(0, "\tError: Could not conduct fsync!!!\n");
722 return -1;
723 }
724 }
725 #endif
726 return 0;
727 }
728
f2fs_init_sparse_file(void)729 int f2fs_init_sparse_file(void)
730 {
731 #ifdef HAVE_SPARSE_SPARSE_H
732 if (c.func == MKFS) {
733 f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE, c.device_size);
734 if (!f2fs_sparse_file)
735 return -1;
736 } else {
737 f2fs_sparse_file = sparse_file_import(c.devices[0].fd,
738 true, false);
739 if (!f2fs_sparse_file)
740 return -1;
741
742 c.blksize = sparse_file_block_size(f2fs_sparse_file);
743 c.blksize_bits = log_base_2(c.blksize);
744 if (c.blksize_bits == -1) {
745 MSG(0, "\tError: Sparse file blocksize not a power of 2.\n");
746 return -1;
747 }
748
749 c.device_size = sparse_file_len(f2fs_sparse_file, 0, 0);
750 c.device_size &= (~((uint64_t)(F2FS_BLKSIZE - 1)));
751 }
752
753 blocks_count = c.device_size / F2FS_BLKSIZE;
754 blocks = calloc(blocks_count, sizeof(char *));
755 if (!blocks) {
756 MSG(0, "\tError: Calloc Failed for blocks!!!\n");
757 return -1;
758 }
759
760 zeroed_block = calloc(1, F2FS_BLKSIZE);
761 if (!zeroed_block) {
762 MSG(0, "\tError: Calloc Failed for zeroed block!!!\n");
763 return -1;
764 }
765
766 return sparse_file_foreach_chunk(f2fs_sparse_file, true, false,
767 sparse_import_segment, NULL);
768 #else
769 MSG(0, "\tError: Sparse mode is only supported for android\n");
770 return -1;
771 #endif
772 }
773
f2fs_release_sparse_resource(void)774 void f2fs_release_sparse_resource(void)
775 {
776 #ifdef HAVE_SPARSE_SPARSE_H
777 int j;
778
779 if (c.sparse_mode) {
780 if (f2fs_sparse_file != NULL) {
781 sparse_file_destroy(f2fs_sparse_file);
782 f2fs_sparse_file = NULL;
783 }
784 for (j = 0; j < blocks_count; j++)
785 free(blocks[j]);
786 free(blocks);
787 blocks = NULL;
788 free(zeroed_block);
789 zeroed_block = NULL;
790 }
791 #endif
792 }
793
794 #define MAX_CHUNK_SIZE (1 * 1024 * 1024 * 1024ULL)
795 #define MAX_CHUNK_COUNT (MAX_CHUNK_SIZE / F2FS_BLKSIZE)
f2fs_finalize_device(void)796 int f2fs_finalize_device(void)
797 {
798 int i;
799 int ret = 0;
800
801 #ifdef HAVE_SPARSE_SPARSE_H
802 if (c.sparse_mode) {
803 int64_t chunk_start = (blocks[0] == NULL) ? -1 : 0;
804 uint64_t j;
805
806 if (c.func != MKFS) {
807 sparse_file_destroy(f2fs_sparse_file);
808 ret = ftruncate(c.devices[0].fd, 0);
809 ASSERT(!ret);
810 lseek(c.devices[0].fd, 0, SEEK_SET);
811 f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE,
812 c.device_size);
813 }
814
815 for (j = 0; j < blocks_count; ++j) {
816 if (chunk_start != -1) {
817 if (j - chunk_start >= MAX_CHUNK_COUNT) {
818 ret = sparse_merge_blocks(chunk_start,
819 j - chunk_start, 0);
820 ASSERT(!ret);
821 chunk_start = -1;
822 }
823 }
824
825 if (chunk_start == -1) {
826 if (!blocks[j])
827 continue;
828
829 if (blocks[j] == zeroed_block) {
830 ret = sparse_merge_blocks(j, 1, 1);
831 ASSERT(!ret);
832 } else {
833 chunk_start = j;
834 }
835 } else {
836 if (blocks[j] && blocks[j] != zeroed_block)
837 continue;
838
839 ret = sparse_merge_blocks(chunk_start,
840 j - chunk_start, 0);
841 ASSERT(!ret);
842
843 if (blocks[j] == zeroed_block) {
844 ret = sparse_merge_blocks(j, 1, 1);
845 ASSERT(!ret);
846 }
847
848 chunk_start = -1;
849 }
850 }
851 if (chunk_start != -1) {
852 ret = sparse_merge_blocks(chunk_start,
853 blocks_count - chunk_start, 0);
854 ASSERT(!ret);
855 }
856
857 sparse_file_write(f2fs_sparse_file, c.devices[0].fd,
858 /*gzip*/0, /*sparse*/1, /*crc*/0);
859
860 f2fs_release_sparse_resource();
861 }
862 #endif
863 /*
864 * We should call fsync() to flush out all the dirty pages
865 * in the block device page cache.
866 */
867 for (i = 0; i < c.ndevs; i++) {
868 #ifdef HAVE_FSYNC
869 if (c.need_fsync) {
870 ret = fsync(c.devices[i].fd);
871 if (ret < 0) {
872 MSG(0, "\tError: Could not conduct fsync!!!\n");
873 break;
874 }
875 }
876 #endif
877 ret = close(c.devices[i].fd);
878 if (ret < 0) {
879 MSG(0, "\tError: Failed to close device file!!!\n");
880 break;
881 }
882 free(c.devices[i].path);
883 free(c.devices[i].zone_cap_blocks);
884 }
885 close(c.kd);
886
887 return ret;
888 }
889