分析getdents64系统调用
在头文件include/uapi/asm-generic/unistd.h 中是所有内核支持的系统调用。通过_SYSCALL宏来定义。
#ifndef __SYSCALL
#define __SYSCALL(x, y)
#endif
/* fs/readdir.c */
#define __NR_getdents64 61
__SYSCALL(__NR_getdents64, sys_getdents64)
arch/arm64/kernel/sys.c
#undef __SYSCALL #define __SYSCALL(nr, sym) asmlinkage long __arm64_##sym(const struct pt_regs *); #include#undef __SYSCALL #define __SYSCALL(nr, sym) [nr] = __arm64_##sym, const syscall_fn_t sys_call_table[__NR_syscalls] = { [0 ... __NR_syscalls - 1] = __arm64_sys_ni_syscall, #include //arch/arm64/include/asm/unistd.h }; include包含:
arch/arm64/include/asm/unistd.h
arch/arm64/include/uapi/asm/unistd.h
include/uapi/asm-generic/unistd.h
系统调用的具体实现通过SYSCALL_DEFINEx宏定义:
linux/syscalls.h
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__) #define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__) #define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__) #define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__) #define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__) #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) #define SYSCALL_DEFINE_MAXARGS 6 #define SYSCALL_DEFINEx(x, sname, ...) \ SYSCALL_METADATA(sname, x, __VA_ARGS__) \ __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
__SYSCALL_DEFINEx:
arch/arm64/include/asm/syscall_wrapper.h
#define __SYSCALL_DEFINEx(x, name, ...) \
asmlinkage long __arm64_sys##name(const struct pt_regs *regs); \
ALLOW_ERROR_INJECTION(__arm64_sys##name, ERRNO); \
static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \
static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
asmlinkage long __arm64_sys##name(const struct pt_regs *regs) \
{ \
return __se_sys##name(SC_ARM64_REGS_TO_ARGS(x,__VA_ARGS__)); \
} \
static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
{ \
long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \
__MAP(x,__SC_TEST,__VA_ARGS__); \
__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \
return ret; \
} \
static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
定义fs/readdir.c
SYSCALL_DEFINE3(getdents64, unsigned int, fd,
struct linux_dirent64 __user *, dirent, unsigned int, count)
{
return ksys_getdents64(fd, dirent, count);
}
展开后:
asmlinkage long __arm64_sysgetdents64(...)定义了一个函数和__SYSCALL宏申明的一致
asmlinkage long __arm64_sysgetdents64(...)
{
......省略内容.......
}static long __se_sysgetdents64(...)
{
......省略内容.......
}static inline long __do_sysgetdents64(__MAP(x,__SC_DECL,__VA_ARGS__))
下面是实现的部分在{}中
{return ksys_getdents64(fd, dirent, count);
}
ls命令的测试:
ls实际上使用的就是getdents64系统调用
[root@localhost ~]# ls /proc
[ 954.398303] ===proc_readdir_de
[ 954.398309] CPU: 3 PID: 1197 Comm: ls Not tainted 4.19.0-fix-full-10+ #38
[ 954.408129] Hardware name: PHYTIUM LTD D2000/D2000, BIOS
[ 954.413601] Call trace:
[ 954.416039] dump_backtrace+0x0/0x1b8
[ 954.419688] show_stack+0x24/0x30
[ 954.422992] dump_stack+0x90/0xb4
[ 954.426296] proc_readdir_de+0x29c/0x2a0
[ 954.430205] proc_readdir+0x30/0x40
[ 954.433681] proc_root_readdir+0x34/0x60
[ 954.437592] iterate_dir+0x8c/0x1a8
[ 954.441067] ksys_getdents64+0xa4/0x190
[ 954.444890] __arm64_sys_getdents64+0x28/0x38
[ 954.449234] el0_svc_handler+0x84/0x140
[ 954.453057] el0_svc+0x8/0xc
上述/proc根目录是静态定义的proc_dir_entry :fs/proc/root.c
static const struct file_operations proc_root_operations = {
.read = generic_read_dir,
.iterate_shared = proc_root_readdir,
.llseek = generic_file_llseek,
};
/*
* proc root can do almost nothing..
*/
static const struct inode_operations proc_root_inode_operations = {
.lookup = proc_root_lookup,
.getattr = proc_root_getattr,
};
/*
* This is the root "inode" in the /proc tree..
*/
struct proc_dir_entry proc_root = {
.low_ino = PROC_ROOT_INO,
.namelen = 5,
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
.nlink = 2,
.refcnt = REFCOUNT_INIT(1),
.proc_iops = &proc_root_inode_operations,
.proc_fops = &proc_root_operations,
.parent = &proc_root,
.subdir = RB_ROOT,
.name = "/proc",
};
目录的iterate_shared函数是generic_read_dir。
创建proc文件目录接口proc_mkdir:fs/proc/generic.c
static const struct file_operations proc_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.iterate_shared = proc_readdir,
};
struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode,
struct proc_dir_entry *parent, void *data)
{
struct proc_dir_entry *ent;
if (mode == 0)
mode = S_IRUGO | S_IXUGO;
ent = __proc_create(&parent, name, S_IFDIR | mode, 2);
if (ent) {
ent->data = data;
ent->proc_fops = &proc_dir_operations; -------对应目录默认的f_ops: proc_dir_operations
ent->proc_iops = &proc_dir_inode_operations;
parent->nlink++;
ent = proc_register(parent, ent);
if (!ent)
parent->nlink--;
}
return ent;
}
EXPORT_SYMBOL_GPL(proc_mkdir_data);
struct proc_dir_entry *proc_mkdir_mode(const char *name, umode_t mode,
struct proc_dir_entry *parent)
{
return proc_mkdir_data(name, mode, parent, NULL);
}
EXPORT_SYMBOL(proc_mkdir_mode);
struct proc_dir_entry *proc_mkdir(const char *name,
struct proc_dir_entry *parent)
{
return proc_mkdir_data(name, 0, parent, NULL);
}
EXPORT_SYMBOL(proc_mkdir);