卸载nfsv3挂载点时报错device is busy,但用lsof +D <挂载点>和fuser -m <挂载点>都无法找到使用挂载点的进程。
用以下命令打开nfs日志开关(参考《nfs调试方法》):
kprobe抓进程信息(参考《内核调试方法》):
kprobe_func_name=nfs_file_open # 或者 nfs_file_read
cd /sys/kernel/debug/tracing/
cat available_filter_functions | grep ${kprobe_func_name}
echo 1 > tracing_on
echo "p:p_${kprobe_func_name} ${kprobe_func_name}" >> kprobe_events
echo 1 > events/kprobes/p_${kprobe_func_name}/enable
echo stacktrace > events/kprobes/p_${kprobe_func_name}/trigger # 打印栈
# echo '!stacktrace' > events/kprobes/p_${kprobe_func_name}/trigger # 关闭栈
# echo 0 > events/kprobes/p_${kprobe_func_name}/enable
# echo "-:p_${kprobe_func_name}" >> kprobe_events
echo 0 > trace # 清除trace信息
cat trace_pipe挂载:
在用户态通过创建两个线程,不断打开又关闭文件,编译运行thread-open-file-short-time.c:
gcc -o thread-open-file-short-time thread-open-file-short-time.c -lpthread
./thread-open-file-short-time这时无法卸载nfs,且用lsof +D <挂载点>和fuser -m <挂载点>都无法找到使用挂载点的进程:
用上面的kprobe trace抓到以下信息:
956是线程id,用以下命令查看完整的进程名:
在内核空间打开文件,用lsof +D <挂载点>和fuser -m <挂载点>无法找到进程。
源码文件如下:
挂载:
加载ko,打开并读文件/mnt/dir/file,注意这个操作不要在生产环境中尝试:
mkdir /mnt/dir -p
echo something > /mnt/dir/file # 创建文件
echo 3 > /proc/sys/vm/drop_caches
insmod kernel-open-file.ko日志请查看nfs-umount-device-is-busy-log.txt:
这时我们卸载nfs挂载点就能得到一样的报错信息,且无法找到使用挂载点的进程:
移除ko后,在内核关闭了文件,就能正常卸载nfs挂载点了:
系统调用的跟踪调试请查看《文件系统延迟卸载》。
只有在用户空间打开文件时会把文件描述符放到files_struct -> fdt中:
在内核空间打开文件时,不会把文件描述符加到fdtable中,fuser -m和lsof +D无法遍历到文件描述符,所以无法找到打开文件的进程。
可以用kprobe-fd_install.c调试, 其中mydebug_dump_stack()相关的用法可以查看《mydebug模块》。