您的位置:首页 > 运维架构 > Linux

Linux内核工程导论——存储:文件系统

2015-10-08 20:39 387 查看
文件系统层文件系统的种类和选用 文件系统有很多种,linux内核是个大杂烩,同时满足企业和个人的需求,文件系统也是如此,发行版也是如此。其中原因自己分析。
我们最常见到的在linux中的文件系统是ext2、ext3、ext4,windows下的则是ntfs、fat和exfat。这些文件系统既可以在企业用户中见到也可以在个人用户中见到。
那为何文件系统有的适合企业,有的适合个人呢?这就要从个人也企业的不同物理条件和需求上来说。对于企业来说,最重要的是数据安全,其次才是效率,然后是可扩展性。而对于个人用户来说,最重要的是效率,因为个人的计算机处理能力一般有限。然后才是安全,然后才是可扩展性。而可扩展性的要求也远没有企业用户的需求大。安全上如加密,数据一致性,备份与恢复,热迁移等对企业来说非常重要的需求对大部分用户来说可能一文不值。但有些功能虽然企业用户比个人用户需求大,但还是都可以接受,例如日志系统,增加数据的一致性。很多用户担心掉电数据丢失也可以考虑采用。但是,如果你采用了ups,并且你的CPU处理能力有限,选用日志型的文件系统也不一定对你来说有意义。

流行文件系统
ext2、3、4
brtfs
cifs
coda
exofs
hfs
hfsplus
isofs
ntfs
vfat

特殊功能文件系统(一般为linux特定目的)
configfs:

configfs与sysfs类似,区别在于sysfs用于查看在内核中创建和销毁的组件,而configfs可有在用户空间创建和销毁内核对象。
mount -t configfs none /config
可以挂载这个文件系统,在这个文件系统中mkdir,rmdir就是对对应的内核组件的创建和删除。而只要创建了一个目录(也就是创建了内核组件),里面对应的内核文件就会自动出现,像操作普通文件一样操作这些出现的文件就可以完成对对应内核组件属性的操作。不过对configfs文件的写操作要注意的是,要一次性全部写入。也就是你需要先把文件整体读取出来,然后修改,然后一次性写入。
当你mount了这个文件系统之后,你可以find /config 查看这个文件系统中支持的子系统(如果你ls的话,下面是没有文件的),查看到了支持的子系统,就可以通过mkdir创建该子系统的条目。在能看到支持的子系统之前,你必须首先加载这些子系统对应的模块。
kernfs
用于创建虚拟的文件系统,给各种虚拟化方案提供一个统一的内核接口,目前cgroup已经使用了这个文件系统.
cramfs
debugfs:专门用于调试内核的虚拟文件系统,大部分子系统都没有使用这个,但是在内核空间提供了一种方法,让新的模块以这个方式向用户端输出内核的调试信息(当然用户也可以自己在proc文件系统或者其他的子系统添加条目),debugfs的出现是为了统一调试输出。printk不方便打印太多的数据,所以按需请求的debugfs有市场,netlink也不太适合这种场景。
devpts
efivarfs:efivarfs filesystem.
proc
ramfs-rootfs-initramfs
seq_file
sysfs
tmpfs
devtmpfs
kernfs:是从sys文件系统中产生,
分布式文件系统
9p:9p (v9fs) :plan 9设计的文件系统
afs: Andrew File System。分布式文件系统
nfs:分布式文件系统
ceph:info for the Ceph Distributed FileSystem.
gfs、gfs2
ocfs2
用于特定设备的文件系统
adfs:Acorn Advanced Disc FilingSystem。Acorn Computer做的文件系统,这可是ARM的母公司喔
affs:Amiga Fast File System.
befs:information about the BeOS filesystemfor Linux.
bfs:info for the SCO UnixWare BootFilesystem (BFS).
ncpfs:info on NovellNetware(tm) filesystem using NCP protocol.

嵌入式文件系统
yaffs:Yet Another FlashFile System(不在内核中)
加密专用文件系统:
ecryptfs:eCryptfs: stackedcryptographic filesystem for Linux.
f2fs
logfs
squashfs
romfs
日志文件系统
jfs
nilfs2
已淘汰文件系统
hpfs

omfs.txt
-info on the Optimized MPEG FileSystem.
pohmelfs/
-directory containing pohmelfs filesystem documentation.
qnx6.txt
-info on the QNX6 filesystem.
quota.txt
-info on Quota subsystem.

spufs.txt
-info and mount options for the SPU filesystem used on Cell.

sysv-fs.txt
-info on the SystemV/V7/Xenix/Coherent filesystem.

ubifs.txt
-info on the Unsorted Block Images FileSystem.
udf.txt
-info and mount options for the UDF filesystem.
ufs.txt
-info on the ufs filesystem.
vfs.txt
-overview of the Virtual File System.
xfs-delayed-logging-design.txt
-info on the XFS Delayed Logging Design.
xfs-self-describing-metadata.txt
-info on XFS Self Describing Metadata.
xfs.txt
-info and mount options for the XFS filesystem.
文件系统意义 那么为什么要有文件系统呢?文件系统存在的必要性是什么?SCSI是一种磁盘命令集,usb与pci是一种传输数据的总线。整个流程中还有一个没有涉及到,就是数据如何在磁盘上组织。我可以发一条读取的scsi命令给磁盘,然而读取命令的参数是块,磁盘只能理解读取哪一块数据,我就将该块返回,换句话说,磁盘不理解文件、目录等结构的存在,只理解数据块。那么在读取一个文件的时候,就需要有逻辑将文件目录转变为对应的磁盘块的逻辑,这个转换就是文件系统最主要的工作。
文件系统在工作时完成目录文件到数据块请求的转换,也正是由于它的这种责任,数据如何在磁盘上存储也必须由其规定(否则其不知道如何转换)。组织数据的方式和转换请求的方式定义了不同的文件系统。
文件系统在组织上大同小异,主要分为分布式、单机文件系统和特殊文件系统。个人使用最多的是单机文件系统。例如ext2、ntfs等。每个文件系统位于一个分区,但是一个磁盘上可以有多个分区。磁盘如何组织多个分区是有约定俗称的数据规范(一个512字节的启动块,内部定义多个分区的文职),不属于任何文件系统的范围。
这些单机文件系统的统一特点是将磁盘分区划分为大小相等的块(一般是1KB~4KB),然后将这些块组织成一个个含有相同块数的组。然后在每个组内包含一个个文件索引,每个索引指向了数据位于该组内的真实数据位置。另外为了表征组内有哪些数据块还可以用,通常还会有一个位图。为了描述组的情况的一般有一个超级块。其实就是一个分层的树形资源组织方式。目录可以组织为普通文件,文件内容是下级文件的索引。也可以组织为特殊构造的实体。只要不遗漏信息,任何组织架构都是可以的。现代的文件系统通常还包含了日志功能,在每次数据写入后要修改日志,没有修改日志的的写入系统会忽视。这样就避免了忽然掉电导致的数据丢失。
文件系统的抽象:VFS 既然我们知道有如此多的文件系统,而内核的很多功能模块都需要同文件系统交互,多以不可能针对每一个文件系统都修改内核的其他部分。文件系统整体应该向外提供一个统一的数据结构和函数操作接口,这个接口叫做VFS。
这个接口有其存在的物理依据是各个文件系统在上层抽象层次都是一样的。数据结构上都包含或者可以生成3个主要元素:超级块(整体的描述整个文件系统分区的使用情况)、目录(里面是各个文件)、文件节点(存放文件信息)。文件数据的具体位置是由文件节点描述的。操作上文件系统都是基本一致的,无非就是读写文件,重命名添加删除等通用的文件操作构成了所有文件系统的通用操作。
因此将3个数据结构和通用操作抽象出来提供给内核其他模块使用就够了内核的VFS文件系统抽象层。各种文件系统驱动代码,本质上都是各自实现各自不同的这些操作的方式。
那既然都是操作同样的文件系统,用户端如何知道操作的是什么文件系统呢?Linux的哲学里,所有的设备资源的操作都在设备目录/dev中,你所操作的文件一定是挂载在某个目录的某个设备。这个设备可能就是分区(也可以是回环)。于是你就对应的可以找到这个设备,查看这个设备的文件系统信息就知道了。也可以直接通过VFS读超级块的信息,从软件的角度查看磁盘信息。
目录树 正是因为内核对所有文件系统的这种统一的抽象,使得内核自己可以即使在没有实际文件系统的使用任意的创建模拟文件系统,只需要3种数据结构的组装即可。然而用途更大的是挂载思想。由于内核看来每个文件系统都有一个根目录,所有该文件系统的子目录都可以通过根目录的dentry结构体向下递归查询得到,而dentry又是位于内核的结构体,所以内核可以自由的改变dentry的下级目录,比如改成某个文件系统的根目录。如此就是挂载。同样的思想,不但是根目录可以挂载,一个文件系统的子目录理论上也可以直接挂载,然而内核并没有直接提供这种功能。通过各个文件系统的挂载,在一个根目录/ 下,内核就可以将所有的存储系统组装为一个目录树。
目前各个发行版都已经基本统一了这个根目录的结构,例如dev、etc等。
FUSE 前面说过,文件系统的作用不过是对存储方式的解析,这个解析过程相当于是一个算法,输入文件的的定位要求,返回定位的结果,然后由内核的SCSI命令部分将其转为SCSI命令。所以其算法主体可以在用户空间执行,这就构成了用户空间文件系统FUSE。
下层接口层块设备抽象
struct block_device {
dev_t bd_dev; /* not a kdev_t - it's a search key */
int bd_openers;
struct inode * bd_inode; /* will die */
struct super_block * bd_super;
struct mutex bd_mutex; /* open/close mutex */
struct list_head bd_inodes;
void * bd_claiming;
void * bd_holder;
int bd_holders;
bool bd_write_holder;
#ifdef CONFIG_SYSFS
struct list_head bd_holder_disks;
#endif
struct block_device * bd_contains;
unsigned bd_block_size;
struct hd_struct * bd_part;
/* number of times partitions within this device have been opened. */
unsigned bd_part_count;
int bd_invalidated;
struct gendisk * bd_disk;
struct request_queue * bd_queue;
struct list_head bd_list;
/*
* Private data. You must have bd_claim'ed the block_device
* to use this. NOTE: bd_claim allows an owner to claim
* the same device multiple times, the owner must take special
* care to not mess up bd_private for that case.
*/
unsigned long bd_private;

/* The counter of freeze processes */
int bd_fsfreeze_count;
/* Mutex for freeze */
struct mutex bd_fsfreeze_mutex;
};
FUSE fuse既是内核的一个特性也是用户空间的一个库。内核中有个模块,像文件系统一样工作,只是把实际的工作交给了用户空间的程序。
我知道文件系统只是负责用它掌握的数据存储结构来计算具体的位置,而不执行实际的读写操作,真正的读写操作还是驱动程序在做的。也就是说文件系统本质上完成的是一个计算的工作,所以完全可以在用户空间计算。
使用用户端命令管理文件系统 linuxhack书里
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息