8.2.2  VFS的索引节点

文件系统处理文件所需要的所有信息都放在称为索引节点的数据结构中。文件名可以随时更改,但是索引节点对文件是唯一的,并且随文件的存在而存在。有关使用索引节点的原因将在下一章中进一步介绍,这里主要是强调一点,具体文件系统的索引节点是存储在磁盘上的,是一种静态结构,要使用它,必须调入内存,填写VFS的索引节点,因此,也称VFS索引节点是动态节点。这里用VFS索引节点来避免与下一章的Ext2索引节点混淆。VFS索引节点的数据结构inode/includ/fs/fs.h中定义如下(2.4.x版本):

 

 struct inode

{

   /**********描述索引节点高速缓存管理的域****************/

 struct list_head        i_hash;  *指向哈希链表的指针*/

 struct list_head        i_list;  /*指向索引节点链表的指针*/

 struct list_head        i_dentry;/*指向目录项链表的指针*/

     

 struct list_head        i_dirty_buffers;

 struct list_head        i_dirty_data_buffers;

 /**********描述文件信息的域****************/  

   unsigned long   i_ino;            /*索引节点号*/

   kdev_t      i_dev;           /*设备标识号 */

  umode_t      i_mode;         /*文件的类型与访问权限 */

  nlink_t      i_nlink;         /*与该节点建立链接的文件数 */

   uid_t       i_uid;            /*文件拥有者标识号*/

   gid_t       i_gid;             /*文件拥有者所在组的标识号*/

      kdev_t          i_rdev;           /*实际设备标识号*/

   off_t       i_size;            /*文件的大小(以字节为单位)*/

   unsigned long   i_blksize;        /*块大小*/

   unsigned long   i_blocks;         /*该文件所占块数*/

  time_t       i_atime;          /*文件的最后访问时间*/

   time_t      i_mtime;         /*文件的最后修改时间*/

   time_t      i_ctime;          /*节点的修改时间*/ 

   unsigned long   i_version;        /*版本号*/

  struct semaphore   i_zombie;   /*僵死索引节点的信号量*/

 

/***********用于索引节点操作的域*****************/

struct inode_operations  *i_op;  /*索引节点的操作*/

struct super_block   *i_sb;     /*指向该文件系统超级块的指针 */

    atomic_t     i_count;     /*当前使用该节点的进程数。计数为0

表明该节点可丢弃或被重新使用 */

  struct file_operations  *i_fop;  /*指向文件操作的指针 */

 

   unsigned char      i_lock;            /*该节点是否被锁定,用于同步操作中*/  

 struct semaphore     i_sem;            /*指向用于同步操作的信号量结构*/    

 wait_queue_head_t   *i_wait;         /*指向索引节点等待队列的指针*/              

 unsigned char           i_dirt;         /*表明该节点是否被修改过,若已被修改,

                         则 应当将该节点写回磁盘*/

struct file_lock        *i_flock;      /*指向文件加锁链表的指针*/

struct dquot            *i_dquot[MAXQUOTAS]; /*索引节点的磁盘限额*/

/************用于分页机制的域**********************************/ 

struct address_space    *i_mapping; * 把所有可交换的页面管理起来*/

     struct address_space    i_data;   

 

/**********以下几个域应当是联合体****************************************/

   struct list_head        i_devices;   /*设备文件形成的链表*/

   struct pipe_inode_info  i_pipe;     /*指向管道文件*/

   struct block_device     *i_bdev;   /*指向块设备文件的指针*/

   struct char_device      *i_cdev; /*指向字符设备文件的指针*/

 

/*************************其他域***************************************/

unsigned long           i_dnotify_mask; /* Directory notify events */

struct dnotify_struct   *i_dnotify; /* for directory notifications */

 

unsigned long           i_state;    /*索引节点的状态标志*/

unsigned int            i_flags;    /*文件系统的安装标志*/

unsigned char           i_sock;     /*如果是套接字文件则为真*/

atomic_t                i_writecount; /*写进程的引用计数*/

unsigned int            i_attr_flags; /*文件创建标志*/

__u32                   i_generation  /*为以后的开发保留*/

/*************************各个具体文件系统的索引节点********************/

union                             /*类似于超级块的一个共用体,其成员是各种具体文件系统的fsname_inode_info数据结构 */                                                                              

}

 

inode数据结构的进一步说明

·      每个文件都有一个inode,每个inode有一个索引节点号i_ino。在同一个文件系统中,每个索引节点号都是唯一的,内核有时根据索引节点号的哈希值查找其inode结构。

·      每个文件都有个文件主,其最初的文件主是创建了这个文件的用户,但以后可以改变。每个用户都有一个用户组,且属于某个用户组,因此,inode结构中就有相应的i_uidi_gid,以指明文件主的身份。

·      inode 中有两个设备号,i_devi_rdev。首先,除特殊文件外,每个节点都存储在某个设备上,这就是i_dev。其次,如果索引节点所代表的并不是常规文件,而是某个设备,那就还得有个设备号,这就是i_rdev

·      每当一个文件被访问时,系统都要在这个文件的inode中记下时间标记,这就是inode中与时间相关的几个域。

·      每个索引节点都会复制磁盘索引节点包含的一些数据,比如文件占用的磁盘块数。如果i_state域的值等于I_DIRTY,该索引节点就是“脏”的,也就是说,对应的磁盘索引节点必须被更新。i_state域的其它值有I_LOCK(这意味着该索引节点对象已加锁),I_FREEING(这意味着该索引节点对象正在被释放)。每个索引节点对象总是出现在下列循环双向链表的某个链表中:

(1) 未用索引节点链表。变量inode_unusednext  prev域分别指向该链表中的首元素和尾元素。这个链表用做内存高速缓存。

(2) 正在使用索引节点链表。变量inode_in_use指向该链表中的首元素和尾元素

(3) 脏索引节点链表。由相应超级块的s_dirty域指向该链表中的首元素和尾元素

这三个链表都是通过索引节点的i_list域链接在一起的。

·      属于“正在使用”或“脏”链表的索引节点对象也同时存放在一个称为inode_hashtable链表中。哈希表加快了对索引节点对象的搜索,前提是系统内核要知道索引节点号及对应文件所在文件系统的超级块对象的地址。由于散列技术可能引发冲突,所以,索引节点对象设置一个i_hash域,其中包含向前和向后的两个指针,分别指向散列到同一地址的前一个索引节点和后一个索引节点;该域由此创建了由这些索引节点组成的一个双向链表。

 

    与索引节点关联的方法也叫索引节点操作,由inode_operations结构来描述,该结构的地址存放在i_op域中,该结构也包括一个指向文件操作方法的指针(参见下一节“文件对象”)。