一、成功“删除”了一个正在写入的文件!
某天,我启动了一个进程,向一个文件a.txt中写入内容,但不留神在另一个窗口用命令rm-fa.txt把它删掉了,我以为这应当会触发一个警告,例如“不能删掉一个打开的正在写入的文件”之类的,结果命令干脆的执行成功了,更超乎意料的是linux操作系统安装,我回到之前的那种窗口,我发觉进程还在正常的写入数据,程序并没有报出任何异常,并复印出了一批批成功写入的日志。
二、为什么会这样?
这就有点让我吃惊了,伟大的好奇心让我找寻答案。原先Linux中真正表示一个文件的是一个叫inode的数据结构,而文件名只是指向了inode(自然能否想到可以有多个文件名指向同一个inode,这就是文件系统中的硬联接)。用rm-fa.txt这样的命令删掉文件,虽然是删掉了文件名到inode之前的联接关系,这么直接表示文件内容的inode是哪些时侯删掉的呢?答案是文件系统判定倘若所有由文件名指向inode的关系都被删掉的时侯,就把inode删掉掉。
那其实还是说不通,我里面并没有给a.txt构建硬链接,也就是a.txt的inode应当马上被删掉,inode都没有了,写入进程应当报错才是啊,最后我通过查看教学版操作系统xv6的源码,发觉似乎文件系统在回收inode时,不仅判定到inode的链接数为0,还要判定到inode的引用数为0,当一个进程打开一个文件时linux _文件是什么,它的inode的引用数都会加1,所以这儿其实链接数为0但引用数为1,文件系统还是不会删掉inode,这么哪些时侯删掉inode呢linux服务器代维,答案是进程结束时引用数归0时。这也是为何,有时我们将一个文件删掉了,并且用du命令查看空间并没有被释放,重起航序空间就释放了的诱因。
三、这些文件都会占用c盘空间吗?
这么问题来了,若果我这个进程持续的写入,这种写入的内容会占用c盘空间吗?
实践出真知,我们做一个小实验,在vmware中加一块小硬盘,空间为50M(vmware以G为单位,写0.05G),这样可以比较容易的模拟出c盘写满的情形。通过fdisk命令进行分区
使用mkfs命令进行低格,之后mount命令将其挂载到/test
mkfs -t ext3 /dev/sdb1
mkdir /test
mount /dev/sdb1 /test
打算工作完毕!
这样,我们就得到了一个空间只有大约50M的文件夹,步入/test目录,写个简单的python脚本向a.txt文件写入内容:
import time
fd = open("a.txt", "wb")
time.sleep(3)
while True:
try:
fd.write("xxx")
fd.flush()
except Exception,e:
print(e)
break
time.sleep(1000)
fd.close()
稍为解释一下代码:
在打开文件后,写入文件前sleep5秒,这样可以让我们从容的启动另一个窗口,将a.txt删掉,导致写入一个“不存在文件”的情形。中间那种异常的捕获,是为了当c盘写满时跳出循环,让程序休眠,否则它会退出(进程结束,空间都会被释放,观察不到实验现象了)
即将开始,pythona.py启动程序linux _文件是什么,快速打开另一个窗口,rm-fa.txt删掉文件,切换回之前窗口,静静的观察正式发生的一切。结果不出意料,c盘很快被写满,程序复印出“[Errno28]Nospaceleftondevice”(注意这时进程并没有结束,而是被sleep冻住了)
这时我们观察一下c盘的使用情况,会发觉c盘确实被占满了
我们也可以写入一个文件验证一下,同样报错:
然而若果我们用du命令看,会发觉/test的空间只有16k,这说明du命令并没有统计这些inode没有删掉的文件
、
四、这些文件的内容还可以见到吗?
另外一个问题,这时我们能从那里听到这个文件呢,由于我们早已未能通过之前的路径的方法了,虽然还是可以的,由于操作系统会将进程打开的文件描述符放在/proc/{pid}/fd目录下,我们可以在这儿听到这个文件的内容
五、可以重新“链接”回来吗?
还有一个问题,是否我们可以通过将一个文件名重新链接到这个inode的形式重新“找回”这个文件呢?(复制是可以的,但复制只有当前的内容,难以获取到以后写入的内容)答案或许是不可以,由于这样是绕开了文件系统的权限机制,操作系统不容许。