[PATCH mmotm] nilfs2: insert checks and hole block allocation in page_mkwrite

From: Ryusuke Konishi
Date: Wed Jan 07 2009 - 08:12:56 EST


Chris Mason told me that page_mkwrite() has some works to do.

On Wed, 17 Dec 2008 21:52:55 -0500, Chris Mason wrote:
> nilfs_page_mkwrite doesn't seem to dirty the page? block_page_mkwrite
> does more, including checks against i_size and others.

This will insert i_size check, and hole block allocation code in the
nilfs_page_mkwrite.

Previously, the hole block allocation was delayed until just before
writing for mmapped pages. This accompanies removal of the delayed
allocation code.

Cc: Chris Mason <chris.mason@xxxxxxxxxx>
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@xxxxxxxxxxxxx>
---
fs/nilfs2/file.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++-
fs/nilfs2/segment.c | 42 ++++--------------------------------
2 files changed, 62 insertions(+), 39 deletions(-)

diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c
index 7ddd42e..146dc23 100644
--- a/fs/nilfs2/file.c
+++ b/fs/nilfs2/file.c
@@ -75,11 +75,66 @@ nilfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,

static int nilfs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
{
- if (!(vma->vm_flags & (VM_WRITE | VM_MAYWRITE)))
- return -EPERM;
+ struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct address_space *mapping = inode->i_mapping;
+ struct nilfs_transaction_info ti;
+ struct buffer_head *bh, *head;
+ int fully_mapped = 1;
+ int ret = -EINVAL;
+
+ /*
+ * use i_alloc_sem to stop truncate operations on the inode
+ */
+ down_read(&inode->i_alloc_sem);
+
+ if (page->mapping != mapping ||
+ page_offset(page) >= i_size_read(inode) || !PageUptodate(page))
+ goto failed;
+
+ if (PageMappedToDisk(page))
+ goto mapped;
+
+ spin_lock(&mapping->private_lock); /* exclude try_to_free_buffers() */
+ if (page_has_buffers(page)) {
+ bh = head = page_buffers(page);
+ do {
+ if (!buffer_mapped(bh)) {
+ fully_mapped = 0;
+ break;
+ }
+ } while (bh = bh->b_this_page, bh != head);
+
+ if (fully_mapped) {
+ spin_unlock(&mapping->private_lock);
+ SetPageMappedToDisk(page);
+ goto mapped;
+ }
+ }
+ spin_unlock(&mapping->private_lock);
+
+ /*
+ * Fill hole blocks. This accompanies a disk capacity check.
+ */
+ ret = nilfs_transaction_begin(inode->i_sb, &ti, 1);
+ if (unlikely(ret))
+ goto failed;
+
+ ret = block_page_mkwrite(vma, page, nilfs_get_block);
+ if (unlikely(ret)) {
+ nilfs_transaction_abort(inode->i_sb);
+ goto failed;
+ }
+ nilfs_transaction_commit(inode->i_sb);
+
+ mapped:
+ up_read(&inode->i_alloc_sem);
SetPageChecked(page);
wait_on_page_writeback(page);
return 0;
+
+ failed:
+ up_read(&inode->i_alloc_sem);
+ return ret;
}

struct vm_operations_struct nilfs_file_vm_ops = {
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
index 182fb26..b5d28d2 100644
--- a/fs/nilfs2/segment.c
+++ b/fs/nilfs2/segment.c
@@ -667,42 +667,6 @@ struct nilfs_sc_operations nilfs_sc_dsync_ops = {
.write_node_binfo = NULL,
};

-static int nilfs_prepare_data_page(struct inode *inode, struct page *page)
-{
- int err = 0;
-
- lock_page(page);
- if (!page_has_buffers(page))
- create_empty_buffers(page, 1 << inode->i_blkbits, 0);
-
- if (!PageMappedToDisk(page)) {
- struct buffer_head *bh, *head;
- sector_t blkoff
- = page->index << (PAGE_SHIFT - inode->i_blkbits);
-
- int non_mapped = 0;
-
- bh = head = page_buffers(page);
- do {
- if (!buffer_mapped(bh)) {
- if (!buffer_dirty(bh)) {
- non_mapped++;
- continue;
- }
- err = nilfs_get_block(inode, blkoff, bh, 1);
- if (unlikely(err))
- goto out_unlock;
- }
- } while (blkoff++, (bh = bh->b_this_page) != head);
- if (!non_mapped)
- SetPageMappedToDisk(page);
- }
-
- out_unlock:
- unlock_page(page);
- return err;
-}
-
static int nilfs_lookup_dirty_data_buffers(struct inode *inode,
struct list_head *listp,
struct nilfs_sc_info *sci)
@@ -727,7 +691,11 @@ static int nilfs_lookup_dirty_data_buffers(struct inode *inode,
struct page *page = pvec.pages[i];

if (mapping->host) {
- err = nilfs_prepare_data_page(inode, page);
+ lock_page(page);
+ if (!page_has_buffers(page))
+ create_empty_buffers(page,
+ 1 << inode->i_blkbits, 0);
+ unlock_page(page);
if (unlikely(err))
break;
}
--
1.5.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/