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

openEuler/eulerfs
关闭

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
file.c 7.30 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/fs.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/uio.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <linux/falloc.h>
#include <asm/mman.h>
#include "euler.h"
#include "dax.h"
#include "dep.h"
static long eufs_fallocate(struct file *file, int mode, loff_t offset,
loff_t len)
{
struct inode *inode = file_inode(file);
struct eufs_inode_info *vi = EUFS_I(inode);
loff_t end = offset + len;
unsigned long start_page = offset >> PAGE_SHIFT,
end_page = DIV_ROUND_UP(end, PAGE_SIZE);
bool zero = mode & FALLOC_FL_ZERO_RANGE;
bool keep = mode & FALLOC_FL_KEEP_SIZE;
long r = 0;
if (mode & (FALLOC_FL_INSERT_RANGE | FALLOC_FL_PUNCH_HOLE |
FALLOC_FL_COLLAPSE_RANGE))
return -EOPNOTSUPP;
/* Fix xfstests 228 */
r = inode_newsize_ok(inode, len + offset);
if (r)
return r;
inode_lock(inode);
down_write(&vi->mmap_rwsem);
r = eufs_alloc_blocks_btree(
inode, start_page, end_page - start_page,
(offset < inode->i_size) ?
/* Zero if overwriting */
EUFS_ALLOC_BLOCKS_ZERO_ALL :
(((offset >> PAGE_SHIFT) <=
(inode->i_size >> PAGE_SHIFT) &&
(offset > inode->i_size)) ?
EUFS_ALLOC_BLOCKS_ZERO_EDGE :
EUFS_ALLOC_BLOCKS_ZERO_NONE));
if (IS_ERR_VALUE(r))
goto out;
eufs_dbg(
"fallocate (f=%px, fsize=%llx, offset=%llx, len=%llx, zero=%d, keep=%d)\n",
file, inode->i_size, offset, len, zero, keep);
if (offset + len >= inode->i_size) {
if (!zero) {
/* zero inode->i_size ~> offset + len */
__eufs_file_write(file->f_mapping, NULL,
offset + len - inode->i_size,
inode->i_size, NULL, true, keep);
/* zero part of the last block goes beyond the new EOF */
eufs_inode_zero_range(inode, offset + len,
PAGE_ALIGN(offset + len));
} else if (offset >= inode->i_size) {
eufs_dbg("zero(f=%px): %llx to %llx\n", file,
inode->i_size, offset);
/* zero inode->i_size ~> offset */
__eufs_file_write(file->f_mapping, NULL,
offset - inode->i_size,
inode->i_size, NULL, true, keep);
}
if (!keep)
inode->i_size = offset + len;
}
if (zero) {
/* zero offset ~> offset + len */
__eufs_file_write(file->f_mapping, NULL, len, offset, NULL,
true, keep);
/* zero part of the last block goes beyond the new EOF */
if (offset + len >= inode->i_size)
eufs_inode_zero_range(inode, offset + len,
PAGE_ALIGN(offset + len));
}
request_persistence(inode);
out:
up_write(&vi->mmap_rwsem);
inode_unlock(inode);
return r;
}
static void eufs_dir_fsync_until_seq(struct inode *dir, u32 dep_seq)
{
struct eufs_inode_info *vinode = EUFS_I(dir);
if (eufs_dep_seq_after_eq(vinode->i_persisted_dep_seq, dep_seq))
return;
inode_lock(dir);
eufs_dir_fsync_oneshot(dir);
inode_unlock(dir);
}
static void eufs_persist_dentries(struct inode *inode)
{
struct eufs_inode_info *vi = EUFS_I(inode);
struct list_head *head = &vi->i_owner_list;
if (list_empty(head))
return;
spin_lock(&vi->i_owner_lock);
while (!list_empty(head)) {
struct dep_node *dep;
struct inode *dir;
u32 seq;
dep = list_first_entry(head, struct dep_node, owner_node);
dir = dep->dir;
seq = dep->seq;
/* let it be deleted by dir persistence ? */
list_del_init(&dep->owner_node);
spin_unlock(&vi->i_owner_lock);
eufs_dir_fsync_until_seq(dir, seq);
spin_lock(&vi->i_owner_lock);
}
spin_unlock(&vi->i_owner_lock);
}
static void eufs_persist_parent_dentry_till_root(struct dentry *child)
{
struct dentry *cur = child;
while (!IS_ROOT(cur)) {
struct dentry *parent;
parent = cur->d_parent;
eufs_persist_dentries(parent->d_inode);
cur = parent;
}
}
static int eufs_persist_parent_dentries_till_root(struct file *filp)
{
struct inode *inode = filp->f_inode;
unsigned int nlink = inode->i_nlink;
struct dentry *alias;
struct dentry **aliases;
unsigned int cnt;
unsigned int idx;
if (nlink == 0)
return 0;
if (nlink == 1) {
eufs_persist_parent_dentry_till_root(filp->f_path.dentry);
return 0;
}
aliases = kmalloc(nlink * sizeof(*aliases), GFP_KERNEL);
if (aliases == NULL)
return -ENOMEM;
cnt = 0;
spin_lock(&inode->i_lock);
hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
dget(alias);
aliases[cnt++] = alias;
if (cnt >= nlink)
break;
}
spin_unlock(&inode->i_lock);
for (idx = 0; idx < cnt; idx++) {
eufs_persist_parent_dentry_till_root(aliases[idx]);
dput(aliases[idx]);
}
kfree(aliases);
return 0;
}
/*
* inconsistency:
*
* non-dir:
* data -> inode & name -> dentries... -> parent dentries...
* dentry [parent data -> parent inode]
* (1) link can be high: new A/1, link B/2 (A/1), fsync A/1
* (2) link can be low: new A/1, link B/2 (A/1), fsync A/1, rm A/1,
* fsync A/1
*
* dir:
* children inodes -> data -> inode & name
* (1) link & size can be low: new A/1..3, fsync A
* (2) link & size can be high: new A/1..3, fsync A, rm A/1, fsync A
*/
/* This function is called by both msync() and fsync(). */
int eufs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
{
/* Sync from start to end[inclusive] */
struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
struct eufs_inode_info *vi = EUFS_I(inode);
umode_t mode;
int err;
bool inode_is_dirty;
mode = inode->i_mode;
/* persist file data written through mmap */
if (S_ISREG(mode)) {
err = filemap_write_and_wait_range(inode->i_mapping, start,
end);
if (err)
return err;
}
/* persist its data and inode first */
inode_is_dirty = false;
inode_lock(inode);
if (vi->i_is_dirty) {
inode_is_dirty = true;
} else {
/*
* modifications of mtime/ctime/atime has not been tracked
* by persister yet, so check it here
*/
spin_lock(&inode->i_lock);
if (inode->i_state & I_DIRTY_SYNC) {
inode->i_state &= ~I_DIRTY_SYNC;
inode_is_dirty = true;
}
spin_unlock(&inode->i_lock);
}
if (inode_is_dirty)
fsync_oneshot(inode);
inode_unlock(inode);
/*
* persist dentries related with the inode. If it is non-dir,
* there may be multiple dentries related with it (namely hard-link).
*/
eufs_persist_dentries(inode);
/*
* persist parent dentries and recurse upward until the root dentry is reached.
* For non-dir, there may be multiple parent dentries due to hard-link.
*/
if (!S_ISDIR(mode))
err = eufs_persist_parent_dentries_till_root(file);
else
eufs_persist_parent_dentry_till_root(file->f_path.dentry);
return err;
}
const struct file_operations eufs_file_operations = {
.llseek = eufs_file_llseek,
.read = eufs_file_read,
.write = eufs_file_write,
.mmap = eufs_dax_file_mmap,
.open = generic_file_open,
.fsync = eufs_fsync,
.flush = NULL,
.fallocate = eufs_fallocate,
};
const struct inode_operations eufs_file_inode_operations = {
.setattr = eufs_notify_change,
.getattr = eufs_file_getattr,
};
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/openeuler/eulerfs.git
git@gitee.com:openeuler/eulerfs.git
openeuler
eulerfs
eulerfs
master

搜索帮助