aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/inode.c
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2008-07-11 19:27:31 -0400
committerTheodore Ts'o <tytso@mit.edu>2008-07-11 19:27:31 -0400
commit2e9ee850355593e311d9a26542290fe51e152f74 (patch)
treee860a33119edf36e367ad354428dfc0d6201273c /fs/ext4/inode.c
parent93e3270c87549dc531a0b0e5d06362d998d810cb (diff)
ext4: Use page_mkwrite vma_operations to get mmap write notification.
We would like to get notified when we are doing a write on mmap section. This is needed with respect to preallocated area. We split the preallocated area into initialzed extent and uninitialzed extent in the call back. This let us handle ENOSPC better. Otherwise we get ENOSPC in the writepage and that would result in data loss. The changes are also needed to handle ENOSPC when writing to an mmap section of files with holes. Acked-by: Jan Kara <jack@suse.cz> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Mingming Cao <cmm@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r--fs/ext4/inode.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c5d506dce8c5..034fc544aa66 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3564,3 +3564,64 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
3564 3564
3565 return err; 3565 return err;
3566} 3566}
3567
3568static int ext4_bh_unmapped(handle_t *handle, struct buffer_head *bh)
3569{
3570 return !buffer_mapped(bh);
3571}
3572
3573int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page)
3574{
3575 loff_t size;
3576 unsigned long len;
3577 int ret = -EINVAL;
3578 struct file *file = vma->vm_file;
3579 struct inode *inode = file->f_path.dentry->d_inode;
3580 struct address_space *mapping = inode->i_mapping;
3581
3582 /*
3583 * Get i_alloc_sem to stop truncates messing with the inode. We cannot
3584 * get i_mutex because we are already holding mmap_sem.
3585 */
3586 down_read(&inode->i_alloc_sem);
3587 size = i_size_read(inode);
3588 if (page->mapping != mapping || size <= page_offset(page)
3589 || !PageUptodate(page)) {
3590 /* page got truncated from under us? */
3591 goto out_unlock;
3592 }
3593 ret = 0;
3594 if (PageMappedToDisk(page))
3595 goto out_unlock;
3596
3597 if (page->index == size >> PAGE_CACHE_SHIFT)
3598 len = size & ~PAGE_CACHE_MASK;
3599 else
3600 len = PAGE_CACHE_SIZE;
3601
3602 if (page_has_buffers(page)) {
3603 /* return if we have all the buffers mapped */
3604 if (!walk_page_buffers(NULL, page_buffers(page), 0, len, NULL,
3605 ext4_bh_unmapped))
3606 goto out_unlock;
3607 }
3608 /*
3609 * OK, we need to fill the hole... Do write_begin write_end
3610 * to do block allocation/reservation.We are not holding
3611 * inode.i__mutex here. That allow * parallel write_begin,
3612 * write_end call. lock_page prevent this from happening
3613 * on the same page though
3614 */
3615 ret = mapping->a_ops->write_begin(file, mapping, page_offset(page),
3616 len, AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
3617 if (ret < 0)
3618 goto out_unlock;
3619 ret = mapping->a_ops->write_end(file, mapping, page_offset(page),
3620 len, len, page, NULL);
3621 if (ret < 0)
3622 goto out_unlock;
3623 ret = 0;
3624out_unlock:
3625 up_read(&inode->i_alloc_sem);
3626 return ret;
3627}