当前位置: 首页 > Linux

从lsof开始,对Linux虚拟文件系统的背景有了深刻的认识

时间:2023-04-06 23:19:45 Linux

有时候会出现这样的情况,磁盘空间已经满了,但是在查看磁盘的具体文件使用情况时,发现磁盘还有很多空闲空间。1、执行df命令查看磁盘使用情况,发现磁盘已满。-bash-4.2$?df?-ThFilesystem?????Type??????Size??Used?Avail?Use%?Mounted?on/dev/vda1??????ext4???????30G????30G?0??????100%?/devtmpfs???????devtmpfs??489M?????0??489M???0%?/devtmpfs??????????tmpfs?????497M?????0??497M???0%?/dev/shmtmpfs??????????tmpfs?????497M???50M??447M11%/runtmpfstmpfs497M0497M0%/sys/fs/cgroup2。执行du命令查看各个目录的磁盘使用情况,加上各个目录文件的大小,发现磁盘没有满,有10多G空间莫名丢失。-bash-4.2$du-h--max-depth=1/home16M/home/logs11G/home/serverdog11G/home3.为什么会这样?因为虽然文件已经被删除,但是一些进程仍然打开着这些文件,所以它们占用的磁盘空间并没有被释放。执行lsof命令以显示打开的已删除文件。重新启动(或清除)有问题的进程,磁盘空间将被释放。-bash-4.2#lsof|GREPDELETEMYSQLD2470mySQL4Ureg253,10523577/var/tmp/ibfteqfn(已删除)mySQLD2470mysql5Ureg253,10523579/var/var/var/var/tmp/ibahcidw(deleteddeleteddeleted)mysssqld25353535353367053.12353670cqQL6.670Myssql6uclVAR/TMP/IBLJIALU(Deleted)MySQLD2470MySQL7UReg253,10523585/VAR/TMP/IBCFNZTB(Deleted)2470MYSQL11UReg253,1那么Linux的文件系统,到底为什么要这样设计呢?要弄明白这些,先搞清楚还不是一件容易的事。下面将从一些基本概念入手,一步步梳理:什么是虚拟文件系统(VFS:virtualfilesystem)?什么是通用文档模型?超级块对象(inodeobject)文件对象(fileobject)目录项对象(dentryobject)文件概念表达内存表达磁盘表达目录树构建软链接vs硬链接文件&磁盘管理InodeStateFile&ProcessManagementOperations:Open&DeleteVirtual文件系统(虚拟文件系统)下图展示了Linux操作系统中负责文件管理的基本组件。上半区是用户态,下半区是内核态。应用程序使用标准库libc访问文件,库将请求映射到系统调用以进入内核模式。所有与文件相关的操作的入口点都是虚拟文件系统(VFS),而不是特定的文件系统(例如Ext3、ReiserFS和NFS)。VFS提供了系统库和特定文件系统之间的接口。所以VFS不仅作为一个抽象层,而且实际上它提供了一个文件系统的基本实现,可以被不同的实现使用和扩展。因此,要了解文件系统的工作原理,必须先了解VFS。通用文件模型VFS的主要思想是引入一个通用文件模型(commonfilemodel)。通用文件模型由以下对象类型组成:超级块对象(superblockobject)内存:文件系统安装时创建,存储文件系统信息磁盘:对应文件系统控制块(filesystemcontrolblock)索引节点存储在磁盘上的对象(inodeobject)内存:在被访问时创建,存储特定文件的一般信息(inode结构)磁盘:对应于存储在磁盘上的一个文件控制块(filecontrolblock)每个inode对象都有一个inodenumber,唯一标识文件系统的文件对象(fileobject)-内存:文件打开时创建,存放打开文件与进程交互的信息(文件结构)打开文件信息,只有进程打开时才存在访问内核内存中的文件。目录项对象(dentryobject)内存:一旦目录项被读入内存,VFS会将其转换为目录项对象的dentry结构磁盘:特定的文件系统以特定的方式存储在磁盘上(名称)和相关信息目录树链接到对应的文件一般情况下,Linux的根文件系统(system'srootfilessystem)是内核启动挂载的第一个文件系统。内核代码镜像文件存放在根文件系统中,系统启动程序会在根文件系统挂载后加载一些基本的初始化脚本和服务到内存中运行(文件系统和内核是完全独立的两部分).其他文件系统后续通过脚本或命令等方式,作为子文件系统安装到已安装文件系统的目录下,最终形成整个目录树。start_kernelvfs_caches_initmnt_initinit_rootfs//注册rootfs文件系统init_mount_tree//挂载rootfs文件系统...rest_initsuperkernel_thread(kernel_init,NULL,CLONE_FS)同时查找对象文件系统树;创建文件时,总是先从初始目录中查找匹配的目录项,得到对应的索引节点,然后读取索引节点的目录文件,转换为dentry对象,检查匹配的目录项,执行重复上述过程,直到找到对应文件的索引节点,并创建一个索引节点对象。软链接vs硬链接软链接是一个普通的文件,它存储了另一个文件的路径名。硬链接指向同一个索引节点,硬链接的个数记录在索引节点对象的i_nlink字段中。当i_nlink字段为零时,表示没有指向该文件的硬链接。文件和进程管理下图是进程如何与文件交互的简单示例。三个不同的进程打开同一个文件,每个进程都有自己的文件对象,其中两个使用同一个硬链接(每个硬链接对应一个目录对象),两个目录项对象都指向同一个索引节点对象。索引节点的数据由两部分组成:内存数据和磁盘数据。Linux使用Writeback作为inode的数据一致性策略。对于索引节点的数据,当文件打开时,索引节点会被加载到内存中;当它不再被进程使用时,就会被踢出内存;如果中间有更新,需要将数据写回磁盘。*"in_use"-有效inode,i_count>0,i_nlink>0*"dirty"-as"in_use"但也是脏的*"unused"-有效inode,i_count=0索引节点是否仍在使用由open决定()和close()操作创建和销毁文件对象,文件对象通过索引节点提供的iget和iput更新索引节点的i_count字段,完成使用计数。打开操作将i_count加一,关闭操作将i_count减一。关闭操作时,判断索引节点是否被释放。如果i_count=0,表示没有进程引用,将从内存中释放。文件&磁盘管理文件和磁盘管理最密切相关的操作是touch和rm操作,尤其是后者最为关键。通过strace(或dtruss)查看rm的实际系统调用#dtrussrmtmp...geteuid(0x0,0x0,0x0)=00ioctl(0x0,0x4004667A,0x7FFEE06F09C4)=0x0lstat64("tmp0",0x9FFEE06)=00access("tmp0",0x2,0x0)=00unlink("tmp0",0x0,0x0)=00可以发现rm其实是通过unlink完成的。unlink表示删除目录项并减少其索引节点的数量。按照一般的文件模型,父目录本身也是一个文件,也就是说目录项是其文件数据的一部分。删除目录项相当于删除父目录下文件的数据,即先打开父目录下的文件。那么,delete操作可以理解为:delete命令(一个进程)使用open操作通过iget获取父目录文件对象增加目录文件的索引节点对象计数读取目录文件数据并转换目录文件数据放入目录项对象包括文件的索引节点,同样需要通过iget增加文件的索引节点对象计数,删除目录的目录项,减少索引节点的硬链接计数文件i_nlink的对象。判断i_count是否为0,如果为0,则释放内存然后判断i_nlink是否为0,如果为0,则释放磁盘空间,通过iput结束对目录索引节点对象的操作。回顾遇到的问题,其实可以从两个角度来理解:索引与数据、文件系统与文件、磁盘管理与文件、进程管理与文件。核心是文件的索引,而不是文件的数据。.将数据与索引分开是理解文件系统的关键。缓存策略由于操作系统采用了Writeback策略,也就是说只有先释放内存才能释放磁盘。为什么是lsof?从上面的模型可以很清楚的理解,因为目录没有索引到文件,但是文件还是有索引到文件的,所以不能立即释放磁盘空间。为什么lsof可以找到已删除但未释放的文件?lsof,顾名思义:listopenfiles,这个命令的原理是查找打开文件列表,这样就可以找到已经删除但没有释放的文件。作者:cyningsun链接:https://juejin.im/post/687511...