博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
文件描述符和df的一个有趣的问题
阅读量:6176 次
发布时间:2019-06-21

本文共 2659 字,大约阅读时间需要 8 分钟。

hot3.png

设想一个这样的场景:
1. 查看各分区使用情况"df -h",结果如下:(省略不重要的打印)
[root
test]# df -h
Filesystem                     Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root   49G   19G   28G  40% /
已用19GB,剩余28GB可用,这只是举个例子,每个硬盘的结果不同
2. 在当前目录创建一个1GB大小的文件"fallocate -l 1G gentoo_root.img"
3. 查看各分区使用情况"df -h",结果如下:(省略不重要的打印)
[root
test]# df -h
Filesystem                     Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root   49G   20G   27G  42% /
已用20GB,剩余27GB可用,很明显,刚才用掉了1GB
4. 一个特殊的程序,源代码如下:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <error.h>
int main(int argc, char *argv[])
{
        int fd;
        if ( -1 == (fd = open("./gentoo_root.img", O_RDWR))) {
                perror("error in open");
                return fd;
        }
        else {
                printf("fd is [%d]\n", fd);
        }
        sleep(1000); // 让程序程序打开某文件,获得文件描述符,并且维持较长的时间
        return 0; // 不会到这一行,实际测试时
}
5. 编译命令如下:
gcc ./a.c -Wall -g
6. 运行./a.out
[root
test]# ./a.out 
fd is [3]
7. 另起一个终端,用root用户删除之前创建的1GB大小的文件,"rm ./gentoo_root.img"
8. 查看各分区使用情况"df -h",结果如下:(省略不重要的打印)
[root
test]# df -h
Filesystem                     Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root   49G   20G   27G  42% /
此结果就奇怪了,为什么还是使用了20GB,应该是19GB啊?为什么呢?
9. 使用lsof命令,为了只看重要信息,我们进行一些过滤,"lsof |grep deleted",结果如下:
[root
test]# lsof |grep deleted
vmware-vm  1405      root    3u      REG      253,0       2946    1442643 /tmp/vmware-root/apploader-1358.log (deleted)
vmtoolsd   1466      root    3u      REG      253,0       4138    1442655 /tmp/vmware-root/apploader-1466.log (deleted)
smbd       1932      root    2w      REG      253,0      51233    1310820 /var/log/samba/log.smbd.old (deleted)
smbd       1932      root    8w      REG      253,0      51233    1310820 /var/log/samba/log.smbd.old (deleted)
a.out     19162      root    3u      REG      253,0 1073741824    1835148 /test/gentoo_root.img (deleted)
看最后一行,a.out把持了文件描述符3,a.out的进程号是19162
10. 结束a.out进程,"kill 19162"
11. 查看各分区使用情况"df -h",结果如下:(省略不重要的打印)
[root
test]# df -h
Filesystem                     Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root   49G   19G   28G  42% /
此时空间回来了!!
上面的所有操作总结一下:
    先打开一个文件并保持,然后在操作系统里用root权限用户删除打开的那个文件,然后df统计得到的空间并没有增大,使用lsof查看,发现a.out程序占有了那个文件描述符,然后"杀死"a.out进程,再使用df,发现空间回来了。
我觉得可能原因是这样的:
    当一个程序调用open打开某个文件时,操作系统分配一个文件描述符给它(只是一个整数),但是在内核中,有张表,每个文件描述符会对应一个结构体,该文件描述符对应了一个结构体,不然你想啊,一个整数怎么可能记录这么多东西。比如你打开方式是只读还是只写,打开文件的路径等等一些信息(多说一点,socket描述符也是有张表,对应了一个socket的结构体)。然而,当你用root用户去删除那个文件的时候,a.out程序并没有去调用close();,那内核里面那张表中那个文件描述符还是没有回收,唯一内核能知道的就是,对应的文件已经删除了,所以lsof得到的结果后面有(deleted)的标记。那如果a.out去调用read(fd, ...);操作,那么我想它应该会得到错误(因为文件被删了)。而巧的是df的统计方式依然会把没有释放文件描述符的对应的文件也统计进来,所以在删除文件之后,df的结果还是已使用20GB,不是19GB。你可能会觉得它的统计策略不准确,明明我删除了,你为什么还统计?而事实上,如果磁盘满了,但是有个大文件正在被打开着(你可以直接用vim打开着),然后另起终端,用root把该文件删了,此时你再创建一个大文件,你觉得结果是什么?不会是你想要的结果,此时系统会提示你空间不足,直到你结束vim程序,释放那个文件描述符,这部分空间才真的被操作系统认为给释放掉了。
    其实还有很多点,由于我了解不深,我也不敢妄下论断,大体上只能这样讲一下我的理解,希望大家补充,指出错误,谢谢。

转载于:https://my.oschina.net/michaelyuanyuan/blog/136496

你可能感兴趣的文章
php返回相对时间(如:20分钟前,3天前)的方法
查看>>
WilliamChart各种图表效果实现大全《IT蓝豹》
查看>>
shell脚本——linux主机监控
查看>>
eclipse配置jsp页面模板
查看>>
基于高德地图写的不同功能的地图应用
查看>>
DHCP服务器配置
查看>>
快速瓶颈识别
查看>>
运维工作总结201403
查看>>
我是菜鸟我加油……mysql主从同步
查看>>
[体系结构]设计模式(五)
查看>>
分布式文件系统
查看>>
其实很简单 微星为你详解Z77主板BIOS设置
查看>>
在Ubuntu Kylin下安装JDK1.8
查看>>
Hadoop 学习一
查看>>
Linux中生成/etc/shadow的加密密码
查看>>
《gcc五分钟系列》第三节:-o选项
查看>>
批量检测主机存活状态
查看>>
解决 error: gnu/stubs-32.h: No such file or directory
查看>>
imread 函数 的相关细节
查看>>
分布式和事务
查看>>