写文件:
[root@localhost ~]# touch xxx
[ 2016.065152] ===ext4_lookup
[ 2016.067945] CPU: 1 PID: 5075 Comm: touch Kdump: loaded Not tainted 4.19.0-fix-full-10+ #45
[ 2016.076194] Hardware name: PHYTIUM LTD D2000/D2000, BIOS
[ 2016.081666] Call trace:
[ 2016.084106] dump_backtrace+0x0/0x1b8
[ 2016.087755] show_stack+0x24/0x30
[ 2016.091059] dump_stack+0x90/0xb4
[ 2016.094363] ext4_lookup+0x244/0x248
[ 2016.097928] lookup_open+0x204/0x638
[ 2016.101491] do_last+0x364/0x7d0
[ 2016.104706] path_openat+0x88/0x2a0 //path_openat创建file *
[ 2016.108182] do_filp_open+0x88/0x108 //调用上面
[ 2016.111745] do_sys_open+0x1a8/0x238 //寻找空闲fd。
[ 2016.115308] __arm64_sys_openat+0x2c/0x38
[ 2016.119305] el0_svc_handler+0x84/0x140
[ 2016.123127] el0_svc+0x8/0xc[ 2016.126020] ===ext4_create
[ 2016.128802] CPU: 1 PID: 5075 Comm: touch Kdump: loaded Not tainted 4.19.0-fix-full-10+ #45
[ 2016.137051] Hardware name: PHYTIUM LTD D2000/D2000, BIOS
[ 2016.142522] Call trace:
[ 2016.144957] dump_backtrace+0x0/0x1b8
[ 2016.148606] show_stack+0x24/0x30
[ 2016.151908] dump_stack+0x90/0xb4
[ 2016.155210] ext4_create+0x234/0x248
[ 2016.158772] lookup_open+0x270/0x638
[ 2016.162335] do_last+0x364/0x7d0
[ 2016.165550] path_openat+0x88/0x2a0
[ 2016.169026] do_filp_open+0x88/0x108
[ 2016.172588] do_sys_open+0x1a8/0x238
[ 2016.176151] __arm64_sys_openat+0x2c/0x38
[ 2016.180147] el0_svc_handler+0x84/0x140
[ 2016.183969] el0_svc+0x8/0xc
lookup_open函数:
static int lookup_open(struct nameidata *nd, struct path *path,
struct file *file,
const struct open_flags *op,
bool got_write)
{
struct dentry *dir = nd->path.dentry;
struct inode *dir_inode = dir->d_inode;
int open_flag = op->open_flag;
struct dentry *dentry;
int error, create_error = 0;
umode_t mode = op->mode;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
if (unlikely(IS_DEADDIR(dir_inode)))
return -ENOENT;
file->f_mode &= ~FMODE_CREATED;
dentry = d_lookup(dir, &nd->last);
for (;;) {
if (!dentry) {
dentry = d_alloc_parallel(dir, &nd->last, &wq);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
}
if (d_in_lookup(dentry))
break;
error = d_revalidate(dentry, nd->flags);
if (likely(error > 0))
break;
if (error)
goto out_dput;
d_invalidate(dentry);
dput(dentry);
dentry = NULL;
}
if (dentry->d_inode) {
/* Cached positive dentry: will open in f_op->open */
goto out_no_open;
}
/*
* Checking write permission is tricky, bacuse we don't know if we are
* going to actually need it: O_CREAT opens should work as long as the
* file exists. But checking existence breaks atomicity. The trick is
* to check access and if not granted clear O_CREAT from the flags.
*
* Another problem is returing the "right" error value (e.g. for an
* O_EXCL open we want to return EEXIST not EROFS).
*/
if (open_flag & O_CREAT) {
if (!IS_POSIXACL(dir->d_inode))
mode &= ~current_umask();
if (unlikely(!got_write)) {
create_error = -EROFS;
open_flag &= ~O_CREAT;
if (open_flag & (O_EXCL | O_TRUNC))
goto no_open;
/* No side effects, safe to clear O_CREAT */
} else {
create_error = may_o_create(&nd->path, dentry, mode);
if (create_error) {
open_flag &= ~O_CREAT;
if (open_flag & O_EXCL)
goto no_open;
}
}
} else if ((open_flag & (O_TRUNC|O_WRONLY|O_RDWR)) &&
unlikely(!got_write)) {
/*
* No O_CREATE -> atomicity not a requirement -> fall
* back to lookup + open
*/
goto no_open;
}
if (dir_inode->i_op->atomic_open) {
error = atomic_open(nd, dentry, path, file, op, open_flag,
mode);
if (unlikely(error == -ENOENT) && create_error)
error = create_error;
return error;
}
no_open:
if (d_in_lookup(dentry)) {
struct dentry *res = dir_inode->i_op->lookup(dir_inode, dentry,
nd->flags); ---------------lookup函数
d_lookup_done(dentry);
if (unlikely(res)) {
if (IS_ERR(res)) {
error = PTR_ERR(res);
goto out_dput;
}
dput(dentry);
dentry = res;
}
}
/* Negative dentry, just create the file */
if (!dentry->d_inode && (open_flag & O_CREAT)) {
file->f_mode |= FMODE_CREATED;
audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE);
if (!dir_inode->i_op->create) {
error = -EACCES;
goto out_dput;
}
error = dir_inode->i_op->create(dir_inode, dentry, mode,
open_flag & O_EXCL); ------------------调用create函数
if (error)
goto out_dput;
fsnotify_create(dir_inode, dentry);
}
if (unlikely(create_error) && !dentry->d_inode) {
error = create_error;
goto out_dput;
}
out_no_open:
path->dentry = dentry;
path->mnt = nd->path.mnt;
return 0;
out_dput:
dput(dentry);
return error;
}
其中有两处调用了父目录的dir_inode->i_op下的函数,一个是lookup一个是create函数。
位于fs/ext4/namei.c中。对应最顶层的根目录,也就是文件系统分区的根目录,其初始化在mount之后,调用了mount回调函数,其在register_filesystem的时候已经定义了:fs/ext4/super.c
static struct file_system_type ext4_fs_type = {
.owner = THIS_MODULE,
.name = "ext4",
.mount = ext4_mount,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
MODULE_ALIAS_FS("ext4");
/* Shared across all ext4 file systems */
wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
static int __init ext4_init_fs(void)
{
int i, err;
ratelimit_state_init(&ext4_mount_msg_ratelimit, 30 * HZ, 64);
ext4_li_info = NULL;
mutex_init(&ext4_li_mtx);
/* Build-time check for flags consistency */
ext4_check_flag_values();
for (i = 0; i < EXT4_WQ_HASH_SZ; i++)
init_waitqueue_head(&ext4__ioend_wq[i]);
err = ext4_init_es();
if (err)
return err;
err = ext4_init_pageio();
if (err)
goto out5;
err = ext4_init_system_zone();
if (err)
goto out4;
err = ext4_init_sysfs();
if (err)
goto out3;
err = ext4_init_mballoc();
if (err)
goto out2;
err = init_inodecache();
if (err)
goto out1;
register_as_ext3();
register_as_ext2();
err = register_filesystem(&ext4_fs_type);-----------注册ext4文件系统
if (err)
goto out;
return 0;
out:
unregister_as_ext2();
unregister_as_ext3();
destroy_inodecache();
out1:
ext4_exit_mballoc();
out2:
ext4_exit_sysfs();
out3:
ext4_exit_system_zone();
out4:
ext4_exit_pageio();
out5:
ext4_exit_es();
return err;
}
ext4_mount函数:
static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data)
{
return mount_bdev(fs_type, flags, dev_name, data, ext4_fill_super);
}
传递的最后一个参数是一个函数指针:ext4_fill_super函数创建了根目录inode。
static int ext4_fill_super(struct super_block *sb, void *data, int silent)
{
....省略
root = ext4_iget(sb, EXT4_ROOT_INO, EXT4_IGET_SPECIAL);
...省略
}
struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
{
....省略
设置inode
if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext4_file_inode_operations;
inode->i_fop = &ext4_file_operations;
ext4_set_aops(inode);
} else if (S_ISDIR(inode->i_mode)) { 目录的inode_operations
inode->i_op = &ext4_dir_inode_operations;
inode->i_fop = &ext4_dir_operations;
....省略
}
目录inode文件关联的inode_operations结构体:
const struct inode_operations ext4_dir_inode_operations = {
.create = ext4_create,
.lookup = ext4_lookup,
.link = ext4_link,
.unlink = ext4_unlink,
.symlink = ext4_symlink,
.mkdir = ext4_mkdir,
.rmdir = ext4_rmdir,
.mknod = ext4_mknod,
.tmpfile = ext4_tmpfile,
.rename = ext4_rename2,
.setattr = ext4_setattr,
.getattr = ext4_getattr,
.listxattr = ext4_listxattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
.fiemap = ext4_fiemap,
};
文件的创建调用 lookup_open函数,其中又调用了目录inode的create函数ext4_create:普通文件的inode_operations是ext4_file_inode_operations,以及f_op的file_operations。
static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode,
bool excl)
{
handle_t *handle;
struct inode *inode;
int err, credits, retries = 0;
err = dquot_initialize(dir);
if (err)
return err;
credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3);
retry:
inode = ext4_new_inode_start_handle(dir, mode, &dentry->d_name, 0,
NULL, EXT4_HT_DIR, credits);
handle = ext4_journal_current_handle();
err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
inode->i_op = &ext4_file_inode_operations;
inode->i_fop = &ext4_file_operations;
ext4_set_aops(inode);
err = ext4_add_nondir(handle, dentry, inode);
if (!err && IS_DIRSYNC(dir))
ext4_handle_sync(handle);
}
if (handle)
ext4_journal_stop(handle);
if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
goto retry;
return err;
}
文件的inode_opearations和file_operations:fs/ext4/file.c 。文件的inode_operations需要使用的函数较少。文件主要几种在打开等操作的file_operations。
const struct file_operations ext4_file_operations = {
.llseek = ext4_llseek,
.read_iter = ext4_file_read_iter,
.write_iter = ext4_file_write_iter,
.unlocked_ioctl = ext4_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ext4_compat_ioctl,
#endif
.mmap = ext4_file_mmap,
.mmap_supported_flags = MAP_SYNC,
.open = ext4_file_open,
.release = ext4_release_file,
.fsync = ext4_sync_file,
.get_unmapped_area = thp_get_unmapped_area,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.fallocate = ext4_fallocate,
};
const struct inode_operations ext4_file_inode_operations = {
.setattr = ext4_setattr,
.getattr = ext4_file_getattr,
.listxattr = ext4_listxattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
.fiemap = ext4_fiemap,
};
目录的创建:
调用文件夹inode_operations的mkdir函数ext4_mkdir:
static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
handle_t *handle;
struct inode *inode;
int err, credits, retries = 0;
if (EXT4_DIR_LINK_MAX(dir))
return -EMLINK;
err = dquot_initialize(dir);
if (err)
return err;
credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3);
retry:
inode = ext4_new_inode_start_handle(dir, S_IFDIR | mode,
&dentry->d_name,
0, NULL, EXT4_HT_DIR, credits);
handle = ext4_journal_current_handle();
err = PTR_ERR(inode);
if (IS_ERR(inode))
goto out_stop;
inode->i_op = &ext4_dir_inode_operations; --------目录的inode_operations
inode->i_fop = &ext4_dir_operations; --------------目录的file_operations
err = ext4_init_new_dir(handle, dir, inode);
if (err)
goto out_clear_inode;
err = ext4_mark_inode_dirty(handle, inode);
if (!err)
err = ext4_add_entry(handle, dentry, inode);
if (err) {
out_clear_inode:
clear_nlink(inode);
unlock_new_inode(inode);
ext4_mark_inode_dirty(handle, inode);
iput(inode);
goto out_stop;
}
ext4_inc_count(handle, dir);
ext4_update_dx_flag(dir);
err = ext4_mark_inode_dirty(handle, dir);
if (err)
goto out_clear_inode;
d_instantiate_new(dentry, inode);
if (IS_DIRSYNC(dir))
ext4_handle_sync(handle);
out_stop:
if (handle)
ext4_journal_stop(handle);
if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
goto retry;
return err;
}
fs/ext4/dir.c目录的file_operations:
const struct file_operations ext4_dir_operations = {
.llseek = ext4_dir_llseek,
.read = generic_read_dir,
.iterate_shared = ext4_readdir,
.unlocked_ioctl = ext4_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ext4_compat_ioctl,
#endif
.fsync = ext4_sync_file,
.open = ext4_dir_open,
.release = ext4_release_dir,
};