分类: LINUX
2009-04-22 11:42:41
在中,内核使用到了面向对象的思想来应对各种不同格式的的处理,它的一些结构的巧妙的使用,使得C这个典型结构化设计的语言也很灵活的实现了面向对象的要求,从而完美的了不同系统不同应对措施。而一些结构的巧妙设计是实现这种目的很重要的基石,因此有必要看看VFS中重要
的数据结构是怎么设计的,下面我会就两个数据结构进行分析。
索引节点是文件系统中的基本对象。它可以是一个正常文件,一个目录,一个符号链接,或者是其他什么东西。VFS并不明显地区分这些对象,而把它们留给真正的文件系统,让它们自己实现适宜的行为。从而使内核的高层子系统对于
不同的对象区别对待。
流程:
1.先看结构体
它是对具体文件的抽象,它封装了一个具体文件常有的属性和操作。
编写驱动的人应该对它比较有兴趣,它直接映射到供了关于特别设备文件/dev/driver(假设此设备名为driver)的信息。下面看内核对它结构的设计。
/*
*索引节点对象由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 *);
/*该函数从给定文件中删除指定的属性*/
};
对具体的一个文件,我们常有的操作有:
创建一个文件(对应的是create()这个系统调用或者是touch又或者是以写的模式调用open())那具体的内核是怎么做的呢,首先先“化”一个inode的对象,接着对它具体的操作函数集的哪个成员进行初始化,对应创建文件的就是int (*create) (struct inode *, struct dentry *,int);这个成员了,那根据具体的文件去具体的实现它了,这就是“实现接口”,从而达到“多态”的目的。(这里使用了面向对象的思想来说明了内核是怎么具体实现新的文件的创建的,至于其他的操作也是一样的,这里不在进行更多的说明了)。具体相识的是改变文件的大小、
修改时间、拷贝等。
注:此文为转载!