linux有没有内核文件操作函数

72次阅读
没有评论

共计 6624 个字符,预计需要花费 17 分钟才能阅读完成。

这篇文章主要介绍“linux 有没有内核文件操作函数”,在日常操作中,相信很多人在 linux 有没有内核文件操作函数问题上存在疑惑,丸趣 TV 小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”linux 有没有内核文件操作函数”的疑惑有所帮助!接下来,请跟着丸趣 TV 小编一起来学习吧!

linux 有内核文件操作函数,例 filp_open()函数可用于打开文件、vfs_read()函数可用于读取文件、vfs_write()函数可用于写文件、filp_close()函数可用于关闭文件。在 vfs_read 和 vfs_write 函数中,其第二个参数指向的用户空间的内存地址,如果直接使用内核空间的指针,则会返回“-EFALUT”。

1. 内核空间文件操作

功能函数原型打开文件 struct file *filp_open(const char *filename, int flags, int mode)读文件 ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)写文件 ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)关闭文件 int filp_close(struct file *filp, fl_owner_t id)

2. 内核空间与用户空间

在 vfs_read 和 vfs_write 函数中,其参数 buf 指向的用户空间的内存地址,如果我们直接使用内核空间的指针,则会返回 -EFALUT。这是因为使用的缓冲区超过了用户空间的地址范围。一般系统调用会要求你使用的缓冲区不能在内核区。这个可以用 set_fs()、get_fs()来解决。

在 include/asm/uaccess.h 中,有如下定义:

#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))

如果使用,如下:

mm_segment_t fs = get_fs();
set_fs(KERNEL_FS);
//vfs_write();
vfs_read();
set_fs(fs);

详尽解释:系统调用本来是提供给用户空间的程序访问的,所以,对传递给它的参数(比如上面的 buf),它默认会认为来自用户空间,在 read 或 write()函数中,为了保护内核空间,一般会用 get_fs()得到的值来和 USER_DS 进行比较,从而防止用户空间程序“蓄意”破坏内核空间;而现在要在内核空间使用系统调用,此时传递给 read 或 write()的参数地址就是内核空间的地址了,在 USER_DS 之上 (USER_DS ~ KERNEL_DS),如果不做任何其它处理,在 write() 函数中,会认为该地址超过了 USER_DS 范围,所以会认为是用户空间的“蓄意破坏”,从而不允许进一步的执行;为了解决这个问题 set_fs(KERNEL_DS)将其能访问的空间限制扩大到 KERNEL_DS, 这样就可以在内核顺利使用系统调用了!

3.Linux struct inode 结构

/* 索引节点对象由 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 结构
struct file 结构体定义在 /linux/include/linux/fs.h(Linux 2.6.11 内核) 中,其原型是:

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;
};

文 件结构体代表一个打开的文件,系统中的每个打开的文件在内核空间都有一个关联的 struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核创建和驱动源码 中,struct file 的指针通常被命名为 file 或 filp。

到此,关于“linux 有没有内核文件操作函数”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注丸趣 TV 网站,丸趣 TV 小编会继续努力为大家带来更多实用的文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-12发表,共计6624字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)