代码拉取完成,页面将自动刷新
// 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/fs.h>
#include <linux/pagemap.h>
#include <linux/crc32c.h>
#include "euler.h"
#include "dht.h"
#include "dep.h"
#include "lock.h"
/*
* If sbi->s_draining is set, do fsync after each namei syscall! This is much
* better than lock transfer for volatility quota.
*/
static void sync_on_draining(struct inode *dir, struct inode *inode)
{
struct eufs_sb_info *sbi = EUFS_SB(dir->i_sb);
if (likely(!sbi->s_draining))
return;
/* fsync the inodes to reduce the number of dirty inodes */
fsync_on_draining(dir, inode);
}
static __always_inline void
eufs_trace_newfile(const char *prompt, struct inode *dir, struct inode *inode,
struct eufs_inode *pi, struct nv_dict_entry *de)
{
eufs_dbg("%s (%s): inode=%px pi=%px pi->root=%llx pi->mode=0%o de=%px de->len=%lld de->name=%6s de->nextname=%llx inode->nlink=%d pi->nlink=%d de->volatile_next=%llx de->next=%llx\n",
__func__, prompt, inode, pi, eufs_iread_root(pi),
eufs_iread_mode(pi), de, HASHLEN_LEN(de->hv), de->name,
de->nextname, inode->i_nlink, pi->i_nlink, de->volatile_next,
de->next);
BUG_ON(inode->i_mode != pi->i_mode);
}
static __always_inline void eufs_trace_delfile(const char *prompt,
struct inode *dir,
struct inode *inode,
struct eufs_inode *pi)
{
eufs_dbg("%s (%s): inode=%px pi=%px pi->root=%llx pi->mode=0%o inode->i_nlink=%d pi->i_nlink=%d\n",
__func__, prompt, inode, pi, eufs_iread_root(pi),
eufs_iread_mode(pi), inode->i_nlink, eufs_iread_nlink(pi));
/*
* because inode is locked by unlink/link, so the increment/decrement
* of nlink should be in order and its max value is (EUFS_LINK_MAX - 1)
* after unlink.
*/
if ((inode->i_mode & S_IFMT) != S_IFDIR)
WARN(inode->i_nlink >= EUFS_LINK_MAX,
"unexpected nlink %d for inode 0x%lx\n", inode->i_nlink,
inode->i_ino);
}
static __always_inline struct nv_dict_entry *
nv_dict_add_wrapper(struct inode *dir, u64 **nv_header, struct eufs_inode *pi,
hashlen_t hv, const char *name)
{
struct eufs_inode_info *vi = EUFS_I(dir);
NV_ASSERT(pi);
if (!vi->i_volatile_dict)
vi->i_volatile_dict = eufs_zalloc_page();
/* insert into parent dir hash table */
return nv_dict_add(dir, nv_header, hv, name, pi);
}
static __always_inline struct nv_dict_entry *
nv_dict_del_wrapper(struct inode *dir, struct nv_dict_entry **prevde,
u64 **nv_header, hashlen_t hv, const char *name)
{
struct eufs_inode_info *vi = EUFS_I(dir);
/* Alloc for dict if necessary */
if (!vi->i_volatile_dict)
vi->i_volatile_dict = eufs_zalloc_page();
/* insert into parent dir hash table */
return nv_dict_delete(dir, prevde, nv_header, hv, name);
}
/*
* Methods themselves.
*/
static struct dentry *eufs_lookup(struct inode *dir, struct dentry *dentry,
unsigned int flags)
{
struct inode *inode = NULL;
struct nv_dict_entry *de;
const char *name;
u64 hv;
if (dentry->d_name.len > EUFS_MAX_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
hv = hash(dentry->d_name.name, dentry->d_name.len);
name = dentry->d_name.name;
de = nv_dict_find(dir, hv, name);
if (!de)
goto not_found;
inode = eufs_iget(dir->i_sb, s2p(dir->i_sb, de->inode));
if (inode == ERR_PTR(-ESTALE)) {
eufs_err(dir->i_sb, "deleted inode referenced: 0x%lx",
inode->i_ino);
return ERR_PTR(-EIO);
}
not_found:
if (inode)
BUG_ON(atomic_read(&inode->i_count) < 1);
return d_splice_alias(inode, dentry);
}
static int add_pinode(struct inode *dir, struct dentry *dentry,
struct inode *inode, bool need_unlock_inode)
{
/* Name must be checked before this is invoked. */
struct eufs_inode_info *dir_vi = EUFS_I(dir);
struct eufs_inode *pi;
const char *name;
struct nv_dict_entry *de;
u64 *nv_header;
u64 hv;
struct dep_node *dep;
int err;
dep = eufs_alloc_dep_node();
if (!dep)
return -ENOMEM;
if (need_unlock_inode)
eufs_inode_mark_lock_transferable(inode);
/* Add to dict */
pi = EUFS_PI(inode);
name = dentry->d_name.name;
hv = hash(name, dentry->d_name.len);
de = nv_dict_add_wrapper(dir, &nv_header, pi, hv, name);
if (IS_ERR(de)) {
err = PTR_ERR(de);
goto err_out;
}
/* One more dentry */
dir->i_size++;
eufs_dbg("diradd +> %lld of %px 0x%lx\n", dir->i_size, dir, dir->i_ino);
/* Update dir time */
dir->i_ctime = dir->i_mtime = current_time(dir);
dep_new_insert(dep, dir, DEP_DIRADD, NULL, nv_header, de, inode,
dir_vi->i_next_dep_seq);
if (need_unlock_inode)
eufs_inode_wait_lock_transfer_done(inode);
dir_vi->i_next_dep_seq++;
return 0;
err_out:
if (need_unlock_inode)
eufs_inode_wait_lock_transfer_done(inode);
eufs_free_dep_node(dep);
return err;
}
static __always_inline int del_pinode(struct inode *dir, struct dentry *dentry,
bool is_dir)
{
struct eufs_inode_info *dir_vi = EUFS_I(dir);
struct inode *inode = dentry->d_inode;
struct nv_dict_entry *de, *prevde;
u64 *nv_header;
const char *name;
u64 hv;
struct dep_node *dep;
struct eufs_inode *pi;
int err;
dep = eufs_alloc_dep_node();
if (!dep)
return -ENOMEM;
eufs_inode_mark_lock_transferable(inode);
/* Remove from parent dir hash table */
name = dentry->d_name.name;
hv = hash(name, dentry->d_name.len);
de = nv_dict_del_wrapper(dir, &prevde, &nv_header, hv, name);
if (unlikely(!de)) {
err = -ENOENT;
goto err_out;
}
/* Drop one dentry */
dir->i_size--;
eufs_dbg("dirdel -> %lld of %px 0x%lx\n", dir->i_size, dir, dir->i_ino);
/* Update parent dir time */
dir->i_ctime = dir->i_mtime = current_time(dir);
/* Update inode ctime and link */
inode->i_ctime = dir->i_ctime;
if (is_dir) {
/* Update nlink and ctime for the removed inode */
WARN_ON(inode->i_nlink != 2);
clear_nlink(inode);
} else if (inode->i_nlink) {
drop_nlink(inode);
} else {
pi = EUFS_PI(inode);
eufs_info("!%s!: inode=%p, inode->i_nlink=%d inode->i_mode=0%o pi=%p pi->i_nlink=%d pi->i_mode=0%o\n",
__func__, inode, inode->i_nlink, inode->i_mode, pi,
eufs_iread_nlink(pi), eufs_iread_mode(pi));
BUG();
}
dep_new_insert(dep, dir, DEP_DIRREM, prevde, nv_header, de, inode,
dir_vi->i_next_dep_seq);
eufs_inode_wait_lock_transfer_done(inode);
dir_vi->i_next_dep_seq++;
return 0;
err_out:
eufs_inode_wait_lock_transfer_done(inode);
eufs_free_dep_node(dep);
return err;
}
static void eufs_free_new_inode(struct inode *inode)
{
clear_nlink(inode);
remove_inode_hash(inode);
unlock_new_inode(inode);
iput(inode);
}
/*
* By the time this is called, we already have created
* the directory cache entry for the new file, but it
* is so far negative - it has no inode.
*
* If the create succeeds, we fill in the inode information
* with d_instantiate().
*/
static int eufs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
bool excl)
{
struct inode *inode;
int err;
/* name checks */
if (unlikely(!dentry->d_name.len))
return -EINVAL;
if (unlikely(dentry->d_name.len > EUFS_MAX_NAME_LEN))
return -ENAMETOOLONG;
inode = pre_inodes_get(dentry, dir, mode, false, 0);
if (IS_ERR(inode))
return PTR_ERR(inode);
err = add_pinode(dir, dentry, inode, false);
if (err) {
eufs_free_new_inode(inode);
return err;
}
inode->i_op = &eufs_file_inode_operations;
inode->i_mapping->a_ops = &eufs_aops;
inode->i_fop = &eufs_file_operations;
eufs_trace_newfile("!create!", dir, inode, EUFS_PI(inode), NULL);
EUFS_I(inode)->i_is_dirty = true;
d_instantiate(dentry, inode);
unlock_new_inode(inode);
sync_on_draining(dir, NULL);
return 0;
}
static int eufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
dev_t rdev)
{
struct inode *inode;
int err;
if (unlikely(!dentry->d_name.len))
return -EINVAL;
if (unlikely(dentry->d_name.len > EUFS_MAX_NAME_LEN))
return -ENAMETOOLONG;
inode = pre_inodes_get(dentry, dir, mode, true, rdev);
if (IS_ERR(inode))
return PTR_ERR(inode);
err = add_pinode(dir, dentry, inode, false);
if (err) {
eufs_free_new_inode(inode);
return err;
}
inode->i_op = &eufs_special_inode_operations;
eufs_trace_newfile("!mknode!", dir, inode, EUFS_PI(inode), NULL);
EUFS_I(inode)->i_is_dirty = true;
d_instantiate(dentry, inode);
unlock_new_inode(inode);
sync_on_draining(dir, NULL);
return 0;
}
static int eufs_symlink(struct inode *dir, struct dentry *dentry,
const char *symname)
{
struct inode *inode = NULL;
struct eufs_inode *pi;
u32 len = strlen(symname);
void *pi_root;
int err;
/* name checks */
if (unlikely(!dentry->d_name.len))
return -EINVAL;
if (unlikely(dentry->d_name.len > EUFS_MAX_NAME_LEN))
return -ENAMETOOLONG;
if (unlikely(len > EUFS_MAX_SYMLINK_LEN))
return -ENAMETOOLONG;
/* alloc vfs inode and xxfs inode */
inode = pre_inodes_get(dentry, dir, S_IFLNK | S_IRWXUGO, false, 0);
if (IS_ERR(inode))
return PTR_ERR(inode);
pi = EUFS_FRESH_PI(EUFS_PI(inode));
pi_root = o2p(dir->i_sb, eufs_iread_root(pi));
/* copy the symname */
*((u64 *)pi_root) = hash(symname, len);
memcpy(((char *)pi_root) + sizeof(u64), symname, len);
BUG_ON(!eufs_access_ok(inode->i_sb, pi_root, PAGE_SIZE));
/* update the size */
inode->i_size = len;
err = add_pinode(dir, dentry, inode, false);
if (err) {
eufs_free_new_inode(inode);
return err;
}
inode->i_op = &eufs_symlink_inode_operations;
inode->i_mapping->a_ops = &eufs_aops;
eufs_trace_newfile("!symlink!", dir, inode, pi, NULL);
EUFS_I(inode)->i_is_dirty = true;
d_instantiate(dentry, inode);
unlock_new_inode(inode);
sync_on_draining(dir, NULL);
return 0;
}
static int eufs_link(struct dentry *dest_dentry, struct inode *dir,
struct dentry *dentry)
{
struct inode *inode = dest_dentry->d_inode;
struct eufs_inode *pi = EUFS_PI(inode);
struct nv_dict_entry *de;
int err;
/* name checks */
if (unlikely(!dentry->d_name.len))
return -EINVAL;
if (unlikely(dentry->d_name.len > EUFS_MAX_NAME_LEN))
return -ENAMETOOLONG;
/* nlink check */
if (unlikely(inode->i_nlink >= EUFS_LINK_MAX))
return -EMLINK;
ihold(inode);
err = add_pinode(dir, dentry, inode, true);
if (unlikely(err)) {
iput(inode);
return err;
}
/* update inode ctime */
inode->i_ctime = current_time(inode);
inc_nlink(inode);
EUFS_I(inode)->i_is_dirty = true;
d_instantiate(dentry, inode);
eufs_trace_newfile("!link!", dir, inode, pi, de);
/* inode_lock() has been acquired */
sync_on_draining(dir, inode);
return 0;
}
static int eufs_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
int ret;
ret = del_pinode(dir, dentry, false);
if (ret < 0)
return ret;
eufs_trace_delfile("!unlink!", dir, inode, EUFS_PI(inode));
EUFS_I(inode)->i_is_dirty = true;
sync_on_draining(dir, inode);
return 0;
}
/* NOTE: do not count the link for directories */
static int eufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
struct inode *inode;
struct eufs_inode *dir_pi = EUFS_PI(dir);
struct eufs_inode_info *vi;
struct eufs_inode *pi;
int err;
/* name checks */
if (unlikely(!dentry->d_name.len))
return -EINVAL;
if (unlikely(dentry->d_name.len > EUFS_MAX_NAME_LEN))
return -ENAMETOOLONG;
/* alloc vfs inode and xxfs inode */
inode = pre_inodes_get(dentry, dir, S_IFDIR | mode, false, 0);
if (IS_ERR(inode))
return PTR_ERR(inode);
inode->i_op = &eufs_dir_inode_operations;
inode->i_fop = &eufs_dir_operations;
inode->i_mapping->a_ops = &eufs_aops;
/* We have to mimic the nlink number */
inc_nlink(inode);
/* alloc & init dir hash table for new inode */
pi = EUFS_FRESH_PI(EUFS_PI(inode));
vi = EUFS_I(inode);
vi->i_dotdot = p2o(dir->i_sb, dir_pi);
pi->i_dotdot = cpu_to_le64(vi->i_dotdot);
err = add_pinode(dir, dentry, inode, false);
if (err) {
eufs_free_new_inode(inode);
return err;
}
/* We have to mimic the nlink number */
inc_nlink(dir);
eufs_trace_newfile("!mkdir!", dir, inode, pi, NULL);
vi->i_is_dirty = true;
d_instantiate(dentry, inode);
unlock_new_inode(inode);
sync_on_draining(dir, NULL);
PRINT_PINODE(pi, "FINAL-CHECK: ");
BUG_ON(atomic_read(&dir->i_count) < 1);
if (inode)
BUG_ON(atomic_read(&inode->i_count) < 1);
return 0;
}
/*
* routine to check that the specified directory is empty (for rmdir)
*/
static __always_inline int eufs_empty_dir(struct inode *inode)
{
return !inode->i_size;
}
static int eufs_rmdir(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
int ret;
/* checks before rmdir */
if (!inode)
return -ENOENT;
if (!eufs_empty_dir(inode))
return -ENOTEMPTY;
ret = del_pinode(dir, dentry, true);
if (ret < 0)
return ret;
/* We have to mimic the nlink number */
drop_nlink(dir);
EUFS_I(inode)->i_is_dirty = true;
eufs_trace_delfile("!rmdir!", dir, inode, EUFS_PI(inode));
sync_on_draining(dir, inode);
return 0;
}
/*
* Precondition: old_dentry exists in the old directory
*/
static int eufs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry,
unsigned int flags)
{
struct inode *old_inode = old_dentry->d_inode;
struct inode *new_inode = new_dentry->d_inode;
/*
* TODO: need to lock old_inode
* If old_inode is a directory, its inode lock will
* not be acquired, so the offset of newest physical node
* may be changed during the rename procedure.
*/
struct eufs_inode *pi = EUFS_FRESH_PI(EUFS_PI(old_inode));
struct eufs_inode *old_dir_pi;
struct eufs_inode *new_dir_pi;
struct inode *locked_inodes[EUFS_INODE_CNT_IN_RENAME] = {
old_dir, new_dir, old_inode, new_inode
};
struct super_block *sb = old_inode->i_sb;
struct nv_dict_entry *new_de;
u64 *new_dir_nv_header;
struct nv_dict_entry *old_de, *old_prevde;
u64 *old_dir_nv_header;
bool in_same_dir = (old_dir == new_dir);
const char *name;
struct eufs_renamej *renamej;
u64 old_hv, new_hv;
struct nv_dict_entry **vde;
int cpu;
void *buffer[16];
NV_ASSERT(pi->i_mode == old_inode->i_mode);
if (flags & (RENAME_EXCHANGE | RENAME_WHITEOUT))
return -EOPNOTSUPP;
/* checks */
if (new_inode) {
eufs_dbg(
"!new_inode=%px new_inode->i_count=%d new_dentry->d_lockref.count=%d\n",
new_inode, atomic_read(&new_inode->i_count),
new_dentry->d_lockref.count);
if (S_ISDIR(new_inode->i_mode) && !eufs_empty_dir(new_inode))
return -ENOTEMPTY;
eufs_dbg("rename overwrites! newinode=%px newpi=%px newinode->i_mode=0%o, newinode->root=%px oldinode=%px oldpi=%px oldinode->i_mode=0%o, oldinode->root=%px\n",
new_inode, EUFS_PI(new_inode), new_inode->i_mode,
EUFS_I(new_inode)->i_volatile_root, old_inode,
EUFS_PI(old_inode), old_inode->i_mode,
EUFS_I(old_inode)->i_volatile_root);
BUG_ON(new_inode->i_mode != EUFS_PI(new_inode)->i_mode);
}
eufs_dbg("%s: rename %s to %s before fsync, old_pi=%px new_pi=%px\n",
__func__, old_dentry->d_name.name, new_dentry->d_name.name,
EUFS_PI(old_inode),
new_inode ? EUFS_PI(new_inode) : (void *)-1);
eufs_dbg("old: dir=%px inode=%px; new: dir=%px inode=%px\n", old_dir,
old_inode, new_dir, new_inode);
if (S_ISDIR(old_inode->i_mode))
locked_inodes[2] = NULL;
if (locked_inodes[0] == locked_inodes[1])
locked_inodes[1] = NULL;
if (locked_inodes[0])
BUG_ON(!inode_is_locked(locked_inodes[0]));
if (locked_inodes[1])
BUG_ON(!inode_is_locked(locked_inodes[1]));
if (locked_inodes[2])
BUG_ON(!inode_is_locked(locked_inodes[2]));
if (locked_inodes[3])
BUG_ON(!inode_is_locked(locked_inodes[3]));
fsync_rename_inodes(old_dir, new_dir, locked_inodes);
/*
* get the newer inodes after fsync_rename_inodes() completes
* which may update the offset of the newer inodes
*/
old_dir_pi = EUFS_FRESH_PI(EUFS_PI(old_dir));
new_dir_pi = EUFS_FRESH_PI(EUFS_PI(new_dir));
/* -------------- get new dentry info -------------- */
/* get new filename */
new_hv = hash(new_dentry->d_name.name, new_dentry->d_name.len);
name = new_dentry->d_name.name;
eufs_dbg("%s: rename %s to %s\n", __func__, old_dentry->d_name.name,
new_dentry->d_name.name);
/* -------------- insertion ---------------- */
/* insert into parent dir hash table */
if (new_inode) {
new_de = nv_dict_find(new_dir, new_hv, name);
if (!new_de)
return -ENOENT;
/* Delay the actual write */
BUG_ON(!new_inode->i_nlink);
ihold(new_inode);
/* We have new_inode in hand */
if (S_ISDIR(new_inode->i_mode)) {
WARN_ON(new_inode->i_nlink != 2);
clear_nlink(new_inode);
} else {
drop_nlink(new_inode);
}
new_dir_nv_header = NULL;
} else {
new_de = nv_dict_add_wrapper(new_dir, &new_dir_nv_header,
EUFS_HEAD_PI(pi), new_hv, name);
if (IS_ERR(new_de))
return PTR_ERR(new_de);
if (unlikely(!new_de))
return -EEXIST;
/* We have no dep in rename. Just release the header lock */
inode_header_unlock(new_dir);
if (!in_same_dir) {
new_dir->i_size++;
if (S_ISDIR(old_inode->i_mode))
inc_nlink(new_dir);
}
eufs_dbg("rename diradd +> %lld of %px 0x%lx\n",
new_dir->i_size, new_dir, new_dir->i_ino);
}
/* update dir time */
new_dir->i_ctime = new_dir->i_mtime = current_time(new_dir);
/* -------------- get old dentry info -------------- */
/* get old filename */
old_hv = hash(old_dentry->d_name.name, old_dentry->d_name.len);
name = old_dentry->d_name.name;
if (!name) {
BUG();
return -ENOENT;
}
/* -------------- removal ---------------- */
old_de = nv_dict_del_wrapper(old_dir, &old_prevde, &old_dir_nv_header,
old_hv, name);
if (unlikely(!old_de)) {
BUG();
return -ENOENT;
}
/* We have no dep in rename. Just release the header lock */
inode_header_unlock(old_dir);
if (!in_same_dir || new_inode) {
old_dir->i_size--;
if (S_ISDIR(old_inode->i_mode))
drop_nlink(old_dir);
}
if (old_dir != new_dir)
old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime;
eufs_dbg("rename dirdel -> %lld of %px 0x%lx\n", old_dir->i_size,
old_dir, old_dir->i_ino);
/* old_inode may NOT be locked ? */
/* update ctime of source inode */
old_inode->i_ctime = new_dir->i_ctime;
if (!in_same_dir && S_ISDIR(old_inode->i_mode)) {
/* update parent pointer of source inode */
struct eufs_inode_info *vi = EUFS_I(old_inode);
vi->i_dotdot = p2o(sb, EUFS_HEAD_PI(new_dir_pi));
}
NV_ASSERT(new_de->inode == old_de->inode);
NV_ASSERT(eufs_valid_inode_in_de(old_de, old_inode));
NV_ASSERT(old_inode->i_mode ==
eufs_iread_mode(EUFS_FRESH_PI(
(struct eufs_inode *)(s2p(sb, old_de->inode)))));
if (!new_inode) {
struct alloc_batch ab;
ab.n_used = 0;
ab.size = 16;
ab.batch = buffer;
eufs_alloc_batch_add(old_dir->i_sb, &ab, new_de);
persist_name(old_dir->i_sb, new_de, &ab);
eufs_dentry_clr_not_persist_flag(new_de);
persist_dentry(new_de);
eufs_alloc_batch_persist_reset(old_dir->i_sb, &ab);
}
cpu = get_cpu();
/* RenameJ is redo log */
renamej = eufs_get_renamej(old_dir->i_sb, cpu);
renamej->crc = 0;
renamej->flags = 0;
/* address to put old_de->next */
renamej->addr_of_oldnext =
p2s(sb, (old_prevde ? &old_prevde->next :
(void *)old_dir_nv_header));
/* the value: old_de->next */
renamej->oldnext =
(old_prevde ?
old_de->next :
old_de->next == EUFS_DIR_EOC ?
NULL_VAL :
COMPOSE_DICT_HEAD_le64(sb, s2p(sb, old_de->next)));
/* address to put new_de if necessary */
renamej->addr_of_newde = p2s(sb, new_dir_nv_header);
/* the value: new_de */
renamej->composed_newde = COMPOSE_DICT_HEAD_le64(sb, new_de);
/* the value: new_de->inode */
renamej->newde_inode = p2s(sb, EUFS_HEAD_PI(pi));
/* dir pi */
renamej->old_dir_pi = p2s(sb, EUFS_HEAD_PI(old_dir_pi));
renamej->new_dir_pi = p2s(sb, EUFS_HEAD_PI(new_dir_pi));
/* inode attributes */
renamej->time = cpu_to_le64(new_dir->i_ctime.tv_sec);
renamej->time_nsec = cpu_to_le32(new_dir->i_ctime.tv_nsec);
renamej->old_link = cpu_to_le16(old_dir->i_nlink);
renamej->new_link = cpu_to_le16(new_dir->i_nlink);
renamej->old_size = cpu_to_le32(old_dir->i_size);
renamej->new_size = cpu_to_le32(new_dir->i_size);
memset(renamej->pad, 0, sizeof(renamej->pad));
renamej->flags = EUFS_RENAME_IN_ACTION;
renamej->crc = cpu_to_le32(
crc32c(EUFS_CRC_SEED, (char *)renamej + sizeof(renamej->crc),
sizeof(*renamej) - sizeof(renamej->crc)));
eufs_flush_cacheline((char *)renamej + CACHELINE_SIZE);
eufs_flush_cacheline(renamej);
if (old_prevde) {
old_prevde->next = old_de->next;
} else {
if (old_de->next == EUFS_DIR_EOC)
*old_dir_nv_header = NULL_VAL;
else
*old_dir_nv_header = COMPOSE_DICT_HEAD_le64(
sb, s2p(sb, old_de->next));
}
eufs_flush_cacheline(old_prevde ? (void *)&old_prevde->next :
(void *)old_dir_nv_header);
vde = &(EUFS_I(old_dir)->i_volatile_dict->table[INDEX(old_hv)]);
if (*vde) {
bool vbool = (*vde == NULL || *vde == (void *)EUFS_DIR_EOC);
bool pbool = (*old_dir_nv_header == NULL_VAL ||
*old_dir_nv_header == EUFS_DIR_EOC);
BUG_ON(vbool != pbool);
*vde = NULL;
}
if (new_inode) {
new_de->inode = p2s(sb, EUFS_HEAD_PI(pi));
eufs_flush_cacheline(new_de);
} else {
*new_dir_nv_header = COMPOSE_DICT_HEAD_le64(sb, new_de);
eufs_flush_cacheline(new_dir_nv_header);
vde = &EUFS_I(new_dir)->i_volatile_dict->table[INDEX(new_hv)];
if (*vde) {
bool vbool =
(*vde == NULL || *vde == (void *)EUFS_DIR_EOC);
bool pbool = (*new_dir_nv_header == NULL_VAL ||
*new_dir_nv_header == EUFS_DIR_EOC);
BUG_ON(vbool != pbool);
*vde = NULL;
}
}
eufs_iwrite_size(old_dir_pi, old_dir->i_size);
eufs_iwrite_nlink(old_dir_pi, old_dir->i_nlink);
eufs_iwrite_ctime_mtime(old_dir_pi, old_dir);
eufs_flush_pi(old_dir_pi);
if (old_dir != new_dir) {
eufs_iwrite_size(new_dir_pi, new_dir->i_size);
eufs_iwrite_nlink(new_dir_pi, new_dir->i_nlink);
eufs_iwrite_ctime_mtime(new_dir_pi, new_dir);
eufs_flush_pi(new_dir_pi);
}
eufs_iwrite_ctime(pi, old_inode->i_ctime.tv_sec);
eufs_iwrite_ctime_nsec(pi, old_inode->i_ctime.tv_nsec);
if (!in_same_dir && S_ISDIR(old_inode->i_mode)) {
struct eufs_inode_info *vi = EUFS_I(old_inode);
eufs_iwrite_dotdot(pi, vi->i_dotdot);
}
eufs_flush_pi(pi);
renamej->flags = 0;
eufs_flush_cacheline(renamej);
put_cpu();
/* remove overwritten inode */
if (new_inode)
iput(new_inode);
/* remove the source dentry */
eufs_free_name(old_dir->i_sb, old_de);
nv_free(old_dir->i_sb, old_de);
eufs_dbg("%s: renamed %s to %s , old_pi=%llx new_pi=%llx\n", __func__,
old_dentry->d_name.name, new_dentry->d_name.name,
old_de->inode, new_de->inode);
return 0;
}
const struct inode_operations eufs_dir_inode_operations = {
.create = eufs_create,
.lookup = eufs_lookup,
.link = eufs_link,
.unlink = eufs_unlink,
.symlink = eufs_symlink,
.mkdir = eufs_mkdir,
.rmdir = eufs_rmdir,
.mknod = eufs_mknod,
.rename = eufs_rename,
.setattr = eufs_notify_change,
};
const struct inode_operations eufs_special_inode_operations = {
.setattr = eufs_notify_change,
};
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。