1.ext4文件系统定义的各种操作
//普通文件操作
const struct file_operations ext4_file_operations = {
.llseek = ext4_llseek,
.read_iter = generic_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,
.open = ext4_file_open,
.release = ext4_release_file,
.fsync = ext4_sync_file,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.fallocate = ext4_fallocate,
};
//目录文件操作
const struct file_operations ext4_dir_operations = {
.llseek = ext4_dir_llseek,
.read = generic_read_dir,
.iterate = 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,
};
//普通文件inode操作
const struct inode_operations ext4_file_inode_operations = {
.setattr = ext4_setattr,
.getattr = ext4_getattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = ext4_listxattr,
.removexattr = generic_removexattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
.fiemap = ext4_fiemap,
};
/*
* 目录文件的inode操作
*/
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,
.rename2 = ext4_rename2,
.setattr = ext4_setattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = ext4_listxattr,
.removexattr = generic_removexattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
.fiemap = ext4_fiemap,
};
由于目录也是一种文件,而目录操作和普通文件操作不同,所以文件系统需要定义两种file_operations,创建普通文件和目录文件时候都要创建inode对象,inode对象中包含两个重要的成员:i_op和i_fop,分别代表inode_operations和file_operations,要根据不同文件类型,给其inode赋予不同的结构体:
2.vfs调用路径举例
2.1 ls命令
通过strace观察ls命令分两步:1)打开目录 2)读取遍历目录
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
getdents(3, /* 320 entries */, 32768) = 10648
2.1.1 打开目录:
openat对应的操作调用栈可以看到调用路径:vsys_openat ->vfs_open->ext4_dir_open
vfs_open由于是操作的目录文件,触发的是目录的open,代码如下:
static int do_dentry_open(struct file *f,
struct inode *inode,
int (*open)(struct inode *, struct file *),
const struct cred *cred)
{
...
if (!open)
//这里f对应的时候一个目录,所以其f_open对应的是ext4_dir_operations这个file_operations
open = f->f_op->open;
if (open) {
error = open(inode, f);
if (error)
goto cleanup_all;
...
}
内核调用栈:
#0 ext4_dir_open (inode=0xffff88000647c508, filp=0xffff880006baec00) at fs/ext4/dir.c:614
#1 0xffffffff811725ef in do_dentry_open (f=0xffff880006baec00, inode=0xffff88000647c508, open=0xffffffff811e7b58 <ext4_dir_open>, cred=0x1 <irq_stack_union+1>) at fs/open.c:753
#2 0xffffffff8117345c in vfs_open (path=0xffffc9000184fde8, file=0xffff880006baec00, cred=0xffff8800070d1540) at fs/open.c:866
#3 0xffffffff81183ccc in do_last (opened=<optimized out>, op=<optimized out>, file=<optimized out>, nd=<optimized out>) at fs/namei.c:3331
#4 path_openat (nd=0xffffc9000184fde8, op=0xffffc9000184fefc, flags=0) at fs/namei.c:3454
#5 0xffffffff81183f39 in do_filp_open (dfd=105366792, pathname=0xffff880006baec00, op=0xffffc9000184fefc) at fs/namei.c:3489
#6 0xffffffff811737fb in do_sys_open (dfd=-100, filename=0xffff880006baec00 "", flags=624640, mode=1) at fs/open.c:1053
#7 0xffffffff811738c1 in SYSC_openat (mode=<optimized out>, flags=<optimized out>, filename=<optimized out>, dfd=<optimized out>) at fs/open.c:1080
#8 SyS_openat (dfd=-131941289966328, filename=-131941282419712, flags=0, mode=1) at fs/open.c:1074
#9 0xffffffff818c1460 in entry_SYSCALL_64_fastpath () at arch/x86/entry/entry_64.S:204
#10 0x0000000000000006 in irq_stack_union ()
#11 0x0000000000000000 in ?? ()
2.1.2 读取目录:
#0 ext4_readdir (file=0xffff880006bae500, ctx=0xffff88000647c508) at fs/ext4/dir.c:108
#1 0xffffffff81186626 in iterate_dir (file=0xffff880006bae500, ctx=0xffffc9000184fef8) at fs/readdir.c:50
#2 0xffffffff81186ac7 in SYSC_getdents (count=<optimized out>, dirent=<optimized out>, fd=<optimized out>) at fs/readdir.c:230
#3 SyS_getdents (fd=-131941282421504, dirent=-60473114034440, count=32768) at fs/readdir.c:211
#4 0xffffffff818c1460 in entry_SYSCALL_64_fastpath () at arch/x86/entry/entry_64.S:204
#5 0x000000000088ac38 in ?? ()
#6 0x0000000000008041 in exception_stacks ()
Backtrace stopped: not enough registers or memory available to unwind further
某个目录下执行ls命令,触发的时候目录文件的遍历操作,调用的是file_operations ext4_dir_operations的iterate操作,最终调用到ext4_readdir函数。
2.2 mkdir命令
vfs调用入口:
int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
int error = may_create(dir, dentry);
unsigned max_links = dir->i_sb->s_max_links;
if (error)
return error;
if (!dir->i_op->mkdir)
return -EPERM;
mode &= (S_IRWXUGO|S_ISVTX);
error = security_inode_mkdir(dir, dentry, mode);
if (error)
return error;
if (max_links && dir->i_nlink >= max_links)
return -EMLINK;
error = dir->i_op->mkdir(dir, dentry, mode);
if (!error)
fsnotify_mkdir(dir, dentry);
return error;
}
内核调用栈:
(gdb) bt
#0 ext4_mkdir (dir=0xffff880006485588, dentry=0xffff880005a5d900, mode=511) at fs/ext4/namei.c:2638
#1 0xffffffff811805f6 in vfs_mkdir (dir=0xffff880006485588, dentry=0xffff880005a5d900, mode=511) at fs/namei.c:3735
#2 0xffffffff811842ae in SYSC_mkdirat (mode=511, pathname=<optimized out>, dfd=<optimized out>) at fs/namei.c:3758
#3 SyS_mkdirat (dfd=-131941289929336, pathname=-131941300578048, mode=511) at fs/namei.c:3742
#4 0xffffffff811842f7 in SYSC_mkdir (mode=<optimized out>, pathname=<optimized out>) at fs/namei.c:3769
#5 SyS_mkdir (pathname=-131941289929336, mode=-131941300578048) at fs/namei.c:3767
#6 0xffffffff818c1460 in entry_SYSCALL_64_fastpath () at arch/x86/entry/entry_64.S:204
#7 0x00007ffc4362cfe8 in ?? ()
#8 0x0000000000000000 in ?? ()
2.3 cd命令
内核调用栈:
#0 ext4_lookup (dir=0xffff88000647c508, dentry=0xffff88000647c508, flags=3) at fs/ext4/namei.c:1573
#1 0xffffffff8117fc70 in lookup_slow (name=0xffff88000647c508, dir=0xffff880005974000, flags=3) at fs/namei.c:1653
#2 0xffffffff811815e1 in walk_component (nd=0xffffc900000b3de8, flags=0) at fs/namei.c:1774
#3 0xffffffff81181ce1 in lookup_last (nd=<optimized out>) at fs/namei.c:2245
#4 path_lookupat (nd=0xffffc900000b3de8, flags=93798400, path=0xffffc900000b3f20) at fs/namei.c:2257
#5 0xffffffff81182428 in filename_lookup (dfd=105366792, name=0xffff880006b75000, flags=3, path=0xffffc900000b3f20, root=0x656d6f68) at fs/namei.c:2291
#6 0xffffffff81182551 in user_path_at_empty (dfd=-100, name=0xffff88000647c508 "\355A\v", flags=3, path=0xffffc900000b3f20, empty=0x656d6f68) at fs/namei.c:2545
#7 0xffffffff81172fa1 in user_path_at (path=<optimized out>, flags=<optimized out>, name=<optimized out>, dfd=<optimized out>) at ./include/linux/namei.h:55
#8 SYSC_chdir (filename=<optimized out>) at fs/open.c:441
#9 SyS_chdir (filename=-131941289966328) at fs/open.c:435
#10 0xffffffff818c1460 in entry_SYSCALL_64_fastpath () at arch/x86/entry/entry_64.S:204
#11 0x0000000000000009 in irq_stack_union ()