当前位置:  技术问答>linux和unix

本文章是我自己写的inode的设计及实现的分析,欢迎大家指教。因论坛不能显示uml图,有兴趣者请同我联系zny_1@sina.com.cn

    来源: 互联网  发布时间:2015-04-28

    本文导语:  inode的设计及实现分析 [摘要]本文将从软件工程的视角来分析Linux中inode的设计和实现,并采用UML标记来表达设计视图。本文试图从详细分析Linux中实现该对象时的考虑和策略来引出一些在内核设计中通用的方法和原理...

inode的设计及实现分析
[摘要]本文将从软件工程的视角来分析Linux中inode的设计和实现,并采用UML标记来表达设计视图。本文试图从详细分析Linux中实现该对象时的考虑和策略来引出一些在内核设计中通用的方法和原理。

[关键字] inode uml 面向对象 状态

[正文]

1、引言
   本文考虑的是内存中的inode对象,Inode作为VFS中的重要对象,其分配、查找、回收等管理策略对整个系统的影响是很大的。一方面,VFS为内核和用户提供了一个统一的接口,对具体的文件系统进行抽象,以统一的数据结构进行管理,从而支持多种文件系统之间的互访问,内核其它子系统也会频繁访问VFS,另一方面,VFS主要功能之一就是管理inode,所以几乎所有的操作都会涉及到inode,因此inode的设计特别是管理方面的设计越发显得重要。本文试图通过分析inode来找到内存对象之间一些共同的地方,为学习和设计内核提供一个参考。

2、inode数据结构
   本文介绍的是最新的linux-2.6.0-test6内核中的inode结构,与以前版本相比变化不是很大,具体如下:

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; /* 文件拥有者标识 */
gid_t i_gid; /* 文件拥有者所在组的标识号 */
dev_t i_rdev; /* 实际设备标识号*/
loff_t i_size; /* 文件的大小(以字节为单位)*/
struct timespec i_atime; /* 文件的最后访问时间 */
struct timespec i_mtime; /* 文件的最后修改时间 */
struct timespec i_ctime; /* 节点的修改时间 */
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 semaphore i_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]; 索引节点的磁盘限额*/
/* These three should probably be a union */
struct list_head i_devices; /* 设备文件形成的链表 */
struct pipe_inode_info *i_pipe;  /* 指向管道文件 */
struct block_device *i_bdev; /* 指向块设备文件的指针 */
struct cdev *i_cdev; /* 指向字符设备文件的指针 */
int i_cindex;

unsigned long i_dnotify_mask; /* 目录事件通知掩码 */ 
struct dnotify_struct *i_dnotify;  /* 目录事件 */

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

unsigned int i_flags; /* 文件系统的安装标志 */
unsigned char i_sock; /* 如果是套接字则为真 */

atomic_t i_writecount; /* 写进程的引用计数 */
void *i_security; /* 
__u32 i_generation; /* 预留 */
union {
void *generic_ip;
} u;
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
};
可以看出inode的数据结构是很复杂的,分析以上各个域,我们可用大致地把他们分成几部分:

2.1描述文件信息的域
   这部分是inode最基本的预,因为inode是与磁盘inode相对应的,而磁盘inode设计来就是标识文件的,它自然要包含描述文件信息的域。这部分最多也是最简单的,与磁盘上的inode基本上都是一一对应的。具体有如下域:i_ino、i_dev、i_mode、i_nlike、i_uid、i_gid、i_rdev、i_size、i_blksize、i_blocks、i_atime、i_mtime、i_ctime、i_version。

2.2用于索引节点操作的域
   该部分都是与Inode的操作相关的。最基本的是 *i_op他是设计改对象时就定的可提供的方法。VFS的设计是按面向对象的方法设计的,但c不提供语言上的oop支持,因此才采用这种方式。作为内存对象设置哪些与操作相关的预,需要考虑几点:

   (1)是否可以对应多个访问对象?如果是自然要设置与访问计数相关的域。Inode可以被若干进程同时访问,而且因为可以建立符号链接和硬链接,所以从不同的路径也可能访问到同一个inode。因此设置了i_count来标识引用该inode的对象个数。另外为了节约内存,在通过不同路径访问同一节点时,只在内存有一个inode对象,因此设置了i_nlink和i_dentry来对链接计数和方便操作。因为可以同时对应多个进程,所以就存在并发访问,即要考虑互斥和同步,为此目的还设置了i_lock、i_sem、*i_wait。如果看内核中的别的模块代码会发现几乎所有内存对象有此要求时都会设置这些类似的域。

   (2)是否与存储在别的介质中的数据有对应关系?很明显,如果有那一定要考虑如何同步,如何防止提供给访问对象脏数据。I_dirty就是用来表明数据已经是脏的,当然不同内存对象可能使用的策略不同,在inode中为此目的还特设了一个脏索引节点链表,为了加快更新是每个超级块中设了一个s_dirty域。

   另外同节点操作有关的还有*i_flock、*i_dquot[MAXQUOTAS]两个域来完成文件锁和磁盘限额管理。

2.3与高速缓存管理相关的域
   我们都知道VFS是采用oop的方法设计的,inode作为一个对象就一定有她的生命周期也就是可以用状态图来表达,我们先看下下面的inode状态图。
 (sorry此处的uml图没法显示)
Inode具有如下几个状态:
(1)inuse状态:处于该状态的inode是有效的节点,表明至少有一个对象正在在使用该inode。该Inode的i_count > 0并且 i_nlink > 0,刚分配的Inode都是处于该状态,因为inode的分配一定源于某个进程对iget()的调用。
(2)unused状态:处于改状态的inode包含的数据也是有效的,她是曾经被使用过的,现在暂时还没有对象要使用的inode。因此其域i_count = 0。
(3)dirty状态:处于改状态的inode所包含的数据就是脏的,一般是因为写操作造成的,正等待内核将其写回到磁盘或别的存储介质上,以保持同步。该inode的i_count>0、i_nlink>0同时i_state&dirty。我们知道VFS设计来就是可以访问各个不同的磁盘文件系统,但不同的文件系统可能读写操作不同,为了加快同步的速度,VFS特别给每个超级块都设了一个sb->s_dirty链表,来保存这些脏inode。
(4)buffered状态:该状态不同于其它三种,其它三种状态下inode的数据都是有效的,唯独该状态inode没有有效数据。

   上面的状态图只是一个inode的状态图。但实际上在运行时,系统会动态构造或析构大量的inode对象。所以针对每个状态都存在一个集会,在Linux内核中表达集合的最常用方法就是struct list_head结构:该结构的定义如下:
struct list_head {
struct list_head *next, *prev;
};
   在需要作为集合管理的内核对象中都少不了定义至少一个list_head结构的域,inode中是i_list。从而把这些处于某状态的inode组织成了一个双向循环链表,当然每个链表都应该有表首。
   全局变量inode_in_use、inode_unused就是这样的表首,dirty链表如前所述设在每个超级块中。另外因为实际运行时的inode数量是大量的,所以内核对所有这类对象都设置了哈希表,以加快查找。Inode中的相关域是i_hash,对应全局哈希表inode_hashtable。比较特别的是对于不属于任何超级块的inode即inode->i_sb==NULL的节点是存放在anon_hash_chain中的,比如通过sock_alloc()分配的节点。而buffered inode则是放在由inode_cachep所指的slab高速缓存中。
由状态图可知一个inode对象同时只能处于三种状态中的一种,所以只设了一个i_list域。

2.4其它域
    剩下的域还有用于分页管理,特殊文件管理等等,都比较容易理解。值得提一下的是i_dnotify_mask和*i_dnotify这两个域提供了一个机制在目录被操作时可以通知相应的进程,这种事件驱动的机制在软件设计中大量采用,可以简化程序的设计。比如一个进程在读某个目录下的所有目录项,而另一个进程增加或删除了其中某几项,如果没有这种事件驱动机制,该进程只有在下次重读该目录节点时才会得到正确的结果,问题是该进程认为数据是对的也不会主动去重读,而有了这种事件驱动机制后就可以马上进行更新。


|
关注,共同研究ing

    
 
 

您可能感兴趣的文章:

 
本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • unable to read inode block - inode
  • Inode(索引节点)中是否包含分区标示?
  • inode被耗尽!高手求救!
  • inode在哪里初始化
  • Open函数的inode疑问
  • file结构和inode结构
  • 请问:我想根据 文件 的 inode number 删除文件,应该怎么办。非常感谢。
  • 请问为什么用vi会改变文件的inode?
  • ubuntu用iNode联网的问题!
  • 关于无名管道释放后,inode节点释放的问题
  • 文件inode的疑问。。
  • 如何通过inode查找文件?
  • 初用Linux关于iNode客户端的疑问
  • inode的链接计数器(Link Count)出错,会造成什么后果?
  • 什么是inode节点
  • 在scull.c中,是怎样找到inode 的
  • /sys 和 /proc 的inode number怎么都是1?
  • struct inode 里的u 呢???
  • PCI驱动程序的是不是可以不要file_operations;file;inode?
  • inode,file,file_operations类型问题


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3