标题:奇技淫巧(?) 之 解决被删掉又占用磁盘空间的文件 出处:Felix021 时间:Wed, 20 Nov 2013 18:00:13 +0000 作者:felix021 地址:https://www.felix021.com/blog/read.php?2128 内容: UPDATE@2014-01-09:注意,在gdb attach成功以后,这个进程会被暂停,可能会导致一些问题。 UPDATE@2017-11-11:用 lsof | grep deleted ,可以看到被删除的问题文件,记住占用该文件的PID, 到 /proc//fd (该进程打开的所有文件,按fd的值命名)下面可以看到这个文件的另一个链接,把这个链接的内容清空,也可以解决。 场景:Linux下,进程 p 打开了文件 f 并在后台持续地往 f 中写入日志。某日发现磁盘空间不够,把 f 删掉了,这时 ls 已经看不到 f 的存在,但是 df 发现磁盘空间占用并未减小,而 lsof 仍然可以看到该文件被占用(并显示一个 "(deleted)" 后缀)。更不幸的是,进程 p 是需要长期驻留在后台运行的,不能直接干掉它。 解决:简单地说就是替进程解决这个文件。 1) 根据链接文件名,可以查到该文件在进程中的 fd : $ ls -l /proc/[PID]/fd 2) 通过 gdb 连上该进程(一般需要root权限) $ sudo gdb (gdb) attach [PID] 3) 清除该文件所占空间 (gdb) call ftruncate(3, 0) #这里假定fd = 3 $1 = 0 这种方式治标,但不治本 —— 随着进程的继续运行,被删掉的 f 仍然会占用越来越多的空间;但是又不能残暴地直接 close(3) ,否则 p 的后续写入操作会出错,可能导致进程报错结束。 但是还是有办法的: 4) 移花接木 (gdb) call dup(3) $2 = 4 (gdb) call open("/dev/null", 2) #注:2 = O_RDWR,x86/x86_64/arm上都是这个值。 $3 = 5 (gdb) call dup2(5, 3) $4 = 3 (gdb) call close(4) $5 = 0 注:未测试该招式是否可能因多线程竞争导致错误。 OVER. Generated by Bo-blog 2.1.0