Linux has kernel file operation functions. For example, the filp_open() function can be used to open files, the vfs_read() function can be used to read files, the vfs_write() function can be used to write files, and the filp_close() function can be used to close files. . In the vfs_read and vfs_write functions, the second parameter points to the memory address of the user space. If the kernel space pointer is used directly, "-EFALUT" will be returned.
#The operating environment of this tutorial: linux7.3 system, Dell G3 computer.
1. Kernel space file operation
Function | Function prototype |
---|---|
Open file | struct file *filp_open(const char *filename, int flags, int mode) |
Read file | ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) |
Write file | ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) |
Close file | int filp_close(struct file *filp, fl_owner_t id) |
2. Kernel space and user space
In the vfs_read and vfs_write functions, the The memory address of user space pointed to by parameter buf. If we directly use the pointer of kernel space, -EFALUT will be returned. This is because the buffer used exceeds the user space address range. General system calls will require that the buffer you use cannot be in the kernel area. This can be solved using set_fs(), get_fs()
.
In include/asm/uaccess.h
, there is the following definition:
#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) #define USER_DS MAKE_MM_SEG(PAGE_OFFSET) #define get_ds() (KERNEL_DS) #define get_fs() (current->addr_limit) #define set_fs(x) (current->addr_limit = (x))
If used, it is as follows:
mm_segment_t fs = get_fs(); set_fs(KERNEL_FS); //vfs_write(); vfs_read(); set_fs(fs);
Detailed explanation: System calls are originally provided to user-space programs for access. Therefore, for the parameters passed to it (such as the above buf), it will be considered to come from user-space by default. In read or write () function, in order to protect the kernel space, the value obtained by get_fs()
is generally used to compare with USER_DS, thereby preventing user space programs from "deliberately" destroying the kernel space; now it is used in the kernel space System call. At this time, the parameter address passed to read or write() is the address of the kernel space. It is above USER_DS (USER_DS ~ KERNEL_DS). If no other processing is done, the address will be considered in the write() function. It exceeds the scope of USER_DS, so it will be considered as "deliberate destruction" of the user space, and further execution is not allowed; in order to solve this problemset_fs(KERNEL_DS)
expand the space limit that it can access to KERNEL_DS, so You can now use system calls in the kernel smoothly!
3.Linux struct inode structure
/*索引节点对象由inode结构体表示,定义文件在linux/fs.h中 */ struct inode { struct hlist_node i_hash; /* 哈希表 */ struct list_head i_list; /* 索引节点链表 */ struct list_head i_dentry; /* 目录项链表 */ unsigned long i_ino; /* 节点号 */ atomic_t i_count; /* 引用记数 */ umode_t i_mode; /* 访问权限控制 */ unsigned int i_nlink; /* 硬链接数 */ uid_t i_uid; /* 使用者id */ gid_t i_gid; /* 使用者id组 */ kdev_t i_rdev; /* 实设备标识符 */ loff_t i_size; /* 以字节为单位的文件大小 */ struct timespec i_atime; /* 最后访问时间 */ struct timespec i_mtime; /* 最后修改(modify)时间 */ struct timespec i_ctime; /* 最后改变(change)时间 */ unsigned int i_blkbits; /* 以位为单位的块大小 */ unsigned long i_blksize; /* 以字节为单位的块大小 */ unsigned long i_version; /* 版本号 */ unsigned long i_blocks; /* 文件的块数 */ unsigned short i_bytes; /* 使用的字节数 */ spinlock_t i_lock; /* 自旋锁 */ struct rw_semaphore i_alloc_sem; /* 索引节点信号量 */ struct inode_operations *i_op; /* 索引节点操作表 */ struct file_operations *i_fop; /* 默认的索引节点操作 */ struct super_block *i_sb; /* 相关的超级块 */ struct file_lock *i_flock; /* 文件锁链表 */ struct address_space *i_mapping; /* 相关的地址映射 */ struct address_space i_data; /* 设备地址映射 */ struct dquot *i_dquot[MAXQUOTAS]; /* 节点的磁盘限额 */ struct list_head i_devices; /* 块设备链表 */ struct pipe_inode_info *i_pipe; /* 管道信息 */ struct block_device *i_bdev; /* 块设备驱动 */ unsigned long i_dnotify_mask; /* 目录通知掩码 */ struct dnotify_struct *i_dnotify; /* 目录通知 */ unsigned long i_state; /* 状态标志 */ unsigned long dirtied_when; /* 首次修改时间 */ unsigned int i_flags; /* 文件系统标志 */ unsigned char i_sock; /* 可能是个套接字吧 */ atomic_t i_writecount; /* 写者记数 */ void *i_security; /* 安全模块 */ __u32 i_generation; /* 索引节点版本号 */ union { void *generic_ip; /* 文件特殊信息 */ } u; }; /* *索引节点的操作inode_operations定义在linux/fs.h中 */ struct inode_operations { int (*create) (struct inode *, struct dentry *,int); /*VFS通过系统调用create()和open()来调用该函数,从而为dentry对象创建一个新的索引节点。在创建时使用mode制定初始模式*/ struct dentry * (*lookup) (struct inode *, struct dentry *); /*该韩式在特定目录中寻找索引节点,该索引节点要对应于dentry中给出的文件名*/ int (*link) (struct dentry *, struct inode *, struct dentry *); /*该函数被系统调用link()电泳,用来创建硬连接。硬链接名称由dentry参数指定,连接对象是dir目录中ld_dentry目录想所代表的文件*/ int (*unlink) (struct inode *, struct dentry *); /*该函数被系统调用unlink()调用,从目录dir中删除由目录项dentry制动的索引节点对象*/ int (*symlink) (struct inode *, struct dentry *, const char *); /*该函数被系统电泳symlik()调用,创建符号连接,该符号连接名称由symname指定,连接对象是dir目录中的dentry目录项*/ int (*mkdir) (struct inode *, struct dentry *, int); /*该函数被mkdir()调用,创建一个新鲁姆。创建时使用mode制定的初始模式*/ int (*rmdir) (struct inode *, struct dentry *); /*该函数被系统调用rmdir()调用,删除dir目录中的dentry目录项代表的文件*/ int (*mknod) (struct inode *, struct dentry *, int, dev_t); /*该函数被系统调用mknod()调用,创建特殊文件(设备文件、命名管道或套接字)。要创建的文件放在dir目录中,其目录项问dentry,关联的设备为rdev,初始权限由mode指定*/ int (*rename) (struct inode *, struct dentry *, struct inode *, struct dentry *); /*VFS调用该函数来移动文件。文件源路径在old_dir目录中,源文件由old_dentry目录项所指定,目标路径在new_dir目录中,目标文件由new_dentry指定*/ int (*readlink) (struct dentry *, char *, int); /*该函数被系统调用readlink()调用,拷贝数据到特定的缓冲buffer中。拷贝的数据来自dentry指定的符号链接,最大拷贝大小可达到buflen字节*/ int (*follow_link) (struct dentry *, struct nameidata *); /*该函数由VFS调用,从一个符号连接查找他指向的索引节点,由dentry指向的连接被解析*/ int (*put_link) (struct dentry *, struct nameidata *); /*在follow_link()调用之后,该函数由vfs调用进行清楚工作*/ void (*truncate) (struct inode *); /*该函数由VFS调用,修改文件的大小,在调用之前,索引节点的i_size项必须被设置成预期的大小*/ int (*permission) (struct inode *, int); /*该函数用来检查给低昂的inode所代表的文件是否允许特定的访问模式,如果允许特定的访问模式,返回0,否则返回负值的错误码。多数文件系统 都将此区域设置为null,使用VFS提供的通用方法进行检查,这种检查操作仅仅比较索引及诶但对象中的访问模式位是否和mask一致,比较复杂的系统, 比如支持访问控制链(ACL)的文件系统,需要使用特殊的permission()方法*/ int (*setattr) (struct dentry *, struct iattr *); /*该函数被notify_change调用,在修改索引节点之后,通知发生了改变事件*/ int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *); /*在通知索引节点需要从磁盘中更新时,VFS会调用该函数*/ int (*setxattr) (struct dentry *, const char *, const void *, size_t, int); /*该函数由VFS调用,向dentry指定的文件设置扩展属性,属性名为name,值为value*/ ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); /*该函数被VFS调用,向value中拷贝给定文件的扩展属性name对应的数值*/ ssize_t (*listxattr) (struct dentry *, char *, size_t); /*该函数将特定文件所有属性别表拷贝到一个缓冲列表中*/ int (*removexattr) (struct dentry *, const char *); /*该函数从给定文件中删除指定的属性*/ };
4.Linux struct file structure
The struct file structure is defined in /linux/include/linux/fs.h (Linux 2.6.11 kernel), and its prototype is:
struct file { /* * fu_list becomes invalid after file_free is called and queued via * fu_rcuhead for RCU freeing */ union { struct list_head fu_list; struct rcu_head fu_rcuhead; } f_u; struct path f_path; #define f_dentry f_path.dentry #define f_vfsmnt f_path.mnt const struct file_operations *f_op; atomic_t f_count; unsigned int f_flags; mode_t f_mode; loff_t f_pos; struct fown_struct f_owner; unsigned int f_uid, f_gid; struct file_ra_state f_ra; unsigned long f_version; #ifdef CONFIG_SECURITY void *f_security; #endif /* needed for tty driver, and maybe others */ void *private_data; #ifdef CONFIG_EPOLL /* Used by fs/eventpoll.c to link all the hooks to this file */ struct list_head f_ep_links; spinlock_t f_ep_lock; #endif /* #ifdef CONFIG_EPOLL */ struct address_space *f_mapping; };
The file structure represents an open file, in the system Every open file has an associated struct file in kernel space. It is created by the kernel when a file is opened and passed to any function that operates on the file. The kernel releases this data structure after all instances of the file have been closed. In the kernel creation and driver source code, the pointer of struct file is usually named file or filp.
Related recommendations: "Linux Video Tutorial"
The above is the detailed content of Does Linux have kernel file operation functions?. For more information, please follow other related articles on the PHP Chinese website!