forked from luck/tmp_suning_uos_patched
ext4: dirty page has always buffers attached
ext4_writepage(), write_cache_pages_da(), and mpage_da_submit_io() doesn't have to deal with the case when page doesn't have buffers. We attach buffers to a page in ->write_begin() and ->page_mkwrite() which covers all places where a page can become dirty. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
parent
002bd7fa3a
commit
f8bec37037
147
fs/ext4/inode.c
147
fs/ext4/inode.c
@ -132,8 +132,6 @@ static inline int ext4_begin_ordered_truncate(struct inode *inode,
|
||||
}
|
||||
|
||||
static void ext4_invalidatepage(struct page *page, unsigned long offset);
|
||||
static int noalloc_get_block_write(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create);
|
||||
static int __ext4_journalled_writepage(struct page *page, unsigned int len);
|
||||
static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh);
|
||||
static int ext4_discard_partial_page_buffers_no_lock(handle_t *handle,
|
||||
@ -1374,7 +1372,7 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
|
||||
if (nr_pages == 0)
|
||||
break;
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
int commit_write = 0, skip_page = 0;
|
||||
int skip_page = 0;
|
||||
struct page *page = pvec.pages[i];
|
||||
|
||||
index = page->index;
|
||||
@ -1396,27 +1394,9 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
|
||||
BUG_ON(!PageLocked(page));
|
||||
BUG_ON(PageWriteback(page));
|
||||
|
||||
/*
|
||||
* If the page does not have buffers (for
|
||||
* whatever reason), try to create them using
|
||||
* __block_write_begin. If this fails,
|
||||
* skip the page and move on.
|
||||
*/
|
||||
if (!page_has_buffers(page)) {
|
||||
if (__block_write_begin(page, 0, len,
|
||||
noalloc_get_block_write)) {
|
||||
skip_page:
|
||||
unlock_page(page);
|
||||
continue;
|
||||
}
|
||||
commit_write = 1;
|
||||
}
|
||||
|
||||
bh = page_bufs = page_buffers(page);
|
||||
block_start = 0;
|
||||
do {
|
||||
if (!bh)
|
||||
goto skip_page;
|
||||
if (map && (cur_logical >= map->m_lblk) &&
|
||||
(cur_logical <= (map->m_lblk +
|
||||
(map->m_len - 1)))) {
|
||||
@ -1444,12 +1424,10 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
|
||||
pblock++;
|
||||
} while (bh != page_bufs);
|
||||
|
||||
if (skip_page)
|
||||
goto skip_page;
|
||||
|
||||
if (commit_write)
|
||||
/* mark the buffer_heads as dirty & uptodate */
|
||||
block_commit_write(page, 0, len);
|
||||
if (skip_page) {
|
||||
unlock_page(page);
|
||||
continue;
|
||||
}
|
||||
|
||||
clear_page_dirty_for_io(page);
|
||||
err = ext4_bio_write_page(&io_submit, page, len,
|
||||
@ -1869,27 +1847,6 @@ int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_write_begin(). 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 ext4_bio_write_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)
|
||||
{
|
||||
BUG_ON(bh_result->b_size != inode->i_sb->s_blocksize);
|
||||
return _ext4_get_block(inode, iblock, bh_result, 0);
|
||||
}
|
||||
|
||||
static int bget_one(handle_t *handle, struct buffer_head *bh)
|
||||
{
|
||||
get_bh(bh);
|
||||
@ -2014,7 +1971,7 @@ static int __ext4_journalled_writepage(struct page *page,
|
||||
static int ext4_writepage(struct page *page,
|
||||
struct writeback_control *wbc)
|
||||
{
|
||||
int ret = 0, commit_write = 0;
|
||||
int ret = 0;
|
||||
loff_t size;
|
||||
unsigned int len;
|
||||
struct buffer_head *page_bufs = NULL;
|
||||
@ -2028,21 +1985,6 @@ static int ext4_writepage(struct page *page,
|
||||
else
|
||||
len = PAGE_CACHE_SIZE;
|
||||
|
||||
/*
|
||||
* If the page does not have buffers (for whatever reason),
|
||||
* try to create them using __block_write_begin. If this
|
||||
* fails, redirty the page and move on.
|
||||
*/
|
||||
if (!page_has_buffers(page)) {
|
||||
if (__block_write_begin(page, 0, len,
|
||||
noalloc_get_block_write)) {
|
||||
redirty_page:
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
unlock_page(page);
|
||||
return 0;
|
||||
}
|
||||
commit_write = 1;
|
||||
}
|
||||
page_bufs = page_buffers(page);
|
||||
if (ext4_walk_page_buffers(NULL, page_bufs, 0, len, NULL,
|
||||
ext4_bh_delay_or_unwritten)) {
|
||||
@ -2056,11 +1998,10 @@ static int ext4_writepage(struct page *page,
|
||||
*/
|
||||
WARN_ON_ONCE((current->flags & (PF_MEMALLOC|PF_KSWAPD)) ==
|
||||
PF_MEMALLOC);
|
||||
goto redirty_page;
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
unlock_page(page);
|
||||
return 0;
|
||||
}
|
||||
if (commit_write)
|
||||
/* now mark the buffer_heads as dirty and uptodate */
|
||||
block_commit_write(page, 0, len);
|
||||
|
||||
if (PageChecked(page) && ext4_should_journal_data(inode))
|
||||
/*
|
||||
@ -2203,51 +2144,39 @@ static int write_cache_pages_da(handle_t *handle,
|
||||
logical = (sector_t) page->index <<
|
||||
(PAGE_CACHE_SHIFT - inode->i_blkbits);
|
||||
|
||||
if (!page_has_buffers(page)) {
|
||||
mpage_add_bh_to_extent(mpd, logical,
|
||||
PAGE_CACHE_SIZE,
|
||||
(1 << BH_Dirty) | (1 << BH_Uptodate));
|
||||
if (mpd->io_done)
|
||||
goto ret_extent_tail;
|
||||
} else {
|
||||
/* Add all dirty buffers to mpd */
|
||||
head = page_buffers(page);
|
||||
bh = head;
|
||||
do {
|
||||
BUG_ON(buffer_locked(bh));
|
||||
/*
|
||||
* Page with regular buffer heads,
|
||||
* just add all dirty ones
|
||||
* We need to try to allocate unmapped blocks
|
||||
* in the same page. Otherwise we won't make
|
||||
* progress with the page in ext4_writepage
|
||||
*/
|
||||
head = page_buffers(page);
|
||||
bh = head;
|
||||
do {
|
||||
BUG_ON(buffer_locked(bh));
|
||||
if (ext4_bh_delay_or_unwritten(NULL, bh)) {
|
||||
mpage_add_bh_to_extent(mpd, logical,
|
||||
bh->b_size,
|
||||
bh->b_state);
|
||||
if (mpd->io_done)
|
||||
goto ret_extent_tail;
|
||||
} else if (buffer_dirty(bh) &&
|
||||
buffer_mapped(bh)) {
|
||||
/*
|
||||
* We need to try to allocate
|
||||
* unmapped blocks in the same page.
|
||||
* Otherwise we won't make progress
|
||||
* with the page in ext4_writepage
|
||||
* mapped dirty buffer. We need to
|
||||
* update the b_state because we look
|
||||
* at b_state in mpage_da_map_blocks.
|
||||
* We don't update b_size because if we
|
||||
* find an unmapped buffer_head later
|
||||
* we need to use the b_state flag of
|
||||
* that buffer_head.
|
||||
*/
|
||||
if (ext4_bh_delay_or_unwritten(NULL, bh)) {
|
||||
mpage_add_bh_to_extent(mpd, logical,
|
||||
bh->b_size,
|
||||
bh->b_state);
|
||||
if (mpd->io_done)
|
||||
goto ret_extent_tail;
|
||||
} else if (buffer_dirty(bh) && (buffer_mapped(bh))) {
|
||||
/*
|
||||
* mapped dirty buffer. We need
|
||||
* to update the b_state
|
||||
* because we look at b_state
|
||||
* in mpage_da_map_blocks. We
|
||||
* don't update b_size because
|
||||
* if we find an unmapped
|
||||
* buffer_head later we need to
|
||||
* use the b_state flag of that
|
||||
* buffer_head.
|
||||
*/
|
||||
if (mpd->b_size == 0)
|
||||
mpd->b_state = bh->b_state & BH_FLAGS;
|
||||
}
|
||||
logical++;
|
||||
} while ((bh = bh->b_this_page) != head);
|
||||
}
|
||||
if (mpd->b_size == 0)
|
||||
mpd->b_state =
|
||||
bh->b_state & BH_FLAGS;
|
||||
}
|
||||
logical++;
|
||||
} while ((bh = bh->b_this_page) != head);
|
||||
|
||||
if (nr_to_write > 0) {
|
||||
nr_to_write--;
|
||||
|
Loading…
Reference in New Issue
Block a user