Commit f51623b2 authored by Nathan Scott's avatar Nathan Scott

[XFS] Move some code around to avoid prototypes and prep for future

writepages code. 

SGI-PV: 950211
SGI-Modid: xfs-linux-melb:xfs-kern:25311a
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarNathan Scott <nathans@sgi.com>
parent 02d7c923
......@@ -43,7 +43,32 @@
#include <linux/pagevec.h>
#include <linux/writeback.h>
STATIC void xfs_count_page_state(struct page *, int *, int *, int *);
STATIC void
xfs_count_page_state(
struct page *page,
int *delalloc,
int *unmapped,
int *unwritten)
{
struct buffer_head *bh, *head;
*delalloc = *unmapped = *unwritten = 0;
bh = head = page_buffers(page);
do {
if (buffer_uptodate(bh) && !buffer_mapped(bh))
(*unmapped) = 1;
else if (buffer_unwritten(bh) && !buffer_delay(bh))
clear_buffer_unwritten(bh);
else if (buffer_unwritten(bh))
(*unwritten) = 1;
else if (buffer_delay(bh))
(*delalloc) = 1;
} while ((bh = bh->b_this_page) != head);
}
#if defined(XFS_RW_TRACE)
void
......@@ -1040,6 +1065,154 @@ xfs_page_state_convert(
return err;
}
/*
* writepage: Called from one of two places:
*
* 1. we are flushing a delalloc buffer head.
*
* 2. we are writing out a dirty page. Typically the page dirty
* state is cleared before we get here. In this case is it
* conceivable we have no buffer heads.
*
* For delalloc space on the page we need to allocate space and
* flush it. For unmapped buffer heads on the page we should
* allocate space if the page is uptodate. For any other dirty
* buffer heads on the page we should flush them.
*
* If we detect that a transaction would be required to flush
* the page, we have to check the process flags first, if we
* are already in a transaction or disk I/O during allocations
* is off, we need to fail the writepage and redirty the page.
*/
STATIC int
linvfs_writepage(
struct page *page,
struct writeback_control *wbc)
{
int error;
int need_trans;
int delalloc, unmapped, unwritten;
struct inode *inode = page->mapping->host;
xfs_page_trace(XFS_WRITEPAGE_ENTER, inode, page, 0);
/*
* We need a transaction if:
* 1. There are delalloc buffers on the page
* 2. The page is uptodate and we have unmapped buffers
* 3. The page is uptodate and we have no buffers
* 4. There are unwritten buffers on the page
*/
if (!page_has_buffers(page)) {
unmapped = 1;
need_trans = 1;
} else {
xfs_count_page_state(page, &delalloc, &unmapped, &unwritten);
if (!PageUptodate(page))
unmapped = 0;
need_trans = delalloc + unmapped + unwritten;
}
/*
* If we need a transaction and the process flags say
* we are already in a transaction, or no IO is allowed
* then mark the page dirty again and leave the page
* as is.
*/
if (PFLAGS_TEST_FSTRANS() && need_trans)
goto out_fail;
/*
* Delay hooking up buffer heads until we have
* made our go/no-go decision.
*/
if (!page_has_buffers(page))
create_empty_buffers(page, 1 << inode->i_blkbits, 0);
/*
* Convert delayed allocate, unwritten or unmapped space
* to real space and flush out to disk.
*/
error = xfs_page_state_convert(inode, page, wbc, 1, unmapped);
if (error == -EAGAIN)
goto out_fail;
if (unlikely(error < 0))
goto out_unlock;
return 0;
out_fail:
redirty_page_for_writepage(wbc, page);
unlock_page(page);
return 0;
out_unlock:
unlock_page(page);
return error;
}
/*
* Called to move a page into cleanable state - and from there
* to be released. Possibly the page is already clean. We always
* have buffer heads in this call.
*
* Returns 0 if the page is ok to release, 1 otherwise.
*
* Possible scenarios are:
*
* 1. We are being called to release a page which has been written
* to via regular I/O. buffer heads will be dirty and possibly
* delalloc. If no delalloc buffer heads in this case then we
* can just return zero.
*
* 2. We are called to release a page which has been written via
* mmap, all we need to do is ensure there is no delalloc
* state in the buffer heads, if not we can let the caller
* free them and we should come back later via writepage.
*/
STATIC int
linvfs_release_page(
struct page *page,
gfp_t gfp_mask)
{
struct inode *inode = page->mapping->host;
int dirty, delalloc, unmapped, unwritten;
struct writeback_control wbc = {
.sync_mode = WB_SYNC_ALL,
.nr_to_write = 1,
};
xfs_page_trace(XFS_RELEASEPAGE_ENTER, inode, page, gfp_mask);
xfs_count_page_state(page, &delalloc, &unmapped, &unwritten);
if (!delalloc && !unwritten)
goto free_buffers;
if (!(gfp_mask & __GFP_FS))
return 0;
/* If we are already inside a transaction or the thread cannot
* do I/O, we cannot release this page.
*/
if (PFLAGS_TEST_FSTRANS())
return 0;
/*
* Convert delalloc space to real space, do not flush the
* data out to disk, that will be done by the caller.
* Never need to allocate space here - we will always
* come back to writepage in that case.
*/
dirty = xfs_page_state_convert(inode, page, &wbc, 0, 0);
if (dirty == 0 && !unwritten)
goto free_buffers;
return 0;
free_buffers:
return try_to_free_buffers(page);
}
STATIC int
__linvfs_get_block(
struct inode *inode,
......@@ -1223,6 +1396,15 @@ linvfs_direct_IO(
return ret;
}
STATIC int
linvfs_prepare_write(
struct file *file,
struct page *page,
unsigned int from,
unsigned int to)
{
return block_prepare_write(page, from, to, linvfs_get_block);
}
STATIC sector_t
linvfs_bmap(
......@@ -1259,118 +1441,6 @@ linvfs_readpages(
return mpage_readpages(mapping, pages, nr_pages, linvfs_get_block);
}
STATIC void
xfs_count_page_state(
struct page *page,
int *delalloc,
int *unmapped,
int *unwritten)
{
struct buffer_head *bh, *head;
*delalloc = *unmapped = *unwritten = 0;
bh = head = page_buffers(page);
do {
if (buffer_uptodate(bh) && !buffer_mapped(bh))
(*unmapped) = 1;
else if (buffer_unwritten(bh) && !buffer_delay(bh))
clear_buffer_unwritten(bh);
else if (buffer_unwritten(bh))
(*unwritten) = 1;
else if (buffer_delay(bh))
(*delalloc) = 1;
} while ((bh = bh->b_this_page) != head);
}
/*
* writepage: Called from one of two places:
*
* 1. we are flushing a delalloc buffer head.
*
* 2. we are writing out a dirty page. Typically the page dirty
* state is cleared before we get here. In this case is it
* conceivable we have no buffer heads.
*
* For delalloc space on the page we need to allocate space and
* flush it. For unmapped buffer heads on the page we should
* allocate space if the page is uptodate. For any other dirty
* buffer heads on the page we should flush them.
*
* If we detect that a transaction would be required to flush
* the page, we have to check the process flags first, if we
* are already in a transaction or disk I/O during allocations
* is off, we need to fail the writepage and redirty the page.
*/
STATIC int
linvfs_writepage(
struct page *page,
struct writeback_control *wbc)
{
int error;
int need_trans;
int delalloc, unmapped, unwritten;
struct inode *inode = page->mapping->host;
xfs_page_trace(XFS_WRITEPAGE_ENTER, inode, page, 0);
/*
* We need a transaction if:
* 1. There are delalloc buffers on the page
* 2. The page is uptodate and we have unmapped buffers
* 3. The page is uptodate and we have no buffers
* 4. There are unwritten buffers on the page
*/
if (!page_has_buffers(page)) {
unmapped = 1;
need_trans = 1;
} else {
xfs_count_page_state(page, &delalloc, &unmapped, &unwritten);
if (!PageUptodate(page))
unmapped = 0;
need_trans = delalloc + unmapped + unwritten;
}
/*
* If we need a transaction and the process flags say
* we are already in a transaction, or no IO is allowed
* then mark the page dirty again and leave the page
* as is.
*/
if (PFLAGS_TEST_FSTRANS() && need_trans)
goto out_fail;
/*
* Delay hooking up buffer heads until we have
* made our go/no-go decision.
*/
if (!page_has_buffers(page))
create_empty_buffers(page, 1 << inode->i_blkbits, 0);
/*
* Convert delayed allocate, unwritten or unmapped space
* to real space and flush out to disk.
*/
error = xfs_page_state_convert(inode, page, wbc, 1, unmapped);
if (error == -EAGAIN)
goto out_fail;
if (unlikely(error < 0))
goto out_unlock;
return 0;
out_fail:
redirty_page_for_writepage(wbc, page);
unlock_page(page);
return 0;
out_unlock:
unlock_page(page);
return error;
}
STATIC int
linvfs_invalidate_page(
struct page *page,
......@@ -1381,77 +1451,6 @@ linvfs_invalidate_page(
return block_invalidatepage(page, offset);
}
/*
* Called to move a page into cleanable state - and from there
* to be released. Possibly the page is already clean. We always
* have buffer heads in this call.
*
* Returns 0 if the page is ok to release, 1 otherwise.
*
* Possible scenarios are:
*
* 1. We are being called to release a page which has been written
* to via regular I/O. buffer heads will be dirty and possibly
* delalloc. If no delalloc buffer heads in this case then we
* can just return zero.
*
* 2. We are called to release a page which has been written via
* mmap, all we need to do is ensure there is no delalloc
* state in the buffer heads, if not we can let the caller
* free them and we should come back later via writepage.
*/
STATIC int
linvfs_release_page(
struct page *page,
gfp_t gfp_mask)
{
struct inode *inode = page->mapping->host;
int dirty, delalloc, unmapped, unwritten;
struct writeback_control wbc = {
.sync_mode = WB_SYNC_ALL,
.nr_to_write = 1,
};
xfs_page_trace(XFS_RELEASEPAGE_ENTER, inode, page, gfp_mask);
xfs_count_page_state(page, &delalloc, &unmapped, &unwritten);
if (!delalloc && !unwritten)
goto free_buffers;
if (!(gfp_mask & __GFP_FS))
return 0;
/* If we are already inside a transaction or the thread cannot
* do I/O, we cannot release this page.
*/
if (PFLAGS_TEST_FSTRANS())
return 0;
/*
* Convert delalloc space to real space, do not flush the
* data out to disk, that will be done by the caller.
* Never need to allocate space here - we will always
* come back to writepage in that case.
*/
dirty = xfs_page_state_convert(inode, page, &wbc, 0, 0);
if (dirty == 0 && !unwritten)
goto free_buffers;
return 0;
free_buffers:
return try_to_free_buffers(page);
}
STATIC int
linvfs_prepare_write(
struct file *file,
struct page *page,
unsigned int from,
unsigned int to)
{
return block_prepare_write(page, from, to, linvfs_get_block);
}
struct address_space_operations linvfs_aops = {
.readpage = linvfs_readpage,
.readpages = linvfs_readpages,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment