12.1 가상 파일 시스템 (VFS) 의 역할

12.1虚拟文件系统(VFS)的角色 	虚拟文件系统(VFS)是一个内核软件层,它用于处理所有和标准Unix文件系统相关的系统调用。它的优势在于屏蔽不同文件系统之间的差异,为用户提供了一个统一的调用界面。 	举个例子,我们假定用户在shell下发出了命令: 	$cp /floppy/TEST /tmp/test 	其中floppy是一个装有MS-DOS文件系统的软盘的挂载点,而tmp则是一个普通的Linux Ext2文件 系统目录。因为有了VFS这么一个位于应用程序和具体的文件系统之间的抽象层,cp命令无需知道它们各 自实际所在的文件系统类型就可以实现文件在两者之间的复制操作。cp程序只需使用VFS提供的标准调用 接口就可以了,而VFS提供的这些接口和标准Unix下文件系统提供的接口完全一致。  基于磁盘的文件系统 	这类文件系统管理本地磁盘的存储空间。当然它们也可以用于管理先在常见的Flash存储设备(U盘), 但前提是这类设备需要能够把自己模拟成一个块设备。VFS支持的基于磁盘的文件系统如下: 	Linux常用的Ext2,Ext3本地文件系统,ReiserFS(这是一种日志文件系统),它们先在也被移植到 了其它操作系统上。 	一些Unix变种所使用的文件系统,例如sysv文件系统(System V, Coherent, Xenix),UFS(BSD,  Solaris, NEXTSTEP),Minix文件系统和Veritas VxFS(SCO UnixWare)。 	微软的文件系统,如MS-DOS(FAT12, FAT16),VFAT(FAT32),NTFS 	ISO9660 CD-ROM文件系统(正式名称是High Sierra文件系统)和Universal Disk Format(UDF,用于 DVD)。 	其它专用文件系统,例如HPFS(IBM OS/2),HFS(Apple),AFFS(Amiga's Fast File System)和 ADFS(Acorn Disk Filing System)。 	来自其他系统的日志文件系统(IBM JFS, SGI XFS)。  网络文件系统 	这种文件系统使得通过网络访问位于另一台计算机上的文件变得很容易,就像访问本地文件系统一 样。其中最著名的网络文件系统是NFS,除此之外Linux还支持Coda,AFS,CIFS和NCP等网络文件系统。  特殊文件系统 	这类文件系统不会像以上两类文件系统一样管理本地或远程的磁盘空间。/proc文件系统是一个典 型的例子。关于特殊文件系统在本章第三节会有详细介绍。 	本书重点介绍Ext2和Ext3文件系统,限于篇幅,对其它文件系统不做介绍。 	第一章已经介绍过,Unix的目录组成了一个树状结构,"/"是文件系统的根目录。根目录包含在根文 件系统中。在Linux上根文件系统一般是Ext2或Ext3文件系统。所有其它的文件系统都可以通过挂载 (mount)操作,装载到根文件系统的某个子目录下。 	当一个文件系统被挂载到某个目录以后,这个目录下原来的文件就不可见了,但是当文件系统被卸 载(umount)以后,原来的文件还会出现。这一特性常常被系统管理员用来隐藏某些文件。 	基于磁盘的文件系统常常被存储在块设备上,例如硬盘,软盘,光盘等。Linux的VFS允许处理虚 拟块设备,例如/dev/loop0,他可以用来加载一个存储在普通文件中的文件系统。例如,某个用户可能希望 保护他自己的私有文件系统,那么他可以把文件系统加密以后存储在一个普通文件中。 	第一个虚拟文件系统出现在Sun Microsystem的SunOS操作系统中。以后大多数的Unix文件系统包 含了VFS,但是Linux的VFS支持的文件系统类型是最多的。 	 12.1.1通用文件模型 	VFS的核心思想在于引入一种通用的文件模型,这一模型能够描述所有支持的文件系统。Linux采用 的模型严格地和传统的Unix提供的文件系统模型对应。这一点并不奇怪,因为linux希望在运行它的本地 文件系统(Ext2,Ext3)的时候引入的系统开销最小。由于有了VFS的存在,每个具体的文件系统在工作的时 候必须把它的物理组织形式转换为VFS所要求的通用文件模型的形式。 	例如,在通用文件模型里,每个目录都被看作是一个文件,只不过它的内容是一个文件和子目录的 列表。但是一些非Unix系统的磁盘文件系统使用文件分配表(FAT)的形式。它在目录中存储每个文件的具体 存储位置。在这类文件系统中,目录不能和文件同样处理。为了让这类文件系统能够和VFS的通用文件模型 对应,Linux在实现这类文件系统的时候必须能够动态构造这些目录对应的文件,而这些文件也只能作为内 存对象报存在内核空间中。 	此外,Linux内核不能直接编写函数对文件系统进行操作,例如read(),write()。它只能使用这些操 作函数的指针,这些指针指向的函数真正实现对特定文件系统的操作。 	下面我们通过研究read()系统调用来解释这个调用如何被转换为对MS-DOS文件系统的操作。应用程 序的read()调用使内核调用sys_read()服务例程,就像其它的系统调用一样。内核会在自己的空间构造一个 file结构代表这一文件。这个结构包含了一个f_op的字段,这一字段指向一组函数,这些函数能够完成对 MS-DOS文件系统的操作,当然包括读操作。sys_read()找到对应的读操作函数,并调用它,所以read()操作 实际被转换成以下形式: 	file->f_op->read(); 	与此类似,在Ext2文件系统上,write()操作将触发一个Ext2文件系统的写操作。简而言之,内核 负责把一组正确的操作函数指针分配给和打开的文件相关联的file结构,然后在需要的时候调用正确的操 作函数。 	通用文件模型的设计从某中程度上来说使用了面向对象的思想,在这一模型中,文件对象由数据结 构和方法组成。出于效率方面的考虑,Linux没有使用面向对象的语言(例如C++)进行编程。模型的实现 使用C语言的数据结构表示对象的数据,使用指向函数的指针字段表示对象的方法。 	通用文件模型包括以下对象类型:  超级块对象 	存储了关于已经被挂载的文件系统的相关信息。对于基于磁盘的文件系统来说,这一对象通常对应 于一个存储在磁盘上的文件系统控制块。  索引节点(inode)对象 	存储了关于某个文件的相关信息。对于基于磁盘的文件系统来说,这一对象通常对应于一个存储在 磁盘上的文件控制块。每个索引节点对象都有一个编号,这个编号唯一标志了在这个文件系统中的这一文件。  文件对象 	存储了一个打开的文件和一个进程之间的交互信息。这一信息只有在进程打开这一文件的时候才会 在内核空间中存在。  目录项(dentry)对象 	存储了每个目录条目(就是文件名)和实际文件之间的对应关系信息。每个磁盘文件系统都以它自己 的方式保存这一信息。  	图12-2用一个简单的例子解释了进程如何与文件交互。三个不同的进程打开了同一个文件,其中有 两个使用了同一个硬链接。在这种情况下,每个进程都有自己的文件对象,但是只有两个目录项对象,每个 硬链接对应一个。两个目录项对象指向同一个索引节点对象,索引节点对象指出了它所在文件系统的超级块 对象,索引节点对象和超级块对象一起指出磁盘上真实的文件。 	 	除了对所有的文件系统实现提供一套标准接口之外,VFS在系统性能方面也很重要。用得最多的目 录项对象被包含在磁盘高速缓存中,称为目录项缓存,它可以加快文件从路径名到索引节点的转换速度。  	一般说来,磁盘高速缓存是一种软件机制,它允许内核把经常要使用的一些信息报存在内存中,而 这些信息平时会被报存在磁盘上。这样当内核需要使用这些信息的时候可以快速地从内存中获取这些信息, 而不是通过进行磁盘I/O获取。 	需要注意的是磁盘高速缓存不同于硬件高速缓存或内存高速缓存,这两者和磁盘或其他设备都没有 关系。硬件高速缓存是一种快速的静态RAM,通过它可以加速对动态RAM的直接访问速度(参见第2章“硬 件高速缓存”)。内存高速缓存是一种软件机制,它被用于绕过内核内存分配器(参见第8章的“Slab分 配器”)。 	除了目录项高速缓存和索引节点高速缓存,linux还使用了其他磁盘高速缓存。其中最重要的是页 高速缓存,关于页高速缓存将在第15章进行描述。  12.1.2由VFS处理的系统调用 	表12-1列出了和文件系统本身,文件,目录,符号链接相关的系统调用。另外还有一些和设备文件 及管道相关的系统调用,例如ioperm(),ioctl(),pipe()和mknod(),他们将在后面的相关章节进行讨论。最 后一组是和socket相关的系统调用,例如socket(),connect(),bind()等,它们也由VFS处理,用于处理网 络通讯。其中和内核服务直接对应的系统调用将在本章和第18章进行讨论。

시스템 호출 이름
묘사 하 다.
mount(),umount(),umount2()
파일 시스템 마 운 트/마 운 트 해제
sysfs()
파일 시스템 정보 가 져 오기
statfs(),fstatfs(),statfs64(),fstatfs64(),ustat()
파일 시스템 의 통계 정 보 를 얻다
chroot(),pivot_root()
루트 디 렉 터 리 변경
chdir(),fchdir(),getcwd()
현재 디 렉 터 리 작업
mkdir(),rmdir()
디 렉 터 리 만 들 기 및 삭제
getdents(),getdents64(),readdir(),link(),ulink(),rename(),lookup_dcookie()
디 렉 터 리 항목 작업
readlink(),symlink()
심 볼 릭 링크 조작
chown( ) fchown( ) lchown( ) chown16( ) fchown16( ) lchown16( )
파일 소유자 수정
chmod( ) fchmod( ) utime( )
파일 속성 수정
stat( ) fstat( ) lstat( ) access( ) oldstat( ) oldfstat( ) oldlstat( ) stat64( ) lstat64( ) fstat64( )
파일 상태 읽 기
open( ) close( ) creat( ) umask( )
파일 열기, 닫 기, 만 들 기
dup( ) dup2( ) fcntl( ) fcntl64( )
파일 설명자 작업
select( ) poll( )
파일 설명자 에서 이 벤트 를 기다 리 고 있 습 니 다.
truncate( ) ftruncate( ) truncate64( ) ftruncate64( )
파일 크기 변경
lseek( ) _llseek( )
파일 포인터 변경
read( ) write( ) readv( ) writev( ) sendfile( ) sendfile64( ) readahead( )
파일 읽 기와 쓰기 동작 실행
io_setup( ) io_submit( ) io_getevents( ) io_cancel( ) io_destroy( )
비동기 I/O 조작
pread64( ) pwrite64( )
파일 포인터 위 치 를 다시 찾 아 읽 기와 쓰기
mmap( ) mmap2( ) munmap( ) madvise( ) mincore( ) remap_file_pages( )
처리 파일 메모리 맵 작업
fdatasync( ) fsync( ) sync( ) msync( )
파일 데이터 동기 화
flock( )
조작 파일 잠 금
setxattr( ) lsetxattr( ) fsetxattr( ) getxattr( ) lgetxattr( ) fgetxattr( ) listxattr( ) llistxattr( ) flistxattr( ) removexattr( ) lremovexattr( ) fremovexattr( )
작업 파일 확장 속성
표 12 - 1. VFS 로 처 리 된 시스템 호출
앞에서 언급 했 듯 이 VFS 는 응용 프로그램 과 구체 적 인 파일 시스템 사이 에 있 습 니 다.그러나 어떤 경우 에는 하위 처리 프로그램 을 호출 하지 않 고 파일 에 대한 작업 을 VFS 로 직접 수행 할 수 있 습 니 다.예 를 들 어 프로 세 스 가 파일 을 닫 을 때 실제 디스크 에 저 장 된 파일 을 조작 하지 않 습 니 다. VFS 는 메모리 에 있 는 해당 파일 대상 만 간단하게 풀 면 됩 니 다.또한, lseek () 시스템 호출 이 파일 포인터 (파일 포인터 프로 세 스 와 파일 이 상호작용 할 때 사용 하 는 속성) 를 수정 한 후에 VFS 는 메모리 에 있 는 파일 대상 의 해당 정 보 를 수정 하고 물리 디스크 파일 에 실제 접근 할 필요 가 없 기 때문에 시스템 호출 을 한 번 할 필요 가 없습니다.그런 의미 에서 VFS 는 필요 할 때 만 하위 특정 파일 시스템 에 의존 하 는 '유 니 버 설' 파일 시스템 으로 볼 수 있다.
 

좋은 웹페이지 즐겨찾기