lxg*_*xgr 5 linux filesystems fat32
我很清楚在使用 inode 的文件系统上删除打开的文件是如何工作的 - unlink() 只是将链接计数减少到零,并且当文件的最后一个文件句柄关闭时,inode 将被删除。
但是,在 Linux 中使用不使用 inode 的文件系统(如 FAT32)时,它是如何工作的?
一些实验表明删除打开的文件仍然是可能的(不像在 Windows 上,unlink 调用不会成功),但是当文件系统被不干净地卸载时会发生什么?
当文件系统本身不支持这样的操作时,Linux 如何将文件标记为未链接?是刚刚删除的目录项,还保留在内存中吗(无论如何都保证卸载后删除,但会使文件系统处于不一致的状态),还是只在内存中标记删除,并在删除时写入关闭最后一个文件句柄,避免可能的损坏,但在不干净的卸载后恢复已删除的文件?
您的假设是正确的,虽然所有目录条目在调用 unlink() 后立即被删除,但物理上构成文件的实际块仅在没有任何东西再使用 inode 时才会在磁盘上清除。(我说“目录条目”是因为在 vfat 中,一个文件实际上可以有多个目录条目,这取决于 vfat 的长文件名支持的实现方式。)
在这种情况下,我所说的inode是指 Linux 内核用于处理文件的内存结构。即使文件系统不是“基于索引节点”,它也会被使用。对于 vfat,inode 只是由磁盘上的一些块支持。
查看Linux内核源代码,我们看到vfat_unlink实现了unlink()vfat的系统调用,大致执行以下操作(为了说明而极其简化):
static int vfat_unlink(struct inode *dir, struct dentry *dentry)
{
fat_remove_entries(dir, &sinfo);
clear_nlink(inode);
}
Run Code Online (Sandbox Code Playgroud)
那么发生的事情是:
fat_remove_entries只需删除其目录中文件的条目即可。clear_nlink将索引节点的链接计数设置为0,这意味着没有文件(即没有目录条目)再指向该索引节点。请注意,此时,索引节点及其物理表示都没有以任何方式受到影响(除了减少的链接计数),因此它仍然愉快地存在于内存和磁盘中,就好像什么也没发生一样!
(顺便说一句,值得注意的是,vfat_unlink总是将链接计数设置为0,而不是仅仅使用 来减少它drop_link。这应该提醒您 FAT 文件系统不支持硬链接!并且进一步表明 FAT 本身不知道任何硬链接。单独的索引节点概念。)
现在让我们看看当 inode 被驱逐时会发生什么。evict_inode当我们不再需要内存中的 inode 时调用。最早,这当然只能在没有进程再持有该 inode 的任何打开文件描述符时发生(但理论上也可能在以后发生)。FAT 实现evict_inode看起来(再次简化)如下:
static void fat_evict_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
if (!inode->i_nlink) {
inode->i_size = 0;
fat_truncate_blocks(inode, 0);
}
invalidate_inode_buffers(inode);
clear_inode(inode);
}
Run Code Online (Sandbox Code Playgroud)
神奇的事情就发生在 -clause 中if:如果 inode 的链接计数为 0,则意味着没有目录条目实际指向它。因此,我们将其大小设置为 0,并将其实际截断为 0 字节,这实际上是通过清除其组成的块来将其从磁盘中删除。
因此,您在实验中遇到的损坏很容易解释:正如您所怀疑的那样,目录条目已被删除(由vfat_unlink),但由于 inode 尚未被逐出,因此实际块仍然未受影响,并且仍然存在在 FAT(文件分配表的缩写)中标记为已使用。fsck.vfat然而,检测到不再有指向这些块的目录条目,抱怨并修复它。
顺便说一句,CHKDSK不仅会通过将这些块标记为空闲来清除这些块,还会在根目录中创建指向每个链中第一个块的新文件,其名称类似于FILE0001.CHK.
| 归档时间: |
|
| 查看次数: |
3265 次 |
| 最近记录: |