10d163575Sopenharmony_ci/*
20d163575Sopenharmony_ci * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
30d163575Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
40d163575Sopenharmony_ci *
50d163575Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification,
60d163575Sopenharmony_ci * are permitted provided that the following conditions are met:
70d163575Sopenharmony_ci *
80d163575Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, this list of
90d163575Sopenharmony_ci *    conditions and the following disclaimer.
100d163575Sopenharmony_ci *
110d163575Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, this list
120d163575Sopenharmony_ci *    of conditions and the following disclaimer in the documentation and/or other materials
130d163575Sopenharmony_ci *    provided with the distribution.
140d163575Sopenharmony_ci *
150d163575Sopenharmony_ci * 3. Neither the name of the copyright holder nor the names of its contributors may be used
160d163575Sopenharmony_ci *    to endorse or promote products derived from this software without specific prior written
170d163575Sopenharmony_ci *    permission.
180d163575Sopenharmony_ci *
190d163575Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
200d163575Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
210d163575Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
220d163575Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
230d163575Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
240d163575Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
250d163575Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
260d163575Sopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
270d163575Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
280d163575Sopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
290d163575Sopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
300d163575Sopenharmony_ci */
310d163575Sopenharmony_ci
320d163575Sopenharmony_ci#include "bcache.h"
330d163575Sopenharmony_ci#include "assert.h"
340d163575Sopenharmony_ci#include "stdlib.h"
350d163575Sopenharmony_ci#include "linux/delay.h"
360d163575Sopenharmony_ci#include "disk_pri.h"
370d163575Sopenharmony_ci#include "user_copy.h"
380d163575Sopenharmony_ci
390d163575Sopenharmony_ci#undef HALARC_ALIGNMENT
400d163575Sopenharmony_ci#define DMA_ALLGN          64
410d163575Sopenharmony_ci#define HALARC_ALIGNMENT   DMA_ALLGN
420d163575Sopenharmony_ci#define BCACHE_MAGIC_NUM   20132016
430d163575Sopenharmony_ci#define BCACHE_STATCK_SIZE 0x3000
440d163575Sopenharmony_ci#define ASYNC_EVENT_BIT    0x01
450d163575Sopenharmony_ci
460d163575Sopenharmony_ci#ifdef DEBUG
470d163575Sopenharmony_ci#define D(args) printf args
480d163575Sopenharmony_ci#else
490d163575Sopenharmony_ci#define D(args)
500d163575Sopenharmony_ci#endif
510d163575Sopenharmony_ci
520d163575Sopenharmony_ci#ifdef BCACHE_ANALYSE
530d163575Sopenharmony_ciUINT32 g_memSize;
540d163575Sopenharmony_civolatile UINT32 g_blockNum;
550d163575Sopenharmony_civolatile UINT32 g_dataSize;
560d163575Sopenharmony_civolatile UINT8 *g_memStart;
570d163575Sopenharmony_civolatile UINT32 g_switchTimes[CONFIG_FS_FAT_BLOCK_NUMS] = { 0 };
580d163575Sopenharmony_civolatile UINT32 g_hitTimes[CONFIG_FS_FAT_BLOCK_NUMS] = { 0 };
590d163575Sopenharmony_ci#endif
600d163575Sopenharmony_ci
610d163575Sopenharmony_ciVOID BcacheAnalyse(UINT32 level)
620d163575Sopenharmony_ci{
630d163575Sopenharmony_ci    (VOID)level;
640d163575Sopenharmony_ci#ifdef BCACHE_ANALYSE
650d163575Sopenharmony_ci    int i;
660d163575Sopenharmony_ci
670d163575Sopenharmony_ci    PRINTK("Bcache information:\n");
680d163575Sopenharmony_ci    PRINTK("    mem: %u\n", g_memSize);
690d163575Sopenharmony_ci    PRINTK("    block number: %u\n", g_blockNum);
700d163575Sopenharmony_ci    PRINTK("index, switch, hit\n");
710d163575Sopenharmony_ci    for (i = 0; i < g_blockNum; i++) {
720d163575Sopenharmony_ci        PRINTK("%5d, %6d, %3d\n", i, g_switchTimes[i], g_hitTimes[i]);
730d163575Sopenharmony_ci    }
740d163575Sopenharmony_ci#else
750d163575Sopenharmony_ci    PRINTK("Bcache hasn't started\n");
760d163575Sopenharmony_ci#endif
770d163575Sopenharmony_ci}
780d163575Sopenharmony_ci
790d163575Sopenharmony_ci#ifdef LOSCFG_FS_FAT_CACHE_SYNC_THREAD
800d163575Sopenharmony_ci
810d163575Sopenharmony_ciUINT32 g_syncThreadPrio = CONFIG_FS_FAT_SYNC_THREAD_PRIO;
820d163575Sopenharmony_ciUINT32 g_dirtyRatio = CONFIG_FS_FAT_DIRTY_RATIO;
830d163575Sopenharmony_ciUINT32 g_syncInterval = CONFIG_FS_FAT_SYNC_INTERVAL;
840d163575Sopenharmony_ci
850d163575Sopenharmony_ciVOID LOS_SetDirtyRatioThreshold(UINT32 dirtyRatio)
860d163575Sopenharmony_ci{
870d163575Sopenharmony_ci    if ((dirtyRatio != g_dirtyRatio) && (dirtyRatio <= 100)) { /* The ratio cannot exceed 100% */
880d163575Sopenharmony_ci        g_dirtyRatio = dirtyRatio;
890d163575Sopenharmony_ci    }
900d163575Sopenharmony_ci}
910d163575Sopenharmony_ci
920d163575Sopenharmony_ciVOID LOS_SetSyncThreadInterval(UINT32 interval)
930d163575Sopenharmony_ci{
940d163575Sopenharmony_ci    g_syncInterval = interval;
950d163575Sopenharmony_ci}
960d163575Sopenharmony_ci
970d163575Sopenharmony_ciINT32 LOS_SetSyncThreadPrio(UINT32 prio, const CHAR *name)
980d163575Sopenharmony_ci{
990d163575Sopenharmony_ci    INT32 ret = VFS_ERROR;
1000d163575Sopenharmony_ci    INT32 diskID;
1010d163575Sopenharmony_ci    los_disk *disk = NULL;
1020d163575Sopenharmony_ci    if ((prio == 0) || (prio >= OS_TASK_PRIORITY_LOWEST)) { /* The priority can not be zero */
1030d163575Sopenharmony_ci        return ret;
1040d163575Sopenharmony_ci    }
1050d163575Sopenharmony_ci
1060d163575Sopenharmony_ci    g_syncThreadPrio = prio;
1070d163575Sopenharmony_ci
1080d163575Sopenharmony_ci    /*
1090d163575Sopenharmony_ci     * If the name is NULL, it only sets the value of a global variable,
1100d163575Sopenharmony_ci     * and takes effect the next time the thread is created.
1110d163575Sopenharmony_ci     */
1120d163575Sopenharmony_ci    if (name == NULL) {
1130d163575Sopenharmony_ci        return ENOERR;
1140d163575Sopenharmony_ci    }
1150d163575Sopenharmony_ci
1160d163575Sopenharmony_ci    /* If the name is not NULL, it shall return an error if can't find the disk corresponding to name. */
1170d163575Sopenharmony_ci    diskID = los_get_diskid_byname(name);
1180d163575Sopenharmony_ci    disk = get_disk(diskID);
1190d163575Sopenharmony_ci    if (disk == NULL) {
1200d163575Sopenharmony_ci        return ret;
1210d163575Sopenharmony_ci    }
1220d163575Sopenharmony_ci
1230d163575Sopenharmony_ci    if (pthread_mutex_lock(&disk->disk_mutex) != ENOERR) {
1240d163575Sopenharmony_ci        PRINT_ERR("%s %d, mutex lock fail!\n", __FUNCTION__, __LINE__);
1250d163575Sopenharmony_ci        return ret;
1260d163575Sopenharmony_ci    }
1270d163575Sopenharmony_ci    if ((disk->disk_status == STAT_INUSED) && (disk->bcache != NULL)) {
1280d163575Sopenharmony_ci        ret = LOS_TaskPriSet(disk->bcache->syncTaskId, prio);
1290d163575Sopenharmony_ci    }
1300d163575Sopenharmony_ci    if (pthread_mutex_unlock(&disk->disk_mutex) != ENOERR) {
1310d163575Sopenharmony_ci        PRINT_ERR("%s %d, mutex unlock fail!\n", __FUNCTION__, __LINE__);
1320d163575Sopenharmony_ci        return VFS_ERROR;
1330d163575Sopenharmony_ci    }
1340d163575Sopenharmony_ci    return ret;
1350d163575Sopenharmony_ci}
1360d163575Sopenharmony_ci#endif
1370d163575Sopenharmony_ci
1380d163575Sopenharmony_cistatic OsBcacheBlock *RbFindBlock(const OsBcache *bc, UINT64 num)
1390d163575Sopenharmony_ci{
1400d163575Sopenharmony_ci    OsBcacheBlock *block = NULL;
1410d163575Sopenharmony_ci    struct rb_node *node = bc->rbRoot.rb_node;
1420d163575Sopenharmony_ci
1430d163575Sopenharmony_ci    for (; node != NULL; node = (block->num < num) ? node->rb_right : node->rb_left) {
1440d163575Sopenharmony_ci        block = rb_entry(node, OsBcacheBlock, rbNode);
1450d163575Sopenharmony_ci        if (block->num == num) {
1460d163575Sopenharmony_ci            return block;
1470d163575Sopenharmony_ci        }
1480d163575Sopenharmony_ci    }
1490d163575Sopenharmony_ci    return NULL;
1500d163575Sopenharmony_ci}
1510d163575Sopenharmony_ci
1520d163575Sopenharmony_cistatic VOID RbAddBlock(OsBcache *bc, OsBcacheBlock *block)
1530d163575Sopenharmony_ci{
1540d163575Sopenharmony_ci    struct rb_node *node = bc->rbRoot.rb_node;
1550d163575Sopenharmony_ci    struct rb_node **link = NULL;
1560d163575Sopenharmony_ci    OsBcacheBlock *b = NULL;
1570d163575Sopenharmony_ci
1580d163575Sopenharmony_ci    if (node == NULL) {
1590d163575Sopenharmony_ci        rb_link_node(&block->rbNode, NULL, &bc->rbRoot.rb_node);
1600d163575Sopenharmony_ci    } else {
1610d163575Sopenharmony_ci        for (; node != NULL; link = (b->num > block->num) ? &node->rb_left : &node->rb_right, node = *link) {
1620d163575Sopenharmony_ci            b = rb_entry(node, OsBcacheBlock, rbNode);
1630d163575Sopenharmony_ci            if (b->num == block->num) {
1640d163575Sopenharmony_ci                PRINT_ERR("RbAddBlock fail, b->num = %llu, block->num = %llu\n", b->num, block->num);
1650d163575Sopenharmony_ci                return;
1660d163575Sopenharmony_ci            }
1670d163575Sopenharmony_ci        }
1680d163575Sopenharmony_ci        rb_link_node(&block->rbNode, &b->rbNode, link);
1690d163575Sopenharmony_ci    }
1700d163575Sopenharmony_ci    rb_insert_color(&block->rbNode, &bc->rbRoot);
1710d163575Sopenharmony_ci}
1720d163575Sopenharmony_ci
1730d163575Sopenharmony_cistatic inline VOID RbDelBlock(OsBcache *bc, OsBcacheBlock *block)
1740d163575Sopenharmony_ci{
1750d163575Sopenharmony_ci    rb_erase(&block->rbNode, &bc->rbRoot);
1760d163575Sopenharmony_ci}
1770d163575Sopenharmony_ci
1780d163575Sopenharmony_cistatic inline VOID ListMoveBlockToHead(OsBcache *bc, OsBcacheBlock *block)
1790d163575Sopenharmony_ci{
1800d163575Sopenharmony_ci    LOS_ListDelete(&block->listNode);
1810d163575Sopenharmony_ci    LOS_ListAdd(&bc->listHead, &block->listNode);
1820d163575Sopenharmony_ci}
1830d163575Sopenharmony_ci
1840d163575Sopenharmony_cistatic inline VOID FreeBlock(OsBcache *bc, OsBcacheBlock *block)
1850d163575Sopenharmony_ci{
1860d163575Sopenharmony_ci    block->used = FALSE;
1870d163575Sopenharmony_ci    LOS_ListAdd(&bc->freeListHead, &block->listNode);
1880d163575Sopenharmony_ci}
1890d163575Sopenharmony_ci
1900d163575Sopenharmony_cistatic UINT32 GetValLog2(UINT32 val)
1910d163575Sopenharmony_ci{
1920d163575Sopenharmony_ci    UINT32 i, log2;
1930d163575Sopenharmony_ci
1940d163575Sopenharmony_ci    i = val;
1950d163575Sopenharmony_ci    log2 = 0;
1960d163575Sopenharmony_ci    while ((i & 1) == 0) { /* Check if the last bit is 1 */
1970d163575Sopenharmony_ci        i >>= 1;
1980d163575Sopenharmony_ci        log2++;
1990d163575Sopenharmony_ci    }
2000d163575Sopenharmony_ci    if (i != 1) { /* Not the power of 2 */
2010d163575Sopenharmony_ci        return 0;
2020d163575Sopenharmony_ci    }
2030d163575Sopenharmony_ci
2040d163575Sopenharmony_ci    return log2;
2050d163575Sopenharmony_ci}
2060d163575Sopenharmony_ci
2070d163575Sopenharmony_cistatic INT32 FindFlagPos(const UINT32 *arr, UINT32 len, UINT32 *p1, UINT32 *p2)
2080d163575Sopenharmony_ci{
2090d163575Sopenharmony_ci    UINT32 *start = p1;
2100d163575Sopenharmony_ci    UINT32 *end = p2;
2110d163575Sopenharmony_ci    UINT32 i, j, tmp;
2120d163575Sopenharmony_ci    UINT32 val = 1;
2130d163575Sopenharmony_ci
2140d163575Sopenharmony_ci    *start = BCACHE_MAGIC_NUM;
2150d163575Sopenharmony_ci    *end = 0;
2160d163575Sopenharmony_ci    for (i = 0; i < len; i++) {
2170d163575Sopenharmony_ci        for (j = 0; j < UNSIGNED_INTEGER_BITS; j++) {
2180d163575Sopenharmony_ci            tmp = arr[i] << j;
2190d163575Sopenharmony_ci            tmp = tmp >> UNINT_MAX_SHIFT_BITS;
2200d163575Sopenharmony_ci            if (tmp != val) {
2210d163575Sopenharmony_ci                continue;
2220d163575Sopenharmony_ci            }
2230d163575Sopenharmony_ci            if (val && (*start == BCACHE_MAGIC_NUM)) {
2240d163575Sopenharmony_ci                *start = (i << UNINT_LOG2_SHIFT) + j;
2250d163575Sopenharmony_ci                val = 1 - val; /* Control parity by 0 and 1 */
2260d163575Sopenharmony_ci            } else if (val && (*start != BCACHE_MAGIC_NUM)) {
2270d163575Sopenharmony_ci                *start = 0;
2280d163575Sopenharmony_ci                return VFS_ERROR;
2290d163575Sopenharmony_ci            } else {
2300d163575Sopenharmony_ci                *end = (i << UNINT_LOG2_SHIFT) + j;
2310d163575Sopenharmony_ci                val = 1 - val; /* Control parity by 0 and 1 */
2320d163575Sopenharmony_ci            }
2330d163575Sopenharmony_ci        }
2340d163575Sopenharmony_ci    }
2350d163575Sopenharmony_ci    if (*start == BCACHE_MAGIC_NUM) {
2360d163575Sopenharmony_ci        *start = 0;
2370d163575Sopenharmony_ci        return VFS_ERROR;
2380d163575Sopenharmony_ci    }
2390d163575Sopenharmony_ci    if (*end == 0) {
2400d163575Sopenharmony_ci        *end = len << UNINT_LOG2_SHIFT;
2410d163575Sopenharmony_ci    }
2420d163575Sopenharmony_ci
2430d163575Sopenharmony_ci    return ENOERR;
2440d163575Sopenharmony_ci}
2450d163575Sopenharmony_ci
2460d163575Sopenharmony_cistatic INT32 BlockRead(OsBcache *bc, OsBcacheBlock *block, UINT8 *buf)
2470d163575Sopenharmony_ci{
2480d163575Sopenharmony_ci    INT32 ret = bc->breadFun(bc->priv, buf, bc->sectorPerBlock,
2490d163575Sopenharmony_ci                             (block->num) << GetValLog2(bc->sectorPerBlock));
2500d163575Sopenharmony_ci    if (ret) {
2510d163575Sopenharmony_ci        PRINT_ERR("BlockRead, brread_fn error, ret = %d\n", ret);
2520d163575Sopenharmony_ci        if (block->modified == FALSE) {
2530d163575Sopenharmony_ci            if (block->listNode.pstNext != NULL) {
2540d163575Sopenharmony_ci                LOS_ListDelete(&block->listNode); /* list del block */
2550d163575Sopenharmony_ci                RbDelBlock(bc, block);
2560d163575Sopenharmony_ci            }
2570d163575Sopenharmony_ci            FreeBlock(bc, block);
2580d163575Sopenharmony_ci        }
2590d163575Sopenharmony_ci        return ret;
2600d163575Sopenharmony_ci    }
2610d163575Sopenharmony_ci
2620d163575Sopenharmony_ci    block->readFlag = TRUE;
2630d163575Sopenharmony_ci    return ENOERR;
2640d163575Sopenharmony_ci}
2650d163575Sopenharmony_ci
2660d163575Sopenharmony_cistatic INT32 BcacheGetFlag(OsBcache *bc, OsBcacheBlock *block)
2670d163575Sopenharmony_ci{
2680d163575Sopenharmony_ci    UINT32 i, n, f, sectorPos, val, start, pos, currentSize;
2690d163575Sopenharmony_ci    UINT32 flagUse = bc->sectorPerBlock >> UNINT_LOG2_SHIFT;
2700d163575Sopenharmony_ci    UINT32 flag = UINT_MAX;
2710d163575Sopenharmony_ci    INT32 ret, bits;
2720d163575Sopenharmony_ci
2730d163575Sopenharmony_ci    if (block->readFlag == TRUE) {
2740d163575Sopenharmony_ci        return ENOERR;
2750d163575Sopenharmony_ci    }
2760d163575Sopenharmony_ci
2770d163575Sopenharmony_ci    for (i = 0; i < flagUse; i++) {
2780d163575Sopenharmony_ci        flag &= block->flag[i];
2790d163575Sopenharmony_ci    }
2800d163575Sopenharmony_ci
2810d163575Sopenharmony_ci    if (flag == UINT_MAX) {
2820d163575Sopenharmony_ci        return ENOERR;
2830d163575Sopenharmony_ci    }
2840d163575Sopenharmony_ci
2850d163575Sopenharmony_ci    ret = BlockRead(bc, block, bc->rwBuffer);
2860d163575Sopenharmony_ci    if (ret != ENOERR) {
2870d163575Sopenharmony_ci        return ret;
2880d163575Sopenharmony_ci    }
2890d163575Sopenharmony_ci
2900d163575Sopenharmony_ci    for (i = 0, sectorPos = 0; i < flagUse; i++) {
2910d163575Sopenharmony_ci        val = block->flag[i];
2920d163575Sopenharmony_ci        /* use unsigned integer for bit map */
2930d163575Sopenharmony_ci        for (f = 0, bits = UNSIGNED_INTEGER_BITS; bits > 0; val = ~(val << n), f++, bits = bits - (INT32)n) {
2940d163575Sopenharmony_ci            if (val == 0) {
2950d163575Sopenharmony_ci                n = UNSIGNED_INTEGER_BITS;
2960d163575Sopenharmony_ci            } else {
2970d163575Sopenharmony_ci                n = (UINT32)CLZ(val);
2980d163575Sopenharmony_ci            }
2990d163575Sopenharmony_ci            sectorPos += n;
3000d163575Sopenharmony_ci            if (((f % EVEN_JUDGED) != 0) || (n == 0)) { /* Number of leading zeros of n is zero */
3010d163575Sopenharmony_ci                goto LOOP;
3020d163575Sopenharmony_ci            }
3030d163575Sopenharmony_ci            if (sectorPos > ((i + 1) << UNINT_LOG2_SHIFT)) {
3040d163575Sopenharmony_ci                start = sectorPos - n;
3050d163575Sopenharmony_ci                currentSize = (((i + 1) << UNINT_LOG2_SHIFT) - start) * bc->sectorSize;
3060d163575Sopenharmony_ci            } else {
3070d163575Sopenharmony_ci                start = sectorPos - n;
3080d163575Sopenharmony_ci                currentSize = n * bc->sectorSize;
3090d163575Sopenharmony_ci            }
3100d163575Sopenharmony_ci            pos = start * bc->sectorSize;
3110d163575Sopenharmony_ci            if (memcpy_s(block->data + pos, bc->blockSize - pos, bc->rwBuffer + pos, currentSize) != EOK) {
3120d163575Sopenharmony_ci                return VFS_ERROR;
3130d163575Sopenharmony_ci            }
3140d163575Sopenharmony_ciLOOP:
3150d163575Sopenharmony_ci            if (sectorPos > ((i + 1) << UNINT_LOG2_SHIFT)) {
3160d163575Sopenharmony_ci                sectorPos = (i + 1) << UNINT_LOG2_SHIFT;
3170d163575Sopenharmony_ci            }
3180d163575Sopenharmony_ci        }
3190d163575Sopenharmony_ci    }
3200d163575Sopenharmony_ci
3210d163575Sopenharmony_ci    return ENOERR;
3220d163575Sopenharmony_ci}
3230d163575Sopenharmony_ci
3240d163575Sopenharmony_cistatic VOID BcacheSetFlag(const OsBcache *bc, OsBcacheBlock *block, UINT32 pos, UINT32 size)
3250d163575Sopenharmony_ci{
3260d163575Sopenharmony_ci    UINT32 start, num, i, j, k;
3270d163575Sopenharmony_ci
3280d163575Sopenharmony_ci    if (bc->sectorSize == 0) {
3290d163575Sopenharmony_ci        PRINT_ERR("BcacheSetFlag sectorSize is equal to zero! \n");
3300d163575Sopenharmony_ci        return;
3310d163575Sopenharmony_ci    }
3320d163575Sopenharmony_ci
3330d163575Sopenharmony_ci    start = pos / bc->sectorSize;
3340d163575Sopenharmony_ci    num = size / bc->sectorSize;
3350d163575Sopenharmony_ci
3360d163575Sopenharmony_ci    i = start / UNSIGNED_INTEGER_BITS;
3370d163575Sopenharmony_ci    j = start % UNSIGNED_INTEGER_BITS;
3380d163575Sopenharmony_ci    for (k = 0; k < num; k++) {
3390d163575Sopenharmony_ci        block->flag[i] |= 1u << (UNINT_MAX_SHIFT_BITS - j);
3400d163575Sopenharmony_ci        j++;
3410d163575Sopenharmony_ci        if (j == UNSIGNED_INTEGER_BITS) {
3420d163575Sopenharmony_ci            j = 0;
3430d163575Sopenharmony_ci            i++;
3440d163575Sopenharmony_ci        }
3450d163575Sopenharmony_ci    }
3460d163575Sopenharmony_ci}
3470d163575Sopenharmony_ci
3480d163575Sopenharmony_cistatic INT32 BcacheSyncBlock(OsBcache *bc, OsBcacheBlock *block)
3490d163575Sopenharmony_ci{
3500d163575Sopenharmony_ci    INT32 ret = ENOERR;
3510d163575Sopenharmony_ci    UINT32 len, start, end;
3520d163575Sopenharmony_ci
3530d163575Sopenharmony_ci    if (block->modified == TRUE) {
3540d163575Sopenharmony_ci        D(("bcache writing block = %llu\n", block->num));
3550d163575Sopenharmony_ci
3560d163575Sopenharmony_ci        ret = FindFlagPos(block->flag, bc->sectorPerBlock >> UNINT_LOG2_SHIFT, &start, &end);
3570d163575Sopenharmony_ci        if (ret == ENOERR) {
3580d163575Sopenharmony_ci            len = end - start;
3590d163575Sopenharmony_ci        } else {
3600d163575Sopenharmony_ci            ret = BcacheGetFlag(bc, block);
3610d163575Sopenharmony_ci            if (ret != ENOERR) {
3620d163575Sopenharmony_ci                return ret;
3630d163575Sopenharmony_ci            }
3640d163575Sopenharmony_ci
3650d163575Sopenharmony_ci            len = bc->sectorPerBlock;
3660d163575Sopenharmony_ci        }
3670d163575Sopenharmony_ci
3680d163575Sopenharmony_ci        ret = bc->bwriteFun(bc->priv, (const UINT8 *)(block->data + (start * bc->sectorSize)),
3690d163575Sopenharmony_ci                            len, (block->num * bc->sectorPerBlock) + start);
3700d163575Sopenharmony_ci        if (ret == ENOERR) {
3710d163575Sopenharmony_ci            block->modified = FALSE;
3720d163575Sopenharmony_ci            bc->modifiedBlock--;
3730d163575Sopenharmony_ci        } else {
3740d163575Sopenharmony_ci            PRINT_ERR("BcacheSyncBlock fail, ret = %d, len = %u, block->num = %llu, start = %u\n",
3750d163575Sopenharmony_ci                      ret, len, block->num, start);
3760d163575Sopenharmony_ci        }
3770d163575Sopenharmony_ci    }
3780d163575Sopenharmony_ci    return ret;
3790d163575Sopenharmony_ci}
3800d163575Sopenharmony_ci
3810d163575Sopenharmony_cistatic void NumListAdd(OsBcache *bc, OsBcacheBlock *block)
3820d163575Sopenharmony_ci{
3830d163575Sopenharmony_ci    OsBcacheBlock *temp = NULL;
3840d163575Sopenharmony_ci
3850d163575Sopenharmony_ci    LOS_DL_LIST_FOR_EACH_ENTRY(temp, &bc->numHead, OsBcacheBlock, numNode) {
3860d163575Sopenharmony_ci        if (temp->num > block->num) {
3870d163575Sopenharmony_ci            LOS_ListTailInsert(&temp->numNode, &block->numNode);
3880d163575Sopenharmony_ci            return;
3890d163575Sopenharmony_ci        }
3900d163575Sopenharmony_ci    }
3910d163575Sopenharmony_ci
3920d163575Sopenharmony_ci    LOS_ListTailInsert(&bc->numHead, &block->numNode);
3930d163575Sopenharmony_ci}
3940d163575Sopenharmony_ci
3950d163575Sopenharmony_cistatic void AddBlock(OsBcache *bc, OsBcacheBlock *block)
3960d163575Sopenharmony_ci{
3970d163575Sopenharmony_ci    RbAddBlock(bc, block);
3980d163575Sopenharmony_ci    NumListAdd(bc, block);
3990d163575Sopenharmony_ci    bc->sumNum += block->num;
4000d163575Sopenharmony_ci    bc->nBlock++;
4010d163575Sopenharmony_ci    LOS_ListAdd(&bc->listHead, &block->listNode);
4020d163575Sopenharmony_ci}
4030d163575Sopenharmony_ci
4040d163575Sopenharmony_cistatic void DelBlock(OsBcache *bc, OsBcacheBlock *block)
4050d163575Sopenharmony_ci{
4060d163575Sopenharmony_ci    LOS_ListDelete(&block->listNode); /* lru list del */
4070d163575Sopenharmony_ci    LOS_ListDelete(&block->numNode);  /* num list del */
4080d163575Sopenharmony_ci    bc->sumNum -= block->num;
4090d163575Sopenharmony_ci    bc->nBlock--;
4100d163575Sopenharmony_ci    RbDelBlock(bc, block);            /* rb  tree del */
4110d163575Sopenharmony_ci    FreeBlock(bc, block);             /* free list add */
4120d163575Sopenharmony_ci}
4130d163575Sopenharmony_ci
4140d163575Sopenharmony_cistatic BOOL BlockAllDirty(const OsBcache *bc, OsBcacheBlock *block)
4150d163575Sopenharmony_ci{
4160d163575Sopenharmony_ci    UINT32 start = 0;
4170d163575Sopenharmony_ci    UINT32 end = 0;
4180d163575Sopenharmony_ci    UINT32 len = bc->sectorPerBlock >> UNINT_LOG2_SHIFT;
4190d163575Sopenharmony_ci
4200d163575Sopenharmony_ci    if (block->modified == TRUE) {
4210d163575Sopenharmony_ci        if (block->allDirty) {
4220d163575Sopenharmony_ci            return TRUE;
4230d163575Sopenharmony_ci        }
4240d163575Sopenharmony_ci
4250d163575Sopenharmony_ci        if (FindFlagPos(block->flag, len, &start, &end) == ENOERR) {
4260d163575Sopenharmony_ci            if ((end - start) == bc->sectorPerBlock) {
4270d163575Sopenharmony_ci                block->allDirty = TRUE;
4280d163575Sopenharmony_ci                return TRUE;
4290d163575Sopenharmony_ci            }
4300d163575Sopenharmony_ci        }
4310d163575Sopenharmony_ci    }
4320d163575Sopenharmony_ci
4330d163575Sopenharmony_ci    return FALSE;
4340d163575Sopenharmony_ci}
4350d163575Sopenharmony_ci
4360d163575Sopenharmony_cistatic OsBcacheBlock *GetBaseBlock(OsBcache *bc)
4370d163575Sopenharmony_ci{
4380d163575Sopenharmony_ci    OsBcacheBlock *base = bc->wStart;
4390d163575Sopenharmony_ci    OsBcacheBlock *end = bc->wEnd;
4400d163575Sopenharmony_ci    while (base < end) {
4410d163575Sopenharmony_ci        if (base->used == FALSE) {
4420d163575Sopenharmony_ci            base->used = TRUE;
4430d163575Sopenharmony_ci            LOS_ListDelete(&base->listNode);
4440d163575Sopenharmony_ci            return base;
4450d163575Sopenharmony_ci        }
4460d163575Sopenharmony_ci        base++;
4470d163575Sopenharmony_ci    }
4480d163575Sopenharmony_ci
4490d163575Sopenharmony_ci    return NULL;
4500d163575Sopenharmony_ci}
4510d163575Sopenharmony_ci
4520d163575Sopenharmony_ci/* try get free block first, if failed free a useless block */
4530d163575Sopenharmony_cistatic OsBcacheBlock *GetSlowBlock(OsBcache *bc, BOOL read)
4540d163575Sopenharmony_ci{
4550d163575Sopenharmony_ci    LOS_DL_LIST *node = NULL;
4560d163575Sopenharmony_ci    OsBcacheBlock *block = NULL;
4570d163575Sopenharmony_ci
4580d163575Sopenharmony_ci    LOS_DL_LIST_FOR_EACH_ENTRY(block, &bc->freeListHead, OsBcacheBlock, listNode) {
4590d163575Sopenharmony_ci        if (block->readBuff == read) {
4600d163575Sopenharmony_ci            block->used = TRUE;
4610d163575Sopenharmony_ci            LOS_ListDelete(&block->listNode);
4620d163575Sopenharmony_ci            return block; /* get free one */
4630d163575Sopenharmony_ci        }
4640d163575Sopenharmony_ci    }
4650d163575Sopenharmony_ci
4660d163575Sopenharmony_ci    node = bc->listHead.pstPrev;
4670d163575Sopenharmony_ci    while (node != &bc->listHead) {
4680d163575Sopenharmony_ci        block = LOS_DL_LIST_ENTRY(node, OsBcacheBlock, listNode);
4690d163575Sopenharmony_ci        node = block->listNode.pstPrev;
4700d163575Sopenharmony_ci
4710d163575Sopenharmony_ci        if (block->readBuff == read) {
4720d163575Sopenharmony_ci            if (block->modified == TRUE) {
4730d163575Sopenharmony_ci                BcacheSyncBlock(bc, block);
4740d163575Sopenharmony_ci            }
4750d163575Sopenharmony_ci
4760d163575Sopenharmony_ci            DelBlock(bc, block);
4770d163575Sopenharmony_ci            block->used = TRUE;
4780d163575Sopenharmony_ci            LOS_ListDelete(&block->listNode);
4790d163575Sopenharmony_ci            return block; /* get used one */
4800d163575Sopenharmony_ci        }
4810d163575Sopenharmony_ci    }
4820d163575Sopenharmony_ci
4830d163575Sopenharmony_ci    return NULL;
4840d163575Sopenharmony_ci}
4850d163575Sopenharmony_ci
4860d163575Sopenharmony_ci/* flush combined blocks */
4870d163575Sopenharmony_cistatic VOID WriteMergedBlocks(OsBcache *bc, OsBcacheBlock *begin, int blocks)
4880d163575Sopenharmony_ci{
4890d163575Sopenharmony_ci    INT32 ret;
4900d163575Sopenharmony_ci    OsBcacheBlock *cur = NULL;
4910d163575Sopenharmony_ci    OsBcacheBlock *next = NULL;
4920d163575Sopenharmony_ci    UINT32 len = blocks * bc->sectorPerBlock;
4930d163575Sopenharmony_ci    UINT64 pos = begin->num * bc->sectorPerBlock;
4940d163575Sopenharmony_ci
4950d163575Sopenharmony_ci    ret = bc->bwriteFun(bc->priv, (const UINT8 *)begin->data, len, pos);
4960d163575Sopenharmony_ci    if (ret != ENOERR) {
4970d163575Sopenharmony_ci        PRINT_ERR("WriteMergedBlocks bwriteFun failed ret %d\n", ret);
4980d163575Sopenharmony_ci        return;
4990d163575Sopenharmony_ci    }
5000d163575Sopenharmony_ci
5010d163575Sopenharmony_ci    bc->modifiedBlock -= blocks;
5020d163575Sopenharmony_ci    cur = begin;
5030d163575Sopenharmony_ci    while (blocks > 0) {
5040d163575Sopenharmony_ci        next = LOS_DL_LIST_ENTRY(cur->numNode.pstNext, OsBcacheBlock, numNode);
5050d163575Sopenharmony_ci        DelBlock(bc, cur);
5060d163575Sopenharmony_ci        cur->modified = FALSE;
5070d163575Sopenharmony_ci        blocks--;
5080d163575Sopenharmony_ci        cur = next;
5090d163575Sopenharmony_ci    }
5100d163575Sopenharmony_ci}
5110d163575Sopenharmony_ci
5120d163575Sopenharmony_ci/* find continue blocks and flush them */
5130d163575Sopenharmony_cistatic VOID MergeSyncBlocks(OsBcache *bc, OsBcacheBlock *start)
5140d163575Sopenharmony_ci{
5150d163575Sopenharmony_ci    INT32 mergedBlock = 0;
5160d163575Sopenharmony_ci    OsBcacheBlock *cur = start;
5170d163575Sopenharmony_ci    OsBcacheBlock *last = NULL;
5180d163575Sopenharmony_ci
5190d163575Sopenharmony_ci    while (cur <= bc->wEnd) {
5200d163575Sopenharmony_ci        if (!cur->used || !BlockAllDirty(bc, cur)) {
5210d163575Sopenharmony_ci            break;
5220d163575Sopenharmony_ci        }
5230d163575Sopenharmony_ci
5240d163575Sopenharmony_ci        if (last && (last->num + 1 != cur->num)) {
5250d163575Sopenharmony_ci            break;
5260d163575Sopenharmony_ci        }
5270d163575Sopenharmony_ci
5280d163575Sopenharmony_ci        mergedBlock++;
5290d163575Sopenharmony_ci        last = cur;
5300d163575Sopenharmony_ci        cur++;
5310d163575Sopenharmony_ci    }
5320d163575Sopenharmony_ci
5330d163575Sopenharmony_ci    if (mergedBlock > 0) {
5340d163575Sopenharmony_ci        WriteMergedBlocks(bc, start, mergedBlock);
5350d163575Sopenharmony_ci    }
5360d163575Sopenharmony_ci}
5370d163575Sopenharmony_ci
5380d163575Sopenharmony_ci/* get the min write block num of block cache buffer */
5390d163575Sopenharmony_cistatic inline UINT64 GetMinWriteNum(OsBcache *bc)
5400d163575Sopenharmony_ci{
5410d163575Sopenharmony_ci    UINT64 ret = 0;
5420d163575Sopenharmony_ci    OsBcacheBlock *block = NULL;
5430d163575Sopenharmony_ci
5440d163575Sopenharmony_ci    LOS_DL_LIST_FOR_EACH_ENTRY(block, &bc->numHead, OsBcacheBlock, numNode) {
5450d163575Sopenharmony_ci        if (!block->readBuff) {
5460d163575Sopenharmony_ci            ret = block->num;
5470d163575Sopenharmony_ci            break;
5480d163575Sopenharmony_ci        }
5490d163575Sopenharmony_ci    }
5500d163575Sopenharmony_ci
5510d163575Sopenharmony_ci    return ret;
5520d163575Sopenharmony_ci}
5530d163575Sopenharmony_ci
5540d163575Sopenharmony_cistatic OsBcacheBlock *AllocNewBlock(OsBcache *bc, BOOL read, UINT64 num)
5550d163575Sopenharmony_ci{
5560d163575Sopenharmony_ci    OsBcacheBlock *last = NULL;
5570d163575Sopenharmony_ci    OsBcacheBlock *prefer = NULL;
5580d163575Sopenharmony_ci
5590d163575Sopenharmony_ci    if (read) { /* read */
5600d163575Sopenharmony_ci        return GetSlowBlock(bc, TRUE);
5610d163575Sopenharmony_ci    }
5620d163575Sopenharmony_ci
5630d163575Sopenharmony_ci    /* fallback, this may happen when the block previously flushed, use read buffer */
5640d163575Sopenharmony_ci    if (bc->nBlock && num < GetMinWriteNum(bc)) {
5650d163575Sopenharmony_ci        return GetSlowBlock(bc, TRUE);
5660d163575Sopenharmony_ci    }
5670d163575Sopenharmony_ci
5680d163575Sopenharmony_ci    last = RbFindBlock(bc, num - 1);  /* num=0 is ok */
5690d163575Sopenharmony_ci    if (last == NULL || last->readBuff) {
5700d163575Sopenharmony_ci        return GetBaseBlock(bc);      /* new block */
5710d163575Sopenharmony_ci    }
5720d163575Sopenharmony_ci
5730d163575Sopenharmony_ci    prefer = last + 1;
5740d163575Sopenharmony_ci    if (prefer > bc->wEnd) {
5750d163575Sopenharmony_ci        prefer = bc->wStart;
5760d163575Sopenharmony_ci    }
5770d163575Sopenharmony_ci
5780d163575Sopenharmony_ci    /* this is a sync thread synced block! */
5790d163575Sopenharmony_ci    if (prefer->used && !prefer->modified) {
5800d163575Sopenharmony_ci        prefer->used = FALSE;
5810d163575Sopenharmony_ci        DelBlock(bc, prefer);
5820d163575Sopenharmony_ci    }
5830d163575Sopenharmony_ci
5840d163575Sopenharmony_ci    if (prefer->used) { /* do not combine with next check */
5850d163575Sopenharmony_ci        MergeSyncBlocks(bc, prefer); /* prefer->used may be changed here */
5860d163575Sopenharmony_ci    }
5870d163575Sopenharmony_ci
5880d163575Sopenharmony_ci    if (prefer->used) {
5890d163575Sopenharmony_ci        BcacheSyncBlock(bc, prefer);
5900d163575Sopenharmony_ci        DelBlock(bc, prefer);
5910d163575Sopenharmony_ci    }
5920d163575Sopenharmony_ci
5930d163575Sopenharmony_ci    prefer->used = TRUE;
5940d163575Sopenharmony_ci    LOS_ListDelete(&prefer->listNode); /* del from free list */
5950d163575Sopenharmony_ci
5960d163575Sopenharmony_ci    return prefer;
5970d163575Sopenharmony_ci}
5980d163575Sopenharmony_ci
5990d163575Sopenharmony_cistatic INT32 BcacheSync(OsBcache *bc)
6000d163575Sopenharmony_ci{
6010d163575Sopenharmony_ci    LOS_DL_LIST *node = NULL;
6020d163575Sopenharmony_ci    OsBcacheBlock *block = NULL;
6030d163575Sopenharmony_ci    INT32 ret = ENOERR;
6040d163575Sopenharmony_ci
6050d163575Sopenharmony_ci    D(("bcache cache sync\n"));
6060d163575Sopenharmony_ci
6070d163575Sopenharmony_ci    (VOID)pthread_mutex_lock(&bc->bcacheMutex);
6080d163575Sopenharmony_ci    node = bc->listHead.pstPrev;
6090d163575Sopenharmony_ci    while (&bc->listHead != node) {
6100d163575Sopenharmony_ci        block = LOS_DL_LIST_ENTRY(node, OsBcacheBlock, listNode);
6110d163575Sopenharmony_ci        ret = BcacheSyncBlock(bc, block);
6120d163575Sopenharmony_ci        if (ret != ENOERR) {
6130d163575Sopenharmony_ci            PRINT_ERR("BcacheSync error, ret = %d\n", ret);
6140d163575Sopenharmony_ci            break;
6150d163575Sopenharmony_ci        }
6160d163575Sopenharmony_ci        node = node->pstPrev;
6170d163575Sopenharmony_ci    }
6180d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&bc->bcacheMutex);
6190d163575Sopenharmony_ci
6200d163575Sopenharmony_ci    return ret;
6210d163575Sopenharmony_ci}
6220d163575Sopenharmony_ci
6230d163575Sopenharmony_cistatic VOID BlockInit(OsBcache *bc, OsBcacheBlock *block, UINT64 num)
6240d163575Sopenharmony_ci{
6250d163575Sopenharmony_ci    (VOID)memset_s(block->flag, sizeof(block->flag), 0, sizeof(block->flag));
6260d163575Sopenharmony_ci    block->num = num;
6270d163575Sopenharmony_ci    block->readFlag = FALSE;
6280d163575Sopenharmony_ci    if (block->modified == TRUE) {
6290d163575Sopenharmony_ci        block->modified = FALSE;
6300d163575Sopenharmony_ci        bc->modifiedBlock--;
6310d163575Sopenharmony_ci    }
6320d163575Sopenharmony_ci    block->allDirty = FALSE;
6330d163575Sopenharmony_ci}
6340d163575Sopenharmony_ci
6350d163575Sopenharmony_cistatic INT32 BcacheGetBlock(OsBcache *bc, UINT64 num, BOOL readData, OsBcacheBlock **dblock)
6360d163575Sopenharmony_ci{
6370d163575Sopenharmony_ci    INT32 ret;
6380d163575Sopenharmony_ci    OsBcacheBlock *block = NULL;
6390d163575Sopenharmony_ci    OsBcacheBlock *first = NULL;
6400d163575Sopenharmony_ci
6410d163575Sopenharmony_ci    /*
6420d163575Sopenharmony_ci     * First check if the most recently used block is the requested block,
6430d163575Sopenharmony_ci     * this can improve performance when using byte access functions.
6440d163575Sopenharmony_ci     */
6450d163575Sopenharmony_ci    if (LOS_ListEmpty(&bc->listHead) == FALSE) {
6460d163575Sopenharmony_ci        first = LOS_DL_LIST_ENTRY(bc->listHead.pstNext, OsBcacheBlock, listNode);
6470d163575Sopenharmony_ci        block = (first->num == num) ? first : RbFindBlock(bc, num);
6480d163575Sopenharmony_ci    }
6490d163575Sopenharmony_ci
6500d163575Sopenharmony_ci    if (block != NULL) {
6510d163575Sopenharmony_ci        D(("bcache block = %llu found in cache\n", num));
6520d163575Sopenharmony_ci#ifdef BCACHE_ANALYSE
6530d163575Sopenharmony_ci        UINT32 index = ((UINT32)(block->data - g_memStart)) / g_dataSize;
6540d163575Sopenharmony_ci        PRINTK(", [HIT], %llu, %u\n", num, index);
6550d163575Sopenharmony_ci        g_hitTimes[index]++;
6560d163575Sopenharmony_ci#endif
6570d163575Sopenharmony_ci
6580d163575Sopenharmony_ci        if (first != block) {
6590d163575Sopenharmony_ci            ListMoveBlockToHead(bc, block);
6600d163575Sopenharmony_ci        }
6610d163575Sopenharmony_ci        *dblock = block;
6620d163575Sopenharmony_ci
6630d163575Sopenharmony_ci        if ((bc->prereadFun != NULL) && (readData == TRUE) && (block->pgHit == 1)) {
6640d163575Sopenharmony_ci            block->pgHit = 0;
6650d163575Sopenharmony_ci            bc->prereadFun(bc, block);
6660d163575Sopenharmony_ci        }
6670d163575Sopenharmony_ci
6680d163575Sopenharmony_ci        return ENOERR;
6690d163575Sopenharmony_ci    }
6700d163575Sopenharmony_ci
6710d163575Sopenharmony_ci    D(("bcache block = %llu NOT found in cache\n", num));
6720d163575Sopenharmony_ci
6730d163575Sopenharmony_ci    block = AllocNewBlock(bc, readData, num);
6740d163575Sopenharmony_ci    if (block == NULL) {
6750d163575Sopenharmony_ci        block = GetSlowBlock(bc, readData);
6760d163575Sopenharmony_ci    }
6770d163575Sopenharmony_ci
6780d163575Sopenharmony_ci    if (block == NULL) {
6790d163575Sopenharmony_ci        return -ENOMEM;
6800d163575Sopenharmony_ci    }
6810d163575Sopenharmony_ci#ifdef BCACHE_ANALYSE
6820d163575Sopenharmony_ci    UINT32 index = ((UINT32)(block->data - g_memStart)) / g_dataSize;
6830d163575Sopenharmony_ci    PRINTK(", [MISS], %llu, %u\n", num, index);
6840d163575Sopenharmony_ci    g_switchTimes[index]++;
6850d163575Sopenharmony_ci#endif
6860d163575Sopenharmony_ci    BlockInit(bc, block, num);
6870d163575Sopenharmony_ci
6880d163575Sopenharmony_ci    if (readData == TRUE) {
6890d163575Sopenharmony_ci        D(("bcache reading block = %llu\n", block->num));
6900d163575Sopenharmony_ci
6910d163575Sopenharmony_ci        ret = BlockRead(bc, block, block->data);
6920d163575Sopenharmony_ci        if (ret != ENOERR) {
6930d163575Sopenharmony_ci            return ret;
6940d163575Sopenharmony_ci        }
6950d163575Sopenharmony_ci        if (bc->prereadFun != NULL) {
6960d163575Sopenharmony_ci            bc->prereadFun(bc, block);
6970d163575Sopenharmony_ci        }
6980d163575Sopenharmony_ci    }
6990d163575Sopenharmony_ci
7000d163575Sopenharmony_ci    AddBlock(bc, block);
7010d163575Sopenharmony_ci
7020d163575Sopenharmony_ci    *dblock = block;
7030d163575Sopenharmony_ci    return ENOERR;
7040d163575Sopenharmony_ci}
7050d163575Sopenharmony_ci
7060d163575Sopenharmony_ciINT32 BcacheClearCache(OsBcache *bc)
7070d163575Sopenharmony_ci{
7080d163575Sopenharmony_ci    OsBcacheBlock *block = NULL;
7090d163575Sopenharmony_ci    OsBcacheBlock *next = NULL;
7100d163575Sopenharmony_ci    LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(block, next, &bc->listHead, OsBcacheBlock, listNode) {
7110d163575Sopenharmony_ci        DelBlock(bc, block);
7120d163575Sopenharmony_ci    }
7130d163575Sopenharmony_ci    return 0;
7140d163575Sopenharmony_ci}
7150d163575Sopenharmony_ci
7160d163575Sopenharmony_cistatic INT32 BcacheInitCache(OsBcache *bc,
7170d163575Sopenharmony_ci                             UINT8 *memStart,
7180d163575Sopenharmony_ci                             UINT32 memSize,
7190d163575Sopenharmony_ci                             UINT32 blockSize)
7200d163575Sopenharmony_ci{
7210d163575Sopenharmony_ci    UINT8 *blockMem = NULL;
7220d163575Sopenharmony_ci    UINT8 *dataMem = NULL;
7230d163575Sopenharmony_ci    OsBcacheBlock *block = NULL;
7240d163575Sopenharmony_ci    UINT32 blockNum, i;
7250d163575Sopenharmony_ci
7260d163575Sopenharmony_ci    LOS_ListInit(&bc->listHead);
7270d163575Sopenharmony_ci    LOS_ListInit(&bc->numHead);
7280d163575Sopenharmony_ci    bc->sumNum = 0;
7290d163575Sopenharmony_ci    bc->nBlock = 0;
7300d163575Sopenharmony_ci
7310d163575Sopenharmony_ci    if (!GetValLog2(blockSize)) {
7320d163575Sopenharmony_ci        PRINT_ERR("GetValLog2(%u) return 0.\n", blockSize);
7330d163575Sopenharmony_ci        return -EINVAL;
7340d163575Sopenharmony_ci    }
7350d163575Sopenharmony_ci
7360d163575Sopenharmony_ci    bc->rbRoot.rb_node = NULL;
7370d163575Sopenharmony_ci    bc->memStart = memStart;
7380d163575Sopenharmony_ci    bc->blockSize = blockSize;
7390d163575Sopenharmony_ci    bc->blockSizeLog2 = GetValLog2(blockSize);
7400d163575Sopenharmony_ci    bc->modifiedBlock = 0;
7410d163575Sopenharmony_ci
7420d163575Sopenharmony_ci    /* init block memory pool */
7430d163575Sopenharmony_ci    LOS_ListInit(&bc->freeListHead);
7440d163575Sopenharmony_ci
7450d163575Sopenharmony_ci    blockNum = (memSize - DMA_ALLGN) / (sizeof(OsBcacheBlock) + bc->blockSize);
7460d163575Sopenharmony_ci    blockMem = bc->memStart;
7470d163575Sopenharmony_ci    dataMem = blockMem + (sizeof(OsBcacheBlock) * blockNum);
7480d163575Sopenharmony_ci    dataMem += ALIGN_DISP((UINTPTR)dataMem);
7490d163575Sopenharmony_ci
7500d163575Sopenharmony_ci#ifdef BCACHE_ANALYSE
7510d163575Sopenharmony_ci    g_memSize = memSize;
7520d163575Sopenharmony_ci    g_blockNum = blockNum;
7530d163575Sopenharmony_ci    g_dataSize = bc->blockSize;
7540d163575Sopenharmony_ci    g_memStart = dataMem;
7550d163575Sopenharmony_ci#endif
7560d163575Sopenharmony_ci
7570d163575Sopenharmony_ci    for (i = 0; i < blockNum; i++) {
7580d163575Sopenharmony_ci        block = (OsBcacheBlock *)(VOID *)blockMem;
7590d163575Sopenharmony_ci        block->data = dataMem;
7600d163575Sopenharmony_ci        block->readBuff = (i < CONFIG_FS_FAT_READ_NUMS) ? TRUE : FALSE;
7610d163575Sopenharmony_ci
7620d163575Sopenharmony_ci        if (i == CONFIG_FS_FAT_READ_NUMS) {
7630d163575Sopenharmony_ci            bc->wStart = block;
7640d163575Sopenharmony_ci        }
7650d163575Sopenharmony_ci
7660d163575Sopenharmony_ci        LOS_ListTailInsert(&bc->freeListHead, &block->listNode);
7670d163575Sopenharmony_ci
7680d163575Sopenharmony_ci        blockMem += sizeof(OsBcacheBlock);
7690d163575Sopenharmony_ci        dataMem += bc->blockSize;
7700d163575Sopenharmony_ci    }
7710d163575Sopenharmony_ci
7720d163575Sopenharmony_ci    bc->wEnd = block;
7730d163575Sopenharmony_ci
7740d163575Sopenharmony_ci    return ENOERR;
7750d163575Sopenharmony_ci}
7760d163575Sopenharmony_ci
7770d163575Sopenharmony_cistatic INT32 DrvBread(struct Vnode *priv, UINT8 *buf, UINT32 len, UINT64 pos)
7780d163575Sopenharmony_ci{
7790d163575Sopenharmony_ci    struct block_operations *bops = (struct block_operations *)((struct drv_data *)priv->data)->ops;
7800d163575Sopenharmony_ci
7810d163575Sopenharmony_ci    INT32 ret = bops->read(priv, buf, pos, len);
7820d163575Sopenharmony_ci    if (ret != (INT32)len) {
7830d163575Sopenharmony_ci        PRINT_ERR("%s failure\n", __FUNCTION__);
7840d163575Sopenharmony_ci        return ret;
7850d163575Sopenharmony_ci    }
7860d163575Sopenharmony_ci    return ENOERR;
7870d163575Sopenharmony_ci}
7880d163575Sopenharmony_ci
7890d163575Sopenharmony_cistatic INT32 DrvBwrite(struct Vnode *priv, const UINT8 *buf, UINT32 len, UINT64 pos)
7900d163575Sopenharmony_ci{
7910d163575Sopenharmony_ci    struct block_operations *bops = (struct block_operations *)((struct drv_data *)priv->data)->ops;
7920d163575Sopenharmony_ci    INT32 ret = bops->write(priv, buf, pos, len);
7930d163575Sopenharmony_ci    if (ret != (INT32)len) {
7940d163575Sopenharmony_ci        PRINT_ERR("%s failure\n", __FUNCTION__);
7950d163575Sopenharmony_ci        return ret;
7960d163575Sopenharmony_ci    }
7970d163575Sopenharmony_ci    return ENOERR;
7980d163575Sopenharmony_ci}
7990d163575Sopenharmony_ci
8000d163575Sopenharmony_ciINT32 BlockCacheDrvCreate(VOID *handle,
8010d163575Sopenharmony_ci                          UINT8 *memStart,
8020d163575Sopenharmony_ci                          UINT32 memSize,
8030d163575Sopenharmony_ci                          UINT32 blockSize,
8040d163575Sopenharmony_ci                          OsBcache *bc)
8050d163575Sopenharmony_ci{
8060d163575Sopenharmony_ci    INT32 ret;
8070d163575Sopenharmony_ci    bc->priv = handle;
8080d163575Sopenharmony_ci    bc->breadFun = DrvBread;
8090d163575Sopenharmony_ci    bc->bwriteFun = DrvBwrite;
8100d163575Sopenharmony_ci
8110d163575Sopenharmony_ci    ret = BcacheInitCache(bc, memStart, memSize, blockSize);
8120d163575Sopenharmony_ci    if (ret != ENOERR) {
8130d163575Sopenharmony_ci        return ret;
8140d163575Sopenharmony_ci    }
8150d163575Sopenharmony_ci
8160d163575Sopenharmony_ci    if (pthread_mutex_init(&bc->bcacheMutex, NULL) != ENOERR) {
8170d163575Sopenharmony_ci        return VFS_ERROR;
8180d163575Sopenharmony_ci    }
8190d163575Sopenharmony_ci    bc->bcacheMutex.attr.type = PTHREAD_MUTEX_RECURSIVE;
8200d163575Sopenharmony_ci
8210d163575Sopenharmony_ci    return ENOERR;
8220d163575Sopenharmony_ci}
8230d163575Sopenharmony_ci
8240d163575Sopenharmony_ciINT32 BlockCacheRead(OsBcache *bc, UINT8 *buf, UINT32 *len, UINT64 sector, BOOL useRead)
8250d163575Sopenharmony_ci{
8260d163575Sopenharmony_ci    OsBcacheBlock *block = NULL;
8270d163575Sopenharmony_ci    UINT8 *tempBuf = buf;
8280d163575Sopenharmony_ci    UINT32 size;
8290d163575Sopenharmony_ci    UINT32 currentSize;
8300d163575Sopenharmony_ci    INT32 ret = ENOERR;
8310d163575Sopenharmony_ci    UINT64 pos;
8320d163575Sopenharmony_ci    UINT64 num;
8330d163575Sopenharmony_ci#ifdef BCACHE_ANALYSE
8340d163575Sopenharmony_ci    PRINTK("bcache read:\n");
8350d163575Sopenharmony_ci#endif
8360d163575Sopenharmony_ci
8370d163575Sopenharmony_ci    if (bc == NULL || buf == NULL || len == NULL) {
8380d163575Sopenharmony_ci        return -EPERM;
8390d163575Sopenharmony_ci    }
8400d163575Sopenharmony_ci
8410d163575Sopenharmony_ci    size = *len;
8420d163575Sopenharmony_ci    pos = sector * bc->sectorSize;
8430d163575Sopenharmony_ci    num = pos >> bc->blockSizeLog2;
8440d163575Sopenharmony_ci    pos = pos & (bc->blockSize - 1);
8450d163575Sopenharmony_ci
8460d163575Sopenharmony_ci    while (size > 0) {
8470d163575Sopenharmony_ci        if ((size + pos) > bc->blockSize) {
8480d163575Sopenharmony_ci            currentSize = bc->blockSize - (UINT32)pos;
8490d163575Sopenharmony_ci        } else {
8500d163575Sopenharmony_ci            currentSize = size;
8510d163575Sopenharmony_ci        }
8520d163575Sopenharmony_ci
8530d163575Sopenharmony_ci        (VOID)pthread_mutex_lock(&bc->bcacheMutex);
8540d163575Sopenharmony_ci
8550d163575Sopenharmony_ci        /* useRead should be FALSE when reading large contiguous data */
8560d163575Sopenharmony_ci        ret = BcacheGetBlock(bc, num, useRead, &block);
8570d163575Sopenharmony_ci        if (ret != ENOERR) {
8580d163575Sopenharmony_ci            (VOID)pthread_mutex_unlock(&bc->bcacheMutex);
8590d163575Sopenharmony_ci            break;
8600d163575Sopenharmony_ci        }
8610d163575Sopenharmony_ci
8620d163575Sopenharmony_ci        if ((block->readFlag == FALSE) && (block->modified == TRUE)) {
8630d163575Sopenharmony_ci            ret = BcacheGetFlag(bc, block);
8640d163575Sopenharmony_ci            if (ret != ENOERR) {
8650d163575Sopenharmony_ci                (VOID)pthread_mutex_unlock(&bc->bcacheMutex);
8660d163575Sopenharmony_ci                return ret;
8670d163575Sopenharmony_ci            }
8680d163575Sopenharmony_ci        } else if ((block->readFlag == FALSE) && (block->modified == FALSE)) {
8690d163575Sopenharmony_ci            ret = BlockRead(bc, block, block->data);
8700d163575Sopenharmony_ci            if (ret != ENOERR) {
8710d163575Sopenharmony_ci                (VOID)pthread_mutex_unlock(&bc->bcacheMutex);
8720d163575Sopenharmony_ci                return ret;
8730d163575Sopenharmony_ci            }
8740d163575Sopenharmony_ci        }
8750d163575Sopenharmony_ci
8760d163575Sopenharmony_ci        if (LOS_CopyFromKernel((VOID *)tempBuf, size, (VOID *)(block->data + pos), currentSize) != EOK) {
8770d163575Sopenharmony_ci            (VOID)pthread_mutex_unlock(&bc->bcacheMutex);
8780d163575Sopenharmony_ci            return VFS_ERROR;
8790d163575Sopenharmony_ci        }
8800d163575Sopenharmony_ci
8810d163575Sopenharmony_ci        (VOID)pthread_mutex_unlock(&bc->bcacheMutex);
8820d163575Sopenharmony_ci
8830d163575Sopenharmony_ci        tempBuf += currentSize;
8840d163575Sopenharmony_ci        size -= currentSize;
8850d163575Sopenharmony_ci        pos = 0;
8860d163575Sopenharmony_ci        num++;
8870d163575Sopenharmony_ci    }
8880d163575Sopenharmony_ci    *len -= size;
8890d163575Sopenharmony_ci    return ret;
8900d163575Sopenharmony_ci}
8910d163575Sopenharmony_ci
8920d163575Sopenharmony_ciINT32 BlockCacheWrite(OsBcache *bc, const UINT8 *buf, UINT32 *len, UINT64 sector)
8930d163575Sopenharmony_ci{
8940d163575Sopenharmony_ci    OsBcacheBlock *block = NULL;
8950d163575Sopenharmony_ci    const UINT8 *tempBuf = buf;
8960d163575Sopenharmony_ci    UINT32 size = *len;
8970d163575Sopenharmony_ci    INT32 ret = ENOERR;
8980d163575Sopenharmony_ci    UINT32 currentSize;
8990d163575Sopenharmony_ci    UINT64 pos;
9000d163575Sopenharmony_ci    UINT64 num;
9010d163575Sopenharmony_ci#ifdef BCACHE_ANALYSE
9020d163575Sopenharmony_ci    PRINTK("bcache write:\n");
9030d163575Sopenharmony_ci#endif
9040d163575Sopenharmony_ci
9050d163575Sopenharmony_ci    pos = sector * bc->sectorSize;
9060d163575Sopenharmony_ci    num = pos >> bc->blockSizeLog2;
9070d163575Sopenharmony_ci    pos = pos & (bc->blockSize - 1);
9080d163575Sopenharmony_ci
9090d163575Sopenharmony_ci    D(("bcache write len = %u pos = %llu bnum = %llu\n", *len, pos, num));
9100d163575Sopenharmony_ci
9110d163575Sopenharmony_ci    while (size > 0) {
9120d163575Sopenharmony_ci        if ((size + pos) > bc->blockSize) {
9130d163575Sopenharmony_ci            currentSize = bc->blockSize - (UINT32)pos;
9140d163575Sopenharmony_ci        } else {
9150d163575Sopenharmony_ci            currentSize = size;
9160d163575Sopenharmony_ci        }
9170d163575Sopenharmony_ci
9180d163575Sopenharmony_ci        (VOID)pthread_mutex_lock(&bc->bcacheMutex);
9190d163575Sopenharmony_ci        ret = BcacheGetBlock(bc, num, FALSE, &block);
9200d163575Sopenharmony_ci        if (ret != ENOERR) {
9210d163575Sopenharmony_ci            (VOID)pthread_mutex_unlock(&bc->bcacheMutex);
9220d163575Sopenharmony_ci            break;
9230d163575Sopenharmony_ci        }
9240d163575Sopenharmony_ci
9250d163575Sopenharmony_ci        if (LOS_CopyToKernel((VOID *)(block->data + pos), bc->blockSize - (UINT32)pos,
9260d163575Sopenharmony_ci            (VOID *)tempBuf, currentSize) != EOK) {
9270d163575Sopenharmony_ci            (VOID)pthread_mutex_unlock(&bc->bcacheMutex);
9280d163575Sopenharmony_ci            return VFS_ERROR;
9290d163575Sopenharmony_ci        }
9300d163575Sopenharmony_ci        if (block->modified == FALSE) {
9310d163575Sopenharmony_ci            block->modified = TRUE;
9320d163575Sopenharmony_ci            bc->modifiedBlock++;
9330d163575Sopenharmony_ci        }
9340d163575Sopenharmony_ci        if ((pos == 0) && (currentSize == bc->blockSize)) {
9350d163575Sopenharmony_ci            (void)memset_s(block->flag, sizeof(block->flag), 0xFF, sizeof(block->flag));
9360d163575Sopenharmony_ci            block->allDirty = TRUE;
9370d163575Sopenharmony_ci        } else {
9380d163575Sopenharmony_ci            BcacheSetFlag(bc, block, (UINT32)pos, currentSize);
9390d163575Sopenharmony_ci        }
9400d163575Sopenharmony_ci        (VOID)pthread_mutex_unlock(&bc->bcacheMutex);
9410d163575Sopenharmony_ci
9420d163575Sopenharmony_ci        tempBuf += currentSize;
9430d163575Sopenharmony_ci        size -= currentSize;
9440d163575Sopenharmony_ci        pos = 0;
9450d163575Sopenharmony_ci        num++;
9460d163575Sopenharmony_ci    }
9470d163575Sopenharmony_ci    *len -= size;
9480d163575Sopenharmony_ci    return ret;
9490d163575Sopenharmony_ci}
9500d163575Sopenharmony_ci
9510d163575Sopenharmony_ciINT32 BlockCacheSync(OsBcache *bc)
9520d163575Sopenharmony_ci{
9530d163575Sopenharmony_ci    return BcacheSync(bc);
9540d163575Sopenharmony_ci}
9550d163575Sopenharmony_ci
9560d163575Sopenharmony_ciINT32 OsSdSync(INT32 id)
9570d163575Sopenharmony_ci{
9580d163575Sopenharmony_ci#ifdef LOSCFG_FS_FAT_CACHE
9590d163575Sopenharmony_ci    INT32 ret;
9600d163575Sopenharmony_ci    los_disk *disk = get_disk(id);
9610d163575Sopenharmony_ci    if ((disk == NULL) || (disk->disk_status == STAT_UNUSED)) {
9620d163575Sopenharmony_ci        return VFS_ERROR;
9630d163575Sopenharmony_ci    }
9640d163575Sopenharmony_ci    if (pthread_mutex_lock(&disk->disk_mutex) != ENOERR) {
9650d163575Sopenharmony_ci        PRINT_ERR("%s %d, mutex lock fail!\n", __FUNCTION__, __LINE__);
9660d163575Sopenharmony_ci        return VFS_ERROR;
9670d163575Sopenharmony_ci    }
9680d163575Sopenharmony_ci    if ((disk->disk_status == STAT_INUSED) && (disk->bcache != NULL)) {
9690d163575Sopenharmony_ci        ret = BcacheSync(disk->bcache);
9700d163575Sopenharmony_ci    } else {
9710d163575Sopenharmony_ci        ret = VFS_ERROR;
9720d163575Sopenharmony_ci    }
9730d163575Sopenharmony_ci    if (pthread_mutex_unlock(&disk->disk_mutex) != ENOERR) {
9740d163575Sopenharmony_ci        PRINT_ERR("%s %d, mutex unlock fail!\n", __FUNCTION__, __LINE__);
9750d163575Sopenharmony_ci        return VFS_ERROR;
9760d163575Sopenharmony_ci    }
9770d163575Sopenharmony_ci    return ret;
9780d163575Sopenharmony_ci#else
9790d163575Sopenharmony_ci    return VFS_ERROR;
9800d163575Sopenharmony_ci#endif
9810d163575Sopenharmony_ci}
9820d163575Sopenharmony_ci
9830d163575Sopenharmony_ciINT32 LOS_BcacheSyncByName(const CHAR *name)
9840d163575Sopenharmony_ci{
9850d163575Sopenharmony_ci    INT32 diskID = los_get_diskid_byname(name);
9860d163575Sopenharmony_ci    return OsSdSync(diskID);
9870d163575Sopenharmony_ci}
9880d163575Sopenharmony_ci
9890d163575Sopenharmony_ciINT32 BcacheGetDirtyRatio(INT32 id)
9900d163575Sopenharmony_ci{
9910d163575Sopenharmony_ci#ifdef LOSCFG_FS_FAT_CACHE
9920d163575Sopenharmony_ci    INT32 ret;
9930d163575Sopenharmony_ci    los_disk *disk = get_disk(id);
9940d163575Sopenharmony_ci    if (disk == NULL) {
9950d163575Sopenharmony_ci        return VFS_ERROR;
9960d163575Sopenharmony_ci    }
9970d163575Sopenharmony_ci
9980d163575Sopenharmony_ci    if (pthread_mutex_lock(&disk->disk_mutex) != ENOERR) {
9990d163575Sopenharmony_ci        PRINT_ERR("%s %d, mutex lock fail!\n", __FUNCTION__, __LINE__);
10000d163575Sopenharmony_ci        return VFS_ERROR;
10010d163575Sopenharmony_ci    }
10020d163575Sopenharmony_ci    if ((disk->disk_status == STAT_INUSED) && (disk->bcache != NULL)) {
10030d163575Sopenharmony_ci        ret = (INT32)((disk->bcache->modifiedBlock * PERCENTAGE) / GetFatBlockNums());
10040d163575Sopenharmony_ci    } else {
10050d163575Sopenharmony_ci        ret = VFS_ERROR;
10060d163575Sopenharmony_ci    }
10070d163575Sopenharmony_ci    if (pthread_mutex_unlock(&disk->disk_mutex) != ENOERR) {
10080d163575Sopenharmony_ci        PRINT_ERR("%s %d, mutex unlock fail!\n", __FUNCTION__, __LINE__);
10090d163575Sopenharmony_ci        return VFS_ERROR;
10100d163575Sopenharmony_ci    }
10110d163575Sopenharmony_ci    return ret;
10120d163575Sopenharmony_ci#else
10130d163575Sopenharmony_ci    return VFS_ERROR;
10140d163575Sopenharmony_ci#endif
10150d163575Sopenharmony_ci}
10160d163575Sopenharmony_ci
10170d163575Sopenharmony_ciINT32 LOS_GetDirtyRatioByName(const CHAR *name)
10180d163575Sopenharmony_ci{
10190d163575Sopenharmony_ci    INT32 diskID = los_get_diskid_byname(name);
10200d163575Sopenharmony_ci    return BcacheGetDirtyRatio(diskID);
10210d163575Sopenharmony_ci}
10220d163575Sopenharmony_ci
10230d163575Sopenharmony_ci#ifdef LOSCFG_FS_FAT_CACHE_SYNC_THREAD
10240d163575Sopenharmony_cistatic VOID BcacheSyncThread(UINT32 id)
10250d163575Sopenharmony_ci{
10260d163575Sopenharmony_ci    INT32 diskID = (INT32)id;
10270d163575Sopenharmony_ci    INT32 dirtyRatio;
10280d163575Sopenharmony_ci    while (1) {
10290d163575Sopenharmony_ci        dirtyRatio = BcacheGetDirtyRatio(diskID);
10300d163575Sopenharmony_ci        if (dirtyRatio > (INT32)g_dirtyRatio) {
10310d163575Sopenharmony_ci            (VOID)OsSdSync(diskID);
10320d163575Sopenharmony_ci        }
10330d163575Sopenharmony_ci        msleep(g_syncInterval);
10340d163575Sopenharmony_ci    }
10350d163575Sopenharmony_ci}
10360d163575Sopenharmony_ci
10370d163575Sopenharmony_ciVOID BcacheSyncThreadInit(OsBcache *bc, INT32 id)
10380d163575Sopenharmony_ci{
10390d163575Sopenharmony_ci    UINT32 ret;
10400d163575Sopenharmony_ci    TSK_INIT_PARAM_S appTask;
10410d163575Sopenharmony_ci
10420d163575Sopenharmony_ci    (VOID)memset_s(&appTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
10430d163575Sopenharmony_ci    appTask.pfnTaskEntry = (TSK_ENTRY_FUNC)BcacheSyncThread;
10440d163575Sopenharmony_ci    appTask.uwStackSize = BCACHE_STATCK_SIZE;
10450d163575Sopenharmony_ci    appTask.pcName = "bcache_sync_task";
10460d163575Sopenharmony_ci    appTask.usTaskPrio = g_syncThreadPrio;
10470d163575Sopenharmony_ci    appTask.auwArgs[0] = (UINTPTR)id;
10480d163575Sopenharmony_ci    appTask.uwResved = LOS_TASK_STATUS_DETACHED;
10490d163575Sopenharmony_ci    ret = LOS_TaskCreate(&bc->syncTaskId, &appTask);
10500d163575Sopenharmony_ci    if (ret != ENOERR) {
10510d163575Sopenharmony_ci        PRINT_ERR("Bcache sync task create failed in %s, %d\n", __FUNCTION__, __LINE__);
10520d163575Sopenharmony_ci    }
10530d163575Sopenharmony_ci}
10540d163575Sopenharmony_ci
10550d163575Sopenharmony_ciVOID BcacheSyncThreadDeinit(const OsBcache *bc)
10560d163575Sopenharmony_ci{
10570d163575Sopenharmony_ci    if (bc != NULL) {
10580d163575Sopenharmony_ci        if (LOS_TaskDelete(bc->syncTaskId) != ENOERR) {
10590d163575Sopenharmony_ci            PRINT_ERR("Bcache sync task delete failed in %s, %d\n", __FUNCTION__, __LINE__);
10600d163575Sopenharmony_ci        }
10610d163575Sopenharmony_ci    }
10620d163575Sopenharmony_ci}
10630d163575Sopenharmony_ci#endif
10640d163575Sopenharmony_ci
10650d163575Sopenharmony_ciOsBcache *BlockCacheInit(struct Vnode *devNode, UINT32 sectorSize, UINT32 sectorPerBlock,
10660d163575Sopenharmony_ci                         UINT32 blockNum, UINT64 blockCount)
10670d163575Sopenharmony_ci{
10680d163575Sopenharmony_ci    OsBcache *bcache = NULL;
10690d163575Sopenharmony_ci    struct Vnode *blkDriver = devNode;
10700d163575Sopenharmony_ci    UINT8 *bcacheMem = NULL;
10710d163575Sopenharmony_ci    UINT8 *rwBuffer = NULL;
10720d163575Sopenharmony_ci    UINT32 blockSize, memSize;
10730d163575Sopenharmony_ci
10740d163575Sopenharmony_ci    if ((blkDriver == NULL) || (sectorSize * sectorPerBlock * blockNum == 0) || (blockCount == 0)) {
10750d163575Sopenharmony_ci        return NULL;
10760d163575Sopenharmony_ci    }
10770d163575Sopenharmony_ci
10780d163575Sopenharmony_ci    blockSize = sectorSize * sectorPerBlock;
10790d163575Sopenharmony_ci    if ((((UINT64)(sizeof(OsBcacheBlock) + blockSize) * blockNum) + DMA_ALLGN) > UINT_MAX) {
10800d163575Sopenharmony_ci        return NULL;
10810d163575Sopenharmony_ci    }
10820d163575Sopenharmony_ci    memSize = ((sizeof(OsBcacheBlock) + blockSize) * blockNum) + DMA_ALLGN;
10830d163575Sopenharmony_ci
10840d163575Sopenharmony_ci    bcache = (OsBcache *)zalloc(sizeof(OsBcache));
10850d163575Sopenharmony_ci    if (bcache == NULL) {
10860d163575Sopenharmony_ci        PRINT_ERR("bcache_init : malloc %u Bytes failed!\n", sizeof(OsBcache));
10870d163575Sopenharmony_ci        return NULL;
10880d163575Sopenharmony_ci    }
10890d163575Sopenharmony_ci
10900d163575Sopenharmony_ci    bcacheMem = (UINT8 *)zalloc(memSize);
10910d163575Sopenharmony_ci    if (bcacheMem == NULL) {
10920d163575Sopenharmony_ci        PRINT_ERR("bcache_init : malloc %u Bytes failed!\n", memSize);
10930d163575Sopenharmony_ci        goto ERROR_OUT_WITH_BCACHE;
10940d163575Sopenharmony_ci    }
10950d163575Sopenharmony_ci
10960d163575Sopenharmony_ci    rwBuffer = (UINT8 *)memalign(DMA_ALLGN, blockSize);
10970d163575Sopenharmony_ci    if (rwBuffer == NULL) {
10980d163575Sopenharmony_ci        PRINT_ERR("bcache_init : malloc %u Bytes failed!\n", blockSize);
10990d163575Sopenharmony_ci        goto ERROR_OUT_WITH_MEM;
11000d163575Sopenharmony_ci    }
11010d163575Sopenharmony_ci
11020d163575Sopenharmony_ci    bcache->rwBuffer = rwBuffer;
11030d163575Sopenharmony_ci    bcache->sectorSize = sectorSize;
11040d163575Sopenharmony_ci    bcache->sectorPerBlock = sectorPerBlock;
11050d163575Sopenharmony_ci    bcache->blockCount = blockCount;
11060d163575Sopenharmony_ci
11070d163575Sopenharmony_ci    if (BlockCacheDrvCreate(blkDriver, bcacheMem, memSize, blockSize, bcache) != ENOERR) {
11080d163575Sopenharmony_ci        goto ERROR_OUT_WITH_BUFFER;
11090d163575Sopenharmony_ci    }
11100d163575Sopenharmony_ci
11110d163575Sopenharmony_ci    return bcache;
11120d163575Sopenharmony_ci
11130d163575Sopenharmony_ciERROR_OUT_WITH_BUFFER:
11140d163575Sopenharmony_ci    free(rwBuffer);
11150d163575Sopenharmony_ciERROR_OUT_WITH_MEM:
11160d163575Sopenharmony_ci    free(bcacheMem);
11170d163575Sopenharmony_ciERROR_OUT_WITH_BCACHE:
11180d163575Sopenharmony_ci    free(bcache);
11190d163575Sopenharmony_ci    return NULL;
11200d163575Sopenharmony_ci}
11210d163575Sopenharmony_ci
11220d163575Sopenharmony_ciVOID BlockCacheDeinit(OsBcache *bcache)
11230d163575Sopenharmony_ci{
11240d163575Sopenharmony_ci    if (bcache != NULL) {
11250d163575Sopenharmony_ci        (VOID)pthread_mutex_destroy(&bcache->bcacheMutex);
11260d163575Sopenharmony_ci        free(bcache->memStart);
11270d163575Sopenharmony_ci        bcache->memStart = NULL;
11280d163575Sopenharmony_ci        free(bcache->rwBuffer);
11290d163575Sopenharmony_ci        bcache->rwBuffer = NULL;
11300d163575Sopenharmony_ci        free(bcache);
11310d163575Sopenharmony_ci    }
11320d163575Sopenharmony_ci}
11330d163575Sopenharmony_ci
11340d163575Sopenharmony_cistatic VOID BcacheAsyncPrereadThread(VOID *arg)
11350d163575Sopenharmony_ci{
11360d163575Sopenharmony_ci    OsBcache *bc = (OsBcache *)arg;
11370d163575Sopenharmony_ci    OsBcacheBlock *block = NULL;
11380d163575Sopenharmony_ci    INT32 ret;
11390d163575Sopenharmony_ci    UINT32 i;
11400d163575Sopenharmony_ci
11410d163575Sopenharmony_ci    for (;;) {
11420d163575Sopenharmony_ci        ret = (INT32)LOS_EventRead(&bc->bcacheEvent, PREREAD_EVENT_MASK,
11430d163575Sopenharmony_ci                                   LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
11440d163575Sopenharmony_ci        if (ret != ASYNC_EVENT_BIT) {
11450d163575Sopenharmony_ci            PRINT_ERR("The event read in %s, %d is error!!!\n", __FUNCTION__, __LINE__);
11460d163575Sopenharmony_ci            continue;
11470d163575Sopenharmony_ci        }
11480d163575Sopenharmony_ci
11490d163575Sopenharmony_ci        for (i = 1; i <= PREREAD_BLOCK_NUM; i++) {
11500d163575Sopenharmony_ci            if ((bc->curBlockNum + i) >= bc->blockCount) {
11510d163575Sopenharmony_ci                break;
11520d163575Sopenharmony_ci            }
11530d163575Sopenharmony_ci
11540d163575Sopenharmony_ci            (VOID)pthread_mutex_lock(&bc->bcacheMutex);
11550d163575Sopenharmony_ci            ret = BcacheGetBlock(bc, bc->curBlockNum + i, TRUE, &block);
11560d163575Sopenharmony_ci            if (ret != ENOERR) {
11570d163575Sopenharmony_ci                PRINT_ERR("read block %llu error : %d!\n", bc->curBlockNum, ret);
11580d163575Sopenharmony_ci            }
11590d163575Sopenharmony_ci
11600d163575Sopenharmony_ci            (VOID)pthread_mutex_unlock(&bc->bcacheMutex);
11610d163575Sopenharmony_ci        }
11620d163575Sopenharmony_ci
11630d163575Sopenharmony_ci        if (block != NULL) {
11640d163575Sopenharmony_ci            block->pgHit = 1; /* preread complete */
11650d163575Sopenharmony_ci        }
11660d163575Sopenharmony_ci    }
11670d163575Sopenharmony_ci}
11680d163575Sopenharmony_ci
11690d163575Sopenharmony_ciVOID ResumeAsyncPreread(OsBcache *arg1, const OsBcacheBlock *arg2)
11700d163575Sopenharmony_ci{
11710d163575Sopenharmony_ci    UINT32 ret;
11720d163575Sopenharmony_ci    OsBcache *bc = arg1;
11730d163575Sopenharmony_ci    const OsBcacheBlock *block = arg2;
11740d163575Sopenharmony_ci
11750d163575Sopenharmony_ci    if (OsCurrTaskGet()->taskID != bc->prereadTaskId) {
11760d163575Sopenharmony_ci        bc->curBlockNum = block->num;
11770d163575Sopenharmony_ci        ret = LOS_EventWrite(&bc->bcacheEvent, ASYNC_EVENT_BIT);
11780d163575Sopenharmony_ci        if (ret != ENOERR) {
11790d163575Sopenharmony_ci            PRINT_ERR("Write event failed in %s, %d\n", __FUNCTION__, __LINE__);
11800d163575Sopenharmony_ci        }
11810d163575Sopenharmony_ci    }
11820d163575Sopenharmony_ci}
11830d163575Sopenharmony_ci
11840d163575Sopenharmony_ciUINT32 BcacheAsyncPrereadInit(OsBcache *bc)
11850d163575Sopenharmony_ci{
11860d163575Sopenharmony_ci    UINT32 ret;
11870d163575Sopenharmony_ci    TSK_INIT_PARAM_S appTask;
11880d163575Sopenharmony_ci
11890d163575Sopenharmony_ci    ret = LOS_EventInit(&bc->bcacheEvent);
11900d163575Sopenharmony_ci    if (ret != ENOERR) {
11910d163575Sopenharmony_ci        PRINT_ERR("Async event init failed in %s, %d\n", __FUNCTION__, __LINE__);
11920d163575Sopenharmony_ci        return ret;
11930d163575Sopenharmony_ci    }
11940d163575Sopenharmony_ci
11950d163575Sopenharmony_ci    (VOID)memset_s(&appTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
11960d163575Sopenharmony_ci    appTask.pfnTaskEntry = (TSK_ENTRY_FUNC)BcacheAsyncPrereadThread;
11970d163575Sopenharmony_ci    appTask.uwStackSize = BCACHE_STATCK_SIZE;
11980d163575Sopenharmony_ci    appTask.pcName = "bcache_async_task";
11990d163575Sopenharmony_ci    appTask.usTaskPrio = BCACHE_PREREAD_PRIO;
12000d163575Sopenharmony_ci    appTask.auwArgs[0] = (UINTPTR)bc;
12010d163575Sopenharmony_ci    appTask.uwResved = LOS_TASK_STATUS_DETACHED;
12020d163575Sopenharmony_ci    ret = LOS_TaskCreate(&bc->prereadTaskId, &appTask);
12030d163575Sopenharmony_ci    if (ret != ENOERR) {
12040d163575Sopenharmony_ci        PRINT_ERR("Bcache async task create failed in %s, %d\n", __FUNCTION__, __LINE__);
12050d163575Sopenharmony_ci    }
12060d163575Sopenharmony_ci
12070d163575Sopenharmony_ci    return ret;
12080d163575Sopenharmony_ci}
12090d163575Sopenharmony_ci
12100d163575Sopenharmony_ciUINT32 BcacheAsyncPrereadDeinit(OsBcache *bc)
12110d163575Sopenharmony_ci{
12120d163575Sopenharmony_ci    UINT32 ret = LOS_NOK;
12130d163575Sopenharmony_ci
12140d163575Sopenharmony_ci    if (bc != NULL) {
12150d163575Sopenharmony_ci        ret = LOS_TaskDelete(bc->prereadTaskId);
12160d163575Sopenharmony_ci        if (ret != ENOERR) {
12170d163575Sopenharmony_ci            PRINT_ERR("Bcache async task delete failed in %s, %d\n", __FUNCTION__, __LINE__);
12180d163575Sopenharmony_ci        }
12190d163575Sopenharmony_ci
12200d163575Sopenharmony_ci        ret = LOS_EventDestroy(&bc->bcacheEvent);
12210d163575Sopenharmony_ci        if (ret != ENOERR) {
12220d163575Sopenharmony_ci            PRINT_ERR("Async event destroy failed in %s, %d\n", __FUNCTION__, __LINE__);
12230d163575Sopenharmony_ci            return ret;
12240d163575Sopenharmony_ci        }
12250d163575Sopenharmony_ci    }
12260d163575Sopenharmony_ci
12270d163575Sopenharmony_ci    return ret;
12280d163575Sopenharmony_ci}
1229