提交 b920c755 编写于 作者: T Theodore Ts'o

ext4: Add documentation to the ext4_*get_block* functions

This adds more documentation to various internal functions in
fs/ext4/inode.c, most notably ext4_ind_get_blocks(),
ext4_da_get_block_write(), ext4_da_get_block_prep(),
ext4_normal_get_block_write().

In addition, the static function ext4_normal_get_block_write() has
been renamed noalloc_get_block_write(), since it is used in many
places far beyond ext4_normal_writepage().

Plenty of warnings have been added to the noalloc_get_block_write()
function, since the way it is used is amazingly fragile.
Signed-off-by: N"Theodore Ts'o" <tytso@mit.edu>
上级 c2177057
...@@ -892,6 +892,10 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode, ...@@ -892,6 +892,10 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
} }
/* /*
* The ext4_ind_get_blocks() function handles non-extents inodes
* (i.e., using the traditional indirect/double-indirect i_blocks
* scheme) for ext4_get_blocks().
*
* Allocation strategy is simple: if we have to allocate something, we will * Allocation strategy is simple: if we have to allocate something, we will
* have to go the whole way to leaf. So let's do it before attaching anything * have to go the whole way to leaf. So let's do it before attaching anything
* to tree, set linkage between the newborn blocks, write them if sync is * to tree, set linkage between the newborn blocks, write them if sync is
...@@ -909,10 +913,11 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode, ...@@ -909,10 +913,11 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
* return = 0, if plain lookup failed. * return = 0, if plain lookup failed.
* return < 0, error case. * return < 0, error case.
* *
* * The ext4_ind_get_blocks() function should be called with
* Need to be called with * down_write(&EXT4_I(inode)->i_data_sem) if allocating filesystem
* down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block * blocks (i.e., flags has EXT4_GET_BLOCKS_CREATE set) or
* (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem) * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system
* blocks.
*/ */
static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
ext4_lblk_t iblock, unsigned int maxblocks, ext4_lblk_t iblock, unsigned int maxblocks,
...@@ -1152,8 +1157,8 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block, ...@@ -1152,8 +1157,8 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
clear_buffer_unwritten(bh); clear_buffer_unwritten(bh);
/* /*
* Try to see if we can get the block without requesting * Try to see if we can get the block without requesting a new
* for new file system block. * file system block.
*/ */
down_read((&EXT4_I(inode)->i_data_sem)); down_read((&EXT4_I(inode)->i_data_sem));
if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) { if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
...@@ -2000,6 +2005,12 @@ static void ext4_print_free_blocks(struct inode *inode) ...@@ -2000,6 +2005,12 @@ static void ext4_print_free_blocks(struct inode *inode)
return; return;
} }
/*
* This function is used by mpage_da_map_blocks(). We separate it out
* as a separate function just to make life easier, and because
* mpage_da_map_blocks() used to be a generic function that took a
* get_block_t.
*/
static int ext4_da_get_block_write(struct inode *inode, sector_t iblock, static int ext4_da_get_block_write(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result) struct buffer_head *bh_result)
{ {
...@@ -2031,8 +2042,8 @@ static int ext4_da_get_block_write(struct inode *inode, sector_t iblock, ...@@ -2031,8 +2042,8 @@ static int ext4_da_get_block_write(struct inode *inode, sector_t iblock,
/* /*
* Update on-disk size along with block allocation we don't * Update on-disk size along with block allocation we don't
* use 'extend_disksize' as size may change within already * use EXT4_GET_BLOCKS_EXTEND_DISKSIZE as size may change
* allocated block -bzzz * within already allocated block -bzzz
*/ */
disksize = ((loff_t) iblock + ret) << inode->i_blkbits; disksize = ((loff_t) iblock + ret) << inode->i_blkbits;
if (disksize > i_size_read(inode)) if (disksize > i_size_read(inode))
...@@ -2338,8 +2349,9 @@ static int __mpage_da_writepage(struct page *page, ...@@ -2338,8 +2349,9 @@ static int __mpage_da_writepage(struct page *page,
} }
/* /*
* this is a special callback for ->write_begin() only * This is a special get_blocks_t callback which is used by
* it's intention is to return mapped block or reserve space * ext4_da_write_begin(). It will either return mapped block or
* reserve space for a single block.
* *
* For delayed buffer_head we have BH_Mapped, BH_New, BH_Delay set. * For delayed buffer_head we have BH_Mapped, BH_New, BH_Delay set.
* We also have b_blocknr = -1 and b_bdev initialized properly * We also have b_blocknr = -1 and b_bdev initialized properly
...@@ -2347,7 +2359,6 @@ static int __mpage_da_writepage(struct page *page, ...@@ -2347,7 +2359,6 @@ static int __mpage_da_writepage(struct page *page,
* For unwritten buffer_head we have BH_Mapped, BH_New, BH_Unwritten set. * For unwritten buffer_head we have BH_Mapped, BH_New, BH_Unwritten set.
* We also have b_blocknr = physicalblock mapping unwritten extent and b_bdev * We also have b_blocknr = physicalblock mapping unwritten extent and b_bdev
* initialized properly. * initialized properly.
*
*/ */
static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock, static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create) struct buffer_head *bh_result, int create)
...@@ -2400,7 +2411,23 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock, ...@@ -2400,7 +2411,23 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
return ret; return ret;
} }
static int ext4_normal_get_block_write(struct inode *inode, sector_t iblock, /*
* This function is used as a standard get_block_t calback function
* when there is no desire to allocate any blocks. It is used as a
* callback function for block_prepare_write(), nobh_writepage(), and
* block_write_full_page(). These functions should only try to map a
* single block at a time.
*
* Since this function doesn't do block allocations even if the caller
* requests it by passing in create=1, it is critically important that
* any caller checks to make sure that any buffer heads are returned
* by this function are either all already mapped or marked for
* delayed allocation before calling nobh_writepage() or
* block_write_full_page(). Otherwise, b_blocknr could be left
* unitialized, and the page write functions will be taken by
* surprise.
*/
static int noalloc_get_block_write(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create) struct buffer_head *bh_result, int create)
{ {
int ret = 0; int ret = 0;
...@@ -2419,10 +2446,11 @@ static int ext4_normal_get_block_write(struct inode *inode, sector_t iblock, ...@@ -2419,10 +2446,11 @@ static int ext4_normal_get_block_write(struct inode *inode, sector_t iblock,
} }
/* /*
* get called vi ext4_da_writepages after taking page lock (have journal handle) * This function can get called via...
* get called via journal_submit_inode_data_buffers (no journal handle) * - ext4_da_writepages after taking page lock (have journal handle)
* get called via shrink_page_list via pdflush (no journal handle) * - journal_submit_inode_data_buffers (no journal handle)
* or grab_page_cache when doing write_begin (have journal handle) * - shrink_page_list via pdflush (no journal handle)
* - grab_page_cache when doing write_begin (have journal handle)
*/ */
static int ext4_da_writepage(struct page *page, static int ext4_da_writepage(struct page *page,
struct writeback_control *wbc) struct writeback_control *wbc)
...@@ -2473,7 +2501,7 @@ static int ext4_da_writepage(struct page *page, ...@@ -2473,7 +2501,7 @@ static int ext4_da_writepage(struct page *page,
* do block allocation here. * do block allocation here.
*/ */
ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE, ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
ext4_normal_get_block_write); noalloc_get_block_write);
if (!ret) { if (!ret) {
page_bufs = page_buffers(page); page_bufs = page_buffers(page);
/* check whether all are mapped and non delay */ /* check whether all are mapped and non delay */
...@@ -2498,11 +2526,10 @@ static int ext4_da_writepage(struct page *page, ...@@ -2498,11 +2526,10 @@ static int ext4_da_writepage(struct page *page,
} }
if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
ret = nobh_writepage(page, ext4_normal_get_block_write, wbc); ret = nobh_writepage(page, noalloc_get_block_write, wbc);
else else
ret = block_write_full_page(page, ret = block_write_full_page(page, noalloc_get_block_write,
ext4_normal_get_block_write, wbc);
wbc);
return ret; return ret;
} }
...@@ -2814,7 +2841,7 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, ...@@ -2814,7 +2841,7 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
*pagep = page; *pagep = page;
ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
ext4_da_get_block_prep); ext4_da_get_block_prep);
if (ret < 0) { if (ret < 0) {
unlock_page(page); unlock_page(page);
ext4_journal_stop(handle); ext4_journal_stop(handle);
...@@ -3122,12 +3149,10 @@ static int __ext4_normal_writepage(struct page *page, ...@@ -3122,12 +3149,10 @@ static int __ext4_normal_writepage(struct page *page,
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
if (test_opt(inode->i_sb, NOBH)) if (test_opt(inode->i_sb, NOBH))
return nobh_writepage(page, return nobh_writepage(page, noalloc_get_block_write, wbc);
ext4_normal_get_block_write, wbc);
else else
return block_write_full_page(page, return block_write_full_page(page, noalloc_get_block_write,
ext4_normal_get_block_write, wbc);
wbc);
} }
static int ext4_normal_writepage(struct page *page, static int ext4_normal_writepage(struct page *page,
...@@ -3179,7 +3204,7 @@ static int __ext4_journalled_writepage(struct page *page, ...@@ -3179,7 +3204,7 @@ static int __ext4_journalled_writepage(struct page *page,
int err; int err;
ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE, ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
ext4_normal_get_block_write); noalloc_get_block_write);
if (ret != 0) if (ret != 0)
goto out_unlock; goto out_unlock;
...@@ -3264,9 +3289,8 @@ static int ext4_journalled_writepage(struct page *page, ...@@ -3264,9 +3289,8 @@ static int ext4_journalled_writepage(struct page *page,
* really know unless we go poke around in the buffer_heads. * really know unless we go poke around in the buffer_heads.
* But block_write_full_page will do the right thing. * But block_write_full_page will do the right thing.
*/ */
return block_write_full_page(page, return block_write_full_page(page, noalloc_get_block_write,
ext4_normal_get_block_write, wbc);
wbc);
} }
no_write: no_write:
redirty_page_for_writepage(wbc, page); redirty_page_for_writepage(wbc, page);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册