如果指向的文件被移动或删除,Linux 上打开的文件句柄会发生什么情况
如果指向的文件同时获得以下信息,Linux 上打开的文件句柄会发生什么情况:
- 已移走 ->文件句柄仍然有效吗?
- 已删除->这是否会导致 EBADF,表明文件句柄无效?
- 替换为新文件->文件句柄是否指向这个新文件?
- 替换为新文件的硬链接 ->我的文件是否处理“跟随”此链接?
- 替换为新文件的软链接 ->我的文件句柄现在是否命中此软链接文件?
为什么我会问这样的问题:我正在使用热插拔硬件(例如 USB 设备等)。用户或另一个 Gremlin 可能会重新连接设备(及其 /dev/文件)。
处理这个问题的最佳实践是什么?
What happens to an open file handle on Linux if the pointed file meanwhile gets:
- Moved away -> Does the file handle stay valid?
- Deleted -> Does this lead to an EBADF, indicating an invalid file handle?
- Replaced by a new file -> Does the file handle pointing to this new file?
- Replaced by a hard link to a new file -> Does my file handle "follow" this link?
- Replaced by a soft link to a new file -> Does my file handle hit this soft link file now?
Why I'm asking such questions: I'm using hot-plugged hardware (such as USB devices etc.). It can happen, that the device (and also its /dev/file) gets reattached by the user or another Gremlin.
What's the best practice dealing with this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
下面的实验表明MarkR的答案是正确的。
code.c:
数据:
使用
gcc code.c
生成a.out
。运行./a.out
。当您看到以下输出时:使用
rm data
删除data
。但是./a.out
将继续运行,不会出现错误,并产生以下完整输出:我已经在 Ubuntu 16.04.3 上完成了实验。
The following experiment shows that MarkR's answer is correct.
code.c:
data:
Use
gcc code.c
to producea.out
. Run./a.out
. When you see the following output:Use
rm data
to deletedata
. But./a.out
will continue to run without errors and produce the following whole output:I have done the experiment on Ubuntu 16.04.3.
在 /proc/ 目录下,您将找到当前活动的每个进程的列表,只需找到您的 PID 和所有相关数据即可。一个有趣的信息是文件夹 fd/,您将找到该进程当前打开的所有文件处理程序。
最终你会发现一个到你的设备的符号链接(在/dev/甚至/proc/bus/usb/下),如果设备挂起该链接将失效并且无法刷新该句柄,进程必须关闭并且再次打开它(即使重新连接)
此代码可以读取您的PID的链接当前状态
最后的代码很简单,您可以使用linkat功能。
Under /proc/ directory you will find a list of every process currently active, just find your PID and all data regarding is there. An interresting info is the folder fd/, you will find all file handlers currently opened by the process.
Eventually you will find a symbolic link to your device (under /dev/ or even /proc/bus/usb/), if the device hangs the link will be dead and it will be impossible to refresh this handle, the process must close and open it again (even with reconnection)
This code can read your PID's link current status
This final code is simple, you can play with linkat function.
如果文件被移动(在同一文件系统中)或重命名,则文件句柄保持打开状态,并且仍然可用于读取和写入文件。
如果文件被删除,文件句柄保持打开状态并且仍然可以使用(这不是某些人所期望的)。直到最后一个句柄关闭后,文件才会真正被删除。
如果该文件被新文件替换,则具体取决于如何替换。如果文件内容被覆盖,文件句柄仍然有效并可以访问新内容。如果现有文件被取消链接并创建一个具有相同名称的新文件,或者如果使用
rename()
将新文件移动到现有文件上,则与删除相同(见上文) - 即也就是说,文件句柄将继续引用文件的原始版本。一般来说,一旦文件打开,文件就打开了,任何人都无法更改目录结构 - 他们可以移动、重命名文件或将其他内容放在其位置,它只是保持打开状态。
在 Unix 中没有删除,只有
unlink()
,这是有道理的,因为它不一定删除文件 - 只是从目录中删除链接。另一方面,如果底层设备消失(例如 USB 拔出),则文件句柄将不再有效,并且可能会在任何操作中出现 IO/错误。但你仍然必须关闭它。即使设备重新插入,情况也是如此,因为在这种情况下保持文件打开是不明智的。
If the file is moved (in the same filesystem) or renamed, then the file handle remains open and can still be used to read and write the file.
If the file is deleted, the file handle remains open and can still be used (This is not what some people expect). The file will not really be deleted until the last handle is closed.
If the file is replaced by a new file, it depends exactly how. If the file's contents are overwritten, the file handle will still be valid and access the new content. If the existing file is unlinked and a new one created with the same name or, if a new file is moved onto the existing file using
rename()
, it's the same as deletion (see above) - that is, the file handle will continue to refer to the original version of the file.In general, once the file is open, the file is open, and nobody changing the directory structure can change that - they can move, rename the file, or put something else in its place, it simply remains open.
In Unix there is no delete, only
unlink()
, which makes sense as it doesn't necessarily delete the file - just removes the link from the directory.If on the other hand the underlying device disappears (e.g. USB unplug) then the file handle won't be valid any more and is likely to give IO/error on any operation. You still have to close it though. This is going to be true even if the device is plugged back in, as it's not sensible to keep a file open in this case.
文件句柄指向索引节点而不是路径,因此大多数场景仍然按照您的假设工作,因为句柄仍然指向文件。
具体来说,在删除场景中 - 该函数被称为“取消链接”是有原因的,它会破坏文件名(目录项)和文件之间的“链接”。当您打开一个文件,然后取消链接它时,该文件实际上仍然存在,直到其引用计数变为零,即关闭句柄时。
编辑:对于硬件,您已经打开了特定设备节点的句柄,如果拔出该设备,内核将导致对其的所有访问失败,即使该设备回来了。您必须关闭设备并重新打开它。
File handles point to an inode not to a path, so most of your scenarios still work as you assume, since the handle still points to the file.
Specifically, with the delete scenario - the function is called "unlink" for a reason, it destroys a "link" between a filename (a dentry) and a file. When you open a file, then unlink it, the file actually still exists until its reference count goes to zero, which is when you close the handle.
Edit: In the case of hardware, you have opened a handle to a specific device node, if you unplug the device, the kernel will fail all accesses to it, even if the device comes back. You will have to close the device and reopen it.
我不确定其他操作,但至于删除:删除根本不会发生(物理上,即在文件系统中),直到文件的最后一个打开句柄被关闭。因此,不可能从您的应用程序中删除文件。
一些应用程序(没有想到)依赖于这种行为,通过创建、打开和立即删除文件,然后这些文件的生存时间与应用程序一样长 - 允许其他应用程序了解第一个应用程序的生命周期,而无需查看流程图等。
类似的考虑可能也适用于其他事情。
I'm not sure about the other operations, but as for deletion: Deletion simply doesn't take place (physically, i.e. in the file system) until the last open handle to the file is closed. Thus it should not be possible to delete a file out from under your application.
A few apps (that don't come to mind) rely on this behavior, by creating, opening and immediately deleting files, which then live exactly as long as the application - allowing other applications to be aware of the first app's lifecycle without needing to look at process maps and such.
It's possible similar considerations apply to the other stuff.
如果你想检查文件处理程序(文件描述符)是否正常,可以调用此函数。
if you want to check if the file handler(file descriptor) is okay, you can call this function.
已删除文件的内存中信息(您给出的所有示例都是已删除文件的实例)以及磁盘上的 inode 一直存在,直到文件关闭。
硬件热插拔是一个完全不同的问题,如果磁盘上的索引节点或元数据发生了根本改变,您不应该指望您的程序能够长时间保持活动状态。
The in-memory information of a deleted file (all the examples you give are instances of a deleted file) as well as the inodes on-disk remain in existence until the file is closed.
Hardware being hotplugged is a completely different issue, and you should not expect your program to stay alive long if the on-disk inodes or metadata have changed at all.