Linux下数据文件删除文件系统空间不释放的问题
首先数据文件删除文件系统空间不释放的问题不只出现在Linux平台,所有平台都可能有这样的问题。这里只是在Linux平台做一些测试,其他平台类似;其次只有将数据文件存放在文件系统中才会有此类问题,如果数据库存放在ASM中也不会有类似的问题,这篇文章的目的是对相关问题进行总结,熟悉一些工具和方法,这是比较重要的。
写这篇文章是因为客户有一套数据库,AIX 6.1,数据文件存放在文件系统中,在使用DROP TABLESPACE UNDO INCLUDING CONTENTS AND DATAFILES删除了UNDO表空间之后,文件系统空间没有得到释放。如何解决问题就成了写这篇文章的初衷。
空间没有释放我们可能是通过df命令看确认的,当我们用du去扫描目录的大小可能会发现df和du两个命令看到的空间使用情况是不同的,可能差别很大,下面这篇MOS文章说明了原因:
'du' and 'df' tools report different space utilization (文档 ID 457444.1) |
In this Document
Applies to:
Linux OS - Version Oracle Linux 4.4 and later
Linux x86-64
Linux x86
Linux Kernel - Version: 4.4 to 5.3
Symptoms
The 'du' (/usr/bin/du) and 'df' (/bin/df) command output displays conflicting space utilisation values, for example:
# df -k /
Filesystem 1k-blocks Used Available Use% Mounted on
/dev/sda6 9288792 8672768 144120 99% /
# du -xsh /
2.1G /
In the example above, 'df' reports 8.6 Gb to have been used on the root (/) filesystem, whereas 'du' reports only 2.1 Gb to have been used.
Cause
The 'df' command reports how many disk blocks are used, whilst 'du' traverses the filesystem and reports the actual number of blocks used (directory by directory), including any relating to files in use by processes.
In most cases, space utilisation values returned from 'df' and 'du' will be consistent. However, the potential exists for a running process to delete a large file, say. In this instance, according to 'du', the large file no longer exists, so the blocks associated with the deleted file are not reported. With the process still running, and with an open file descriptor still held against the deleted file, 'df' continues to track and report all disk blocks used, including those associated with the deleted (phantom) file. In this situation, the disk space associated with the deleted file will only be relinquished back to the system when the process completely releases the deleted file's descriptor or the process terminates (either gracefully or killed).
Solution
The solution is to identify and stop (or kill) the process that continues to hold a file descriptor open for the deleted file. To do so, run the lsof command (/usr/sbin/lsof | grep deleted) as root to identify the holding process, for example:
# lsof | grep deleted
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
cannaserv 3825 canna 0u CHR 136,0 2 /dev/pts/0 (deleted)
vmware 4295 root 6u REG 253,0 6770 13074503 /tmp/vmware-root/ui-4295.log (deleted)
vmware-re 4316 root 6u REG 253,0 6770 13074503 /tmp/vmware-root/ui-4295.log (deleted)
vmnet-nat 4448 root 0u CHR 136,0 2 /dev/pts/0 (deleted)
vmware-se 4454 root 0u CHR 136,0 2 /dev/pts/0 (deleted)
gdm-binar 4506 root 0u CHR 136,0 2 /dev/pts/0 (deleted)
gconfd-2 5392 root 12wW REG 253,0 609 13090818 /tmp/gconfd-root/lock/0t1188207163ut519551u0p5392r346479926k3219784492 (deleted)
vmware-vm 5822 root 57u REG 253,0 6520832 13074477 /tmp/vmware-root/ram0 (deleted)
vmware-vm 16487 root 57u REG 253,0 11153408 13074520 /tmp/vmware-root/ram0 (deleted)
kdeinit 17991 root 17u REG 253,0 26712 13074524 /tmp/kde-root/khtmlcacheM7jXYb.tmp (deleted)
kdeinit 17991 root 18u REG 253,0 5631 13074501 /tmp/kde-root/khtmlcacheZlJmda.tmp (deleted)
kdeinit 17991 root 21u REG 253,0 44718 13074514 /tmp/kde-root/khtmlcacheH5m4lc.tmp (deleted)
In the example above, the 7th column in the output denotes the size of deleted files (in bytes). The 9th column denotes which file remains held open. The 1st and second columns denotes the process and pid that still holds the open file descriptor.
之所以df和du命令看到的空间使用会有差别,原因在于du不统计已经删除的文件,df会统计已经删除的文件,但该文件依然被进程持有,只有等进程释放了该文件,df才不进行统计。通过lsof | grep deleted命令可以找出被删除的文件依然被进程持有的情况。
通过上面这篇文章我们得知,在文件系统中删除某个大文件空间没有释放是因为依然有进程在持有它,如果找到相关进程就需要用到lsof命令和fuser命令,熟悉这两个命令非常的重要。
>lsof(list open files)是一个列出当前系统打开文件的工具。
>fuser用于标识访问文件或socket的进程信息。
fuser也是我们平时常用的找进程的工具,但它不能列出详细的进程信息,更多的只是一个进程号,无法很好的过滤,在这个场景中lsof工具更加的合适。
另外,大家都知道,在Linux平台文件系统中,即使某个文件被删除,但是它如果任然有进程持有它,这个文件是可以被恢复的,这就是为什么数据库所有数据文件被删除,在实例没有停机的情况下可以完整恢复数据文件的原因,下面这篇MOS文章就讨论了在此情况下如何对数据文件进行恢复:
How To Recover Deleted Files on ext3/ext4 Filesystem (文档 ID 2056343.1) |
|
In this Document
Applies to:
Linux OS - Version Oracle Linux 5.0 and later
Linux x86-64
Linux x86
Goal
How to recover deleted file on ext3/ext4 filesystem, Which still has file descriptor opened.
Solution
A file in Linux is a pointer to an inode which contains the file data (permissions, owner and where its actual content resides on the disk).
Deleting the file removes the link, but not the inode itself.
If any other process has this file open then inode is not released for writing until the process releases it.
So if a process still has the file open, the data are there somewhere, even though the directory listing shows no files.
# ll
total 4
-rw-r--r-- 1 root root 27 Sep 16 05:19 test
# rm test
# lsof /opt/test/test
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
less 21353 root 4r REG 252,2 27 260360 /opt/test/test (deleted) <<<<<<<<<<<<<
Understanding output of "lsof" command:
COMMAND: Command using the file.
PID: PID of the file
USER: Owner of the file
FD: File descriptor. Different flags of File descriptor are as below:
#: The number in front of flag(s) is the file descriptor number of used by the process to associated with the file
u: File open with Read and Write permission
r: File open with Read permission
w: File open with Write permission
W: File open with Write permission and with Write Lock on entire file
mem: Memory mapped file, usually for share library
TYPE: File type. Different flags of File type are as below:
REG - Regular file
DIR - Directory
DEVICE: major, minor number of the device where file resides.
SIZE/OFF: File size
NODE: inode number
NAME: File name
Now we know that process 21353 still has the file open, and the file descriptor is 4.
Now we can look into /proc and there will be a reference to the inode, from which the deleted file can be copied.
Following steps will help to recover the deleted files:
# ls -l /proc/21353/fd/4
lr-x------ 1 root root 64 Sep 16 05:28 /proc/21353/fd/4 -> /opt/test/test (deleted)
# cp /proc/21353/fd/4 /opt/test/test.bkp
Now verify the content of the restored file.
Note: Don't use the -a flag with cp, as this will copy the (broken) symbolic link, rather than the actual file contents.
另外,找到是某个进程持有的文件,通过下面的方法可以看到这个进程相关的环境信息:
Checking the environment variables of ASM pmon process: It shows ORACLE_HOME is set to /oracle_grid/product/11.2.0.3/grid/ ( with 'slash' at the end )
oracle 27232 1 0 May30 ? 00:07:05 asm_pmon_+ASM1
# cat /proc/27232/environ
__CLSAGFW_TYPE_NAME=ora.asm.typeORA_CRS_HOME=/oracle_grid/product/11.2.0.3/grid/HOSTNAME=aude3od015naboi.basdev.aurdev.national.com.auTERM=xtermSHELL=/bin/bash__CR......
总结:对于此类问题,我们首先要明白为什么df和du在空间计算上有所差别,其次要熟悉lsof和fuser两个命令,找出继续持有文件的进程号,通过该进程号可以在/proc目录下恢复文件,查看进程的环境信息,甚至杀掉进程来释放空间。
最后通过一个简单的例子来结束这篇文章:
1.首先确保lsof工具已经安装到操作系统。
[root@rac01 Server]# rpm -ivh lsof-4.78-6.x86_64.rpm
Preparing... ########################################### [100%]
1:lsof ########################################### [100%]
[root@rac01 Server]# which lsof
/usr/sbin/lsof
2.在其中一个会话通过tail -f install2.log命令使tail进程持有该文件,在另一个会话通过rm -rf install2.log命令删除该文件。
3.使用lsof执行如下的操作:
[root@rac01 ~]# lsof | grep deleted
tail 6006 root 3r REG 8,3 29544 4587629 /root/install2.log (deleted)
[root@rac01 ~]# cd /proc/6006/
[root@rac01 6006]# ls
attr cmdline cwd fdinfo loginuid mounts numa_maps pagemap schedstat stat task
auxv comm environ io maps mountstats oom_adj personality sessionid statm wchan
cgroup coredump_filter exe latency mem net oom_score root smaps status
clear_refs cpuset fd limits mountinfo ns oom_score_adj sched stack syscall
[root@rac01 6006]# cd fd
[root@rac01 fd]# ll
total 0
lrwx------ 1 root root 64 Dec 3 19:07 0 -> /dev/pts/0
lrwx------ 1 root root 64 Dec 3 19:07 1 -> /dev/pts/0
lrwx------ 1 root root 64 Dec 3 19:07 2 -> /dev/pts/0
lr-x------ 1 root root 64 Dec 3 19:07 3 -> /root/install2.log (deleted)
[root@rac01 fd]# cd ..
[root@rac01 6006]# cat environ
HOSTNAME=rac01TERM=vt100SHELL=/bin/bashHISTSIZE=1000SSH_CLIENT=172.168.4.123 56823 22OLDPWD=/mnt/ServerSSH_TTY=/dev/pts/0USER=rootLS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:MAIL=/var/spool/mail/rootPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/binINPUTRC=/etc/inputrcPWD=/rootLANG=en_US.UTF-8SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpassSHLVL=1HOME=/rootLOGNAME=rootSSH_CONNECTION=172.168.4.123 56823 172.168.4.200 22LESSOPEN=|/usr/bin/lesspipe.sh %sG_BROKEN_FILENAMES=1_=/usr/bin/tail
[root@rac01 6006]# lsof /root/ <<<< 找出持有/root目录下文件的进程
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 4934 root cwd DIR 8,3 4096 4587521 /root/
tail 6006 root cwd DIR 8,3 4096 4587521 /root/
[root@rac01 6006]# lsof -c tail <<<< 找出tail进程持有的文件
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
tail 6006 root cwd DIR 8,3 4096 4587521 /root
tail 6006 root rtd DIR 8,3 4096 2 /
tail 6006 root txt REG 8,3 37704 1448826 /usr/bin/tail
tail 6006 root mem REG 8,3 56479136 1446088 /usr/lib/locale/locale-archive
tail 6006 root mem REG 8,3 1720736 5242891 /lib64/libc-2.5.so
tail 6006 root mem REG 8,3 142488 5242884 /lib64/ld-2.5.so
tail 6006 root 0u CHR 136,0 0t0 3 /dev/pts/0
tail 6006 root 1u CHR 136,0 0t0 3 /dev/pts/0
tail 6006 root 2u CHR 136,0 0t0 3 /dev/pts/0
tail 6006 root 3r REG 8,3 29544 4587629 /root/install2.log (deleted)
[root@rac01 6006]# lsof +d /root/ <<<< 显示访问/root目录下文件的进程。
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 4934 root cwd DIR 8,3 4096 4587521 /root/
tail 6006 root cwd DIR 8,3 4096 4587521 /root/
[root@rac01 6006]# lsof +D /root/ <<<< 显示访问/root目录及子目录下文件的进程。
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 4934 root cwd DIR 8,3 4096 4587521 /root/
tail 6006 root cwd DIR 8,3 4096 4587521 /root/
[root@rac01 6006]# lsof -d 3 | grep -v grep | grep deleted <<<< 显示持有文件FD为3的进程文件
tail 6006 root 3r REG 8,3 29544 4587629 /root/install2.log (deleted)
[root@rac01 6006]# lsof -p 6006 <<<< 显示6006进程持有的文件
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
tail 6006 root cwd DIR 8,3 4096 4587521 /root
tail 6006 root rtd DIR 8,3 4096 2 /
tail 6006 root txt REG 8,3 37704 1448826 /usr/bin/tail
tail 6006 root mem REG 8,3 56479136 1446088 /usr/lib/locale/locale-archive
tail 6006 root mem REG 8,3 1720736 5242891 /lib64/libc-2.5.so
tail 6006 root mem REG 8,3 142488 5242884 /lib64/ld-2.5.so
tail 6006 root 0u CHR 136,0 0t0 3 /dev/pts/0
tail 6006 root 1u CHR 136,0 0t0 3 /dev/pts/0
tail 6006 root 2u CHR 136,0 0t0 3 /dev/pts/0
tail 6006 root 3r REG 8,3 29544 4587629 /root/install2.log (deleted)
[root@rac01 6006]# lsof -u root | grep deleted <<<< 显示以root用户持有的进程文件
tail 6006 root 3r REG 8,3 29544 4587629 /root/install2.log (deleted)
[root@rac01 6006]# cd /proc/6006/fd/
[root@rac01 fd]# cp 3 /root/install2.log <<<< 恢复删除的install2.log文件
[root@rac01 fd]# cd /proc/6006/fd
[root@rac01 fd]# ll
total 0
lrwx------ 1 root root 64 Dec 3 19:07 0 -> /dev/pts/0
lrwx------ 1 root root 64 Dec 3 19:07 1 -> /dev/pts/0
lrwx------ 1 root root 64 Dec 3 19:07 2 -> /dev/pts/0
lr-x------ 1 root root 64 Dec 3 19:07 3 -> /root/install2.log (deleted) <<<< 文件恢复后deleted状态未发生变化。
[root@rac01 fd]# cd /root/
[root@rac01 ~]# ls
anaconda-ks.cfg core.11067 core.526 core.6027 core.7965 Desktop install2.log install.log install.log.syslog
--end--