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