linux内核分析笔记----虚拟文件系统(上)
来源:互联网 发布:java代码基础 编辑:程序博客网 时间:2024/05/21 12:40
怎么办?特别是百花争鸣的文件系统,这时linux的内核开发者们想到了VFS(虚拟文件系统)。VFS使得用户可以直接使用open(),read()和write()这样的系统调用而不用关注具体文件系统和实际物理介质。也许你感觉不是很新奇啊,告诉你新奇的事情:在老式操作系统上(比如DOS),任何对非本地文件系统的访问都必须依靠特殊工具才能完成。这种实现的方式是内核在它的底层文件系统接口上建立了一个抽象层。该抽象层是linux能够支持各种文件系统,即便是它们在功能和行为上存在很大差别。为了支持文件系统,VFS提供了一个通用文件系统模型,该模型囊括了我们所能想到的文件系统的常用功能和行为。这个VFS抽象层之所以能衔接各种各样的文件系统,是因为它定义了所有文件系统都支持的基本抽象接口和数据结构,同时实际系统也将自身的诸如“如何打开文件”,“目录是什么”等概念在形式上与VFS的定义保持一致。因为实际文件系统的代码在统一的接口和数据结构隐藏了具体的实现细节,所以在VFS层和内核的其他部分看来,所有文件系统都是相同的,它们都支持像文件和目录这样的概念,同时也支持像创建和删除文件这样的操作。
实际文件系统通过编程提供VFS所期望的抽象接口和数据结构,这样,内核就可以毫不费力地和任何文件系统协同工作。那么接下的问题,它们直接的关系如何呢,看下边的例子:
write(f,&buf,len);
该代码不用说,应该明白。这个用户调用首先被一个通用系统调用sys_write()处理,sys_write()函数要找到f所在的文件系统实际给出的是哪个写操作,然后再执行该操作。实际文件系统的写方法是文件系统实现的一部分,数据最终通过该操作写入介质。下图给出流程:
下面我就先从整体上对unix(linux)文件系统做个概述,然后在具体下去。Unix使用了四种和文件系统相关的传统抽象概念,如下:
1.文件:就是一个有序字节串。2.目录项:文件是放在目录中,目录又可以层层嵌套,形成文件路径。路径中的每一项就叫做目录项。目录是文件,这个文件列出了该目录下的所有文件.
3.索引节点:一个文件其实是由两部分组成:相关信息和文件本身。这里的相关信息指的是访问控制权限,大小,拥有者,创建时间等。文件相关信息也叫
做元数据,被存储在一个单独的数据结构中,这个结构就叫做索引点(index node,简写inode)。
4.安装点(挂载点):文件系统被安装在一个特定的安装点上,该安装点在全局层次结构中被称为命名空间,所有的已安装文件系统都作为根文件树的树叶出
现在系统中。
5.超级块:是一种包含文件系统信息的数据结构,里边是文件系统的控制信息。
对应于上图,我们知道VFS是介于用户文件和文件系统之间的一个概念,所以如果文件系统想要穿透VFS供用户空间使用,就必须经过封装,提供一个符合这些概念的界面。上述每个元素都对应一个对象,该对象有属性结构体,描述了该对象的属性。有操作结构体,包含了自身所支持的操作,下面详细介绍:
1.超级块对象:代表一个已安装的文件系统。由数据结构super_block结构体表示,定义在linux/fs.h中。如下所示:
struct
super_block {
struct
list_head s_list;
/* list of all superblocks */
dev_t s_dev;
/* identifier */
unsigned
long
s_blocksize;
/* block size in bytes */
unsigned
long
s_old_blocksize;
/* old block size in bytes */
unsigned
char
s_blocksize_bits;
/* block size in bits */
unsigned
char
s_dirt;
/* dirty flag */
unsigned
long
long
s_maxbytes;
/* max file size */
struct
file_system_type s_type;
/* filesystem type */
struct
super_operations s_op;
/* superblock methods */
struct
dquot_operations *dq_op;
/* quota methods */
struct
quotactl_ops *s_qcop;
/* quota control methods */
struct
export_operations *s_export_op;
/* export methods */
unsigned
long
s_flags;
/* mount flags */
unsigned
long
s_magic;
/* filesystem's magic number */
struct
dentry *s_root;
/* directory mount point */
struct
rw_semaphore s_umount;
/* unmount semaphore */
struct
semaphore s_lock;
/* superblock semaphore */
int
s_count;
/* superblock ref count */
int
s_syncing;
/* filesystem syncing flag */
int
s_need_sync_fs;
/* not-yet-synced flag */
atomic_t s_active;
/* active reference count */
void
*s_security;
/* security module */
struct
list_head s_dirty;
/* list of dirty inodes */
struct
list_head s_io;
/* list of writebacks */
struct
hlist_head s_anon;
/* anonymous dentries */
struct
list_head s_files;
/* list of assigned files */
struct
block_device *s_bdev;
/* associated block device */
struct
list_head s_instances;
/* instances of this fs */
struct
quota_info s_dquot;
/* quota-specific options */
char
s_id[32];
/* text name */
void
*s_fs_info;
/* filesystem-specific info */
struct
semaphore s_vfs_rename_sem;
/* rename semaphore */
};
创建,管理和销毁超级块对象的代码位于文件fs/super.c中,超级块对象通过alloc_super()函数创建并初始化。在文件系统安装时,内核会调用该函数以便从磁盘读取文件系统超级块,并且将其信息填充到内存中的超级块对象中。其中最重要的一个是s_op,指向超级块的操作函数表,由super_operations结构体表示,定义在linux/fs.h中,如下:
struct
super_operations {
struct
inode *(*alloc_inode) (
struct
super_block *sb);
void
(*destroy_inode) (
struct
inode *);
void
(*read_inode) (
struct
inode *);
void
(*dirty_inode) (
struct
inode *);
void
(*write_inode) (
struct
inode *,
int
);
void
(*put_inode) (
struct
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 *,
int
);
void
(*write_super_lockfs) (
struct
super_block *);
void
(*unlockfs) (
struct
super_block *);
int
(*statfs) (
struct
super_block *,
struct
statfs *);
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 *);
};
当文件系统需要对其超级块执行操作时,首先要在超级块对象中寻找需要的操作方法。比如一个文件系统要写自己的超级块,需要调用:sb->s_op->write_super(sb)这里的sb是指向文件系统超级块的指针,沿着该指针进入超级块操作函数表,并从表中取得希望得到的write_super()函数,该函数执行写入超级块的实际操作。
2.索引节点对象:由inode结构体表示,定义在linux/fs.h中,如下:
struct
inode {
struct
hlist_node i_hash;
/* hash list */
struct
list_head i_list;
/* list of inodes */
struct
list_head i_dentry;
/* list of dentries */
unsigned
long
i_ino;
/* inode number */
atomic_t i_count;
/* reference counter */
umode_t i_mode;
/* access permissions */
unsigned
int
i_nlink;
/* number of hard links */
uid_t i_uid;
/* user id of owner */
gid_t i_gid;
/* group id of owner */
kdev_t i_rdev;
/* real device node */
loff_t i_size;
/* file size in bytes */
struct
timespec i_atime;
/* last access time */
struct
timespec i_mtime;
/* last modify time */
struct
timespec i_ctime;
/* last change time */
unsigned
int
i_blkbits;
/* block size in bits */
unsigned
long
i_blksize;
/* block size in bytes */
unsigned
long
i_version;
/* version number */
unsigned
long
i_blocks;
/* file size in blocks */
unsigned
short
i_bytes;
/* bytes consumed */
spinlock_t i_lock;
/* spinlock */
struct
rw_semaphore i_alloc_sem;
/* nests inside of i_sem */
struct
semaphore i_sem;
/* inode semaphore */
struct
inode_operations *i_op;
/* inode ops table */
struct
file_operations *i_fop;
/* default inode ops */
struct
super_block *i_sb;
/* associated superblock */
struct
file_lock *i_flock;
/* file lock list */
struct
address_space *i_mapping;
/* associated mapping */
struct
address_space i_data;
/* mapping for device */
struct
dquot *i_dquot[MAXQUOTAS];
/* disk quotas for inode */
struct
list_head i_devices;
/* list of block devices */
struct
pipe_inode_info *i_pipe;
/* pipe information */
struct
block_device *i_bdev;
/* block device driver */
unsigned
long
i_dnotify_mask;
/* directory notify mask */
struct
dnotify_struct *i_dnotify;
/* dnotify */
unsigned
long
i_state;
/* state flags */
unsigned
long
dirtied_when;
/* first dirtying time */
unsigned
int
i_flags;
/* filesystem flags */
unsigned
char
i_sock;
/* is this a socket? */
atomic_t i_writecount;
/* count of writers */
void
*i_security;
/* security module */
__u32 i_generation;
/* inode version number */
union
{
void
*generic_ip;
/* filesystem-specific info */
} u;
};
有时,某些文件系统可能并不能完整的包含索引节点结构体要求的所有信息。举个例子,有的文件系统可能并不记录文件的创建时间,这时,该文件系统就可以在实现中选择任意合适的办法来解决这个问题,它可以在i_ctime中存储0,或者让i_ctime等于i_mtime,甚至任何其他值。索引节点对象中的inode_operations项存放了操作函数列表,定义在linux/fs.h中,如下:
struct
inode_operations {
int
(*create) (
struct
inode *,
struct
dentry *,
int
);
struct
dentry * (*lookup) (
struct
inode *,
struct
dentry *);
int
(*link) (
struct
dentry *,
struct
inode *,
struct
dentry *);
int
(*unlink) (
struct
inode *,
struct
dentry *);
int
(*symlink) (
struct
inode *,
struct
dentry *,
const
char
*);
int
(*mkdir) (
struct
inode *,
struct
dentry *,
int
);
int
(*rmdir) (
struct
inode *,
struct
dentry *);
int
(*mknod) (
struct
inode *,
struct
dentry *,
int
, dev_t);
int
(*
rename
) (
struct
inode *,
struct
dentry *,
struct
inode *,
struct
dentry *);
int
(*readlink) (
struct
dentry *,
char
*,
int
);
int
(*follow_link) (
struct
dentry *,
struct
nameidata *);
int
(*put_link) (
struct
dentry *,
struct
nameidata *);
void
(*truncate) (
struct
inode *);
int
(*permission) (
struct
inode *,
int
);
int
(*setattr) (
struct
dentry *,
struct
iattr *);
int
(*getattr) (
struct
vfsmount *,
struct
dentry *,
struct
kstat *);
int
(*setxattr) (
struct
dentry *,
const
char
*,
const
void
*,
size_t
,
int
);
ssize_t (*getxattr) (
struct
dentry *,
const
char
*,
void
*,
size_t
);
ssize_t (*listxattr) (
struct
dentry *,
char
*,
size_t
);
int
(*removexattr) (
struct
dentry *,
const
char
*);
};
同样,操作调用时,用以下方式:i->i_op->truncate(i).
由于版面原因,我不得不分两次说了,下次继续后面有关虚拟文件系统的剩余部分.
- linux内核分析笔记----虚拟文件系统(上)
- linux内核分析笔记----虚拟文件系统(上)
- linux内核分析笔记----虚拟文件系统(下)
- linux内核分析笔记----虚拟文件系统(下)
- linux 虚拟文件系统分析笔记
- Linux内核源代码情景分析-虚拟文件系统
- Linux内核学习笔记十——虚拟文件系统概念
- Linux内核设计与实现 学习笔记(3)虚拟文件系统
- Linux内核学习笔记十——虚拟文件系统概念
- Linux内核学习笔记十——虚拟文件系统概念
- linux虚拟内核文件系统介绍
- Linux内核-文件系统之虚拟文件系统
- Linux虚拟文件系统源码分析
- linux虚拟文件系统(VFS)笔记
- Linux内核具体体系结构之虚拟文件系统
- Linux内核具体体系结构之虚拟文件系统
- Linux虚拟文件系统(内核初始化<一>)
- Linux虚拟文件系统(内核初始化<二>)
- hdu 4647 Another Graph Game
- eclipse导出jar(java打包导出jar)
- 试试功能-。-
- Oracle 常用命令
- hdu 4647 - Another Graph Game(思路题)
- linux内核分析笔记----虚拟文件系统(上)
- UVA 11636 - Hello World!
- uva 307 Sticks(DFS+ 剪枝)
- 自定义标签
- c++学习之继承
- 程序员的十楼层。看看自己在第几层。很有意思的文章!绝对给力!
- C++ 文件的复制、删除、重命名
- 老师讲的消息机制
- android组件间的交互和进程间IPC通信