In ext3 file system, if it is on journal mode, would indirect block, double indirect block and triple indirect block be considered as metadata blocks and get journaled?
Asked
Active
Viewed 266 times
1 Answers
0
Use the source, Luke - from Linux fs/ext3/inode.c
(line number for the link correct as per this writing, but the URL is Linus' head tree so this may eventually change):
/*
* 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);
[ ... ]
}
This clearly states file extensions / truncations (i.e. the allocation and/or release of direct/indirect blocks of any level) are always transacted. There's also the code in ext3_get_blocks()
itself which will open a transaction even if called without previously having created a transaction - that's used for direct I/O writes.
So in short - yes, as long as the ext3 has a journal, then modifications of direct/indirect blocks of any level are always transacted.

FrankH.
- 17,675
- 3
- 44
- 63