Linux文件系统原理.docx

上传人:b****6 文档编号:4351523 上传时间:2022-11-30 格式:DOCX 页数:36 大小:57.78KB
下载 相关 举报
Linux文件系统原理.docx_第1页
第1页 / 共36页
Linux文件系统原理.docx_第2页
第2页 / 共36页
Linux文件系统原理.docx_第3页
第3页 / 共36页
Linux文件系统原理.docx_第4页
第4页 / 共36页
Linux文件系统原理.docx_第5页
第5页 / 共36页
点击查看更多>>
下载资源
资源描述

Linux文件系统原理.docx

《Linux文件系统原理.docx》由会员分享,可在线阅读,更多相关《Linux文件系统原理.docx(36页珍藏版)》请在冰豆网上搜索。

Linux文件系统原理.docx

Linux文件系统原理

Linux文件系统原理

第1章概述

要理解linux的文件系统,要从理解虚拟文件系统(VFS,VirtualFilesystem)开始。

其结构可以用图表1来描述。

图表1

第2章虚拟文件系统

2.1它到底是什么?

虚拟文件系统是Linux内核中的一个软件层,用于给用户空间的程序提供文件系统接口。

它也提供了内核中的一个抽象功能,允许不同的文件系统共存。

2.2工作方式概述

2.2.1注册和安装一个文件系统

如果你想在内核中支持一种新的文件系统的话,你所需要做的仅仅是调用函数register_filesystem()。

你向内核中传递一个描述文件系统实现的结构(structfilesystem),此结构将被加入到内核的支持文件系统表中去。

你可以运行下面的命令:

%cat/proc/filesystems

这样可以看到你的系统支持哪些文件系统。

内核模块必须提供两个用于加载和卸载时调用的接口,这两个接口由两个固定的宏引出,分别为module_init(),module_exit()。

文件系统在作为模块被加载到内核时,调用register_filesystem(),把自己注册为一种文件系统。

在模块被卸载时,调用unregister_filesystem()从内核中注消。

以JFFS为例:

//定义一种文件系统jffs_fs_type,其名称为“JFFS”

staticDECLARE_FSTYPE_DEV(jffs_fs_type,"jffs",jffs_read_super);

staticint__init

init_jffs_fs(void)

{

printk(KERN_INFO"JFFSversion"JFFS_VERSION_STRING

",(C)1999,2000AxisCommunicationsAB\n");

#ifdefCONFIG_JFFS_PROC_FS

jffs_proc_root=proc_mkdir("jffs",proc_root_fs);

#endif

fm_cache=kmem_cache_create("jffs_fm",sizeof(structjffs_fm),

0,SLAB_HWCACHE_ALIGN,NULL,NULL);

node_cache=kmem_cache_create("jffs_node",sizeof(structjffs_node),

0,SLAB_HWCACHE_ALIGN,NULL,NULL);

//注册文件系统

returnregister_filesystem(&jffs_fs_type);

}

staticvoid__exit

exit_jffs_fs(void)

{

//注消文件系统

unregister_filesystem(&jffs_fs_type);

kmem_cache_destroy(fm_cache);

kmem_cache_destroy(node_cache);

}

//引出模块的加载和卸载时调用的接口

module_init(init_jffs_fs)

module_exit(exit_jffs_fs)

当一个mount请求出现时,VFS将会为特定的文件系统调用相应的方法。

安装点的dentry结构将会被改为指向新文件系统的根i节点。

2.2.2打开一个文件

VFS实现了open系统调用。

路径参数被VFS用来在目录入口缓存(dentrycacheor"dcache")。

这提供了一个将路径名转化为特定的dentry的一个快的查找机制。

一个单独的dentry通常包含一个指向i节点(inode)的指针。

i节点存在于磁盘驱动器上,它可以是一个规则文件,目录,FIFO文件,等等。

Dentry存在于RAM中,并且永远不会被存到磁盘上:

它们仅仅为了提高系统性能而存在。

i节点存在于磁盘上,当需要时被拷入内存中,之后对它的任何改变将被写回磁盘。

存在于RAM中的i节点就是VFS的i节点,dentry所包含的指针指向的就是它。

dcache是你的整个文件空间的观察点。

大多数情况下不可能有足够的RAM空间来放我们的文件空间的所有文件的目录入口缓存(dentry),所以我们的dcache会有缺少的项。

为了将路径名转换为一个dentry,VFS不得不采取创建dentry的方式,并在创建dentry时将指针指向相应的i节点。

这是通过对i节点的查找完成的。

为了查找一个文件的i节点(通常从磁盘上读),VFS需要调用该文件的父目录的lookup()方法,此方法是特定的文件系统所设置的。

后面对此将会有更详尽的描述。

一旦VFS得到了所需要的dentry(同时也得到了相应的i节点),我们就能够对文件做想要的操作:

打开文件,或者用stat来看i节点中的数据。

stat的操作非常简单:

在VFS得到dentry之后,它取得inode中的一些数据并将其中的一部分送回用户空间。

打开一个文件需要其它的操作:

分配一个structfile(定义于linux/fs.h,这是内核中的文件描述)结构。

新分配的structfile结构被指向dentry的指针和对文件进行操作的函数集合所初始化,这些都是从i节点中得到的。

通过这种方式,特定的文件系统实现才能起作用。

文件结构(structfile)被放在进程的文件描述符表中。

读,写和关闭文件(或者其它的VFS操作)是通过使用用户空间的文件描述符找到相应的文件结构(structfile),然后调用所需要的方法函数来实现的。

当文件处于打开状态时,系统保持相应的dentry为"open"状态(正在使用),这表示相应的i节点在被使用。

2.3主要结构说明

2.3.1structfile_system_type

此结构描述了文件系统。

在内核2.4.18中,此结构的定义如下:

structfile_system_type{

constchar*name;

intfs_flags;

structsuper_block*(*read_super)(structsuper_block*,void*,int);

structmodule*owner;

structfile_system_type*next;

structlist_headfs_supers;

};

其中各个域的意义:

name:

文件系统的类型名称,如"vfat","ext2",等等。

fs_flags:

变量标志,如FS_REQUIRES_DEV,FS_NO_DCACHE,等等。

read_super:

当此种文件系统的一个新的实例要被安装时,此方法会被调用。

owner:

实例所在的模块,通常默认为THIS_MODULE。

next:

被内部的VFS实现所使用,你只需要将其初始化为NULL。

fs_supers:

超级块链表,初始化为NULL即可。

函数read_super具有以下的参数:

structsuper_block*sb:

超级块结构。

此结构的一部分被VFS初始化,余下的部分必须被函数read_super初始化。

void*data:

任意的安装选项,通常是ASCII的字符串。

在JFFS中没有使用。

intsilent:

表示当出现错误时是否保持安静。

(不报警?

)在JFFS中没有使用。

read_super方法必须确定指定的块设备是否包含了一个所支持的文件系统。

当成功时返回超级块结构的指针,错误时返回NULL。

read_super方法填充进超级块结构(structsuper_block)的最有用的域是"s_op"域。

这是一个指向structsuper_operations的指针,此结构描述了文件系统实现的下一层细节。

2.3.2structsuper_operations

此结构描述了VFS对文件系统的超级块所能进行的操作。

在内核2.4.18中,此结构的定义如下:

structsuper_operations{

void(*read_inode)(structinode*);

void(*read_inode2)(structinode*,void*);

void(*dirty_inode)(structinode*);

void(*write_inode)(structinode*,int);

void(*put_inode)(structinode*);

void(*delete_inode)(structinode*);

void(*put_super)(structsuper_block*);

void(*write_super)(structsuper_block*);

void(*write_super_lockfs)(structsuper_block*);

void(*unlockfs)(structsuper_block*);

int(*statfs)(structsuper_block*,structstatfs*);

int(*remount_fs)(structsuper_block*,int*,char*);

void(*clear_inode)(structinode*);

void(*umount_begin)(structsuper_block*);

structdentry*(*fh_to_dentry)(structsuper_block*sb,__u32*fh,intlen,intfhtype,intparent);

int(*dentry_to_fh)(structdentry*,__u32*fh,int*lenp,intneed_parent);

int(*show_options)(structseq_file*,structvfsmount*);

};

除非特别提出,所有的方法都在未加锁的情况下被调用,这意味着大多数方法都可以安全的被阻塞。

所有的方法都仅仅在进程空间被调用(例如,在中断处理程序和底半部中不能调用它们)

read_inode:

从一个文件系统中读取一个特定的i节点时调用此方法。

i节点中的域"i_ino"被VFS初始化为指向所读的i节点,其余的域被此方法所填充。

read_inode2:

专为reiserfs留的,其它文件系统现在用不到。

write_inode:

当VFS需要向磁盘上的一个i节点写时调用。

put_inode:

当VFS的i节点被从i节点缓冲池移走时被调用。

此方法是可选的。

delete_inode:

当VFS想删除一个i节点时调用次方法。

notify_change:

当VFS的i节点的属性被改变时调用。

若此域为NULL则VFS会调用rite_inode。

此方法调用时需要锁住内核。

put_super:

当VFS要释放超级块时调用(umount一个文件系统)。

此方法调用时需要锁住内核。

write_super:

当VFS超级块需要被写入磁盘时被调用。

此方法为可选的。

statfs:

当VFS需要得到文件系统的统计数据时调用。

此方法调用时需要锁住内核。

remount_fs:

当文件系统被重新安装时调用。

此方法调用时需要锁住内核。

clear_inode:

当VFS清除i节点时调用。

可选项。

以上方法中,read_inode需要填充"i_op"域,此域为一个指向structinode_operations结构的指针,它描述了能够对一个单独的i节点所能进行的操作。

其它的一些域在很多文件系统里都没有使用,可以不用关心。

2.3.3structinode_operations

此结构描述了VFS能够对文件系统的一个i节点所能进行的操作。

在内核2.4.18中,此结构的定义如下:

structinode_operations{

int(*create)(structinode*,structdentry*,int);

structdentry*(*lookup)(structinode*,structdentry*);

int(*link)(structdentry*,structinode*,structdentry*);

int(*unlink)(structinode*,structdentry*);

int(*symlink)(structinode*,structdentry*,constchar*);

int(*mkdir)(structinode*,structdentry*,int);

int(*rmdir)(structinode*,structdentry*);

int(*mknod)(structinode*,structdentry*,int,int);

int(*rename)(structinode*,structdentry*,

structinode*,structdentry*);

int(*readlink)(structdentry*,char*,int);

int(*follow_link)(structdentry*,structnameidata*);

void(*truncate)(structinode*);

int(*permission)(structinode*,int);

int(*revalidate)(structdentry*);

int(*setattr)(structdentry*,structiattr*);

int(*getattr)(structdentry*,structiattr*);

};

create:

被open和creat所调用,仅仅在你要支持普通文件时才需要。

参数中的dentry不应该包含有i节点的指针(即应该为一个negativedentry)。

这里你可能需要对传入的dentry和i节点调用函数d_instantiate。

lookup:

当VFS要在一个父目录中查找一个i节点时调用。

待查找的文件名在dentry中。

此方法必须调用d_add函数把找到的i节点插入到dentry中,i节点的"i_count"域要加一。

若指定的i节点不存在的话,一个NULL的i节点指针将被插入到dentry中去(这种情况的dentry被称为negativedentry)。

link:

被link所调用。

仅在你需要支持hardlink时才需要它。

跟create方法相同的原因,你可能在此方法中也需要调用d_instantiate()函数来验证。

unlink:

被unlink所调用。

仅在你要支持对i节点的删除时才需要它。

symlink:

被symlink调用。

仅在需要支持符号链接时才需要它。

通上面两处,你需要对传入的参数进行验证,要调用d_instantiate()函数。

mkdir:

被mkdir调用。

仅在你要支持建立子目录时才需要它。

同上,你需要调用d_instantiate()函数进行验证。

rmdir:

被rmdir所调用。

仅在你要支持对子目录的删除时才需要它。

mknod:

被mknod所调用,用于建立一个设备i节点,或者FIFO,或socket。

仅当你需要支持对这些类型的i节点的建立时才需要此方法。

同上面几个,你可能也需要调用_instantiate来验证参数。

rename:

被rename调用。

仅在你要支持对文件和目录改名时才需要它。

readlink:

被readlink调用。

仅当你要支持对符号链接的读取才需要它。

follow_link:

被VFS调用,用以从一个符号链接找到相应的i节点。

仅当你需要支持符号链接时才需要此方法。

2.3.4structfile_operations

结构file_operations包含了VFS对一个已打开文件的操作。

在内核2.4.18中,此结构的定义如下:

structfile_operations{

structmodule*owner;

loff_t(*llseek)(structfile*,loff_t,int);

ssize_t(*read)(structfile*,char*,size_t,loff_t*);

ssize_t(*write)(structfile*,constchar*,size_t,loff_t*);

int(*readdir)(structfile*,void*,filldir_t);

unsignedint(*poll)(structfile*,structpoll_table_struct*);

int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);

int(*mmap)(structfile*,structvm_area_struct*);

int(*open)(structinode*,structfile*);

int(*flush)(structfile*);

int(*release)(structinode*,structfile*);

int(*fsync)(structfile*,structdentry*,intdatasync);

int(*fasync)(int,structfile*,int);

int(*lock)(structfile*,int,structfile_lock*);

ssize_t(*readv)(structfile*,conststructiovec*,unsignedlong,loff_t*);

ssize_t(*writev)(structfile*,conststructiovec*,unsignedlong,loff_t*);

ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);

unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);

};

llseek:

当VFS需要移动文件指针的位置时调用。

read:

被read所调用。

write:

被write所调用。

readdir:

当VFS需要读取目录中的内容时被调用。

poll:

当一个进程想知道文件是否可用是调用,进程可以一直休眠等待文件可用。

功能有点类似SOCKET中的select。

ioctl:

被ioctl所调用。

mmap:

被mmap所调用。

open:

当VFS要打开一个i节点时调用它。

当VFS打开一个文件时,它建立一个新的structfile结构,并用i节点中的"default_file_ops"来初始化其中的f_op域,然后对新分配的文件结构调用open方法。

你可以认为open方法实际上属于structinode_operations。

open方法是一个很好的初始化文件结构中的"private_data"域的的地方。

release:

当没有对被打开文件的引用时调用此方法。

fsync:

被fsync所调用。

fasync:

当用fcntl激活一个文件的异步模式时此方法被调用。

这些文件操作是由i节点所在的特定文件系统所实现的。

当打开一个设备节点时(字符或块设备特殊文件),大多数文件系统会调用VFS中的特定支持例程,由此来找到所需要的设备驱动信息;

这些支持例程用设备驱动程序的方法来代替文件系统的文件操作,然后继续对文件调用新的open方法。

这就是为什么当你打开文件系统上的一个设备特殊文件时,最后被调用的却是设备驱动程序的open方法。

另外,devfs(DeviceFilesystem)有一个从设备节点到设备驱动程序的更直接的方式(这是非官方的内核补丁)

2.3.5structdentry_operations

operations.Dentries和dcache是属于VFS和单个文件系统实现的,设备驱动与此无关。

在内核2.4.18中,此结构的定义如下:

structdentry_operations{

int(*d_revalidate)(structdentry*,int);

int(*d_hash)(structdentry*,structqstr*);

int(*d_compare)(structdentry*,structqstr*,structqstr*);

int(*d_delete)(structdentry*);

void(*d_release)(structdentry*);

void(*d_iput)(structdentry*,structinode*);

};

d_revalidate:

当VFS要使一个dentry重新生效时被调用。

d_hash:

当VFS向哈希表中加入一个dentry时被调用。

d_compare:

当指向一个dentry的最后的引用被去除时此方法被调用,因为这意味这没有人在使用此dentry;当然,此dentry仍然有效,并且仍然在dcache中。

d_release:

当一个dentry被清除时调用此方法。

d_iput:

当一个dentry释放它的i节点时(在dentry被清除之前)此方法被调用。

为空时自动调用VFS的input(),如果定义了这个函数,那要自己调用input()。

每个dentry都有一个指向其父目录dentry的指针,一个子dentry的哈希列表。

子dentry基本上就是目录中的文件。

dget:

为一个已经存在的dentry打开一个新的句柄(这仅仅增加引用计数)

dput:

关闭一个dentry的句柄(减少引用计数)。

如果引用计数减少为0,d_delete方法将会被调用;并且,如果此dentry仍然在其父目录的哈希列表中的话,此dentry将被放置于一个未被使用的列表中。

将dentry放置于未使用表中意味着当系统需要更多的RAM时,将会遍历未使用的dentry的列表,并回收其内存空间。

假如当detry的引用计数为0时,它已经没有在父目录的哈希表中的话,在d_delete方法被调用之后系统就会回收起内存空间。

d_drop:

此方法将一个dentry从其父目录的哈希列表中去掉

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 中考

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1