aboutsummaryrefslogtreecommitdiff
path: root/fs/xfs/linux-2.6/xfs_aops.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_aops.c')
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c484
1 files changed, 242 insertions, 242 deletions
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 74d8be87f98..97fc056130e 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -43,7 +43,29 @@
#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
@@ -54,7 +76,7 @@ xfs_page_trace(
int mask)
{
xfs_inode_t *ip;
- vnode_t *vp = LINVFS_GET_VP(inode);
+ vnode_t *vp = vn_from_inode(inode);
loff_t isize = i_size_read(inode);
loff_t offset = page_offset(page);
int delalloc = -1, unmapped = -1, unwritten = -1;
@@ -81,7 +103,7 @@ xfs_page_trace(
(void *)((unsigned long)delalloc),
(void *)((unsigned long)unmapped),
(void *)((unsigned long)unwritten),
- (void *)NULL,
+ (void *)((unsigned long)current_pid()),
(void *)NULL);
}
#else
@@ -192,7 +214,7 @@ xfs_alloc_ioend(
ioend->io_uptodate = 1; /* cleared if any I/O fails */
ioend->io_list = NULL;
ioend->io_type = type;
- ioend->io_vnode = LINVFS_GET_VP(inode);
+ ioend->io_vnode = vn_from_inode(inode);
ioend->io_buffer_head = NULL;
ioend->io_buffer_tail = NULL;
atomic_inc(&ioend->io_vnode->v_iocount);
@@ -217,7 +239,7 @@ xfs_map_blocks(
xfs_iomap_t *mapp,
int flags)
{
- vnode_t *vp = LINVFS_GET_VP(inode);
+ vnode_t *vp = vn_from_inode(inode);
int error, nmaps = 1;
VOP_BMAP(vp, offset, count, flags, mapp, &nmaps, error);
@@ -462,28 +484,37 @@ xfs_add_to_ioend(
}
STATIC void
+xfs_map_buffer(
+ struct buffer_head *bh,
+ xfs_iomap_t *mp,
+ xfs_off_t offset,
+ uint block_bits)
+{
+ sector_t bn;
+
+ ASSERT(mp->iomap_bn != IOMAP_DADDR_NULL);
+
+ bn = (mp->iomap_bn >> (block_bits - BBSHIFT)) +
+ ((offset - mp->iomap_offset) >> block_bits);
+
+ ASSERT(bn || (mp->iomap_flags & IOMAP_REALTIME));
+
+ bh->b_blocknr = bn;
+ set_buffer_mapped(bh);
+}
+
+STATIC void
xfs_map_at_offset(
struct buffer_head *bh,
loff_t offset,
int block_bits,
xfs_iomap_t *iomapp)
{
- xfs_daddr_t bn;
- int sector_shift;
-
ASSERT(!(iomapp->iomap_flags & IOMAP_HOLE));
ASSERT(!(iomapp->iomap_flags & IOMAP_DELAY));
- ASSERT(iomapp->iomap_bn != IOMAP_DADDR_NULL);
-
- sector_shift = block_bits - BBSHIFT;
- bn = (iomapp->iomap_bn >> sector_shift) +
- ((offset - iomapp->iomap_offset) >> block_bits);
-
- ASSERT(bn || (iomapp->iomap_flags & IOMAP_REALTIME));
- ASSERT((bn << sector_shift) >= iomapp->iomap_bn);
lock_buffer(bh);
- bh->b_blocknr = bn;
+ xfs_map_buffer(bh, iomapp, offset, block_bits);
bh->b_bdev = iomapp->iomap_target->bt_bdev;
set_buffer_mapped(bh);
clear_buffer_delay(bh);
@@ -616,7 +647,7 @@ xfs_is_delayed_page(
acceptable = (type == IOMAP_UNWRITTEN);
else if (buffer_delay(bh))
acceptable = (type == IOMAP_DELAY);
- else if (buffer_mapped(bh))
+ else if (buffer_dirty(bh) && buffer_mapped(bh))
acceptable = (type == 0);
else
break;
@@ -1040,8 +1071,159 @@ error:
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
+xfs_vm_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_get_block(
+xfs_vm_releasepage(
+ 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);
+
+ if (!page_has_buffers(page))
+ return 0;
+
+ 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
+__xfs_get_block(
struct inode *inode,
sector_t iblock,
unsigned long blocks,
@@ -1050,7 +1232,7 @@ __linvfs_get_block(
int direct,
bmapi_flags_t flags)
{
- vnode_t *vp = LINVFS_GET_VP(inode);
+ vnode_t *vp = vn_from_inode(inode);
xfs_iomap_t iomap;
xfs_off_t offset;
ssize_t size;
@@ -1073,21 +1255,13 @@ __linvfs_get_block(
return 0;
if (iomap.iomap_bn != IOMAP_DADDR_NULL) {
- xfs_daddr_t bn;
- xfs_off_t delta;
-
- /* For unwritten extents do not report a disk address on
+ /*
+ * For unwritten extents do not report a disk address on
* the read case (treat as if we're reading into a hole).
*/
if (create || !(iomap.iomap_flags & IOMAP_UNWRITTEN)) {
- delta = offset - iomap.iomap_offset;
- delta >>= inode->i_blkbits;
-
- bn = iomap.iomap_bn >> (inode->i_blkbits - BBSHIFT);
- bn += delta;
- BUG_ON(!bn && !(iomap.iomap_flags & IOMAP_REALTIME));
- bh_result->b_blocknr = bn;
- set_buffer_mapped(bh_result);
+ xfs_map_buffer(bh_result, &iomap, offset,
+ inode->i_blkbits);
}
if (create && (iomap.iomap_flags & IOMAP_UNWRITTEN)) {
if (direct)
@@ -1130,30 +1304,30 @@ __linvfs_get_block(
}
int
-linvfs_get_block(
+xfs_get_block(
struct inode *inode,
sector_t iblock,
struct buffer_head *bh_result,
int create)
{
- return __linvfs_get_block(inode, iblock, 0, bh_result,
+ return __xfs_get_block(inode, iblock, 0, bh_result,
create, 0, BMAPI_WRITE);
}
STATIC int
-linvfs_get_blocks_direct(
+xfs_get_blocks_direct(
struct inode *inode,
sector_t iblock,
unsigned long max_blocks,
struct buffer_head *bh_result,
int create)
{
- return __linvfs_get_block(inode, iblock, max_blocks, bh_result,
+ return __xfs_get_block(inode, iblock, max_blocks, bh_result,
create, 1, BMAPI_WRITE|BMAPI_DIRECT);
}
STATIC void
-linvfs_end_io_direct(
+xfs_end_io_direct(
struct kiocb *iocb,
loff_t offset,
ssize_t size,
@@ -1191,7 +1365,7 @@ linvfs_end_io_direct(
}
STATIC ssize_t
-linvfs_direct_IO(
+xfs_vm_direct_IO(
int rw,
struct kiocb *iocb,
const struct iovec *iov,
@@ -1200,7 +1374,7 @@ linvfs_direct_IO(
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
- vnode_t *vp = LINVFS_GET_VP(inode);
+ vnode_t *vp = vn_from_inode(inode);
xfs_iomap_t iomap;
int maps = 1;
int error;
@@ -1215,164 +1389,61 @@ linvfs_direct_IO(
ret = blockdev_direct_IO_own_locking(rw, iocb, inode,
iomap.iomap_target->bt_bdev,
iov, offset, nr_segs,
- linvfs_get_blocks_direct,
- linvfs_end_io_direct);
+ xfs_get_blocks_direct,
+ xfs_end_io_direct);
if (unlikely(ret <= 0 && iocb->private))
xfs_destroy_ioend(iocb->private);
return ret;
}
+STATIC int
+xfs_vm_prepare_write(
+ struct file *file,
+ struct page *page,
+ unsigned int from,
+ unsigned int to)
+{
+ return block_prepare_write(page, from, to, xfs_get_block);
+}
STATIC sector_t
-linvfs_bmap(
+xfs_vm_bmap(
struct address_space *mapping,
sector_t block)
{
struct inode *inode = (struct inode *)mapping->host;
- vnode_t *vp = LINVFS_GET_VP(inode);
+ vnode_t *vp = vn_from_inode(inode);
int error;
- vn_trace_entry(vp, "linvfs_bmap", (inst_t *)__return_address);
+ vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
VOP_RWLOCK(vp, VRWLOCK_READ);
VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, 0, FI_REMAPF, error);
VOP_RWUNLOCK(vp, VRWLOCK_READ);
- return generic_block_bmap(mapping, block, linvfs_get_block);
+ return generic_block_bmap(mapping, block, xfs_get_block);
}
STATIC int
-linvfs_readpage(
+xfs_vm_readpage(
struct file *unused,
struct page *page)
{
- return mpage_readpage(page, linvfs_get_block);
+ return mpage_readpage(page, xfs_get_block);
}
STATIC int
-linvfs_readpages(
+xfs_vm_readpages(
struct file *unused,
struct address_space *mapping,
struct list_head *pages,
unsigned nr_pages)
{
- 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);
+ return mpage_readpages(mapping, pages, nr_pages, xfs_get_block);
}
-
-/*
- * 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(
+xfs_vm_invalidatepage(
struct page *page,
unsigned long offset)
{
@@ -1381,87 +1452,16 @@ 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,
- .writepage = linvfs_writepage,
+struct address_space_operations xfs_address_space_operations = {
+ .readpage = xfs_vm_readpage,
+ .readpages = xfs_vm_readpages,
+ .writepage = xfs_vm_writepage,
.sync_page = block_sync_page,
- .releasepage = linvfs_release_page,
- .invalidatepage = linvfs_invalidate_page,
- .prepare_write = linvfs_prepare_write,
+ .releasepage = xfs_vm_releasepage,
+ .invalidatepage = xfs_vm_invalidatepage,
+ .prepare_write = xfs_vm_prepare_write,
.commit_write = generic_commit_write,
- .bmap = linvfs_bmap,
- .direct_IO = linvfs_direct_IO,
+ .bmap = xfs_vm_bmap,
+ .direct_IO = xfs_vm_direct_IO,
.migratepage = buffer_migrate_page,
};