在日常运维中,经常遇到磁盘空间满,但是找不到相应文件的情况。
通常这种情况都是文件被删除,但是还被进程占用,造成du与df结果不一致
处理办法通常是停止占用文件的进程。

但是如果进程不能被停止呢?

另一个处理办法就是通过清空文件释放空间。
处理办法如下:

  1. 通过lsof | grep deleted 找到未能删除掉的文件,确定占用的进程号;
  2. 通过 ls -l /proc/PID/fd/* | grep 文件名,找到相应文件句柄;
  3. 清除文件内容 echo > /proc/PID/fd/FD_NUM

这个操作被不会将文件删除,而是通过将文档内容清空的方法释放空间,文件还是存在的。

实验如下:

1.创造一个大文件

使用dd创建1个5000MB的文件,看df的输出,可用空间从13G降到了7.5G。

[root@test1 /]# df -TH
Filesystem              Type      Size  Used Avail Use% Mounted on
devtmpfs                devtmpfs  2.0G     0  2.0G   0% /dev
tmpfs                   tmpfs     2.0G     0  2.0G   0% /dev/shm
tmpfs                   tmpfs     2.0G   30M  2.0G   2% /run
tmpfs                   tmpfs     2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/mapper/centos-root xfs        39G   27G   13G  68% /
/dev/sda1               xfs       1.1G  394M  671M  37% /boot
tmpfs                   tmpfs     396M     0  396M   0% /run/user/0
[root@test1 /]# dd if=/dev/zero of=/delete.tmp bs=1000MB count=5
5+0 records in
5+0 records out
5000000000 bytes (5.0 GB) copied, 5.35441 s, 934 MB/s
[root@test1 /]# df -TH
Filesystem              Type      Size  Used Avail Use% Mounted on
devtmpfs                devtmpfs  2.0G     0  2.0G   0% /dev
tmpfs                   tmpfs     2.0G     0  2.0G   0% /dev/shm
tmpfs                   tmpfs     2.0G   30M  2.0G   2% /run
tmpfs                   tmpfs     2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/mapper/centos-root xfs        39G   32G  7.5G  81% /
/dev/sda1               xfs       1.1G  394M  671M  37% /boot
tmpfs                   tmpfs     396M     0  396M   0% /run/user/0
[root@test1 /]# du -sh /delete.tmp 
4.7G    /delete.tmp

2.使用tail 打开文件

用tail 打开文件,保证删除文件时,文件仍被占用

[root@test1 /]# tail -f /delete.tmp 

3.删除文件

使用rm 删除文件,在以下df输出中会发现,可用空间还是7.5G,没有变化,但是文件已经消失了。

[root@test1 /]# rm -f /delete.tmp 
[root@test1 /]# df -TH
Filesystem              Type      Size  Used Avail Use% Mounted on
devtmpfs                devtmpfs  2.0G     0  2.0G   0% /dev
tmpfs                   tmpfs     2.0G     0  2.0G   0% /dev/shm
tmpfs                   tmpfs     2.0G   30M  2.0G   2% /run
tmpfs                   tmpfs     2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/mapper/centos-root xfs        39G   32G  7.5G  81% /
/dev/sda1               xfs       1.1G  394M  671M  37% /boot
tmpfs                   tmpfs     396M     0  396M   0% /run/user/0
[root@test1 /]# du -sh /delete.tmp 
du: cannot access ‘/delete.tmp’: No such file or directory

4.查找删除的文件

lsof 显示了deleted状态的文件名和大小(5000000000)。

[root@test1 ~]# lsof | grep deleted 
tail         419                  root    3r      REG              253,0 5000000000      55981 /delete.tmp (deleted)

5.查找文件句柄

[root@test1 ~]# ll /proc/419/fd | grep delete.tmp
lr-x------ 1 root root 64 May 23 16:05 3 -> /delete.tmp (deleted)

6.清空文件

[root@test1 ~]# echo > /proc/419/fd/3
[root@test1 ~]# df -TH
Filesystem              Type      Size  Used Avail Use% Mounted on
devtmpfs                devtmpfs  2.0G     0  2.0G   0% /dev
tmpfs                   tmpfs     2.0G     0  2.0G   0% /dev/shm
tmpfs                   tmpfs     2.0G   30M  2.0G   2% /run
tmpfs                   tmpfs     2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/mapper/centos-root xfs        39G   27G   13G  68% /
/dev/sda1               xfs       1.1G  394M  671M  37% /boot
tmpfs                   tmpfs     396M     0  396M   0% /run/user/0

那么/proc/PID/fd 是啥呢?

man proc

/proc/[pid]/fd/

          This is a subdirectory containing one entry for each file
          which the process has open, named by its file descriptor,
          and which is a symbolic link to the actual file.  Thus, 0
          is standard input, 1 standard output, 2 standard error,
          and so on.

          For file descriptors for pipes and sockets, the entries
          will be symbolic links whose content is the file type with
          the inode.  A readlink(2) call on this file returns a
          string in the format:

              type:[inode]

          For example, socket:[2248868] will be a socket and its
          inode is 2248868.  For sockets, that inode can be used to
          find more information in one of the files under
          /proc/net/.

          For file descriptors that have no corresponding inode
          (e.g., file descriptors produced by bpf(2),
          epoll_create(2), eventfd(2), inotify_init(2),
          perf_event_open(2), signalfd(2), timerfd_create(2), and
          userfaultfd(2)), the entry will be a symbolic link with
          contents of the form

              anon_inode:<file-type>

          In many cases (but not all), the file-type is surrounded
          by square brackets.

          For example, an epoll file descriptor will have a symbolic
          link whose content is the string anon_inode:[eventpoll].

          In a multithreaded process, the contents of this directory
          are not available if the main thread has already
          terminated (typically by calling pthread_exit(3)).

          Programs that take a filename as a command-line argument,
          but don't take input from standard input if no argument is
          supplied, and programs that write to a file named as a
          command-line argument, but don't send their output to
          standard output if no argument is supplied, can
          nevertheless be made to use standard input or standard
          output by using /proc/[pid]/fd files as command-line
          arguments.  For example, assuming that -i is the flag
          designating an input file and -o is the flag designating
          an output file:

              $ foobar -i /proc/self/fd/0 -o /proc/self/fd/1 ...

          and you have a working filter.

          /proc/self/fd/N is approximately the same as /dev/fd/N in
          some UNIX and UNIX-like systems.  Most Linux MAKEDEV
          scripts symbolically link /dev/fd to /proc/self/fd, in
          fact.

          Most systems provide symbolic links /dev/stdin,
          /dev/stdout, and /dev/stderr, which respectively link to
          the files 0, 1, and 2 in /proc/self/fd.  Thus the example
          command above could be written as:

              $ foobar -i /dev/stdin -o /dev/stdout ...

          Permission to dereference or read (readlink(2)) the
          symbolic links in this directory is governed by a ptrace
          access mode PTRACE_MODE_READ_FSCREDS check; see ptrace(2).

          Note that for file descriptors referring to inodes (pipes
          and sockets, see above), those inodes still have
          permission bits and ownership information distinct from
          those of the /proc/[pid]/fd entry, and that the owner may
          differ from the user and group IDs of the process.  An
          unprivileged process may lack permissions to open them, as
          in this example:

              $ echo test | sudo -u nobody cat
              test
              $ echo test | sudo -u nobody cat /proc/self/fd/0
              cat: /proc/self/fd/0: Permission denied

          File descriptor 0 refers to the pipe created by the shell
          and owned by that shell's user, which is not nobody, so
          cat does not have permission to create a new file
          descriptor to read from that inode, even though it can
          still read from its existing file descriptor 0.
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐