Linux文件系统

温故而知新,整理一下看过linux文件系统的资料,以建立一个清晰的系统架构图。

整个体系结构图:


其中Individual file system 可能是Ext2,JFS,romfs 等各种不同格式的文件系统。

为了提高读写速度,数据都是缓存在内存中(页面高速缓存)。


文件读操作的工作流

粗略地分,读操作依次需要经过:

1.  用户界面层——负责从用户函数经过系统调用进入内核;

2.  基本文件系统层——负责调用文件写方法,从高速缓存中搜索数据页,返回给用户。

3.  I/O调度层——负责对请求排队,从而提高吞吐量。

4.  I/O传输层——利用任务列队异步操作设备控制器完成数据传输。




文件系统结构

创建文件系统需要建立“一个结构四个操作表”:
文件系统类型结构(file_system_type)
超级块操作表(super_operations)
索引节点操作表(inode_operations)
页高速缓存(address_space_operations)
文件操作表(file_operations)



文件系统类型结构


挂载的文件系统


超级块

超级块就代表一个文件系统。它包含管理文件系统所需的信息,包括文件系统名称(比如 ext2)、文件系统的大小和状态、块设备的引用和元数据信息(比如空闲列表等等)。超级块通常存储在存储媒体上,但是如果超级块不存在,也可以实时创建它。


inode

inode 表示文件系统中的一个对象,它具有惟一标识符。各个文件系统提供将文件名映射为惟一 inode 标识符和 inode 引用的方法。 Inode 中包含了访问此文件必须的信息,如文件的宿主,访问权限,文件的大小,上一次文件被访问和改变的时间以及文件数据块在磁盘上的分布。 需要注意的是文件内容的改变与文件所对应 inode  的改变是不同的,文件的内容只在对文件进行了写操作以后改变,而 inode  的改变可能是对文件进行了写操作也可能是文件宿主、访问权限以及其它属性的改变。在实际环境中可能有多个进程同时需要改变文件的 inode  ,这样会造成 inode  的不一致,为了避免这种情况的发生, inode  inode  锁的锁机制保护。当文件被读取时, inode  不会改变,而写文件时 inode  会被改变。 JFS2  采用读共享,写独占( read-shared, write-exclusive  )的 inode  锁的锁机制,允许多个进程同时读一个文件,但当一个进程写文件时,其它进程不允许读写此文件。

关于inode,我们可以解析动态库升级的问题。Ld.so是使用文件inode来定位动态库是否已经加载的。在替换so文件时,如果在不停程序的情况下,直接用 cp new.so old.so的方式替换程序使用的动态库文件会导致正在运行中的程序崩溃。解决的办法是采用“rmcp”“mvcp”来替代直接“cp”的操作方法。linux系统的动态库有两种使用方法:运行时动态链接库,动态加载库并在程序控制之下使用。

1、为什么在不停程序的情况下,直接用 cp命令替换程序使用的 so文件,会使程序崩溃?

很多同学在工作中遇到过这样一个问题,在替换 so文件时,如果在不停程序的情况下,直接用cp new.so old.so的方式替换程序使用的动态库文件会导致正在运行中的程序崩溃,退出。这与 cp命令的实现有关,cp并不改变目标文件的 inodecp的目标文件会继承被覆盖文件的属性而非源文件。实际上它是这样实现的:

strace cp libnew.solibold.so 2>&1 |grep open.*lib.*.so

open("libnew.so",O_RDONLY|O_LARGEFILE) = 3

open("libold.so",O_WRONLY|O_TRUNC|O_LARGEFILE) = 4

cp 使用“O_WRONLY|O_TRUNC”打开目标文件时,原 so文件的镜像被意外的破坏了。这样动态链接器 ld.so不能访问到 so文件中的函数入口。从而导致 Segmentation fault,程序崩溃。ld.so加载 so文件及再定位的机制比较复杂,详情可参见参考文献2

2、怎样在不停止程序的情况下替换so文件,并且保证程序不会崩溃?

答案是采用“rmcp”“mvcp”来替代直接“cp”的操作方法。

在用新的so文件 libnew.so替换旧的so文件libold.so时,如果采用如下方法:

rm libold.so

cp libnew.so libold.so

采用这种方法,目标文件 libold.so inode 其实已经改变了,原来的 libold.so 文件虽然不能用  ”ls” 查看到,但其 inode 并没有被真正删除,直到内核释放对它的引用。同理, mv 只是改变了文件名,其 inode 不变,新文件使用了新的 inode 。这样动态链接器 ld.so 仍然使用原来文件的 inode 访问旧的 so 文件。因而程序依然能正常运行。到这里,我们回想在上线操作中在替换可执行程序时,为什么直接使用 “cp new old” 这样的命令时,系统会禁止这样的操作,并且给出这样的提示 “cp:cannot create regular file `old': Text file busy” 。这时,我们采用的办法仍然是用 “rm+cp” 或者 “mv+cp” 来替代直接 “cp” ,这跟以上提到的 so 文件的替换有同样的道理。但是,为什么系统会阻止 cp 覆盖可执行程序,而不阻止覆盖 so 文件呢?这是因为 Linux 有个 Demand Paging 机制,所谓 “Demand Paging” ,简单的说,就是系统为了节约物理内存开销,并不会程序运行时就将所有页( page )都加载到内存中,而只有在系统有访问需求时才将其加载。 “DemandPaging” 要求正在运行中的程序镜像(注意,并非文件本身)不被意外修改,因此内核在启动程序后会锁定这个程序镜像的 inode 。对于 so 文件,它是靠 ld.so 加载的,而 ld.so 毕竟也是用户态程序,没有权利去锁定 inode ,也不应与内核的文件系统底层实现耦合。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值