• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <robinhsu@google.com>
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 #ifdef HAVE_PREAD
283 	if (pread(fd, dcache_buf + entry * F2FS_BLKSIZE, F2FS_BLKSIZE, offset) < 0) {
284 		MSG(0, "\n pread() fail.\n");
285 		return -1;
286 	}
287 #else
288 	if (lseek(fd, offset, SEEK_SET) < 0) {
289 		MSG(0, "\n lseek fail.\n");
290 		return -1;
291 	}
292 	if (read(fd, dcache_buf + entry * F2FS_BLKSIZE, F2FS_BLKSIZE) < 0) {
293 		MSG(0, "\n read() fail.\n");
294 		return -1;
295 	}
296 #endif
297 	dcache_lastused[entry] = ++dcache_usetick;
298 	dcache_valid[entry] = true;
299 	dcache_blk[entry] = blk;
300 	return 0;
301 }
302 
303 /*
304  *  - Note: Read/Write are not symmetric:
305  *       For read, we need to do it block by block, due to the cache nature:
306  *           some blocks may be cached, and others don't.
307  *       For write, since we always do a write-thru, we can join all writes into one,
308  *       and write it once at the caller.  This function updates the cache for write, but
309  *       not the do a physical write.  The caller is responsible for the physical write.
310  *  - Note: We concentrate read/write together, due to the fact of similar structure to find
311  *          the relavant cache entries
312  *  - Return values:
313  *       0: success
314  *       1: cache not available (uninitialized)
315  *      -1: error
316  */
dcache_update_rw(void * buf,__u64 offset,size_t byte_count,bool is_write)317 static int dcache_update_rw(void *buf, __u64 offset,
318 		size_t byte_count, bool is_write)
319 {
320 	__u64 blk, start;
321 	int addr_in_blk;
322 
323 	if (!dcache_initialized)
324 		dcache_init(); /* auto initialize */
325 
326 	if (!dcache_initialized)
327 		return 1; /* not available */
328 
329 	blk = offset / F2FS_BLKSIZE;
330 	addr_in_blk = offset % F2FS_BLKSIZE;
331 	start = blk * F2FS_BLKSIZE;
332 
333 	while (byte_count != 0) {
334 		size_t cur_size = min(byte_count,
335 				(size_t)(F2FS_BLKSIZE - addr_in_blk));
336 		long entry = dcache_find(blk);
337 
338 		if (!is_write)
339 			++dcache_raccess;
340 
341 		if (dcache_valid[entry] && dcache_blk[entry] == blk) {
342 			/* cache hit */
343 			if (is_write)  /* write: update cache */
344 				memcpy(dcache_addr(entry) + addr_in_blk,
345 					buf, cur_size);
346 			else
347 				++dcache_rhit;
348 		} else {
349 			/* cache miss */
350 			if (!is_write) {
351 				int err;
352 				++dcache_rmiss;
353 				if (dcache_valid[entry])
354 					++dcache_rreplace;
355 				/* read: physical I/O read into cache */
356 				err = dcache_io_read(entry, start, blk);
357 				if (err)
358 					return err;
359 			}
360 		}
361 
362 		/* read: copy data from cache */
363 		/* write: nothing to do, since we don't do physical write. */
364 		if (!is_write)
365 			memcpy(buf, dcache_addr(entry) + addr_in_blk,
366 				cur_size);
367 
368 		/* next block */
369 		++blk;
370 		buf += cur_size;
371 		start += F2FS_BLKSIZE;
372 		byte_count -= cur_size;
373 		addr_in_blk = 0;
374 	}
375 	return 0;
376 }
377 
378 /*
379  * dcache_update_cache() just update cache, won't do physical I/O.
380  * Thus even no error, we need normal non-cache I/O for actual write
381  *
382  * return value: 1: cache not available
383  *               0: success, -1: I/O error
384  */
dcache_update_cache(void * buf,__u64 offset,size_t count)385 int dcache_update_cache(void *buf, __u64 offset, size_t count)
386 {
387 	return dcache_update_rw(buf, offset, count, true);
388 }
389 
390 /* handles read into cache + read into buffer  */
dcache_read(void * buf,__u64 offset,size_t count)391 int dcache_read(void *buf, __u64 offset, size_t count)
392 {
393 	return dcache_update_rw(buf, offset, count, false);
394 }
395 
396 /*
397  * IO interfaces
398  */
dev_read_version(void * buf,__u64 offset,size_t len)399 int dev_read_version(void *buf, __u64 offset, size_t len)
400 {
401 	if (c.sparse_mode)
402 		return 0;
403 #ifdef HAVE_RPEAD
404 	if (pread(c.kd, buf, len, (off_t)offset) < 0)
405 		return -1;
406 #else
407 	if (lseek(c.kd, (off_t)offset, SEEK_SET) < 0)
408 		return -1;
409 	if (read(c.kd, buf, len) < 0)
410 		return -1;
411 #endif
412 	return 0;
413 }
414 
415 #ifdef HAVE_SPARSE_SPARSE_H
sparse_read_blk(__u64 block,int count,void * buf)416 static int sparse_read_blk(__u64 block, int count, void *buf)
417 {
418 	int i;
419 	char *out = buf;
420 	__u64 cur_block;
421 
422 	for (i = 0; i < count; ++i) {
423 		cur_block = block + i;
424 		if (blocks[cur_block])
425 			memcpy(out + (i * F2FS_BLKSIZE),
426 					blocks[cur_block], F2FS_BLKSIZE);
427 		else if (blocks)
428 			memset(out + (i * F2FS_BLKSIZE), 0, F2FS_BLKSIZE);
429 	}
430 	return 0;
431 }
432 
sparse_write_blk(__u64 block,int count,const void * buf)433 static int sparse_write_blk(__u64 block, int count, const void *buf)
434 {
435 	int i;
436 	__u64 cur_block;
437 	const char *in = buf;
438 
439 	for (i = 0; i < count; ++i) {
440 		cur_block = block + i;
441 		if (blocks[cur_block] == zeroed_block)
442 			blocks[cur_block] = NULL;
443 		if (!blocks[cur_block]) {
444 			blocks[cur_block] = calloc(1, F2FS_BLKSIZE);
445 			if (!blocks[cur_block])
446 				return -ENOMEM;
447 		}
448 		memcpy(blocks[cur_block], in + (i * F2FS_BLKSIZE),
449 				F2FS_BLKSIZE);
450 	}
451 	return 0;
452 }
453 
sparse_write_zeroed_blk(__u64 block,int count)454 static int sparse_write_zeroed_blk(__u64 block, int count)
455 {
456 	int i;
457 	__u64 cur_block;
458 
459 	for (i = 0; i < count; ++i) {
460 		cur_block = block + i;
461 		if (blocks[cur_block])
462 			continue;
463 		blocks[cur_block] = zeroed_block;
464 	}
465 	return 0;
466 }
467 
468 #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)469 static int sparse_import_segment(void *UNUSED(priv), const void *data,
470 		size_t len, unsigned int block, unsigned int nr_blocks)
471 #else
472 static int sparse_import_segment(void *UNUSED(priv), const void *data, int len,
473 		unsigned int block, unsigned int nr_blocks)
474 #endif
475 {
476 	/* Ignore chunk headers, only write the data */
477 	if (!nr_blocks || len % F2FS_BLKSIZE)
478 		return 0;
479 
480 	return sparse_write_blk(block, nr_blocks, data);
481 }
482 
sparse_merge_blocks(uint64_t start,uint64_t num,int zero)483 static int sparse_merge_blocks(uint64_t start, uint64_t num, int zero)
484 {
485 	char *buf;
486 	uint64_t i;
487 
488 	if (zero) {
489 		blocks[start] = NULL;
490 		return sparse_file_add_fill(f2fs_sparse_file, 0x0,
491 					F2FS_BLKSIZE * num, start);
492 	}
493 
494 	buf = calloc(num, F2FS_BLKSIZE);
495 	if (!buf) {
496 		fprintf(stderr, "failed to alloc %llu\n",
497 			(unsigned long long)num * F2FS_BLKSIZE);
498 		return -ENOMEM;
499 	}
500 
501 	for (i = 0; i < num; i++) {
502 		memcpy(buf + i * F2FS_BLKSIZE, blocks[start + i], F2FS_BLKSIZE);
503 		free(blocks[start + i]);
504 		blocks[start + i] = NULL;
505 	}
506 
507 	/* free_sparse_blocks will release this buf. */
508 	blocks[start] = buf;
509 
510 	return sparse_file_add_data(f2fs_sparse_file, blocks[start],
511 					F2FS_BLKSIZE * num, start);
512 }
513 #else
sparse_read_blk(__u64 UNUSED (block),int UNUSED (count),void * UNUSED (buf))514 static int sparse_read_blk(__u64 UNUSED(block),
515 				int UNUSED(count), void *UNUSED(buf))
516 {
517 	return 0;
518 }
519 
sparse_write_blk(__u64 UNUSED (block),int UNUSED (count),const void * UNUSED (buf))520 static int sparse_write_blk(__u64 UNUSED(block),
521 				int UNUSED(count), const void *UNUSED(buf))
522 {
523 	return 0;
524 }
525 
sparse_write_zeroed_blk(__u64 UNUSED (block),int UNUSED (count))526 static int sparse_write_zeroed_blk(__u64 UNUSED(block), int UNUSED(count))
527 {
528 	return 0;
529 }
530 #endif
531 
dev_read(void * buf,__u64 offset,size_t len)532 int dev_read(void *buf, __u64 offset, size_t len)
533 {
534 	int fd;
535 	int err;
536 
537 	if (c.sparse_mode)
538 		return sparse_read_blk(offset / F2FS_BLKSIZE,
539 					len / F2FS_BLKSIZE, buf);
540 
541 	/* err = 1: cache not available, fall back to non-cache R/W */
542 	/* err = 0: success, err=-1: I/O error */
543 	err = dcache_read(buf, offset, len);
544 	if (err <= 0)
545 		return err;
546 
547 	fd = __get_device_fd(&offset);
548 	if (fd < 0)
549 		return fd;
550 #ifdef HAVE_PREAD
551 	if (pread(fd, buf, len, (off_t)offset) < 0)
552 		return -1;
553 #else
554 	if (lseek(fd, (off_t)offset, SEEK_SET) < 0)
555 		return -1;
556 	if (read(fd, buf, len) < 0)
557 		return -1;
558 #endif
559 	return 0;
560 }
561 
562 #ifdef POSIX_FADV_WILLNEED
dev_readahead(__u64 offset,size_t len)563 int dev_readahead(__u64 offset, size_t len)
564 #else
565 int dev_readahead(__u64 offset, size_t UNUSED(len))
566 #endif
567 {
568 	int fd = __get_device_fd(&offset);
569 
570 	if (fd < 0)
571 		return fd;
572 #ifdef POSIX_FADV_WILLNEED
573 	return posix_fadvise(fd, offset, len, POSIX_FADV_WILLNEED);
574 #else
575 	return 0;
576 #endif
577 }
578 /*
579  * Copied from fs/f2fs/segment.c
580  */
581 /*
582  * This returns write hints for each segment type. This hints will be
583  * passed down to block layer as below by default.
584  *
585  * User                  F2FS                     Block
586  * ----                  ----                     -----
587  *                       META                     WRITE_LIFE_NONE|REQ_META
588  *                       HOT_NODE                 WRITE_LIFE_NONE
589  *                       WARM_NODE                WRITE_LIFE_MEDIUM
590  *                       COLD_NODE                WRITE_LIFE_LONG
591  * ioctl(COLD)           COLD_DATA                WRITE_LIFE_EXTREME
592  * extension list        "                        "
593  *
594  * -- buffered io
595  *                       COLD_DATA                WRITE_LIFE_EXTREME
596  *                       HOT_DATA                 WRITE_LIFE_SHORT
597  *                       WARM_DATA                WRITE_LIFE_NOT_SET
598  *
599  * -- direct io
600  * WRITE_LIFE_EXTREME    COLD_DATA                WRITE_LIFE_EXTREME
601  * WRITE_LIFE_SHORT      HOT_DATA                 WRITE_LIFE_SHORT
602  * WRITE_LIFE_NOT_SET    WARM_DATA                WRITE_LIFE_NOT_SET
603  * WRITE_LIFE_NONE       "                        WRITE_LIFE_NONE
604  * WRITE_LIFE_MEDIUM     "                        WRITE_LIFE_MEDIUM
605  * WRITE_LIFE_LONG       "                        WRITE_LIFE_LONG
606  */
f2fs_io_type_to_rw_hint(int seg_type)607 enum rw_hint f2fs_io_type_to_rw_hint(int seg_type)
608 {
609 	switch (seg_type) {
610 	case CURSEG_WARM_DATA:
611 		return WRITE_LIFE_NOT_SET;
612 	case CURSEG_HOT_DATA:
613 		return WRITE_LIFE_SHORT;
614 	case CURSEG_COLD_DATA:
615 		return WRITE_LIFE_EXTREME;
616 	case CURSEG_WARM_NODE:
617 		return WRITE_LIFE_MEDIUM;
618 	case CURSEG_HOT_NODE:
619 		return WRITE_LIFE_NONE;
620 	case CURSEG_COLD_NODE:
621 		return WRITE_LIFE_LONG;
622 	default:
623 		return WRITE_LIFE_NONE;
624 	}
625 }
626 
__dev_write(void * buf,__u64 offset,size_t len,enum rw_hint whint)627 static int __dev_write(void *buf, __u64 offset, size_t len, enum rw_hint whint)
628 {
629 	int fd;
630 
631 	fd = __get_device_fd(&offset);
632 	if (fd < 0)
633 		return fd;
634 
635 #if ! defined(__MINGW32__)
636 	if (c.need_whint && (c.whint != whint)) {
637 		u64 hint = whint;
638 		int ret;
639 
640 		ret = fcntl(fd, F_SET_RW_HINT, &hint);
641 		if (ret != -1)
642 			c.whint = whint;
643 	}
644 #endif
645 
646 #ifdef HAVE_PWRITE
647 	if (pwrite(fd, buf, len, (off_t)offset) < 0)
648 		return -1;
649 #else
650 	if (lseek(fd, (off_t)offset, SEEK_SET) < 0)
651 		return -1;
652 	if (write(fd, buf, len) < 0)
653 		return -1;
654 #endif
655 
656 	c.need_fsync = true;
657 
658 	return 0;
659 }
660 
dev_write(void * buf,__u64 offset,size_t len,enum rw_hint whint)661 int dev_write(void *buf, __u64 offset, size_t len, enum rw_hint whint)
662 {
663 	if (c.dry_run)
664 		return 0;
665 
666 	if (c.sparse_mode)
667 		return sparse_write_blk(offset / F2FS_BLKSIZE,
668 					len / F2FS_BLKSIZE, buf);
669 
670 	/*
671 	 * dcache_update_cache() just update cache, won't do I/O.
672 	 * Thus even no error, we need normal non-cache I/O for actual write
673 	 */
674 	if (dcache_update_cache(buf, offset, len) < 0)
675 		return -1;
676 
677 	return __dev_write(buf, offset, len, whint);
678 }
679 
dev_write_block(void * buf,__u64 blk_addr,enum rw_hint whint)680 int dev_write_block(void *buf, __u64 blk_addr, enum rw_hint whint)
681 {
682 	return dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE, whint);
683 }
684 
dev_write_dump(void * buf,__u64 offset,size_t len)685 int dev_write_dump(void *buf, __u64 offset, size_t len)
686 {
687 #ifdef HAVE_PWRITE
688 	if (pwrite(c.dump_fd, buf, len, (off_t)offset) < 0)
689 		return -1;
690 #else
691 	if (lseek(c.dump_fd, (off_t)offset, SEEK_SET) < 0)
692 		return -1;
693 	if (write(c.dump_fd, buf, len) < 0)
694 		return -1;
695 #endif
696 	return 0;
697 }
698 
699 #if !defined(__MINGW32__)
dev_write_symlink(char * buf,size_t len)700 int dev_write_symlink(char *buf, size_t len)
701 {
702 	buf[len] = 0;
703 	if (symlink(buf, c.dump_symlink))
704 		return -1;
705 	return 0;
706 }
707 #endif
708 
dev_fill(void * buf,__u64 offset,size_t len,enum rw_hint whint)709 int dev_fill(void *buf, __u64 offset, size_t len, enum rw_hint whint)
710 {
711 	if (c.sparse_mode)
712 		return sparse_write_zeroed_blk(offset / F2FS_BLKSIZE,
713 						len / F2FS_BLKSIZE);
714 
715 	/* Only allow fill to zero */
716 	if (*((__u8*)buf))
717 		return -1;
718 
719 	return __dev_write(buf, offset, len, whint);
720 }
721 
dev_fill_block(void * buf,__u64 blk_addr,enum rw_hint whint)722 int dev_fill_block(void *buf, __u64 blk_addr, enum rw_hint whint)
723 {
724 	return dev_fill(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE, whint);
725 }
726 
dev_read_block(void * buf,__u64 blk_addr)727 int dev_read_block(void *buf, __u64 blk_addr)
728 {
729 	return dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
730 }
731 
dev_reada_block(__u64 blk_addr)732 int dev_reada_block(__u64 blk_addr)
733 {
734 	return dev_readahead(blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
735 }
736 
f2fs_fsync_device(void)737 int f2fs_fsync_device(void)
738 {
739 #ifdef HAVE_FSYNC
740 	int i;
741 
742 	if (!c.need_fsync)
743 		return 0;
744 
745 	for (i = 0; i < c.ndevs; i++) {
746 		if (fsync(c.devices[i].fd) < 0) {
747 			MSG(0, "\tError: Could not conduct fsync!!!\n");
748 			return -1;
749 		}
750 	}
751 #endif
752 	return 0;
753 }
754 
f2fs_init_sparse_file(void)755 int f2fs_init_sparse_file(void)
756 {
757 #ifdef HAVE_SPARSE_SPARSE_H
758 	if (c.func == MKFS) {
759 		f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE, c.device_size);
760 		if (!f2fs_sparse_file)
761 			return -1;
762 	} else {
763 		f2fs_sparse_file = sparse_file_import(c.devices[0].fd,
764 							true, false);
765 		if (!f2fs_sparse_file)
766 			return -1;
767 
768 		c.blksize = sparse_file_block_size(f2fs_sparse_file);
769 		c.blksize_bits = log_base_2(c.blksize);
770 		if (c.blksize_bits == -1) {
771 			MSG(0, "\tError: Sparse file blocksize not a power of 2.\n");
772 			return -1;
773 		}
774 
775 		c.device_size = sparse_file_len(f2fs_sparse_file, 0, 0);
776 		c.device_size &= (~((uint64_t)(F2FS_BLKSIZE - 1)));
777 	}
778 
779 	blocks_count = c.device_size / F2FS_BLKSIZE;
780 	blocks = calloc(blocks_count, sizeof(char *));
781 	if (!blocks) {
782 		MSG(0, "\tError: Calloc Failed for blocks!!!\n");
783 		return -1;
784 	}
785 
786 	zeroed_block = calloc(1, F2FS_BLKSIZE);
787 	if (!zeroed_block) {
788 		MSG(0, "\tError: Calloc Failed for zeroed block!!!\n");
789 		return -1;
790 	}
791 
792 	return sparse_file_foreach_chunk(f2fs_sparse_file, true, false,
793 				sparse_import_segment, NULL);
794 #else
795 	MSG(0, "\tError: Sparse mode is only supported for android\n");
796 	return -1;
797 #endif
798 }
799 
f2fs_release_sparse_resource(void)800 void f2fs_release_sparse_resource(void)
801 {
802 #ifdef HAVE_SPARSE_SPARSE_H
803 	int j;
804 
805 	if (c.sparse_mode) {
806 		if (f2fs_sparse_file != NULL) {
807 			sparse_file_destroy(f2fs_sparse_file);
808 			f2fs_sparse_file = NULL;
809 		}
810 		for (j = 0; j < blocks_count; j++)
811 			free(blocks[j]);
812 		free(blocks);
813 		blocks = NULL;
814 		free(zeroed_block);
815 		zeroed_block = NULL;
816 	}
817 #endif
818 }
819 
820 #define MAX_CHUNK_SIZE		(1 * 1024 * 1024 * 1024ULL)
821 #define MAX_CHUNK_COUNT		(MAX_CHUNK_SIZE / F2FS_BLKSIZE)
f2fs_finalize_device(void)822 int f2fs_finalize_device(void)
823 {
824 	int i;
825 	int ret = 0;
826 
827 #ifdef HAVE_SPARSE_SPARSE_H
828 	if (c.sparse_mode) {
829 		int64_t chunk_start = (blocks[0] == NULL) ? -1 : 0;
830 		uint64_t j;
831 
832 		if (c.func != MKFS) {
833 			sparse_file_destroy(f2fs_sparse_file);
834 			ret = ftruncate(c.devices[0].fd, 0);
835 			ASSERT(!ret);
836 			lseek(c.devices[0].fd, 0, SEEK_SET);
837 			f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE,
838 							c.device_size);
839 		}
840 
841 		for (j = 0; j < blocks_count; ++j) {
842 			if (chunk_start != -1) {
843 				if (j - chunk_start >= MAX_CHUNK_COUNT) {
844 					ret = sparse_merge_blocks(chunk_start,
845 							j - chunk_start, 0);
846 					ASSERT(!ret);
847 					chunk_start = -1;
848 				}
849 			}
850 
851 			if (chunk_start == -1) {
852 				if (!blocks[j])
853 					continue;
854 
855 				if (blocks[j] == zeroed_block) {
856 					ret = sparse_merge_blocks(j, 1, 1);
857 					ASSERT(!ret);
858 				} else {
859 					chunk_start = j;
860 				}
861 			} else {
862 				if (blocks[j] && blocks[j] != zeroed_block)
863 					continue;
864 
865 				ret = sparse_merge_blocks(chunk_start,
866 						j - chunk_start, 0);
867 				ASSERT(!ret);
868 
869 				if (blocks[j] == zeroed_block) {
870 					ret = sparse_merge_blocks(j, 1, 1);
871 					ASSERT(!ret);
872 				}
873 
874 				chunk_start = -1;
875 			}
876 		}
877 		if (chunk_start != -1) {
878 			ret = sparse_merge_blocks(chunk_start,
879 						blocks_count - chunk_start, 0);
880 			ASSERT(!ret);
881 		}
882 
883 		sparse_file_write(f2fs_sparse_file, c.devices[0].fd,
884 				/*gzip*/0, /*sparse*/1, /*crc*/0);
885 
886 		f2fs_release_sparse_resource();
887 	}
888 #endif
889 	/*
890 	 * We should call fsync() to flush out all the dirty pages
891 	 * in the block device page cache.
892 	 */
893 	for (i = 0; i < c.ndevs; i++) {
894 #ifdef HAVE_FSYNC
895 		if (c.need_fsync) {
896 			ret = fsync(c.devices[i].fd);
897 			if (ret < 0) {
898 				MSG(0, "\tError: Could not conduct fsync!!!\n");
899 				break;
900 			}
901 		}
902 #endif
903 		ret = close(c.devices[i].fd);
904 		if (ret < 0) {
905 			MSG(0, "\tError: Failed to close device file!!!\n");
906 			break;
907 		}
908 		free(c.devices[i].path);
909 		free(c.devices[i].zone_cap_blocks);
910 	}
911 	close(c.kd);
912 
913 	return ret;
914 }
915