如何删除 ext2 文件系统中的文件

How removing a file in ext2 file system work

我正在学习EXT2文件系统。我对删除文件对 EXT2 的工作方式感到困惑。我的理解是,删除后,它实际上并没有删除索引节点,而是将一些元数据标记为未使用。我的问题是,它在删除时修改了哪些元数据,文件系统如何知道文件已被删除?谢谢。

在Linux中,这是围绕fs/ext2/inode.c文件的ext2_delete_inode函数实现的: http://lxr.free-electrons.com/source/fs/ext2/inode.c?v=2.6.32#L59

 56 /*
 57  * Called at the last iput() if i_nlink is zero.
 58  */
 59 void ext2_delete_inode (struct inode * inode)
 60 {
 61         truncate_inode_pages(&inode->i_data, 0);
  ..
 65         EXT2_I(inode)->i_dtime  = get_seconds();
 66         mark_inode_dirty(inode);
 67         ext2_write_inode(inode, inode_needs_sync(inode));
 68 
 69         inode->i_size = 0;
 70         if (inode->i_blocks)
 71                 ext2_truncate (inode);
 72         ext2_free_inode (inode);
 73 
 74         return;
  ..
 77 }

因此,它从 truncate_inode_pages, sets dtime (deletion time) and marks inode as dirty - I_DIRTY which is combination of (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES) 中的页面缓存中删除页面:

1601  * I_DIRTY_SYNC         Inode is dirty, but doesn't have to be written on
1602  *                      fdatasync().  i_atime is the usual cause.
1603  * I_DIRTY_DATASYNC     Data-related inode changes pending. We keep track of
1604  *                      these changes separately from I_DIRTY_SYNC so that we
1605  *                      don't have to write inode on fdatasync() when only
1606  *                      mtime has changed in it.
1607  * I_DIRTY_PAGES        Inode has dirty pages.  Inode itself may be clean.

然后写入修改后的 inode,将 大小更改为零 ,截断所有从 inode 链接到 ext2_truncate() 的块(实际将数据块标记为空闲是在那里完成的): http://lxr.free-electrons.com/source/fs/ext2/inode.c?v=2.6.32#L1025

1025 void ext2_truncate(struct inode *inode)
1026 {
..
1059         n = ext2_block_to_path(inode, iblock, offsets, NULL);
 99 /*      ext2_block_to_path - parse the block number into array of offsets
105  *      To store the locations of file's data ext2 uses a data structure common
106  *      for UNIX filesystems - tree of pointers anchored in the inode, with
107  *      data blocks at leaves and indirect blocks in intermediate nodes.
108  *      This function translates the block number into path in that tree -
109  *      return value is the path length and @offsets[n] is the offset of
110  *      pointer to (n+1)th node in the nth one. If @block is out of range
111  *      (negative or too large) warning is printed and zero returned. */
1069         if (n == 1) {
1070                 ext2_free_data(inode, i_data+offsets[0],
1071                                         i_data + EXT2_NDIR_BLOCKS);
1072                 goto do_indirects;
1073         }
..
1082                 ext2_free_branches(inode, &nr, &nr+1, (chain+n-1) - partial);
..
1084         /* Clear the ends of indirect blocks on the shared branch */
1085         while (partial > chain) {
1086                 ext2_free_branches(inode,
1087                                    partial->p + 1,
1088                                    (__le32*)partial->bh->b_data+addr_per_block,
1089                                    (chain+n-1) - partial);
..
1094 do_indirects:
1095         /* Kill the remaining (whole) subtrees */
1096         switch (offsets[0]) {
1097                 default:
1098                         nr = i_data[EXT2_IND_BLOCK];
1099                         if (nr) {
1100                                 i_data[EXT2_IND_BLOCK] = 0;
1101                                 mark_inode_dirty(inode);
1102                                 ext2_free_branches(inode, &nr, &nr+1, 1);
1103                         }
1104                 case EXT2_IND_BLOCK:
1105                         nr = i_data[EXT2_DIND_BLOCK];
1106                         if (nr) {
1107                                 i_data[EXT2_DIND_BLOCK] = 0;
1108                                 mark_inode_dirty(inode);
1109                                 ext2_free_branches(inode, &nr, &nr+1, 2);
1110                         }
1111                 case EXT2_DIND_BLOCK:
1112                         nr = i_data[EXT2_TIND_BLOCK];
1113                         if (nr) {
1114                                 i_data[EXT2_TIND_BLOCK] = 0;
1115                                 mark_inode_dirty(inode);
1116                                 ext2_free_branches(inode, &nr, &nr+1, 3);
1117                         }
1118                 case EXT2_TIND_BLOCK:
1119                         ;
1120         }

(为什么EXT2_TIND_BLOCK没有被清除?)

然后我们可以释放内核内存中的inode结构。

how does the file system know that the file is deleted?

检查在 ext2_iget 函数中:http://lxr.free-electrons.com/source/fs/ext2/inode.c?v=2.6.32#L1251

1251         /* We now have enough fields to check if the inode was active or not.
1252          * This is needed because nfsd might try to access dead inodes
1253          * the test is that same one that e2fsck uses
1254          * NeilBrown 1999oct15
1255          */
1256         if (inode->i_nlink == 0 && (inode->i_mode == 0 || ei->i_dtime)) {
1257                 /* this inode is deleted */
1258                 brelse (bh);
1259                 ret = -ESTALE;
1260                 goto bad_inode;
1261         }

所以,删除的inode是没有传入链接的inode(它在任何目录中都没有提到i_nlink)并且具有零模式或非零删除时间。