08 ext2文件系统IO流程:删除文件unlink

前面几篇博客讲了创建文件、创建目录、查找文件,接下来说一下ext2文件系统是如何删除文件,ext2文件系统删除文件,并没有在物理设备上擦除文件,只是做了一个unlink操作,所谓的逻辑删除。unlink的具体实现,就是解除目录项与inode关系,这样目录项就不会关联到inode,就无法查找到文件,达到了删除的目的。unlink的具体的流程如下:

  • ① 根据文件名和父目录信息,到磁盘上查找目录项(ext2_find_entry),记录对应的页面page和页地址page_addr
  • ② 解除目录项与inode连接,然后删除目录项(逻辑删除,其实是与前一个目录项合并)
  • ③ 修改inode->i_ctime,递减inode的硬链接数i->nlink,同时标记脏inode
ext2 unlink操作
ext2 unlink操作
static int ext2_unlink(struct inode * dir, struct dentry *dentry)
{
    struct inode * inode = d_inode(dentry);

    ......

    de = ext2_find_entry(dir, &dentry->d_name, &page, &page_addr);
    if (IS_ERR(de)) {
        err = PTR_ERR(de);
        goto out;
    }

    err = ext2_delete_entry(de, page, page_addr);
    ext2_put_page(page, page_addr);
    if (err)
        goto out;

    inode->i_ctime = dir->i_ctime;
    inode_dec_link_count(inode);
    err = 0;
out:
    return err;
}

一、查询文件的目录项(磁盘)

与上一篇查询文件的查找目录项逻辑一致(ext2_find_entry()),就是根据循环父目录相关的所有页面,找到目录项位置,在此不做过多赘述,详细参考如下链接。

上一篇:07 ext2文件系统IO流程:文件查找lookup

二、“删除”磁盘目录项

这里的删除加了引号,其实是逻辑删除,最主要就两个动作:一是将inode设为0,也就是不指向任何inode,二是将目录项与前一条合并(修改前一条的rec_len)。

经过这两个动作后,要删除文件的目录项,就不指向inode,在用户端就无法展示,同时合并两个目录项之后,目录项数据仍然是连续的,可以顺序读取。

// dir.c

/*
 * ext2_delete_entry deletes a directory entry by merging it with the
 * previous entry. Page is up-to-date.
 */
int ext2_delete_entry (struct ext2_dir_entry_2 *dir, struct page *page,
            char *kaddr)
{
    struct inode *inode = page->mapping->host;
    unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1);
    unsigned to = ((char *)dir - kaddr) +
                ext2_rec_len_from_disk(dir->rec_len);
    loff_t pos;
    ext2_dirent * pde = NULL; // 记录前一条entry
    ext2_dirent * de = (ext2_dirent *) (kaddr + from);
    int err;

    while ((char*)de < (char*)dir) {
        if (de->rec_len == 0) {
            ext2_error(inode->i_sb, __func__,
                "zero-length directory entry");
            err = -EIO;
            goto out;
        }
        pde = de;
        de = ext2_next_entry(de);
    }
    if (pde)
        from = (char *)pde - kaddr;
    pos = page_offset(page) + from;
    lock_page(page);
    err = ext2_prepare_chunk(page, pos, to - from); // 准备要写入的块
    BUG_ON(err);
    if (pde)
        pde->rec_len = ext2_rec_len_to_disk(to - from); // 修改长度
    dir->inode = 0; // inode置0
    err = ext2_commit_chunk(page, pos, to - from); // 提交页面修改
    inode->i_ctime = inode->i_mtime = current_time(inode);
    EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL;
    mark_inode_dirty(inode);
out:
    return err;
}

三、递减链接数

第二步解除目录项与inode关系,但是一个文件可能被多个目录项使用,不能直接释放inode资源。通过递减inode中的硬链接数,当硬链接数为0时,VFS会调用super_block的操作表完成inode释放工作。

inode->i_ctime = dir->i_ctime;
inode_dec_link_count(inode);

static inline void inode_dec_link_count(struct inode *inode)
{
	drop_nlink(inode);
	mark_inode_dirty(inode);
}

官方文档:VFS

《08 ext2文件系统IO流程:删除文件unlink》有一个想法

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注