157 lines
5.8 KiB
C
157 lines
5.8 KiB
C
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||
|
|
/*
|
||
|
|
* Copyright (C) 2021. Huawei Technologies Co., Ltd. All rights reserved.
|
||
|
|
* This program is free software; you can redistribute it and/or modify
|
||
|
|
* it under the terms of the GNU General Public License version 2 and
|
||
|
|
* only version 2 as published by the Free Software Foundation.
|
||
|
|
*
|
||
|
|
* This program is distributed in the hope that it will be useful,
|
||
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
|
* GNU General Public License for more details.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef EUFS_DHT_H
|
||
|
|
#define EUFS_DHT_H
|
||
|
|
|
||
|
|
#include <linux/atomic.h>
|
||
|
|
#include "filename.h"
|
||
|
|
|
||
|
|
#define DICT_OK (0)
|
||
|
|
#define DICT_ERR (1)
|
||
|
|
|
||
|
|
#define INDEX(h) (h & (NV_DICT_CAPACITY - 1))
|
||
|
|
|
||
|
|
#define CURSOR_IDX(csr) ((csr >> 32) & 0xffffffff)
|
||
|
|
#define CURSOR_CNT(csr) (csr & 0xffffffff)
|
||
|
|
#define CURSOR(idx, cnt) (((idx) << 32) | (cnt))
|
||
|
|
|
||
|
|
/* End of dir */
|
||
|
|
#define EUFS_DIR_EODIR (CURSOR(NV_DICT_CAPACITY, 2))
|
||
|
|
/* Offset of . in a dir */
|
||
|
|
#define EUFS_DIR_DOT (CURSOR(NV_DICT_CAPACITY, 0))
|
||
|
|
/* Offset of .. in a dir */
|
||
|
|
#define EUFS_DIR_DOTDOT (CURSOR(NV_DICT_CAPACITY, 1))
|
||
|
|
|
||
|
|
#define EUFS_DENTRY_FLAG_NOT_PERSIST 1
|
||
|
|
#define EUFS_DENTRY_FLAGS_MASK (~1ULL)
|
||
|
|
|
||
|
|
/* The total size of the hash table (buckets) is 8B * 512 = 4KB */
|
||
|
|
|
||
|
|
struct v_dict {
|
||
|
|
struct nv_dict_entry *table[NV_DICT_CAPACITY];
|
||
|
|
} __aligned(PAGE_SIZE);
|
||
|
|
|
||
|
|
struct nv_dict_entry *nv_dict_add(struct inode *dir, u64 **nv_header, u64 h,
|
||
|
|
const char *key, struct eufs_inode *pi);
|
||
|
|
|
||
|
|
struct nv_dict_entry *nv_dict_find(struct inode *dir, hashlen_t h,
|
||
|
|
const char *key);
|
||
|
|
|
||
|
|
struct nv_dict_entry *nv_dict_delete(struct inode *dir,
|
||
|
|
struct nv_dict_entry **prevde,
|
||
|
|
u64 **nv_header, hashlen_t h,
|
||
|
|
const char *key);
|
||
|
|
|
||
|
|
void nv_dict_scan_via_ptr(struct inode *dir, u64 pos,
|
||
|
|
int (*fn)(void *privdata,
|
||
|
|
const struct nv_dict_entry *de),
|
||
|
|
void *privdata);
|
||
|
|
|
||
|
|
#define EUFS_PRINT_PI(pi, msg) \
|
||
|
|
eufs_info( \
|
||
|
|
msg \
|
||
|
|
" pi=%px, pi->i_mode=%x, pi->i_nlink=%x, " \
|
||
|
|
"pi->root=0x%llx, pi->i_size=0x%llx, pi->i_dotdot=0x%llx\n", \
|
||
|
|
pi, pi ? eufs_iread_mode(pi) : 0, \
|
||
|
|
pi ? eufs_iread_nlink(pi) : 0, pi ? eufs_iread_root(pi) : 0, \
|
||
|
|
pi ? eufs_iread_size(pi) : 0, \
|
||
|
|
pi ? eufs_iread_dotdot(pi) : 0)
|
||
|
|
|
||
|
|
#define EUFS_PRINT_PI_INODE(msg, pi, inode) \
|
||
|
|
eufs_info(msg " pi=%px inode=%px; " \
|
||
|
|
"pi->i_mode=0%o inode->i_mode=0%o; " \
|
||
|
|
"pi->i_nlink=0x%x inode=i_nlink=0x%x; " \
|
||
|
|
"pi->root=0x%llx inode->root=%px; " \
|
||
|
|
"pi->i_size=0x%llx inode->i_size=0x%llx; " \
|
||
|
|
"pi->i_dotdot=0x%llx\n", \
|
||
|
|
pi, inode, pi ? eufs_iread_mode(pi) : 0, \
|
||
|
|
inode ? inode->i_mode : 0, pi ? eufs_iread_nlink(pi) : 0, \
|
||
|
|
inode ? inode->i_nlink : 0, pi ? eufs_iread_root(pi) : 0, \
|
||
|
|
inode ? EUFS_I(inode)->i_volatile_root : 0, \
|
||
|
|
pi ? eufs_iread_size(pi) : 0, inode ? inode->i_size : 0, \
|
||
|
|
pi ? pi->i_dotdot : 0)
|
||
|
|
|
||
|
|
#define _PRINT_DENTRY(de, msg) \
|
||
|
|
{ \
|
||
|
|
char *page; \
|
||
|
|
if (HASHLEN_LEN(de->hv) > FIRST_LEN) { \
|
||
|
|
page = eufs_alloc_name_copy( \
|
||
|
|
de->name, HASHLEN_LEN(de->hv), de->nextname); \
|
||
|
|
info(msg " de=%px, de->name=[%px]%*s, de->inode=%px, " \
|
||
|
|
"de->next=%px, de->volatile_next=%px\n", \
|
||
|
|
de, de->name, (int)HASHLEN_LEN(de->hv), page, \
|
||
|
|
de->inode, de->next, de->volatile_next); \
|
||
|
|
eufs_free_page(page); \
|
||
|
|
} else { \
|
||
|
|
info(msg " de=%px, de->name=[%px]%*s, de->inode=%px, " \
|
||
|
|
"de->next=%px, de->volatile_next=%px\n", \
|
||
|
|
de, de->name, (int)HASHLEN_LEN(de->hv), de->name, \
|
||
|
|
de->inode, de->next, de->volatile_next); \
|
||
|
|
} \
|
||
|
|
}
|
||
|
|
|
||
|
|
#define _PRINT_PINODE(pi, msg) EUFS_PRINT_PI(pi, msg)
|
||
|
|
|
||
|
|
#define PRINT_DENTRY(de, msg)
|
||
|
|
#define PRINT_PINODE(pi, msg)
|
||
|
|
|
||
|
|
void *fix_table(struct super_block *sb, struct nv_dict *dict, u32 idx);
|
||
|
|
|
||
|
|
/* Rule for encoded pointers:
|
||
|
|
* encoding: o2s(encode(p2o()))
|
||
|
|
* decoding: o2p(decode(s2o()))
|
||
|
|
*/
|
||
|
|
#define COMPOSE_DICT_HEAD_le64(sb, head) \
|
||
|
|
((__le64)((void *)head == NULL ? \
|
||
|
|
NULL_VAL : \
|
||
|
|
(cpu_to_le64( \
|
||
|
|
((u64)(p2o(sb, head) & ((1UL << 56) - 1)) | \
|
||
|
|
((u64)EUFS_SB(sb)->s_crash_ver & 0xff) \
|
||
|
|
<< 56)))))
|
||
|
|
|
||
|
|
#define DICT_HEAD_REAL_OFF(head_off) \
|
||
|
|
((u64)((u64)(head_off) & ((1UL << 56) - 1)))
|
||
|
|
|
||
|
|
static inline __le64 eufs_dentry_vnext(const struct nv_dict_entry *entry)
|
||
|
|
{
|
||
|
|
__le64 vnext = entry->volatile_next;
|
||
|
|
|
||
|
|
if (vnext != EUFS_DIR_EOC)
|
||
|
|
vnext = vnext & cpu_to_le64(EUFS_DENTRY_FLAGS_MASK);
|
||
|
|
|
||
|
|
return vnext;
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline bool
|
||
|
|
eufs_dentry_is_not_persist(const struct nv_dict_entry *entry)
|
||
|
|
{
|
||
|
|
return (entry->volatile_next ==
|
||
|
|
(entry->next | cpu_to_le64(EUFS_DENTRY_FLAG_NOT_PERSIST)));
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline void
|
||
|
|
eufs_dentry_clr_not_persist_flag(struct nv_dict_entry *entry)
|
||
|
|
{
|
||
|
|
entry->volatile_next &= cpu_to_le64(EUFS_DENTRY_FLAGS_MASK);
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline void
|
||
|
|
eufs_dentry_set_not_persist_flag(struct nv_dict_entry *entry)
|
||
|
|
{
|
||
|
|
entry->volatile_next =
|
||
|
|
entry->next | cpu_to_le64(EUFS_DENTRY_FLAG_NOT_PERSIST);
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif /* EUFS_DHT_H */
|