2011-7-10 15:27:45

来源:互联网 发布:滑板价格淘宝网 编辑:程序博客网 时间:2024/06/12 03:44


2011-7-10 15:27:45

虚拟文件系统介绍

Linux支持各种文件系统,Linux内核通过虚拟文件系统了对各种文件系统共性的进行抽象,并对外提供统一接口,从面向对象编程的角度来看,

称为抽象文件系统更为合适。虚拟文件系统(VFS virtual file system)用来管理挂接(mount)各种具体文件系统(如:ext4文件系统)。

具体的文件系统可设计成可加载模块,在系统需要时进行加载,例如VFAT就被实现成一个模块,当挂接VFAT文件系统时VFAT文件系统模块将被加载。

挂接具体文件系统时,VFS读取它的超级块,得到具体文件系统的拓扑结构并将这些信息映射到VFS超级块结构中。

当进程或shell命令(如:ls)访问目录和文件时,shell命令及应用程序分解成系统调用,系统调用进入内核空间,遍历虚拟文件系统的VFS节点(inode),
而VFS节点指向了具体文件系统的节点,通过底层块I/O函数调用IDE接口,然后再通过块驱动程序访问块设备(如:硬盘),得到了文件数据。
文件系统的运行流程示意图如图7-1。

虚拟文件系统对文件系统共有的内核上层及底层部分进行了处理,上层处理如:文件路径的查找、文件的读写操作从用户空间向下传递到具体文件系统的部分;

底层进行各种缓存的处理,如:块缓存(buffer)。

虚拟文件系统机制
虚拟文件系统是文件系统共性的抽象,由超级块(superblock)、索引节点(inode)、文件(file)、目录 (dentry)对象组成,每个对象用数据结构进行描述。
它通过系统调用向用户空间提供了API操作文件系统,通过对象操作函数API调用具体文件系统的函数进行读写文件操作。 虚拟文件系统的对象说明如下:

超级块
超级块存放已安装文件系统的信息,与具体文件系统的超级块相对应。超级块由超级块对象结构super_block和超级块操作函数集结构super_operation组成。

索引节点
索引节点存放文件的通用信息,索引节点由索引节点对象结构inode和每个索引节点对象和索引节点操作函数集结构inode_operation组成。每个节点有一个节点号,
用于惟一地标识文件系统中的文件。

文件
文件对象描述了进程与打开文件之间交互过程的信息,目录文件存放目录中的文件列表信息。文件由文件对象结构file和文件操作函数集结构file operation组成。
文件对象的文件指针描述了文件中当前操作的位置,几个进程可以并发访问同一个文件。

目录条目(dentry)
文件系统的每个目录用目录条目对象结构dentry描述。例如,在查找/tmp/test/目录时,VFS为根目录"/"创建一个目录条目对象,

为tmp目录创建一个第二级目录条目对象,为test目录创建一个第三级目录条目对象。 目录条目对象在磁盘上并没有对应的映像,每个具体文件系统都有独特的
方式将目录条目信存放在磁盘上。

VFS数据结构
VFS的数据结构定义了VFS对象和对象的操作函数集,它们是一个接口标准,具体文件系统必须提供VFS接口标准对应的数据结构和操作函数。体文件系统在使用前,必须将自己的结构及操作函数映射到VFS中,这样被访问到。

超级块


超级块对象
VFS用超级块结构super_block描述整个文件系统信息,包括具体文件系统类型、起始级块操作函数、根目录、设备序号、等待队列、具体文件系统信息等数据。超级块是各种具体逻辑文件系统(如:ext4)在挂接时建立的,并在这些文件系统卸载时自动删除, 超级块确实只存在内存中,超级块是针对具体逻辑文件系统的。

每个具体文件系统挂接时,用具体文件系统的信息填充一个超级块结构实例,每个已挂接的文件系统有一个超级块对象,所有挂接文件系统的超级块对象链接成链表。

通常每个具体的文件系统有一个超级块信息结构,如:ext4_sb_info,超级块通过指针s_fs_info指向它。

超级块结构super_block列出如下(在include/linux/fs.h中):
struct super_block {
 struct list_head s_list;  /*超级块链表,必须在结构的最前面 */
/*包含该逻辑文件系统的块设备标识号。如:/dev/hda1设备标识符为0x301*/
 dev_t   s_dev;  
    /*该逻辑文件系统中数据块的大小,以字节为单位*/
 unsigned long  s_blocksize;
    /*块大小的值占用的位数,如:1024字节时为10位*/
 unsigned char  s_blocksize_bits;
    /*脏位,若置该位,表明该超级块已被修改*/
 unsigned char  s_dirt;
 unsigned long long s_maxbytes; /*最大文件长度*/
 struct file_system_type *s_type; /*文件系统类型*/
 const struct super_operations *s_op;  /*特定逻辑文件系统的超级块操作函数集*/
 struct dquot_operations *dq_op;  /*特定逻辑文件系统的限额操作函数集*/
  struct quotactl_ops *s_qcop; /*磁盘限额控制方法操作函数集*/
 const struct export_operations *s_export_op; /*网络文件系统输出的操作函数集*/
 unsigned long  s_flags;    /*文件系统挂接标识*/
 unsigned long  s_magic;   /*为魔数,是逻辑文件系统区别于其他文件系统的标志*/
 struct dentry  *s_root;   /*文件系统根目录的目录条目*/
 struct rw_semaphore s_umount; /*卸载用的读/写信号量*/
 struct mutex  s_lock;       /*超级块互斥锁*/
 int   s_count;          /*引用计数器*/
 int   s_syncing;       /*对超级块的索引节点进行同步的标志*/
 int   s_need_sync_fs; /*已挂接文件系统需要同步的标识*/
 atomic_t  s_active;       /*
#ifdef CONFIG_SECURITY
 void                    *s_security;   /*用于SELinux的安全数据结构指针*/
#endif
 struct xattr_handler **s_xattr;     /*超级块扩展属性处理例程结构指针*/
 
 struct list_head s_inodes;          /* 所有索引节点的链表 */
 struct list_head s_dirty;          /* 脏索引节点的链表 */
 struct list_head s_io;  /*等待写回到磁盘的索引节点的链表 */
 struct list_head s_more_io; /* parked for more writeback */
 struct hlist_head s_anon;  /*用于NFS输出的匿名目录条目的链表*/
 struct list_head s_files;      /*文件对象的链表*/
 
 struct block_device *s_bdev;   /*指向块设备描述结构*/
 struct mtd_info  *s_mtd;   /*指向MTD设备信息结构*/
 struct list_head s_instances;   /*文件系统的超级块实例的链表*/
 struct quota_info s_dquot;       /* 磁盘限额特定选项信息*/
 
 int   s_frozen;           /*冻结文件系统的标识*/
 wait_queue_head_t s_wait_unfrozen; /*等待解冻文件系统的进程队列*/
 
 char s_id[32];    /* 超级块可提供信息的名字 */
 
 void    *s_fs_info; /* 特定具体文件系统的超级块信息结构*/
 
 /*下面的域仅用于VFS */
 struct mutex s_vfs_rename_mutex;   /* 当VFS通过目录重命名文件时用的互斥锁 */
 
 u32     s_time_gran;   /* 时间戳粒度(纳秒)*/
 
 /*如果在/proc/mounts下的文件类型域非空,则文件类型域格式为“type.subtype”*/
 char *s_subtype;
 
 /*为使用generic_show_options()的懒惰文件系统存放挂接选项 */
 char *s_options;
};

 

超级块操作函数集
超级块对象的各种操作方法由超级块操作函数集结构super_operations定义,通过超级块对象的成员s_op可找到该操作函数集,如:sb->s_op->read_inode(inode)。

结构super_operations列出如下:
struct super_operations {
    struct inode *(*alloc_inode)(struct super_block *sb);  /*分配节点对象空间*/
 void (*destroy_inode)(struct inode *);                 /*销毁节点*/
 
    void (*dirty_inode) (struct inode *);         /*处理脏节点,ext4用它更新文件系统日志*/
 int (*write_inode) (struct inode *, int);     /*将节点的内容写回到磁盘节点*/
   /*通常为函数generic_drop_inode,当引用计数和硬连接计数i_nlink为0时,调用delete_inode删除节点*/
 void (*drop_inode) (struct inode *);       
 void (*delete_inode) (struct inode *);       /*删除节点及对应磁盘上的数据*/
 void (*put_super) (struct super_block *);      /*释放超级块对象*/
 void (*write_super) (struct super_block *);     /*将超级块信息写回磁盘*/
    /*日志系统用来同步更新文件系统数据结构在磁盘上的数据*/
 int (*sync_fs)(struct super_block *sb, int wait);
 void (*write_super_lockfs) (struct super_block *); /*锁住文件系统将超级块信息写回磁盘*/
 void (*unlockfs) (struct super_block *);           /*解锁文件系统*/
 int (*statfs) (struct dentry *, struct kstatfs *); /*得到文件系统的一些统计信息*/
 int (*remount_fs) (struct super_block *, int *, char *); /*重新挂接文件系统*/
 void (*clear_inode) (struct inode *);              /*清除节点*/
 void (*umount_begin) (struct super_block *);       /*开始卸载文件系统的操作*、
 
 int (*show_options)(struct seq_file *, struct vfsmount *); /*显示文件系统特定的选项*/
 int (*show_stats)(struct seq_file *, struct vfsmount *);   /*显示状态信息*/
#ifdef CONFIG_QUOTA
    /*读限额,限额系统调用用该方法读取数据*/
 ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
    /*写限额,限额系统调用用该方法将数据写入文件*/
 ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
#endif
};

节点
节点对象在磁盘上有对应的映像,Linux内核需要负责节点对象的数据与磁盘上映像数据的一致性,这通过节点的状态标识完成。

 

索引节点对象
文件(包括目录文件)是管理文件系统的最基本单位,每个文件都有一个索引节点结构inode,存放了文件系统处理文件所需要的各种信息。

节点或索引节点(inode)是文件系统连接任何子目录、任何文件的桥梁。每个子目录或文件只能由惟一的inode描述。它包括结构操作函数、文件操作函数、
等待队列、对应物理块的描述等。

结构inode包括描述文件信息域、索引节点操作域和其他域。文件信息域包括时间戳、块数、文件大小、操作权限、用户ID等文件的信息;索引节点操作域包括文件锁、
文件操作函数集、节点操作函数集、节点脏标识和节点磁盘限额等操作文件所需要的操作函数或信息。

结构inode列出如下(在include/linux/fs.h中):
struct inode {
/*用Hash表加快索引节点的搜索,前提是系统需要知道索引节点号及所在文件系统的超级块地址*/
 struct hlist_node i_hash; /*用于指向散列到同一地址的前一个索引节点和后一个索引节点*/
 struct list_head i_list;  /*索引节点链表*/
 struct list_head i_sb_list;  /*超级块的索引节点链表指针*/
 struct list_head i_dentry;   /*引用索引节点的目录条目链表*/
 unsigned long  i_ino;     /*索引节点号*/
 atomic_t  i_count;         /*引用计数器*/
 unsigned int  i_nlink;    /*硬链接的数目*/
 uid_t   i_uid;      /*文件拥有者标识号*/
 gid_t   i_gid;     /*文件拥有者所在组的标识号*/
 dev_t   i_rdev;    /*实设备标识符*/
 u64   i_version;      /*用于同步的版本号,每次使用后自动增加*/
 loff_t   i_size;    /*文件的大小(以字节为单位)*/
#ifdef __NEED_I_SIZE_ORDERED
 seqcount_t  i_size_seqcount; /*SMP系统为i_size字段获取一致值时使用的顺序计数器*/
#endif
 struct timespec  i_atime;    /*文件的最后访问时间*/
 struct timespec  i_mtime;    /*文件的最后修改时间*/
 struct timespec  i_ctime;    /*节点的最后修改时间*/
 unsigned int  i_blkbits;       /*块大小所占的位数*/
 blkcnt_t  i_blocks;            /*该文件所占块数*/
 unsigned short          i_bytes;  /*文件最后一块所占字节数*/
 umode_t   i_mode;        /*文件的访问权限*/
 spinlock_t  i_lock;       /*保护i_blocks, i_bytes和i_size的自旋锁*/
 struct mutex  i_mutex;        /*索引节点对象的互斥锁*/
 struct rw_semaphore i_alloc_sem;   /*直接I/O文件操作中用的读/写信号量*/
 const struct inode_operations *i_op; /*索引节点的操作函数集*/
    /* 缺省的文件操作函数集:former ->i_op->default_file_ops */
 const 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;               /*文件数据的地址映射空间*/
#ifdef CONFIG_QUOTA
 struct dquot  *i_dquot[MAXQUOTAS];        /*索引节点的磁盘限额*/
#endif
 struct list_head i_devices;                  /*指向设备索引节点的链表*/
 union {
  struct pipe_inode_info *i_pipe;           /*指向管道节点信息*/
  struct block_device *i_bdev;           /*指向块设备描述结构*/
  struct cdev  *i_cdev;               /*指向字符设备描述结构*/
 };
 int   i_cindex;                       /*有次设备号的设备文件的索引*/
 
 __u32  i_generation;                 /*指节点的不同软件版本,有些文件系统使用它*/
 
#ifdef CONFIG_DNOTIFY          /*用于目录通知机制,当目录发生变化时,发出通知*/
 unsigned long  i_dnotify_mask;             /* 目录通知事件*/
 struct dnotify_struct *i_dnotify;            /* 用于目录通知的结构*/
#endif
 
#ifdef CONFIG_INOTIFY       /*用于节点通知机制,当节点发生变化时,发出通知*/
 struct list_head inotify_watches;          /* 监视此节点 */
 struct mutex  inotify_mutex;        /* 用于保护监视链表的互斥锁*/
#endif
 
 unsigned long  i_state;                  /*索引节点的状态标识*/
 unsigned long  dirtied_when;       /* 第1次设置脏位的时间(jiffies)*/
 
 unsigned int  i_flags;            /*文件系统的挂接标志*/
 
 atomic_t  i_writecount;           /*写操作的引用计数*/
#ifdef CONFIG_SECURITY
 void   *i_security;            /*用于SELinux的安全结构*/
#endif
 void   *i_private;          /* 指向文件系统或设备的私有数据*/
};
VFS的索引节点结构存有文件或目录的信息,具体文件系统的索引节点是存储在磁盘上的,是一种静态结构,又称为磁盘索引节点。每个磁盘索引节点有个节点号,
节点号用于指向文件的索引节点所在磁盘地址。
Linux用磁盘索引节点的数据填写VFS的索引节点,也称VFS索引节点是动态节点,通常所说的索引节点指的是VFS索引节点,是结构inode的对象实例。

 

原创粉丝点击