在有序模式下执行ext3日记间接/双间接块



在ext3文件系统中,如果处于日志模式,间接块、双间接块和三间接块会被视为元数据块并被日志记录吗?

使用源代码Luke-来自Linux fs/ext3/inode.c(链接的行号根据本文正确,但URL是Linus的头树,因此最终可能会更改):

/*
 * Note that we always start a transaction even if we're not journalling
 * data.  This is to preserve ordering: any hole instantiation within
 * __block_write_full_page -> ext3_get_block() should be journalled
 * along with the data so we don't crash and then get metadata which
 * refers to old data.
[ ... ]
static int ext3_ordered_writepage(struct page *page,
                                struct writeback_control *wbc)
{
        struct inode *inode = page->mapping->host;
        struct buffer_head *page_bufs;
        handle_t *handle = NULL;
        int ret = 0;
        int err;
[ ... ]
        handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode));
[ ... ]
        ret = block_write_full_page(page, ext3_get_block, wbc);
[ ... ]
        /*
         * And attach them to the current transaction.  But only if
         * block_write_full_page() succeeded.  Otherwise they are unmapped,
         * and generally junk.
         */
        if (ret == 0) {
                err = walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE,
                                        NULL, journal_dirty_data_fn);
                if (!ret)
                        ret = err;
        }
        walk_page_buffers(handle, page_bufs, 0,
                        PAGE_CACHE_SIZE, NULL, bput_one);
        err = ext3_journal_stop(handle);
        if (!ret)
                ret = err;
[ ... ]
        return ret;
}
[ ... ]
/*
 * ext3_truncate()
 *
 * We block out ext3_get_block() block instantiations across the entire
 * transaction, and VFS/VM ensures that ext3_truncate() cannot run
 * simultaneously on behalf of the same inode.
 *
 * As we work through the truncate and commit bits of it to the journal there
 * is one core, guiding principle: the file's tree must always be consistent on
 * disk.  We must be able to restart the truncate after a crash.
 *
[ ... ]
 */
void ext3_truncate(struct inode *inode)
{
        handle_t *handle;
[ ... ]
        handle = start_transaction(inode);
[ ... ]
        /*
         * OK.  This truncate is going to happen.  We add the inode to the
         * orphan list, so that if this truncate spans multiple transactions,
         * and we crash, we will resume the truncate when the filesystem
         * recovers.  It also marks the inode dirty, to catch the new size.
         *
         * Implication: the file must always be in a sane, consistent
         * truncatable state while each transaction commits.
         */
        if (ext3_orphan_add(handle, inode))
                goto out_stop;
[ ... ]
        if (n == 1) {           /* direct blocks */
                ext3_free_data(handle, inode, NULL, i_data+offsets[0],
                               i_data + EXT3_NDIR_BLOCKS);
                goto do_indirects;
        }
[ ... ]
do_indirects:
        /* Kill the remaining (whole) subtrees */
        switch (offsets[0]) {
        default:
                nr = i_data[EXT3_IND_BLOCK];
                if (nr) {
                        ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 1);
                        i_data[EXT3_IND_BLOCK] = 0;
                }
        case EXT3_IND_BLOCK:
                nr = i_data[EXT3_DIND_BLOCK];
                if (nr) {
                        ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 2);
                        i_data[EXT3_DIND_BLOCK] = 0;
                }
        case EXT3_DIND_BLOCK:
                nr = i_data[EXT3_TIND_BLOCK];
                if (nr) {
                        ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 3);
                        i_data[EXT3_TIND_BLOCK] = 0;
                }
        case EXT3_TIND_BLOCK:
                ;
        }
[ ... ]
        ext3_journal_stop(handle);
[ ... ]
}

这清楚地表明,文件扩展名/截断(即任何级别的直接/间接块的分配和/或释放)始终是事务性的。还有ext3_get_blocks()本身中的代码,即使在之前没有创建事务的情况下进行调用,它也会打开事务——用于直接I/O写入。

简而言之,是的,只要ext3有一个日志,那么任何级别的直接/间接块的修改都会被处理。

相关内容

  • 没有找到相关文章

最新更新