当前仓库属于关闭状态,部分功能使用受限,详情请查阅 仓库状态说明
7 Star 7 Fork 8

openEuler/eulerfs
关闭

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
dht.c 7.73 KB
一键复制 编辑 原始数据 按行查看 历史
Yu Kuai 提交于 2021-11-30 16:31 . eulerfs: initial import
// 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.
*/
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/ratelimit.h>
#include <asm/cmpxchg.h>
#include "euler.h"
#include "dht.h"
#include "dep.h"
#define GET_CRASH_VER(ptr) (((unsigned long)ptr) >> 56)
void *fix_table(struct super_block *sb, struct nv_dict *dict, u32 idx)
{
struct nv_dict_entry *he;
void *real_head;
u64 head_off;
head_off = le64_to_cpu(dict->table[idx]);
if (!head_off)
return NULL;
if (head_off == EUFS_DIR_EOC)
return NULL;
real_head = o2p(sb, DICT_HEAD_REAL_OFF(head_off));
if (likely(GET_CRASH_VER(head_off) == EUFS_SB(sb)->s_crash_ver)) {
/* No need fix */
return real_head;
}
he = real_head;
BUG_ON(he == EUFS_DIR_EOC_PTR);
while (he && he != EUFS_DIR_EOC_PTR) {
if (he->volatile_next) {
he->volatile_next = NULL_VAL;
eufs_flush_cacheline(he);
}
he = s2p(sb, he->next);
}
dict->table[idx] = COMPOSE_DICT_HEAD_le64(sb, real_head);
eufs_flush_cacheline(&dict->table[idx]);
eufs_pbarrier();
return real_head;
}
/*
* Insert to nv_dict using spinlocks.
* NOTICE: No resizing supported yet!
* Previous dentry is always the pointer
*/
struct nv_dict_entry *nv_dict_add(struct inode *dir, u64 **nv_header, u64 h,
const char *key, struct eufs_inode *pi)
{
struct super_block *sb = dir->i_sb;
struct nv_dict __pmem *dict =
o2p(sb, eufs_iread_dict(EUFS_FRESH_PI(EUFS_PI(dir))));
struct v_dict *volatile_dict = EUFS_I(dir)->i_volatile_dict;
u32 idx;
long err;
struct nv_dict_entry __pmem *de;
idx = INDEX(h);
NV_ASSERT(dict);
NV_ASSERT(volatile_dict);
/* NOTICE: simplified version w/o resizing */
de = eufs_malloc_dentry(sb);
if (!de)
return ERR_PTR(-ENOSPC);
err = copy_filename(sb, de, h, key);
if (IS_ERR_VALUE(err)) {
nv_free(sb, de);
return ERR_PTR(-ENOSPC);
}
WARN_ON(!EUFS_IS_HEAD_PI(pi));
de->inode = p2s(sb, pi);
de->next = p2s(sb,
(volatile_dict->table[idx]) ?
(volatile_dict->table[idx] == EUFS_DIR_EOC_PTR ?
NULL :
volatile_dict->table[idx]) :
fix_table(sb, dict, idx));
eufs_dentry_set_not_persist_flag(de);
PRINT_DENTRY(de, "new dentry: ");
PRINT_PINODE(de->inode, "inode within dentry: ");
*nv_header = &dict->table[idx];
/* Lock the header. It's to be released right after dep is locked. */
inode_header_lock(dir);
volatile_dict->table[idx] = de;
return de;
}
/*
* Find from nv_dict with the protection of spinlock.
* No resizing support yet!
*/
struct nv_dict_entry *nv_dict_find(struct inode *dir, hashlen_t h,
const char *key)
{
struct super_block *sb = dir->i_sb;
struct nv_dict __pmem *dict =
o2p(sb, eufs_iread_dict(EUFS_FRESH_PI(EUFS_PI(dir))));
struct v_dict *volatile_dict = EUFS_I(dir)->i_volatile_dict;
struct nv_dict_entry *he;
unsigned int idx;
idx = INDEX(h);
/*
* volatile_dict->table[idx] can be EOC after
* all entries have been deleted
*/
if (volatile_dict && volatile_dict->table[idx])
he = volatile_dict->table[idx];
else
he = fix_table(sb, dict, idx);
while (he && he != EUFS_DIR_EOC_PTR) {
__le64 vnext;
if (key_equals(sb, key, h, he))
break;
vnext = eufs_dentry_vnext(he);
he = s2p(sb, vnext ? vnext : he->next);
}
if (he == EUFS_DIR_EOC_PTR)
he = NULL;
return he;
}
/*
* Delete from nv_dict w/ spinlocks.
* No resizing support yet!
* Previous dentry is also returned
*/
struct nv_dict_entry *nv_dict_delete(struct inode *dir,
struct nv_dict_entry **prevde,
u64 **nv_header, hashlen_t h,
const char *key)
{
struct super_block *sb = dir->i_sb;
struct nv_dict __pmem *dict =
o2p(sb, eufs_iread_dict(EUFS_FRESH_PI(EUFS_PI(dir))));
struct eufs_inode_info *dir_vi = EUFS_I(dir);
struct v_dict *volatile_dict = dir_vi->i_volatile_dict;
struct nv_dict_entry *he;
struct nv_dict_entry *prev = NULL;
unsigned int idx;
__le64 vnext;
NV_ASSERT(dict);
NV_ASSERT(volatile_dict);
idx = INDEX(h);
he = volatile_dict->table[idx] ? volatile_dict->table[idx] :
fix_table(sb, dict, idx);
while (he && he != EUFS_DIR_EOC_PTR) {
if (key_equals(sb, key, h, he))
break;
prev = he;
vnext = eufs_dentry_vnext(he);
/* EOC is not NULL, so it's okay. */
he = s2p(sb, vnext ? vnext : he->next);
}
if (he && he != EUFS_DIR_EOC_PTR) {
/* Lock the header. It's to be released right after dep is locked. */
inode_header_lock(dir);
vnext = eufs_dentry_vnext(he);
if (!prev) {
/*
* the first dentry (head of the chain).
* If the target is the end of chain, it is the only
* dentry in the chain, then either its volatile_next
* is EOC, or its next is NULL.
*/
volatile_dict->table[idx] =
s2p(sb, vnext ? vnext : he->next);
if (volatile_dict->table[idx] == NULL)
volatile_dict->table[idx] = EUFS_DIR_EOC_PTR;
} else {
bool persist_prev = !eufs_dentry_is_not_persist(prev);
if (!persist_prev) {
/*
* Protect against the persistence of prev dentry
* by background persister.
*/
spin_lock(&dir_vi->i_dentry_persist_lock);
persist_prev =
!eufs_dentry_is_not_persist(prev);
if (!persist_prev) {
/*
* Prev is a newly created dentry,
* Keep the property,
* Two pointers are updated together,
* no need to worry about the EOC.
*/
prev->next =
vnext ? (vnext == EUFS_DIR_EOC ?
NULL_VAL :
vnext) :
he->next;
eufs_dentry_set_not_persist_flag(prev);
}
spin_unlock(&dir_vi->i_dentry_persist_lock);
}
if (persist_prev)
prev->volatile_next =
vnext ? vnext :
(he->next ? he->next :
EUFS_DIR_EOC);
}
if (eufs_dentry_is_not_persist(he))
he->volatile_next = EUFS_DIR_DELNEW;
*prevde = prev;
/* table[idx] must have been fixed, so it's OK to return it. */
*nv_header = &dict->table[idx];
} else if (he == EUFS_DIR_EOC_PTR) {
he = NULL;
}
return he;
}
void nv_dict_scan_via_ptr(struct inode *dir, u64 pos,
int (*fn)(void *privdata,
const struct nv_dict_entry *de),
void *privdata)
{
struct super_block *sb = dir->i_sb;
struct nv_dict __pmem *dict =
o2p(sb, eufs_iread_dict(EUFS_FRESH_PI(EUFS_PI(dir))));
struct v_dict *volatile_dict = EUFS_I(dir)->i_volatile_dict;
const struct nv_dict_entry *de = 0;
u64 idx;
u64 i;
u64 skip;
struct dir_scan_data *data = (struct dir_scan_data *)privdata;
struct dir_context *ctx = data->ctx;
int err;
if (ctx->pos == EUFS_DIR_DOTDOT) {
idx = 0;
skip = 0;
} else {
idx = CURSOR_IDX(pos);
skip = CURSOR_CNT(pos);
}
/* Next to emit: the skip-th element in dict->table[idx] */
while (idx < NV_DICT_CAPACITY) {
if (!de) {
eufs_ptr_fast_check(dict);
eufs_ptr_fast_check(dict->table);
de = (volatile_dict && volatile_dict->table[idx]) ?
volatile_dict->table[idx] :
fix_table(sb, dict, idx);
}
i = 0;
while (de && de != EUFS_DIR_EOC_PTR) {
__le64 vnext;
/* current is the i-th de in list */
/* skip de's remaining to skip */
if (skip == 0) {
err = fn(privdata, de);
if (err)
return;
/* ctx->pos points to the next de */
ctx->pos = CURSOR(idx, i + 1);
} else
skip--;
i++;
vnext = eufs_dentry_vnext(de);
de = s2p(sb, vnext ? vnext : de->next);
}
if (de == EUFS_DIR_EOC_PTR)
de = NULL;
idx++; /* next idx */
skip = 0;
}
ctx->pos = EUFS_DIR_EODIR;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/openeuler/eulerfs.git
git@gitee.com:openeuler/eulerfs.git
openeuler
eulerfs
eulerfs
master

搜索帮助