15e5c12b0Sopenharmony_ci/**
25e5c12b0Sopenharmony_ci * libf2fs.c
35e5c12b0Sopenharmony_ci *
45e5c12b0Sopenharmony_ci * Copyright (c) 2013 Samsung Electronics Co., Ltd.
55e5c12b0Sopenharmony_ci *             http://www.samsung.com/
65e5c12b0Sopenharmony_ci * Copyright (c) 2019 Google Inc.
75e5c12b0Sopenharmony_ci *             http://www.google.com/
85e5c12b0Sopenharmony_ci * Copyright (c) 2020 Google Inc.
95e5c12b0Sopenharmony_ci *   Robin Hsu <robinhsu@google.com>
105e5c12b0Sopenharmony_ci *  : add quick-buffer for sload compression support
115e5c12b0Sopenharmony_ci *
125e5c12b0Sopenharmony_ci * Dual licensed under the GPL or LGPL version 2 licenses.
135e5c12b0Sopenharmony_ci */
145e5c12b0Sopenharmony_ci#ifndef _LARGEFILE64_SOURCE
155e5c12b0Sopenharmony_ci#define _LARGEFILE64_SOURCE
165e5c12b0Sopenharmony_ci#endif
175e5c12b0Sopenharmony_ci
185e5c12b0Sopenharmony_ci#include <stdio.h>
195e5c12b0Sopenharmony_ci#include <stdlib.h>
205e5c12b0Sopenharmony_ci#include <string.h>
215e5c12b0Sopenharmony_ci#include <errno.h>
225e5c12b0Sopenharmony_ci#include <unistd.h>
235e5c12b0Sopenharmony_ci#include <fcntl.h>
245e5c12b0Sopenharmony_ci#ifdef HAVE_MNTENT_H
255e5c12b0Sopenharmony_ci#include <mntent.h>
265e5c12b0Sopenharmony_ci#endif
275e5c12b0Sopenharmony_ci#include <time.h>
285e5c12b0Sopenharmony_ci#ifdef HAVE_SYS_STAT_H
295e5c12b0Sopenharmony_ci#include <sys/stat.h>
305e5c12b0Sopenharmony_ci#endif
315e5c12b0Sopenharmony_ci#ifdef HAVE_SYS_MOUNT_H
325e5c12b0Sopenharmony_ci#include <sys/mount.h>
335e5c12b0Sopenharmony_ci#endif
345e5c12b0Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H
355e5c12b0Sopenharmony_ci#include <sys/ioctl.h>
365e5c12b0Sopenharmony_ci#endif
375e5c12b0Sopenharmony_ci#ifdef HAVE_LINUX_HDREG_H
385e5c12b0Sopenharmony_ci#include <linux/hdreg.h>
395e5c12b0Sopenharmony_ci#endif
405e5c12b0Sopenharmony_ci
415e5c12b0Sopenharmony_ci#include <stdbool.h>
425e5c12b0Sopenharmony_ci#include <assert.h>
435e5c12b0Sopenharmony_ci#include <inttypes.h>
445e5c12b0Sopenharmony_ci#include "f2fs_fs.h"
455e5c12b0Sopenharmony_ci
465e5c12b0Sopenharmony_cistruct f2fs_configuration c;
475e5c12b0Sopenharmony_ci
485e5c12b0Sopenharmony_ci#ifdef HAVE_SPARSE_SPARSE_H
495e5c12b0Sopenharmony_ci#include <sparse/sparse.h>
505e5c12b0Sopenharmony_cistruct sparse_file *f2fs_sparse_file;
515e5c12b0Sopenharmony_cistatic char **blocks;
525e5c12b0Sopenharmony_ciuint64_t blocks_count;
535e5c12b0Sopenharmony_cistatic char *zeroed_block;
545e5c12b0Sopenharmony_ci#endif
555e5c12b0Sopenharmony_ci
565e5c12b0Sopenharmony_cistatic int __get_device_fd(__u64 *offset)
575e5c12b0Sopenharmony_ci{
585e5c12b0Sopenharmony_ci	__u64 blk_addr = *offset >> F2FS_BLKSIZE_BITS;
595e5c12b0Sopenharmony_ci	int i;
605e5c12b0Sopenharmony_ci
615e5c12b0Sopenharmony_ci	for (i = 0; i < c.ndevs; i++) {
625e5c12b0Sopenharmony_ci		if (c.devices[i].start_blkaddr <= blk_addr &&
635e5c12b0Sopenharmony_ci				c.devices[i].end_blkaddr >= blk_addr) {
645e5c12b0Sopenharmony_ci			*offset -=
655e5c12b0Sopenharmony_ci				c.devices[i].start_blkaddr << F2FS_BLKSIZE_BITS;
665e5c12b0Sopenharmony_ci			return c.devices[i].fd;
675e5c12b0Sopenharmony_ci		}
685e5c12b0Sopenharmony_ci	}
695e5c12b0Sopenharmony_ci	return -1;
705e5c12b0Sopenharmony_ci}
715e5c12b0Sopenharmony_ci
725e5c12b0Sopenharmony_ci#ifndef HAVE_LSEEK64
735e5c12b0Sopenharmony_citypedef off_t	off64_t;
745e5c12b0Sopenharmony_ci
755e5c12b0Sopenharmony_cistatic inline off64_t lseek64(int fd, __u64 offset, int set)
765e5c12b0Sopenharmony_ci{
775e5c12b0Sopenharmony_ci	return lseek(fd, offset, set);
785e5c12b0Sopenharmony_ci}
795e5c12b0Sopenharmony_ci#endif
805e5c12b0Sopenharmony_ci
815e5c12b0Sopenharmony_ci/* ---------- dev_cache, Least Used First (LUF) policy  ------------------- */
825e5c12b0Sopenharmony_ci/*
835e5c12b0Sopenharmony_ci * Least used block will be the first victim to be replaced when max hash
845e5c12b0Sopenharmony_ci * collision exceeds
855e5c12b0Sopenharmony_ci */
865e5c12b0Sopenharmony_cistatic bool *dcache_valid; /* is the cached block valid? */
875e5c12b0Sopenharmony_cistatic off64_t  *dcache_blk; /* which block it cached */
885e5c12b0Sopenharmony_cistatic uint64_t *dcache_lastused; /* last used ticks for cache entries */
895e5c12b0Sopenharmony_cistatic char *dcache_buf; /* cached block data */
905e5c12b0Sopenharmony_cistatic uint64_t dcache_usetick; /* current use tick */
915e5c12b0Sopenharmony_ci
925e5c12b0Sopenharmony_cistatic uint64_t dcache_raccess;
935e5c12b0Sopenharmony_cistatic uint64_t dcache_rhit;
945e5c12b0Sopenharmony_cistatic uint64_t dcache_rmiss;
955e5c12b0Sopenharmony_cistatic uint64_t dcache_rreplace;
965e5c12b0Sopenharmony_ci
975e5c12b0Sopenharmony_cistatic bool dcache_exit_registered = false;
985e5c12b0Sopenharmony_ci
995e5c12b0Sopenharmony_ci/*
1005e5c12b0Sopenharmony_ci *  Shadow config:
1015e5c12b0Sopenharmony_ci *
1025e5c12b0Sopenharmony_ci *  Active set of the configurations.
1035e5c12b0Sopenharmony_ci *  Global configuration 'dcache_config' will be transferred here when
1045e5c12b0Sopenharmony_ci *  when dcache_init() is called
1055e5c12b0Sopenharmony_ci */
1065e5c12b0Sopenharmony_cistatic dev_cache_config_t dcache_config = {0, 16, 1};
1075e5c12b0Sopenharmony_cistatic bool dcache_initialized = false;
1085e5c12b0Sopenharmony_ci
1095e5c12b0Sopenharmony_ci#define MIN_NUM_CACHE_ENTRY  1024L
1105e5c12b0Sopenharmony_ci#define MAX_MAX_HASH_COLLISION  16
1115e5c12b0Sopenharmony_ci
1125e5c12b0Sopenharmony_cistatic long dcache_relocate_offset0[] = {
1135e5c12b0Sopenharmony_ci	20, -20, 40, -40, 80, -80, 160, -160,
1145e5c12b0Sopenharmony_ci	320, -320, 640, -640, 1280, -1280, 2560, -2560,
1155e5c12b0Sopenharmony_ci};
1165e5c12b0Sopenharmony_cistatic int dcache_relocate_offset[16];
1175e5c12b0Sopenharmony_ci
1185e5c12b0Sopenharmony_cistatic void dcache_print_statistics(void)
1195e5c12b0Sopenharmony_ci{
1205e5c12b0Sopenharmony_ci	long i;
1215e5c12b0Sopenharmony_ci	long useCnt;
1225e5c12b0Sopenharmony_ci
1235e5c12b0Sopenharmony_ci	/* Number of used cache entries */
1245e5c12b0Sopenharmony_ci	useCnt = 0;
1255e5c12b0Sopenharmony_ci	for (i = 0; i < dcache_config.num_cache_entry; i++)
1265e5c12b0Sopenharmony_ci		if (dcache_valid[i])
1275e5c12b0Sopenharmony_ci			++useCnt;
1285e5c12b0Sopenharmony_ci
1295e5c12b0Sopenharmony_ci	/*
1305e5c12b0Sopenharmony_ci	 *  c: number of cache entries
1315e5c12b0Sopenharmony_ci	 *  u: used entries
1325e5c12b0Sopenharmony_ci	 *  RA: number of read access blocks
1335e5c12b0Sopenharmony_ci	 *  CH: cache hit
1345e5c12b0Sopenharmony_ci	 *  CM: cache miss
1355e5c12b0Sopenharmony_ci	 *  Repl: read cache replaced
1365e5c12b0Sopenharmony_ci	 */
1375e5c12b0Sopenharmony_ci	printf ("\nc, u, RA, CH, CM, Repl=\n");
1385e5c12b0Sopenharmony_ci	printf ("%ld %ld %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
1395e5c12b0Sopenharmony_ci			dcache_config.num_cache_entry,
1405e5c12b0Sopenharmony_ci			useCnt,
1415e5c12b0Sopenharmony_ci			dcache_raccess,
1425e5c12b0Sopenharmony_ci			dcache_rhit,
1435e5c12b0Sopenharmony_ci			dcache_rmiss,
1445e5c12b0Sopenharmony_ci			dcache_rreplace);
1455e5c12b0Sopenharmony_ci}
1465e5c12b0Sopenharmony_ci
1475e5c12b0Sopenharmony_civoid dcache_release(void)
1485e5c12b0Sopenharmony_ci{
1495e5c12b0Sopenharmony_ci	if (!dcache_initialized)
1505e5c12b0Sopenharmony_ci		return;
1515e5c12b0Sopenharmony_ci
1525e5c12b0Sopenharmony_ci	dcache_initialized = false;
1535e5c12b0Sopenharmony_ci
1545e5c12b0Sopenharmony_ci	if (c.cache_config.dbg_en)
1555e5c12b0Sopenharmony_ci		dcache_print_statistics();
1565e5c12b0Sopenharmony_ci
1575e5c12b0Sopenharmony_ci	if (dcache_blk != NULL)
1585e5c12b0Sopenharmony_ci		free(dcache_blk);
1595e5c12b0Sopenharmony_ci	if (dcache_lastused != NULL)
1605e5c12b0Sopenharmony_ci		free(dcache_lastused);
1615e5c12b0Sopenharmony_ci	if (dcache_buf != NULL)
1625e5c12b0Sopenharmony_ci		free(dcache_buf);
1635e5c12b0Sopenharmony_ci	if (dcache_valid != NULL)
1645e5c12b0Sopenharmony_ci		free(dcache_valid);
1655e5c12b0Sopenharmony_ci	dcache_config.num_cache_entry = 0;
1665e5c12b0Sopenharmony_ci	dcache_blk = NULL;
1675e5c12b0Sopenharmony_ci	dcache_lastused = NULL;
1685e5c12b0Sopenharmony_ci	dcache_buf = NULL;
1695e5c12b0Sopenharmony_ci	dcache_valid = NULL;
1705e5c12b0Sopenharmony_ci}
1715e5c12b0Sopenharmony_ci
1725e5c12b0Sopenharmony_ci// return 0 for success, error code for failure.
1735e5c12b0Sopenharmony_cistatic int dcache_alloc_all(long n)
1745e5c12b0Sopenharmony_ci{
1755e5c12b0Sopenharmony_ci	if (n <= 0)
1765e5c12b0Sopenharmony_ci		return -1;
1775e5c12b0Sopenharmony_ci	if ((dcache_blk = (off64_t *) malloc(sizeof(off64_t) * n)) == NULL
1785e5c12b0Sopenharmony_ci		|| (dcache_lastused = (uint64_t *)
1795e5c12b0Sopenharmony_ci				malloc(sizeof(uint64_t) * n)) == NULL
1805e5c12b0Sopenharmony_ci		|| (dcache_buf = (char *) malloc (F2FS_BLKSIZE * n)) == NULL
1815e5c12b0Sopenharmony_ci		|| (dcache_valid = (bool *) malloc(sizeof(bool) * n)) == NULL)
1825e5c12b0Sopenharmony_ci	{
1835e5c12b0Sopenharmony_ci		dcache_release();
1845e5c12b0Sopenharmony_ci		return -1;
1855e5c12b0Sopenharmony_ci	}
1865e5c12b0Sopenharmony_ci	dcache_config.num_cache_entry = n;
1875e5c12b0Sopenharmony_ci	return 0;
1885e5c12b0Sopenharmony_ci}
1895e5c12b0Sopenharmony_ci
1905e5c12b0Sopenharmony_cistatic void dcache_relocate_init(void)
1915e5c12b0Sopenharmony_ci{
1925e5c12b0Sopenharmony_ci	int i;
1935e5c12b0Sopenharmony_ci	int n0 = (sizeof(dcache_relocate_offset0)
1945e5c12b0Sopenharmony_ci			/ sizeof(dcache_relocate_offset0[0]));
1955e5c12b0Sopenharmony_ci	int n = (sizeof(dcache_relocate_offset)
1965e5c12b0Sopenharmony_ci			/ sizeof(dcache_relocate_offset[0]));
1975e5c12b0Sopenharmony_ci
1985e5c12b0Sopenharmony_ci	ASSERT(n == n0);
1995e5c12b0Sopenharmony_ci	for (i = 0; i < n && i < dcache_config.max_hash_collision; i++) {
2005e5c12b0Sopenharmony_ci		if (labs(dcache_relocate_offset0[i])
2015e5c12b0Sopenharmony_ci				> dcache_config.num_cache_entry / 2) {
2025e5c12b0Sopenharmony_ci			dcache_config.max_hash_collision = i;
2035e5c12b0Sopenharmony_ci			break;
2045e5c12b0Sopenharmony_ci		}
2055e5c12b0Sopenharmony_ci		dcache_relocate_offset[i] =
2065e5c12b0Sopenharmony_ci				dcache_config.num_cache_entry
2075e5c12b0Sopenharmony_ci				+ dcache_relocate_offset0[i];
2085e5c12b0Sopenharmony_ci	}
2095e5c12b0Sopenharmony_ci}
2105e5c12b0Sopenharmony_ci
2115e5c12b0Sopenharmony_civoid dcache_init(void)
2125e5c12b0Sopenharmony_ci{
2135e5c12b0Sopenharmony_ci	long n;
2145e5c12b0Sopenharmony_ci
2155e5c12b0Sopenharmony_ci	if (c.cache_config.num_cache_entry <= 0)
2165e5c12b0Sopenharmony_ci		return;
2175e5c12b0Sopenharmony_ci
2185e5c12b0Sopenharmony_ci	/* release previous cache init, if any */
2195e5c12b0Sopenharmony_ci	dcache_release();
2205e5c12b0Sopenharmony_ci
2215e5c12b0Sopenharmony_ci	dcache_blk = NULL;
2225e5c12b0Sopenharmony_ci	dcache_lastused = NULL;
2235e5c12b0Sopenharmony_ci	dcache_buf = NULL;
2245e5c12b0Sopenharmony_ci	dcache_valid = NULL;
2255e5c12b0Sopenharmony_ci
2265e5c12b0Sopenharmony_ci	dcache_config = c.cache_config;
2275e5c12b0Sopenharmony_ci
2285e5c12b0Sopenharmony_ci	n = max(MIN_NUM_CACHE_ENTRY, dcache_config.num_cache_entry);
2295e5c12b0Sopenharmony_ci
2305e5c12b0Sopenharmony_ci	/* halve alloc size until alloc succeed, or min cache reached */
2315e5c12b0Sopenharmony_ci	while (dcache_alloc_all(n) != 0 && n !=  MIN_NUM_CACHE_ENTRY)
2325e5c12b0Sopenharmony_ci		n = max(MIN_NUM_CACHE_ENTRY, n/2);
2335e5c12b0Sopenharmony_ci
2345e5c12b0Sopenharmony_ci	/* must be the last: data dependent on num_cache_entry */
2355e5c12b0Sopenharmony_ci	dcache_relocate_init();
2365e5c12b0Sopenharmony_ci	dcache_initialized = true;
2375e5c12b0Sopenharmony_ci
2385e5c12b0Sopenharmony_ci	if (!dcache_exit_registered) {
2395e5c12b0Sopenharmony_ci		dcache_exit_registered = true;
2405e5c12b0Sopenharmony_ci		atexit(dcache_release); /* auto release */
2415e5c12b0Sopenharmony_ci	}
2425e5c12b0Sopenharmony_ci
2435e5c12b0Sopenharmony_ci	dcache_raccess = 0;
2445e5c12b0Sopenharmony_ci	dcache_rhit = 0;
2455e5c12b0Sopenharmony_ci	dcache_rmiss = 0;
2465e5c12b0Sopenharmony_ci	dcache_rreplace = 0;
2475e5c12b0Sopenharmony_ci}
2485e5c12b0Sopenharmony_ci
2495e5c12b0Sopenharmony_cistatic inline char *dcache_addr(long entry)
2505e5c12b0Sopenharmony_ci{
2515e5c12b0Sopenharmony_ci	return dcache_buf + F2FS_BLKSIZE * entry;
2525e5c12b0Sopenharmony_ci}
2535e5c12b0Sopenharmony_ci
2545e5c12b0Sopenharmony_ci/* relocate on (n+1)-th collision */
2555e5c12b0Sopenharmony_cistatic inline long dcache_relocate(long entry, int n)
2565e5c12b0Sopenharmony_ci{
2575e5c12b0Sopenharmony_ci	assert(dcache_config.num_cache_entry != 0);
2585e5c12b0Sopenharmony_ci	return (entry + dcache_relocate_offset[n]) %
2595e5c12b0Sopenharmony_ci			dcache_config.num_cache_entry;
2605e5c12b0Sopenharmony_ci}
2615e5c12b0Sopenharmony_ci
2625e5c12b0Sopenharmony_cistatic long dcache_find(off64_t blk)
2635e5c12b0Sopenharmony_ci{
2645e5c12b0Sopenharmony_ci	register long n = dcache_config.num_cache_entry;
2655e5c12b0Sopenharmony_ci	register unsigned m = dcache_config.max_hash_collision;
2665e5c12b0Sopenharmony_ci	long entry, least_used, target;
2675e5c12b0Sopenharmony_ci	unsigned try;
2685e5c12b0Sopenharmony_ci
2695e5c12b0Sopenharmony_ci	assert(n > 0);
2705e5c12b0Sopenharmony_ci	target = least_used = entry = blk % n; /* simple modulo hash */
2715e5c12b0Sopenharmony_ci
2725e5c12b0Sopenharmony_ci	for (try = 0; try < m; try++) {
2735e5c12b0Sopenharmony_ci		if (!dcache_valid[target] || dcache_blk[target] == blk)
2745e5c12b0Sopenharmony_ci			return target;  /* found target or empty cache slot */
2755e5c12b0Sopenharmony_ci		if (dcache_lastused[target] < dcache_lastused[least_used])
2765e5c12b0Sopenharmony_ci			least_used = target;
2775e5c12b0Sopenharmony_ci		target = dcache_relocate(entry, try); /* next target */
2785e5c12b0Sopenharmony_ci	}
2795e5c12b0Sopenharmony_ci	return least_used;  /* max search reached, return least used slot */
2805e5c12b0Sopenharmony_ci}
2815e5c12b0Sopenharmony_ci
2825e5c12b0Sopenharmony_ci/* Physical read into cache */
2835e5c12b0Sopenharmony_cistatic int dcache_io_read(int fd, long entry, off64_t offset, off64_t blk)
2845e5c12b0Sopenharmony_ci{
2855e5c12b0Sopenharmony_ci	if (pread64(fd, dcache_buf + entry * F2FS_BLKSIZE,
2865e5c12b0Sopenharmony_ci		    F2FS_BLKSIZE, offset) < 0) {
2875e5c12b0Sopenharmony_ci		MSG(0, "\n read() fail.\n");
2885e5c12b0Sopenharmony_ci		return -1;
2895e5c12b0Sopenharmony_ci	}
2905e5c12b0Sopenharmony_ci	dcache_lastused[entry] = ++dcache_usetick;
2915e5c12b0Sopenharmony_ci	dcache_valid[entry] = true;
2925e5c12b0Sopenharmony_ci	dcache_blk[entry] = blk;
2935e5c12b0Sopenharmony_ci	return 0;
2945e5c12b0Sopenharmony_ci}
2955e5c12b0Sopenharmony_ci
2965e5c12b0Sopenharmony_ci/*
2975e5c12b0Sopenharmony_ci *  - Note: Read/Write are not symmetric:
2985e5c12b0Sopenharmony_ci *       For read, we need to do it block by block, due to the cache nature:
2995e5c12b0Sopenharmony_ci *           some blocks may be cached, and others don't.
3005e5c12b0Sopenharmony_ci *       For write, since we always do a write-thru, we can join all writes into one,
3015e5c12b0Sopenharmony_ci *       and write it once at the caller.  This function updates the cache for write, but
3025e5c12b0Sopenharmony_ci *       not the do a physical write.  The caller is responsible for the physical write.
3035e5c12b0Sopenharmony_ci *  - Note: We concentrate read/write together, due to the fact of similar structure to find
3045e5c12b0Sopenharmony_ci *          the relavant cache entries
3055e5c12b0Sopenharmony_ci *  - Return values:
3065e5c12b0Sopenharmony_ci *       0: success
3075e5c12b0Sopenharmony_ci *       1: cache not available (uninitialized)
3085e5c12b0Sopenharmony_ci *      -1: error
3095e5c12b0Sopenharmony_ci */
3105e5c12b0Sopenharmony_cistatic int dcache_update_rw(int fd, void *buf, off64_t offset,
3115e5c12b0Sopenharmony_ci		size_t byte_count, bool is_write)
3125e5c12b0Sopenharmony_ci{
3135e5c12b0Sopenharmony_ci	off64_t blk;
3145e5c12b0Sopenharmony_ci	int addr_in_blk;
3155e5c12b0Sopenharmony_ci	off64_t start;
3165e5c12b0Sopenharmony_ci
3175e5c12b0Sopenharmony_ci	if (!dcache_initialized)
3185e5c12b0Sopenharmony_ci		dcache_init(); /* auto initialize */
3195e5c12b0Sopenharmony_ci
3205e5c12b0Sopenharmony_ci	if (!dcache_initialized)
3215e5c12b0Sopenharmony_ci		return 1; /* not available */
3225e5c12b0Sopenharmony_ci
3235e5c12b0Sopenharmony_ci	blk = offset / F2FS_BLKSIZE;
3245e5c12b0Sopenharmony_ci	addr_in_blk = offset % F2FS_BLKSIZE;
3255e5c12b0Sopenharmony_ci	start = blk * F2FS_BLKSIZE;
3265e5c12b0Sopenharmony_ci
3275e5c12b0Sopenharmony_ci	while (byte_count != 0) {
3285e5c12b0Sopenharmony_ci		size_t cur_size = min(byte_count,
3295e5c12b0Sopenharmony_ci				(size_t)(F2FS_BLKSIZE - addr_in_blk));
3305e5c12b0Sopenharmony_ci		long entry = dcache_find(blk);
3315e5c12b0Sopenharmony_ci
3325e5c12b0Sopenharmony_ci		if (!is_write)
3335e5c12b0Sopenharmony_ci			++dcache_raccess;
3345e5c12b0Sopenharmony_ci
3355e5c12b0Sopenharmony_ci		if (dcache_valid[entry] && dcache_blk[entry] == blk) {
3365e5c12b0Sopenharmony_ci			/* cache hit */
3375e5c12b0Sopenharmony_ci			if (is_write)  /* write: update cache */
3385e5c12b0Sopenharmony_ci				memcpy(dcache_addr(entry) + addr_in_blk,
3395e5c12b0Sopenharmony_ci					buf, cur_size);
3405e5c12b0Sopenharmony_ci			else
3415e5c12b0Sopenharmony_ci				++dcache_rhit;
3425e5c12b0Sopenharmony_ci		} else {
3435e5c12b0Sopenharmony_ci			/* cache miss */
3445e5c12b0Sopenharmony_ci			if (!is_write) {
3455e5c12b0Sopenharmony_ci				int err;
3465e5c12b0Sopenharmony_ci				++dcache_rmiss;
3475e5c12b0Sopenharmony_ci				if (dcache_valid[entry])
3485e5c12b0Sopenharmony_ci					++dcache_rreplace;
3495e5c12b0Sopenharmony_ci				/* read: physical I/O read into cache */
3505e5c12b0Sopenharmony_ci				err = dcache_io_read(fd, entry, start, blk);
3515e5c12b0Sopenharmony_ci				if (err)
3525e5c12b0Sopenharmony_ci					return err;
3535e5c12b0Sopenharmony_ci			}
3545e5c12b0Sopenharmony_ci		}
3555e5c12b0Sopenharmony_ci
3565e5c12b0Sopenharmony_ci		/* read: copy data from cache */
3575e5c12b0Sopenharmony_ci		/* write: nothing to do, since we don't do physical write. */
3585e5c12b0Sopenharmony_ci		if (!is_write)
3595e5c12b0Sopenharmony_ci			memcpy(buf, dcache_addr(entry) + addr_in_blk,
3605e5c12b0Sopenharmony_ci				cur_size);
3615e5c12b0Sopenharmony_ci
3625e5c12b0Sopenharmony_ci		/* next block */
3635e5c12b0Sopenharmony_ci		++blk;
3645e5c12b0Sopenharmony_ci		buf += cur_size;
3655e5c12b0Sopenharmony_ci		start += F2FS_BLKSIZE;
3665e5c12b0Sopenharmony_ci		byte_count -= cur_size;
3675e5c12b0Sopenharmony_ci		addr_in_blk = 0;
3685e5c12b0Sopenharmony_ci	}
3695e5c12b0Sopenharmony_ci	return 0;
3705e5c12b0Sopenharmony_ci}
3715e5c12b0Sopenharmony_ci
3725e5c12b0Sopenharmony_ci/*
3735e5c12b0Sopenharmony_ci * dcache_update_cache() just update cache, won't do physical I/O.
3745e5c12b0Sopenharmony_ci * Thus even no error, we need normal non-cache I/O for actual write
3755e5c12b0Sopenharmony_ci *
3765e5c12b0Sopenharmony_ci * return value: 1: cache not available
3775e5c12b0Sopenharmony_ci *               0: success, -1: I/O error
3785e5c12b0Sopenharmony_ci */
3795e5c12b0Sopenharmony_ciint dcache_update_cache(int fd, void *buf, off64_t offset, size_t count)
3805e5c12b0Sopenharmony_ci{
3815e5c12b0Sopenharmony_ci	return dcache_update_rw(fd, buf, offset, count, true);
3825e5c12b0Sopenharmony_ci}
3835e5c12b0Sopenharmony_ci
3845e5c12b0Sopenharmony_ci/* handles read into cache + read into buffer  */
3855e5c12b0Sopenharmony_ciint dcache_read(int fd, void *buf, off64_t offset, size_t count)
3865e5c12b0Sopenharmony_ci{
3875e5c12b0Sopenharmony_ci	return dcache_update_rw(fd, buf, offset, count, false);
3885e5c12b0Sopenharmony_ci}
3895e5c12b0Sopenharmony_ci
3905e5c12b0Sopenharmony_ci/*
3915e5c12b0Sopenharmony_ci * IO interfaces
3925e5c12b0Sopenharmony_ci */
3935e5c12b0Sopenharmony_ciint dev_read_version(void *buf, __u64 offset, size_t len)
3945e5c12b0Sopenharmony_ci{
3955e5c12b0Sopenharmony_ci	if (c.sparse_mode)
3965e5c12b0Sopenharmony_ci		return 0;
3975e5c12b0Sopenharmony_ci	if (pread64(c.kd, buf, len, offset) < 0)
3985e5c12b0Sopenharmony_ci		return -1;
3995e5c12b0Sopenharmony_ci	return 0;
4005e5c12b0Sopenharmony_ci}
4015e5c12b0Sopenharmony_ci
4025e5c12b0Sopenharmony_ci#ifdef HAVE_SPARSE_SPARSE_H
4035e5c12b0Sopenharmony_cistatic int sparse_read_blk(__u64 block, int count, void *buf)
4045e5c12b0Sopenharmony_ci{
4055e5c12b0Sopenharmony_ci	int i;
4065e5c12b0Sopenharmony_ci	char *out = buf;
4075e5c12b0Sopenharmony_ci	__u64 cur_block;
4085e5c12b0Sopenharmony_ci
4095e5c12b0Sopenharmony_ci	for (i = 0; i < count; ++i) {
4105e5c12b0Sopenharmony_ci		cur_block = block + i;
4115e5c12b0Sopenharmony_ci		if (blocks[cur_block])
4125e5c12b0Sopenharmony_ci			memcpy(out + (i * F2FS_BLKSIZE),
4135e5c12b0Sopenharmony_ci					blocks[cur_block], F2FS_BLKSIZE);
4145e5c12b0Sopenharmony_ci		else if (blocks)
4155e5c12b0Sopenharmony_ci			memset(out + (i * F2FS_BLKSIZE), 0, F2FS_BLKSIZE);
4165e5c12b0Sopenharmony_ci	}
4175e5c12b0Sopenharmony_ci	return 0;
4185e5c12b0Sopenharmony_ci}
4195e5c12b0Sopenharmony_ci
4205e5c12b0Sopenharmony_cistatic int sparse_write_blk(__u64 block, int count, const void *buf)
4215e5c12b0Sopenharmony_ci{
4225e5c12b0Sopenharmony_ci	int i;
4235e5c12b0Sopenharmony_ci	__u64 cur_block;
4245e5c12b0Sopenharmony_ci	const char *in = buf;
4255e5c12b0Sopenharmony_ci
4265e5c12b0Sopenharmony_ci	for (i = 0; i < count; ++i) {
4275e5c12b0Sopenharmony_ci		cur_block = block + i;
4285e5c12b0Sopenharmony_ci		if (blocks[cur_block] == zeroed_block)
4295e5c12b0Sopenharmony_ci			blocks[cur_block] = NULL;
4305e5c12b0Sopenharmony_ci		if (!blocks[cur_block]) {
4315e5c12b0Sopenharmony_ci			blocks[cur_block] = calloc(1, F2FS_BLKSIZE);
4325e5c12b0Sopenharmony_ci			if (!blocks[cur_block])
4335e5c12b0Sopenharmony_ci				return -ENOMEM;
4345e5c12b0Sopenharmony_ci		}
4355e5c12b0Sopenharmony_ci		memcpy(blocks[cur_block], in + (i * F2FS_BLKSIZE),
4365e5c12b0Sopenharmony_ci				F2FS_BLKSIZE);
4375e5c12b0Sopenharmony_ci	}
4385e5c12b0Sopenharmony_ci	return 0;
4395e5c12b0Sopenharmony_ci}
4405e5c12b0Sopenharmony_ci
4415e5c12b0Sopenharmony_cistatic int sparse_write_zeroed_blk(__u64 block, int count)
4425e5c12b0Sopenharmony_ci{
4435e5c12b0Sopenharmony_ci	int i;
4445e5c12b0Sopenharmony_ci	__u64 cur_block;
4455e5c12b0Sopenharmony_ci
4465e5c12b0Sopenharmony_ci	for (i = 0; i < count; ++i) {
4475e5c12b0Sopenharmony_ci		cur_block = block + i;
4485e5c12b0Sopenharmony_ci		if (blocks[cur_block])
4495e5c12b0Sopenharmony_ci			continue;
4505e5c12b0Sopenharmony_ci		blocks[cur_block] = zeroed_block;
4515e5c12b0Sopenharmony_ci	}
4525e5c12b0Sopenharmony_ci	return 0;
4535e5c12b0Sopenharmony_ci}
4545e5c12b0Sopenharmony_ci
4555e5c12b0Sopenharmony_ci#ifdef SPARSE_CALLBACK_USES_SIZE_T
4565e5c12b0Sopenharmony_cistatic int sparse_import_segment(void *UNUSED(priv), const void *data,
4575e5c12b0Sopenharmony_ci		size_t len, unsigned int block, unsigned int nr_blocks)
4585e5c12b0Sopenharmony_ci#else
4595e5c12b0Sopenharmony_cistatic int sparse_import_segment(void *UNUSED(priv), const void *data, int len,
4605e5c12b0Sopenharmony_ci		unsigned int block, unsigned int nr_blocks)
4615e5c12b0Sopenharmony_ci#endif
4625e5c12b0Sopenharmony_ci{
4635e5c12b0Sopenharmony_ci	/* Ignore chunk headers, only write the data */
4645e5c12b0Sopenharmony_ci	if (!nr_blocks || len % F2FS_BLKSIZE)
4655e5c12b0Sopenharmony_ci		return 0;
4665e5c12b0Sopenharmony_ci
4675e5c12b0Sopenharmony_ci	return sparse_write_blk(block, nr_blocks, data);
4685e5c12b0Sopenharmony_ci}
4695e5c12b0Sopenharmony_ci
4705e5c12b0Sopenharmony_cistatic int sparse_merge_blocks(uint64_t start, uint64_t num, int zero)
4715e5c12b0Sopenharmony_ci{
4725e5c12b0Sopenharmony_ci	char *buf;
4735e5c12b0Sopenharmony_ci	uint64_t i;
4745e5c12b0Sopenharmony_ci
4755e5c12b0Sopenharmony_ci	if (zero) {
4765e5c12b0Sopenharmony_ci		blocks[start] = NULL;
4775e5c12b0Sopenharmony_ci		return sparse_file_add_fill(f2fs_sparse_file, 0x0,
4785e5c12b0Sopenharmony_ci					F2FS_BLKSIZE * num, start);
4795e5c12b0Sopenharmony_ci	}
4805e5c12b0Sopenharmony_ci
4815e5c12b0Sopenharmony_ci	buf = calloc(num, F2FS_BLKSIZE);
4825e5c12b0Sopenharmony_ci	if (!buf) {
4835e5c12b0Sopenharmony_ci		fprintf(stderr, "failed to alloc %llu\n",
4845e5c12b0Sopenharmony_ci			(unsigned long long)num * F2FS_BLKSIZE);
4855e5c12b0Sopenharmony_ci		return -ENOMEM;
4865e5c12b0Sopenharmony_ci	}
4875e5c12b0Sopenharmony_ci
4885e5c12b0Sopenharmony_ci	for (i = 0; i < num; i++) {
4895e5c12b0Sopenharmony_ci		memcpy(buf + i * F2FS_BLKSIZE, blocks[start + i], F2FS_BLKSIZE);
4905e5c12b0Sopenharmony_ci		free(blocks[start + i]);
4915e5c12b0Sopenharmony_ci		blocks[start + i] = NULL;
4925e5c12b0Sopenharmony_ci	}
4935e5c12b0Sopenharmony_ci
4945e5c12b0Sopenharmony_ci	/* free_sparse_blocks will release this buf. */
4955e5c12b0Sopenharmony_ci	blocks[start] = buf;
4965e5c12b0Sopenharmony_ci
4975e5c12b0Sopenharmony_ci	return sparse_file_add_data(f2fs_sparse_file, blocks[start],
4985e5c12b0Sopenharmony_ci					F2FS_BLKSIZE * num, start);
4995e5c12b0Sopenharmony_ci}
5005e5c12b0Sopenharmony_ci#else
5015e5c12b0Sopenharmony_cistatic int sparse_read_blk(__u64 UNUSED(block),
5025e5c12b0Sopenharmony_ci				int UNUSED(count), void *UNUSED(buf))
5035e5c12b0Sopenharmony_ci{
5045e5c12b0Sopenharmony_ci	return 0;
5055e5c12b0Sopenharmony_ci}
5065e5c12b0Sopenharmony_ci
5075e5c12b0Sopenharmony_cistatic int sparse_write_blk(__u64 UNUSED(block),
5085e5c12b0Sopenharmony_ci				int UNUSED(count), const void *UNUSED(buf))
5095e5c12b0Sopenharmony_ci{
5105e5c12b0Sopenharmony_ci	return 0;
5115e5c12b0Sopenharmony_ci}
5125e5c12b0Sopenharmony_ci
5135e5c12b0Sopenharmony_cistatic int sparse_write_zeroed_blk(__u64 UNUSED(block), int UNUSED(count))
5145e5c12b0Sopenharmony_ci{
5155e5c12b0Sopenharmony_ci	return 0;
5165e5c12b0Sopenharmony_ci}
5175e5c12b0Sopenharmony_ci#endif
5185e5c12b0Sopenharmony_ci
5195e5c12b0Sopenharmony_ciint dev_read(void *buf, __u64 offset, size_t len)
5205e5c12b0Sopenharmony_ci{
5215e5c12b0Sopenharmony_ci	int fd;
5225e5c12b0Sopenharmony_ci	int err;
5235e5c12b0Sopenharmony_ci
5245e5c12b0Sopenharmony_ci	if (c.sparse_mode)
5255e5c12b0Sopenharmony_ci		return sparse_read_blk(offset / F2FS_BLKSIZE,
5265e5c12b0Sopenharmony_ci					len / F2FS_BLKSIZE, buf);
5275e5c12b0Sopenharmony_ci
5285e5c12b0Sopenharmony_ci	fd = __get_device_fd(&offset);
5295e5c12b0Sopenharmony_ci	if (fd < 0)
5305e5c12b0Sopenharmony_ci		return fd;
5315e5c12b0Sopenharmony_ci
5325e5c12b0Sopenharmony_ci	/* err = 1: cache not available, fall back to non-cache R/W */
5335e5c12b0Sopenharmony_ci	/* err = 0: success, err=-1: I/O error */
5345e5c12b0Sopenharmony_ci	err = dcache_read(fd, buf, (off64_t)offset, len);
5355e5c12b0Sopenharmony_ci	if (err <= 0)
5365e5c12b0Sopenharmony_ci		return err;
5375e5c12b0Sopenharmony_ci	if (pread64(fd, buf, len, offset) < 0)
5385e5c12b0Sopenharmony_ci		return -1;
5395e5c12b0Sopenharmony_ci	return 0;
5405e5c12b0Sopenharmony_ci}
5415e5c12b0Sopenharmony_ci
5425e5c12b0Sopenharmony_ci#ifdef POSIX_FADV_WILLNEED
5435e5c12b0Sopenharmony_ciint dev_readahead(__u64 offset, size_t len)
5445e5c12b0Sopenharmony_ci#else
5455e5c12b0Sopenharmony_ciint dev_readahead(__u64 offset, size_t UNUSED(len))
5465e5c12b0Sopenharmony_ci#endif
5475e5c12b0Sopenharmony_ci{
5485e5c12b0Sopenharmony_ci	int fd = __get_device_fd(&offset);
5495e5c12b0Sopenharmony_ci
5505e5c12b0Sopenharmony_ci	if (fd < 0)
5515e5c12b0Sopenharmony_ci		return fd;
5525e5c12b0Sopenharmony_ci#ifdef POSIX_FADV_WILLNEED
5535e5c12b0Sopenharmony_ci	return posix_fadvise(fd, offset, len, POSIX_FADV_WILLNEED);
5545e5c12b0Sopenharmony_ci#else
5555e5c12b0Sopenharmony_ci	return 0;
5565e5c12b0Sopenharmony_ci#endif
5575e5c12b0Sopenharmony_ci}
5585e5c12b0Sopenharmony_ci
5595e5c12b0Sopenharmony_ciint dev_write(void *buf, __u64 offset, size_t len)
5605e5c12b0Sopenharmony_ci{
5615e5c12b0Sopenharmony_ci	int fd;
5625e5c12b0Sopenharmony_ci
5635e5c12b0Sopenharmony_ci	if (c.dry_run)
5645e5c12b0Sopenharmony_ci		return 0;
5655e5c12b0Sopenharmony_ci
5665e5c12b0Sopenharmony_ci	if (c.sparse_mode)
5675e5c12b0Sopenharmony_ci		return sparse_write_blk(offset / F2FS_BLKSIZE,
5685e5c12b0Sopenharmony_ci					len / F2FS_BLKSIZE, buf);
5695e5c12b0Sopenharmony_ci
5705e5c12b0Sopenharmony_ci	fd = __get_device_fd(&offset);
5715e5c12b0Sopenharmony_ci	if (fd < 0)
5725e5c12b0Sopenharmony_ci		return fd;
5735e5c12b0Sopenharmony_ci
5745e5c12b0Sopenharmony_ci	/*
5755e5c12b0Sopenharmony_ci	 * dcache_update_cache() just update cache, won't do I/O.
5765e5c12b0Sopenharmony_ci	 * Thus even no error, we need normal non-cache I/O for actual write
5775e5c12b0Sopenharmony_ci	 */
5785e5c12b0Sopenharmony_ci	if (dcache_update_cache(fd, buf, (off64_t)offset, len) < 0)
5795e5c12b0Sopenharmony_ci		return -1;
5805e5c12b0Sopenharmony_ci	if (pwrite64(fd, buf, len, offset) < 0)
5815e5c12b0Sopenharmony_ci		return -1;
5825e5c12b0Sopenharmony_ci	return 0;
5835e5c12b0Sopenharmony_ci}
5845e5c12b0Sopenharmony_ci
5855e5c12b0Sopenharmony_ciint dev_write_block(void *buf, __u64 blk_addr)
5865e5c12b0Sopenharmony_ci{
5875e5c12b0Sopenharmony_ci	return dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
5885e5c12b0Sopenharmony_ci}
5895e5c12b0Sopenharmony_ci
5905e5c12b0Sopenharmony_ciint dev_write_dump(void *buf, __u64 offset, size_t len)
5915e5c12b0Sopenharmony_ci{
5925e5c12b0Sopenharmony_ci	if (pwrite64(c.dump_fd, buf, len, offset) < 0)
5935e5c12b0Sopenharmony_ci		return -1;
5945e5c12b0Sopenharmony_ci	return 0;
5955e5c12b0Sopenharmony_ci}
5965e5c12b0Sopenharmony_ci
5975e5c12b0Sopenharmony_ciint dev_fill(void *buf, __u64 offset, size_t len)
5985e5c12b0Sopenharmony_ci{
5995e5c12b0Sopenharmony_ci	int fd;
6005e5c12b0Sopenharmony_ci
6015e5c12b0Sopenharmony_ci	if (c.sparse_mode)
6025e5c12b0Sopenharmony_ci		return sparse_write_zeroed_blk(offset / F2FS_BLKSIZE,
6035e5c12b0Sopenharmony_ci						len / F2FS_BLKSIZE);
6045e5c12b0Sopenharmony_ci
6055e5c12b0Sopenharmony_ci	fd = __get_device_fd(&offset);
6065e5c12b0Sopenharmony_ci	if (fd < 0)
6075e5c12b0Sopenharmony_ci		return fd;
6085e5c12b0Sopenharmony_ci
6095e5c12b0Sopenharmony_ci	/* Only allow fill to zero */
6105e5c12b0Sopenharmony_ci	if (*((__u8*)buf))
6115e5c12b0Sopenharmony_ci		return -1;
6125e5c12b0Sopenharmony_ci	if (pwrite64(fd, buf, len, offset) < 0)
6135e5c12b0Sopenharmony_ci		return -1;
6145e5c12b0Sopenharmony_ci	return 0;
6155e5c12b0Sopenharmony_ci}
6165e5c12b0Sopenharmony_ci
6175e5c12b0Sopenharmony_ciint dev_fill_block(void *buf, __u64 blk_addr)
6185e5c12b0Sopenharmony_ci{
6195e5c12b0Sopenharmony_ci	return dev_fill(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
6205e5c12b0Sopenharmony_ci}
6215e5c12b0Sopenharmony_ci
6225e5c12b0Sopenharmony_ciint dev_read_block(void *buf, __u64 blk_addr)
6235e5c12b0Sopenharmony_ci{
6245e5c12b0Sopenharmony_ci	return dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
6255e5c12b0Sopenharmony_ci}
6265e5c12b0Sopenharmony_ci
6275e5c12b0Sopenharmony_ciint dev_reada_block(__u64 blk_addr)
6285e5c12b0Sopenharmony_ci{
6295e5c12b0Sopenharmony_ci	return dev_readahead(blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
6305e5c12b0Sopenharmony_ci}
6315e5c12b0Sopenharmony_ci
6325e5c12b0Sopenharmony_ciint f2fs_fsync_device(void)
6335e5c12b0Sopenharmony_ci{
6345e5c12b0Sopenharmony_ci#ifdef HAVE_FSYNC
6355e5c12b0Sopenharmony_ci	int i;
6365e5c12b0Sopenharmony_ci
6375e5c12b0Sopenharmony_ci	for (i = 0; i < c.ndevs; i++) {
6385e5c12b0Sopenharmony_ci		if (fsync(c.devices[i].fd) < 0) {
6395e5c12b0Sopenharmony_ci			MSG(0, "\tError: Could not conduct fsync!!!\n");
6405e5c12b0Sopenharmony_ci			return -1;
6415e5c12b0Sopenharmony_ci		}
6425e5c12b0Sopenharmony_ci	}
6435e5c12b0Sopenharmony_ci#endif
6445e5c12b0Sopenharmony_ci	return 0;
6455e5c12b0Sopenharmony_ci}
6465e5c12b0Sopenharmony_ci
6475e5c12b0Sopenharmony_ciint f2fs_init_sparse_file(void)
6485e5c12b0Sopenharmony_ci{
6495e5c12b0Sopenharmony_ci#ifdef HAVE_SPARSE_SPARSE_H
6505e5c12b0Sopenharmony_ci	if (c.func == MKFS) {
6515e5c12b0Sopenharmony_ci		f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE, c.device_size);
6525e5c12b0Sopenharmony_ci		if (!f2fs_sparse_file)
6535e5c12b0Sopenharmony_ci			return -1;
6545e5c12b0Sopenharmony_ci	} else {
6555e5c12b0Sopenharmony_ci		f2fs_sparse_file = sparse_file_import(c.devices[0].fd,
6565e5c12b0Sopenharmony_ci							true, false);
6575e5c12b0Sopenharmony_ci		if (!f2fs_sparse_file)
6585e5c12b0Sopenharmony_ci			return -1;
6595e5c12b0Sopenharmony_ci
6605e5c12b0Sopenharmony_ci		c.device_size = sparse_file_len(f2fs_sparse_file, 0, 0);
6615e5c12b0Sopenharmony_ci		c.device_size &= (~((uint64_t)(F2FS_BLKSIZE - 1)));
6625e5c12b0Sopenharmony_ci	}
6635e5c12b0Sopenharmony_ci
6645e5c12b0Sopenharmony_ci	if (sparse_file_block_size(f2fs_sparse_file) != F2FS_BLKSIZE) {
6655e5c12b0Sopenharmony_ci		MSG(0, "\tError: Corrupted sparse file\n");
6665e5c12b0Sopenharmony_ci		return -1;
6675e5c12b0Sopenharmony_ci	}
6685e5c12b0Sopenharmony_ci	blocks_count = c.device_size / F2FS_BLKSIZE;
6695e5c12b0Sopenharmony_ci	blocks = calloc(blocks_count, sizeof(char *));
6705e5c12b0Sopenharmony_ci	if (!blocks) {
6715e5c12b0Sopenharmony_ci		MSG(0, "\tError: Calloc Failed for blocks!!!\n");
6725e5c12b0Sopenharmony_ci		return -1;
6735e5c12b0Sopenharmony_ci	}
6745e5c12b0Sopenharmony_ci
6755e5c12b0Sopenharmony_ci	zeroed_block = calloc(1, F2FS_BLKSIZE);
6765e5c12b0Sopenharmony_ci	if (!zeroed_block) {
6775e5c12b0Sopenharmony_ci		MSG(0, "\tError: Calloc Failed for zeroed block!!!\n");
6785e5c12b0Sopenharmony_ci		return -1;
6795e5c12b0Sopenharmony_ci	}
6805e5c12b0Sopenharmony_ci
6815e5c12b0Sopenharmony_ci	return sparse_file_foreach_chunk(f2fs_sparse_file, true, false,
6825e5c12b0Sopenharmony_ci				sparse_import_segment, NULL);
6835e5c12b0Sopenharmony_ci#else
6845e5c12b0Sopenharmony_ci	MSG(0, "\tError: Sparse mode is only supported for android\n");
6855e5c12b0Sopenharmony_ci	return -1;
6865e5c12b0Sopenharmony_ci#endif
6875e5c12b0Sopenharmony_ci}
6885e5c12b0Sopenharmony_ci
6895e5c12b0Sopenharmony_civoid f2fs_release_sparse_resource(void)
6905e5c12b0Sopenharmony_ci{
6915e5c12b0Sopenharmony_ci#ifdef HAVE_SPARSE_SPARSE_H
6925e5c12b0Sopenharmony_ci	int j;
6935e5c12b0Sopenharmony_ci
6945e5c12b0Sopenharmony_ci	if (c.sparse_mode) {
6955e5c12b0Sopenharmony_ci		if (f2fs_sparse_file != NULL) {
6965e5c12b0Sopenharmony_ci			sparse_file_destroy(f2fs_sparse_file);
6975e5c12b0Sopenharmony_ci			f2fs_sparse_file = NULL;
6985e5c12b0Sopenharmony_ci		}
6995e5c12b0Sopenharmony_ci		for (j = 0; j < blocks_count; j++)
7005e5c12b0Sopenharmony_ci			free(blocks[j]);
7015e5c12b0Sopenharmony_ci		free(blocks);
7025e5c12b0Sopenharmony_ci		blocks = NULL;
7035e5c12b0Sopenharmony_ci		free(zeroed_block);
7045e5c12b0Sopenharmony_ci		zeroed_block = NULL;
7055e5c12b0Sopenharmony_ci	}
7065e5c12b0Sopenharmony_ci#endif
7075e5c12b0Sopenharmony_ci}
7085e5c12b0Sopenharmony_ci
7095e5c12b0Sopenharmony_ci#define MAX_CHUNK_SIZE		(1 * 1024 * 1024 * 1024ULL)
7105e5c12b0Sopenharmony_ci#define MAX_CHUNK_COUNT		(MAX_CHUNK_SIZE / F2FS_BLKSIZE)
7115e5c12b0Sopenharmony_ciint f2fs_finalize_device(void)
7125e5c12b0Sopenharmony_ci{
7135e5c12b0Sopenharmony_ci	int i;
7145e5c12b0Sopenharmony_ci	int ret = 0;
7155e5c12b0Sopenharmony_ci
7165e5c12b0Sopenharmony_ci#ifdef HAVE_SPARSE_SPARSE_H
7175e5c12b0Sopenharmony_ci	if (c.sparse_mode) {
7185e5c12b0Sopenharmony_ci		int64_t chunk_start = (blocks[0] == NULL) ? -1 : 0;
7195e5c12b0Sopenharmony_ci		uint64_t j;
7205e5c12b0Sopenharmony_ci
7215e5c12b0Sopenharmony_ci		if (c.func != MKFS) {
7225e5c12b0Sopenharmony_ci			sparse_file_destroy(f2fs_sparse_file);
7235e5c12b0Sopenharmony_ci			ret = ftruncate(c.devices[0].fd, 0);
7245e5c12b0Sopenharmony_ci			ASSERT(!ret);
7255e5c12b0Sopenharmony_ci			lseek(c.devices[0].fd, 0, SEEK_SET);
7265e5c12b0Sopenharmony_ci			f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE,
7275e5c12b0Sopenharmony_ci							c.device_size);
7285e5c12b0Sopenharmony_ci		}
7295e5c12b0Sopenharmony_ci
7305e5c12b0Sopenharmony_ci		for (j = 0; j < blocks_count; ++j) {
7315e5c12b0Sopenharmony_ci			if (chunk_start != -1) {
7325e5c12b0Sopenharmony_ci				if (j - chunk_start >= MAX_CHUNK_COUNT) {
7335e5c12b0Sopenharmony_ci					ret = sparse_merge_blocks(chunk_start,
7345e5c12b0Sopenharmony_ci							j - chunk_start, 0);
7355e5c12b0Sopenharmony_ci					ASSERT(!ret);
7365e5c12b0Sopenharmony_ci					chunk_start = -1;
7375e5c12b0Sopenharmony_ci				}
7385e5c12b0Sopenharmony_ci			}
7395e5c12b0Sopenharmony_ci
7405e5c12b0Sopenharmony_ci			if (chunk_start == -1) {
7415e5c12b0Sopenharmony_ci				if (!blocks[j])
7425e5c12b0Sopenharmony_ci					continue;
7435e5c12b0Sopenharmony_ci
7445e5c12b0Sopenharmony_ci				if (blocks[j] == zeroed_block) {
7455e5c12b0Sopenharmony_ci					ret = sparse_merge_blocks(j, 1, 1);
7465e5c12b0Sopenharmony_ci					ASSERT(!ret);
7475e5c12b0Sopenharmony_ci				} else {
7485e5c12b0Sopenharmony_ci					chunk_start = j;
7495e5c12b0Sopenharmony_ci				}
7505e5c12b0Sopenharmony_ci			} else {
7515e5c12b0Sopenharmony_ci				if (blocks[j] && blocks[j] != zeroed_block)
7525e5c12b0Sopenharmony_ci					continue;
7535e5c12b0Sopenharmony_ci
7545e5c12b0Sopenharmony_ci				ret = sparse_merge_blocks(chunk_start,
7555e5c12b0Sopenharmony_ci						j - chunk_start, 0);
7565e5c12b0Sopenharmony_ci				ASSERT(!ret);
7575e5c12b0Sopenharmony_ci
7585e5c12b0Sopenharmony_ci				if (blocks[j] == zeroed_block) {
7595e5c12b0Sopenharmony_ci					ret = sparse_merge_blocks(j, 1, 1);
7605e5c12b0Sopenharmony_ci					ASSERT(!ret);
7615e5c12b0Sopenharmony_ci				}
7625e5c12b0Sopenharmony_ci
7635e5c12b0Sopenharmony_ci				chunk_start = -1;
7645e5c12b0Sopenharmony_ci			}
7655e5c12b0Sopenharmony_ci		}
7665e5c12b0Sopenharmony_ci		if (chunk_start != -1) {
7675e5c12b0Sopenharmony_ci			ret = sparse_merge_blocks(chunk_start,
7685e5c12b0Sopenharmony_ci						blocks_count - chunk_start, 0);
7695e5c12b0Sopenharmony_ci			ASSERT(!ret);
7705e5c12b0Sopenharmony_ci		}
7715e5c12b0Sopenharmony_ci
7725e5c12b0Sopenharmony_ci		sparse_file_write(f2fs_sparse_file, c.devices[0].fd,
7735e5c12b0Sopenharmony_ci				/*gzip*/0, /*sparse*/1, /*crc*/0);
7745e5c12b0Sopenharmony_ci
7755e5c12b0Sopenharmony_ci		f2fs_release_sparse_resource();
7765e5c12b0Sopenharmony_ci	}
7775e5c12b0Sopenharmony_ci#endif
7785e5c12b0Sopenharmony_ci	/*
7795e5c12b0Sopenharmony_ci	 * We should call fsync() to flush out all the dirty pages
7805e5c12b0Sopenharmony_ci	 * in the block device page cache.
7815e5c12b0Sopenharmony_ci	 */
7825e5c12b0Sopenharmony_ci	for (i = 0; i < c.ndevs; i++) {
7835e5c12b0Sopenharmony_ci#ifdef HAVE_FSYNC
7845e5c12b0Sopenharmony_ci		ret = fsync(c.devices[i].fd);
7855e5c12b0Sopenharmony_ci		if (ret < 0) {
7865e5c12b0Sopenharmony_ci			MSG(0, "\tError: Could not conduct fsync!!!\n");
7875e5c12b0Sopenharmony_ci			break;
7885e5c12b0Sopenharmony_ci		}
7895e5c12b0Sopenharmony_ci#endif
7905e5c12b0Sopenharmony_ci		ret = close(c.devices[i].fd);
7915e5c12b0Sopenharmony_ci		if (ret < 0) {
7925e5c12b0Sopenharmony_ci			MSG(0, "\tError: Failed to close device file!!!\n");
7935e5c12b0Sopenharmony_ci			break;
7945e5c12b0Sopenharmony_ci		}
7955e5c12b0Sopenharmony_ci		free(c.devices[i].path);
7965e5c12b0Sopenharmony_ci		free(c.devices[i].zone_cap_blocks);
7975e5c12b0Sopenharmony_ci	}
7985e5c12b0Sopenharmony_ci	close(c.kd);
7995e5c12b0Sopenharmony_ci
8005e5c12b0Sopenharmony_ci	return ret;
8015e5c12b0Sopenharmony_ci}
802