最近尝试了一段代码,发现发现在系统的文件系统中是运行正常的,但是在 NFS 文件系统下却不行,于是就找了一下资料:

// created by: https://liqiang.io
func main() {
	var dirName string
	flag.StringVar(&dirName, "dir.name", "", "dir rectory to remove")
	flag.Parse()

	subDirName := fmt.Sprintf("%s/b", dirName)
	err := os.Mkdir(subDirName, 0x777)
	if err != nil {
		panic(err)
	}

	file := fmt.Sprintf("%s/c", subDirName)
	f, err := os.Create(file)
	if err != nil {
		panic(err)
	}
	f.Write([]byte("hehe"))

	if err = os.RemoveAll(dirName); err != nil {
		panic(err)
	}
	fmt.Println("done!")
}

这个问题的原因是 nfs 是无状态的协议,即使服务器重启了,一个客户端也是可以无痛操作的。为了实现这种效果,nfs 通过文件名来记录文件,那么问题就来了,如果一个文件被其中一个客户端删除了,那其他客户端怎么办?是返回没有这个文件还是这个文件被删除了,所以对于被 nfs 客户端打开的文件,如果被 client 删除了,那么 nfs 就会记录一个隐藏的文件,文件名为:.nfsxxxx,然后当拥有这个文件的所有 client 都退出之后,才会释放。

如果一个 client 删除之后没有释放就掉线了,那么只有等到 server 发现这个事情的时候才会释放,这就是这段代码的问题了。