简体   繁体   English

当我的 shell 使用该目录时,为什么可以删除该目录?

[英]Why can a directory be removed when my shell is using that directory?

I don't know if what I encountered was a bug or is intended behavior, but luckily I figured out pretty quick what was going on.我不知道我遇到的是错误还是预期的行为,但幸运的是我很快就知道发生了什么。

I had my shell cd'd inside a subdirectory of the git repo, and I performed a git rebase -i squash operation in which the commits involved included the creation of this directory.我将 shell cd 放在 git repo 的子目录中,并且我执行了git rebase -i squash 操作,其中涉及的提交包括创建此目录。

After that operation completed without incident, the shell became in an orphaned state where the git status (neither in the zsh theme helper RPROMPT nor when run) indicated that I wasn't even in a git repository anymore.在该操作顺利完成后,shell 处于孤立状态,其中git status (既不在 zsh 主题助手 RPROMPT 中,也不在运行时)表明我什至不在 git 存储库中了。

Once I ran cd .. everything was fine, and it all made sense.一旦我运行cd ..一切都很好,一切都有意义。 During the course of the rebasing operation, Git had rm 'd the directory that I was in (at the first step of the rebase) and subsequently put it back.在变基操作的过程中,Git 已经rm 'd 了我所在的目录(在变基的第一步),然后将其放回原处。 Since it got put back, I could also have ran cd $(pwd) to go there in one step.既然它被放回去了,我也可以一步运行cd $(pwd)去那里。

This is some confusing behavior.这是一些令人困惑的行为。 Although, it is not clear that anything was technically done wrong by git.虽然,尚不清楚 git 在技术上做错了什么。 My question is would this be a bug in git or should users be expected to know how to deal with this situation?我的问题是这会是git的错误还是应该期望用户知道如何处理这种情况?

Also, the wider, actual root question: Why is it permitted to remove a directory that my shell is in, when it is not permitted to eject a disk if I have a shell on a mounted directory?此外,更广泛的实际根问题是:如果我在已挂载的目录上有一个 shell,为什么不允许删除我的 shell 所在的目录,而不允许弹出磁盘? It seems inconsistent to me.这对我来说似乎不一致。

Case in point: fuser <directory> shows current directory uses.举个例子: fuser <directory>显示当前目录的使用。 If a program is "on" a directory it is "using" it.如果一个程序“在”一个目录上,它就是“使用”它。

Terminal 1: 1号航站楼:

$ cd tmp/
$ mkdir test
$ cd test

Terminal 2: 2 号航站楼:

$ rmdir tmp/test 

Terminal 1: 1号航站楼:

$ ls 
sh: 0: getcwd() failed: No such file or directory

Inconsistent, yes.不一致,是的。 But allowed.但允许。

PS.附注。 And this has nothing to do with git .这与git无关。

To answer your first question:回答你的第一个问题:

It is not a bug, it is how Unix systems, including Linux, have always worked.这不是错误,它是 Unix 系统(包括 Linux)一直以来的工作方式。

There's even some nice text in the POSIX spec : POSIX 规范中甚至还有一些不错的文字:

[EBUSY] The directory to be removed is currently in use by the system or some process and the implementation considers this to be an error. [EBUSY] 要删除的目录当前正在被系统或某个进程使用,并且实现认为这是一个错误。

Namely, some implementation (eg Windows...) can call it an error, but most implementations.即,某些实现(例如 Windows...)可以将其称为错误,但大多数实现。 namely Unix variants, do not.即 Unix 变体,不要。

The way this is implemented in a filesystem is by having the processes hold a reference on the object which represents the directory.在文件系统中实现的方式是让进程持有对代表目录的对象的引用。 Another thing that holds such a reference is the parent directory.保存此类引用的另一件事是父目录。 git rebase has removed the latter reference, but the former remains. git rebase删除了后一个引用,但前一个引用仍然存在。 Even if the directory is re-created, it is a new filesystem object, whereas your shell was holding a reference to the old object.即使重新创建目录,它也是一个新的文件系统对象,而您的 shell 持有对旧对象的引用。

That's why cd .. and cd $(pwd) still work - they re-lookup the directory and grab the new reference, and release the old reference.这就是为什么cd ..cd $(pwd)仍然有效 - 它们重新查找目录并获取新引用,然后释放旧引用。

Officially the old object is not cleaned up until the old reference is released.在旧引用被释放之前,旧对象不会被正式清除。 That means that the metadata of the directory is not removed from the disk until the process releases the old working directory.这意味着在进程释放旧的工作目录之前,目录的元数据不会从磁盘中删除。

To answer your second question:回答你的第二个问题:

In order to eject a drive you have to unmount the mountpoint, and as above, the processes you find with fuser hold references to that mountpoint.为了弹出驱动器,您必须卸载挂载点,如上所述,您使用fuser找到的进程持有对该挂载点的引用。

As with directory references, a amount point cannot be cleaned up until all references to it have been removed.与目录引用一样,在删除对它的所有引用之前,无法清除数量点。 That is why you cannot eject a drive which has references.这就是您无法弹出具有引用的驱动器的原因。

The consistent thing to do would be to allow detaching the filesystem from the directory tree without actually cleaning up.一致的做法是允许从目录树中分离文件系统而不实际清理。 You still won't be able to eject the drive, but at least you can use the directory tree as you wish.您仍然无法弹出驱动器,但至少您可以随意使用目录树。

Well, that is actually possible to do with umount --lazy .嗯,这实际上可以用umount --lazy来完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM