Commit 729963a1 authored by Joel Becker's avatar Joel Becker
Browse files

Merge branch 'cow_readahead' of git://oss.oracle.com/git/tma/linux-2.6 into merge-2

parents 17ae5211 6ea4843f
Loading
Loading
Loading
Loading
+4 −3
Original line number Original line Diff line number Diff line
@@ -1642,7 +1642,8 @@ static int ocfs2_zero_tail(struct inode *inode, struct buffer_head *di_bh,
	return ret;
	return ret;
}
}


int ocfs2_write_begin_nolock(struct address_space *mapping,
int ocfs2_write_begin_nolock(struct file *filp,
			     struct address_space *mapping,
			     loff_t pos, unsigned len, unsigned flags,
			     loff_t pos, unsigned len, unsigned flags,
			     struct page **pagep, void **fsdata,
			     struct page **pagep, void **fsdata,
			     struct buffer_head *di_bh, struct page *mmap_page)
			     struct buffer_head *di_bh, struct page *mmap_page)
@@ -1692,7 +1693,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
		mlog_errno(ret);
		mlog_errno(ret);
		goto out;
		goto out;
	} else if (ret == 1) {
	} else if (ret == 1) {
		ret = ocfs2_refcount_cow(inode, di_bh,
		ret = ocfs2_refcount_cow(inode, filp, di_bh,
					 wc->w_cpos, wc->w_clen, UINT_MAX);
					 wc->w_cpos, wc->w_clen, UINT_MAX);
		if (ret) {
		if (ret) {
			mlog_errno(ret);
			mlog_errno(ret);
@@ -1854,7 +1855,7 @@ static int ocfs2_write_begin(struct file *file, struct address_space *mapping,
	 */
	 */
	down_write(&OCFS2_I(inode)->ip_alloc_sem);
	down_write(&OCFS2_I(inode)->ip_alloc_sem);


	ret = ocfs2_write_begin_nolock(mapping, pos, len, flags, pagep,
	ret = ocfs2_write_begin_nolock(file, mapping, pos, len, flags, pagep,
				       fsdata, di_bh, NULL);
				       fsdata, di_bh, NULL);
	if (ret) {
	if (ret) {
		mlog_errno(ret);
		mlog_errno(ret);
+2 −1
Original line number Original line Diff line number Diff line
@@ -48,7 +48,8 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
			   loff_t pos, unsigned len, unsigned copied,
			   loff_t pos, unsigned len, unsigned copied,
			   struct page *page, void *fsdata);
			   struct page *page, void *fsdata);


int ocfs2_write_begin_nolock(struct address_space *mapping,
int ocfs2_write_begin_nolock(struct file *filp,
			     struct address_space *mapping,
			     loff_t pos, unsigned len, unsigned flags,
			     loff_t pos, unsigned len, unsigned flags,
			     struct page **pagep, void **fsdata,
			     struct page **pagep, void **fsdata,
			     struct buffer_head *di_bh, struct page *mmap_page);
			     struct buffer_head *di_bh, struct page *mmap_page);
+10 −7
Original line number Original line Diff line number Diff line
@@ -360,7 +360,7 @@ static int ocfs2_cow_file_pos(struct inode *inode,
	if (!(ext_flags & OCFS2_EXT_REFCOUNTED))
	if (!(ext_flags & OCFS2_EXT_REFCOUNTED))
		goto out;
		goto out;


	return ocfs2_refcount_cow(inode, fe_bh, cpos, 1, cpos+1);
	return ocfs2_refcount_cow(inode, NULL, fe_bh, cpos, 1, cpos+1);


out:
out:
	return status;
	return status;
@@ -903,8 +903,8 @@ static int ocfs2_zero_extend_get_range(struct inode *inode,
		zero_clusters = last_cpos - zero_cpos;
		zero_clusters = last_cpos - zero_cpos;


	if (needs_cow) {
	if (needs_cow) {
		rc = ocfs2_refcount_cow(inode, di_bh, zero_cpos, zero_clusters,
		rc = ocfs2_refcount_cow(inode, NULL, di_bh, zero_cpos,
					UINT_MAX);
					zero_clusters, UINT_MAX);
		if (rc) {
		if (rc) {
			mlog_errno(rc);
			mlog_errno(rc);
			goto out;
			goto out;
@@ -2052,6 +2052,7 @@ out:
}
}


static int ocfs2_prepare_inode_for_refcount(struct inode *inode,
static int ocfs2_prepare_inode_for_refcount(struct inode *inode,
					    struct file *file,
					    loff_t pos, size_t count,
					    loff_t pos, size_t count,
					    int *meta_level)
					    int *meta_level)
{
{
@@ -2069,7 +2070,7 @@ static int ocfs2_prepare_inode_for_refcount(struct inode *inode,


	*meta_level = 1;
	*meta_level = 1;


	ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters, UINT_MAX);
	ret = ocfs2_refcount_cow(inode, file, di_bh, cpos, clusters, UINT_MAX);
	if (ret)
	if (ret)
		mlog_errno(ret);
		mlog_errno(ret);
out:
out:
@@ -2077,7 +2078,7 @@ out:
	return ret;
	return ret;
}
}


static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
static int ocfs2_prepare_inode_for_write(struct file *file,
					 loff_t *ppos,
					 loff_t *ppos,
					 size_t count,
					 size_t count,
					 int appending,
					 int appending,
@@ -2085,6 +2086,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
					 int *has_refcount)
					 int *has_refcount)
{
{
	int ret = 0, meta_level = 0;
	int ret = 0, meta_level = 0;
	struct dentry *dentry = file->f_path.dentry;
	struct inode *inode = dentry->d_inode;
	struct inode *inode = dentry->d_inode;
	loff_t saved_pos, end;
	loff_t saved_pos, end;


@@ -2140,6 +2142,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
			meta_level = -1;
			meta_level = -1;


			ret = ocfs2_prepare_inode_for_refcount(inode,
			ret = ocfs2_prepare_inode_for_refcount(inode,
							       file,
							       saved_pos,
							       saved_pos,
							       count,
							       count,
							       &meta_level);
							       &meta_level);
@@ -2254,7 +2257,7 @@ relock:
	}
	}


	can_do_direct = direct_io;
	can_do_direct = direct_io;
	ret = ocfs2_prepare_inode_for_write(file->f_path.dentry, ppos,
	ret = ocfs2_prepare_inode_for_write(file, ppos,
					    iocb->ki_left, appending,
					    iocb->ki_left, appending,
					    &can_do_direct, &has_refcount);
					    &can_do_direct, &has_refcount);
	if (ret < 0) {
	if (ret < 0) {
@@ -2373,7 +2376,7 @@ static int ocfs2_splice_to_file(struct pipe_inode_info *pipe,
{
{
	int ret;
	int ret;


	ret = ocfs2_prepare_inode_for_write(out->f_path.dentry,	&sd->pos,
	ret = ocfs2_prepare_inode_for_write(out, &sd->pos,
					    sd->total_len, 0, NULL, NULL);
					    sd->total_len, 0, NULL, NULL);
	if (ret < 0) {
	if (ret < 0) {
		mlog_errno(ret);
		mlog_errno(ret);
+4 −3
Original line number Original line Diff line number Diff line
@@ -59,10 +59,11 @@ static int ocfs2_fault(struct vm_area_struct *area, struct vm_fault *vmf)
	return ret;
	return ret;
}
}


static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh,
static int __ocfs2_page_mkwrite(struct file *file, struct buffer_head *di_bh,
				struct page *page)
				struct page *page)
{
{
	int ret;
	int ret;
	struct inode *inode = file->f_path.dentry->d_inode;
	struct address_space *mapping = inode->i_mapping;
	struct address_space *mapping = inode->i_mapping;
	loff_t pos = page_offset(page);
	loff_t pos = page_offset(page);
	unsigned int len = PAGE_CACHE_SIZE;
	unsigned int len = PAGE_CACHE_SIZE;
@@ -111,7 +112,7 @@ static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh,
	if (page->index == last_index)
	if (page->index == last_index)
		len = ((size - 1) & ~PAGE_CACHE_MASK) + 1;
		len = ((size - 1) & ~PAGE_CACHE_MASK) + 1;


	ret = ocfs2_write_begin_nolock(mapping, pos, len, 0, &locked_page,
	ret = ocfs2_write_begin_nolock(file, mapping, pos, len, 0, &locked_page,
				       &fsdata, di_bh, page);
				       &fsdata, di_bh, page);
	if (ret) {
	if (ret) {
		if (ret != -ENOSPC)
		if (ret != -ENOSPC)
@@ -159,7 +160,7 @@ static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
	 */
	 */
	down_write(&OCFS2_I(inode)->ip_alloc_sem);
	down_write(&OCFS2_I(inode)->ip_alloc_sem);


	ret = __ocfs2_page_mkwrite(inode, di_bh, page);
	ret = __ocfs2_page_mkwrite(vma->vm_file, di_bh, page);


	up_write(&OCFS2_I(inode)->ip_alloc_sem);
	up_write(&OCFS2_I(inode)->ip_alloc_sem);


+41 −2
Original line number Original line Diff line number Diff line
@@ -49,6 +49,7 @@


struct ocfs2_cow_context {
struct ocfs2_cow_context {
	struct inode *inode;
	struct inode *inode;
	struct file *file;
	u32 cow_start;
	u32 cow_start;
	u32 cow_len;
	u32 cow_len;
	struct ocfs2_extent_tree data_et;
	struct ocfs2_extent_tree data_et;
@@ -2932,13 +2933,16 @@ static int ocfs2_duplicate_clusters_by_page(handle_t *handle,
	u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster);
	u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster);
	struct page *page;
	struct page *page;
	pgoff_t page_index;
	pgoff_t page_index;
	unsigned int from, to;
	unsigned int from, to, readahead_pages;
	loff_t offset, end, map_end;
	loff_t offset, end, map_end;
	struct address_space *mapping = context->inode->i_mapping;
	struct address_space *mapping = context->inode->i_mapping;


	mlog(0, "old_cluster %u, new %u, len %u at offset %u\n", old_cluster,
	mlog(0, "old_cluster %u, new %u, len %u at offset %u\n", old_cluster,
	     new_cluster, new_len, cpos);
	     new_cluster, new_len, cpos);


	readahead_pages =
		(ocfs2_cow_contig_clusters(sb) <<
		 OCFS2_SB(sb)->s_clustersize_bits) >> PAGE_CACHE_SHIFT;
	offset = ((loff_t)cpos) << OCFS2_SB(sb)->s_clustersize_bits;
	offset = ((loff_t)cpos) << OCFS2_SB(sb)->s_clustersize_bits;
	end = offset + (new_len << OCFS2_SB(sb)->s_clustersize_bits);
	end = offset + (new_len << OCFS2_SB(sb)->s_clustersize_bits);
	/*
	/*
@@ -2969,6 +2973,14 @@ static int ocfs2_duplicate_clusters_by_page(handle_t *handle,
		if (PAGE_CACHE_SIZE <= OCFS2_SB(sb)->s_clustersize)
		if (PAGE_CACHE_SIZE <= OCFS2_SB(sb)->s_clustersize)
			BUG_ON(PageDirty(page));
			BUG_ON(PageDirty(page));


		if (PageReadahead(page) && context->file) {
			page_cache_async_readahead(mapping,
						   &context->file->f_ra,
						   context->file,
						   page, page_index,
						   readahead_pages);
		}

		if (!PageUptodate(page)) {
		if (!PageUptodate(page)) {
			ret = block_read_full_page(page, ocfs2_get_block);
			ret = block_read_full_page(page, ocfs2_get_block);
			if (ret) {
			if (ret) {
@@ -3409,12 +3421,35 @@ static int ocfs2_replace_cow(struct ocfs2_cow_context *context)
	return ret;
	return ret;
}
}


static void ocfs2_readahead_for_cow(struct inode *inode,
				    struct file *file,
				    u32 start, u32 len)
{
	struct address_space *mapping;
	pgoff_t index;
	unsigned long num_pages;
	int cs_bits = OCFS2_SB(inode->i_sb)->s_clustersize_bits;

	if (!file)
		return;

	mapping = file->f_mapping;
	num_pages = (len << cs_bits) >> PAGE_CACHE_SHIFT;
	if (!num_pages)
		num_pages = 1;

	index = ((loff_t)start << cs_bits) >> PAGE_CACHE_SHIFT;
	page_cache_sync_readahead(mapping, &file->f_ra, file,
				  index, num_pages);
}

/*
/*
 * Starting at cpos, try to CoW write_len clusters.  Don't CoW
 * Starting at cpos, try to CoW write_len clusters.  Don't CoW
 * past max_cpos.  This will stop when it runs into a hole or an
 * past max_cpos.  This will stop when it runs into a hole or an
 * unrefcounted extent.
 * unrefcounted extent.
 */
 */
static int ocfs2_refcount_cow_hunk(struct inode *inode,
static int ocfs2_refcount_cow_hunk(struct inode *inode,
				   struct file *file,
				   struct buffer_head *di_bh,
				   struct buffer_head *di_bh,
				   u32 cpos, u32 write_len, u32 max_cpos)
				   u32 cpos, u32 write_len, u32 max_cpos)
{
{
@@ -3443,6 +3478,8 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode,


	BUG_ON(cow_len == 0);
	BUG_ON(cow_len == 0);


	ocfs2_readahead_for_cow(inode, file, cow_start, cow_len);

	context = kzalloc(sizeof(struct ocfs2_cow_context), GFP_NOFS);
	context = kzalloc(sizeof(struct ocfs2_cow_context), GFP_NOFS);
	if (!context) {
	if (!context) {
		ret = -ENOMEM;
		ret = -ENOMEM;
@@ -3464,6 +3501,7 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode,
	context->ref_root_bh = ref_root_bh;
	context->ref_root_bh = ref_root_bh;
	context->cow_duplicate_clusters = ocfs2_duplicate_clusters_by_page;
	context->cow_duplicate_clusters = ocfs2_duplicate_clusters_by_page;
	context->get_clusters = ocfs2_di_get_clusters;
	context->get_clusters = ocfs2_di_get_clusters;
	context->file = file;


	ocfs2_init_dinode_extent_tree(&context->data_et,
	ocfs2_init_dinode_extent_tree(&context->data_et,
				      INODE_CACHE(inode), di_bh);
				      INODE_CACHE(inode), di_bh);
@@ -3492,6 +3530,7 @@ out:
 * clusters between cpos and cpos+write_len are safe to modify.
 * clusters between cpos and cpos+write_len are safe to modify.
 */
 */
int ocfs2_refcount_cow(struct inode *inode,
int ocfs2_refcount_cow(struct inode *inode,
		       struct file *file,
		       struct buffer_head *di_bh,
		       struct buffer_head *di_bh,
		       u32 cpos, u32 write_len, u32 max_cpos)
		       u32 cpos, u32 write_len, u32 max_cpos)
{
{
@@ -3511,7 +3550,7 @@ int ocfs2_refcount_cow(struct inode *inode,
			num_clusters = write_len;
			num_clusters = write_len;


		if (ext_flags & OCFS2_EXT_REFCOUNTED) {
		if (ext_flags & OCFS2_EXT_REFCOUNTED) {
			ret = ocfs2_refcount_cow_hunk(inode, di_bh, cpos,
			ret = ocfs2_refcount_cow_hunk(inode, file, di_bh, cpos,
						      num_clusters, max_cpos);
						      num_clusters, max_cpos);
			if (ret) {
			if (ret) {
				mlog_errno(ret);
				mlog_errno(ret);
Loading