linux系统下inotify源码分析

1.inotify调用

inotify_init:用于创建一个 inotify 实例的系统调用,并返回一个指向该实例的文件描述符。
inotify_add_watch:增加对文件或者目录的监控,并指定需要监控哪些事件。
read:读取包含一个或者多个事件信息的缓存。
inotify_rm_watch:从监控列表中移出监控项目。

2.在系统中的实现。

2.1 inotify头文件定义

2.1.1系统中的定位位置

bionic/tools/versioner/dependencies/common/kernel_uapi/linux/inotify.h

2.1.2定义的实现

#ifndef _UAPI_LINUX_INOTIFY_H
#define _UAPI_LINUX_INOTIFY_H
#include <linux/fcntl.h>
#include <linux/types.h>
struct inotify_event {
    
    
  __s32 wd;
  __u32 mask;
  __u32 cookie;
  __u32 len;
  char name[0];
};
#define IN_ACCESS 0x00000001
#define IN_MODIFY 0x00000002
#define IN_ATTRIB 0x00000004
#define IN_CLOSE_WRITE 0x00000008
#define IN_CLOSE_NOWRITE 0x00000010
#define IN_OPEN 0x00000020
#define IN_MOVED_FROM 0x00000040
#define IN_MOVED_TO 0x00000080
#define IN_CREATE 0x00000100
#define IN_DELETE 0x00000200
#define IN_DELETE_SELF 0x00000400
#define IN_MOVE_SELF 0x00000800
#define IN_UNMOUNT 0x00002000
#define IN_Q_OVERFLOW 0x00004000
#define IN_IGNORED 0x00008000
#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO)
#define IN_ONLYDIR 0x01000000
#define IN_DONT_FOLLOW 0x02000000
#define IN_EXCL_UNLINK 0x04000000
#define IN_MASK_ADD 0x20000000
#define IN_ISDIR 0x40000000
#define IN_ONESHOT 0x80000000
#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | IN_MOVE_SELF)
#define IN_CLOEXEC O_CLOEXEC
#define IN_NONBLOCK O_NONBLOCK
#endif

2.2 inotify_add_watch实现

2.2.1inotify_add_watch.S在系统的位置

bionic/libc/arch-x86/syscalls/inotify_add_watch.S

2.2.2 inotify_add_watch.S具体代码实现

ENTRY(inotify_add_watch)
	pushl   %ebx
	.cfi_def_cfa_offset 8  
	.cfi_rel_offset ebx, 0 
	pushl   %ecx 
	.cfi_adjust_cfa_offset 4  
	.cfi_rel_offset ecx, 0  
	pushl   %edx  
	.cfi_adjust_cfa_offset 4
	.cfi_rel_offset edx, 0
	call    __kernel_syscall 
	pushl   %eax 
	.cfi_adjust_cfa_offset 4 
	.cfi_rel_offset eax, 0
	mov     20(%esp), %ebx
	mov     24(%esp), %ecx
	mov     28(%esp), %edx
	movl    $__NR_inotify_add_watch, %eax 
	call    *(%esp) 
	addl    $4, %esp
	cmpl    $-MAX_ERRNO, %eax 
	jb      1f
	negl    %eax 
	pushl   %eax
	call    __set_errno_internal
	addl    $4, %esp

1:
	popl    %edx
	popl    %ecx
    popl    %ebx
	ret
END(inotify_add_watch)

2.3 inotify_init实现

2.3.1在系统中inotify_init的位置

bionic/libc/arch-x86/syscalls/inotify_init1.S

2.3.2具体的代码实现

ENTRY(inotify_init1)
  mov     ip, r7
 .cfi_register r7, ip
 ldr     r7, =__NR_inotify_init1
 swi     #0
 mov     r7, ip
 .cfi_restore r7
 cmn     r0, #(MAX_ERRNO + 1)
 bxls    lr
 neg     r0, r0  
 b       __set_errno_internal
END(inotify_init1)

2.4inotify_rm_watch 实现

2.4.1系统中定位的位置

bionic/libc/arch-x86/syscalls/inotify_rm_watch.S

2.4.2具体的实现

ENTRY(inotify_rm_watch)
	movl    $__NR_inotify_rm_watch, %eax
	syscall
	cmpq    $-MAX_ERRNO, %rax
	jb      1f
	negl    %eax
	movl    %eax, %edi
	call    __set_errno_internal
1:
    ret
END(inotify_rm_watch)

2.5 inotify调用

2.5.1在系统中的位置

external/strace/tests/inotify.c

2.5.2调用的实现


```cpp
int main(void)
{
    
    
	static const struct {
    
    
		const char *path;
		const char *str;
	} bogus_path_str = {
    
    
		ARG_STR("/abc\1/def\2/ghi\3/jkl\4/mno\5/pqr\6/stu\7/vwx\10") };
	static const kernel_ulong_t bogus_fd =
		(kernel_ulong_t) 0xfffffeedfffffaceULL;
	static const kernel_ulong_t bogus_mask =
		(kernel_ulong_t) 0xffffda7affffdeadULL;
	static const char *bogus_mask_str = "IN_ACCESS|IN_ATTRIB|"
		"IN_CLOSE_WRITE|IN_OPEN|IN_MOVED_TO|IN_DELETE|IN_DELETE_SELF|"
		"IN_MOVE_SELF|IN_Q_OVERFLOW|IN_IGNORED|IN_ONLYDIR|"
		"IN_DONT_FOLLOW|IN_EXCL_UNLINK|IN_MASK_ADD|IN_ISDIR|IN_ONESHOT|"
		"0x18ff1000";

	long rc;
	char *bogus_path = tail_memdup(bogus_path_str.path,
		strlen(bogus_path_str.path) + 1);

	rc = syscall(__NR_inotify_add_watch, 0, NULL, 0);
	printf("inotify_add_watch(0, NULL, 0) = %s\n", sprintrc(rc));

	rc = syscall(__NR_inotify_add_watch, bogus_fd, bogus_path + 4096, 0);
	printf("inotify_add_watch(%d, %p, %u) = %s\n",
	       (int) bogus_fd, bogus_path + 4096, 0, sprintrc(rc));

	rc = syscall(__NR_inotify_add_watch, bogus_fd, bogus_path, bogus_mask);
	printf("inotify_add_watch(%d, %s, %s) = %s\n",
	       (int) bogus_fd, bogus_path_str.str, bogus_mask_str,
	       sprintrc(rc));

	rc = syscall(__NR_inotify_rm_watch, 0, 0);
	printf("inotify_rm_watch(0, 0) = %s\n", sprintrc(rc));

	rc = syscall(__NR_inotify_rm_watch, bogus_fd, bogus_fd);
	printf("inotify_rm_watch(%d, %d) = %s\n",
	       (int) bogus_fd, (int) bogus_fd, sprintrc(rc));

	puts("+++ exited with 0 +++");

	return 0;
}

3.syscall系统调用

Syscall是通过中断方式实现的,ARM平台上通过swi中断来实现系统调用,实现从用户态切换到内核态,发送软中断swi时,从中断向量表中查看跳转代码,其中异常向量表定义在文件/kernelarch/arm/kernel/entry-armv.S(汇编语言文件)。当执行系统调用时会根据系统调用号从系统调用表中来查看目标函数的入口地址,在calls.S文件中声明了入口地址信息。

总体流程:kill() -> kill.S -> swi陷入内核态 -> 从sys_call_table查看到sys_kill -> ret_fast_syscall -> 回到用户态执行kill()下一行代码。

猜你喜欢

转载自blog.csdn.net/c_kongfei/article/details/116747213