/* 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 #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 */