Commit 293b2f70 authored by Tao Ma's avatar Tao Ma Committed by Joel Becker

ocfs2: Integrate CoW in file write.

When we use mmap, we CoW the refcountd clusters in
ocfs2_write_begin_nolock. While for normal file
io(including directio), we do CoW in
ocfs2_prepare_inode_for_write.
Signed-off-by: default avatarTao Ma <tao.ma@oracle.com>
parent 6ae23c55
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include "suballoc.h" #include "suballoc.h"
#include "super.h" #include "super.h"
#include "symlink.h" #include "symlink.h"
#include "refcounttree.h"
#include "buffer_head_io.h" #include "buffer_head_io.h"
...@@ -590,6 +591,8 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, ...@@ -590,6 +591,8 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
goto bail; goto bail;
} }
/* We should already CoW the refcounted extent. */
BUG_ON(ext_flags & OCFS2_EXT_REFCOUNTED);
/* /*
* get_more_blocks() expects us to describe a hole by clearing * get_more_blocks() expects us to describe a hole by clearing
* the mapped bit on bh_result(). * the mapped bit on bh_result().
...@@ -1449,6 +1452,9 @@ static int ocfs2_populate_write_desc(struct inode *inode, ...@@ -1449,6 +1452,9 @@ static int ocfs2_populate_write_desc(struct inode *inode,
goto out; goto out;
} }
/* We should already CoW the refcountd extent. */
BUG_ON(ext_flags & OCFS2_EXT_REFCOUNTED);
/* /*
* Assume worst case - that we're writing in * Assume worst case - that we're writing in
* the middle of the extent. * the middle of the extent.
...@@ -1700,6 +1706,19 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, ...@@ -1700,6 +1706,19 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
goto out; goto out;
} }
ret = ocfs2_check_range_for_refcount(inode, pos, len);
if (ret < 0) {
mlog_errno(ret);
goto out;
} else if (ret == 1) {
ret = ocfs2_refcount_cow(inode, di_bh,
wc->w_cpos, wc->w_clen);
if (ret) {
mlog_errno(ret);
goto out;
}
}
ret = ocfs2_populate_write_desc(inode, wc, &clusters_to_alloc, ret = ocfs2_populate_write_desc(inode, wc, &clusters_to_alloc,
&extents_to_split); &extents_to_split);
if (ret) { if (ret) {
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#include "xattr.h" #include "xattr.h"
#include "acl.h" #include "acl.h"
#include "quota.h" #include "quota.h"
#include "refcounttree.h"
#include "buffer_head_io.h" #include "buffer_head_io.h"
...@@ -1656,6 +1657,70 @@ static long ocfs2_fallocate(struct inode *inode, int mode, loff_t offset, ...@@ -1656,6 +1657,70 @@ static long ocfs2_fallocate(struct inode *inode, int mode, loff_t offset,
OCFS2_IOC_RESVSP64, &sr, change_size); OCFS2_IOC_RESVSP64, &sr, change_size);
} }
int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos,
size_t count)
{
int ret = 0;
unsigned int extent_flags;
u32 cpos, clusters, extent_len, phys_cpos;
struct super_block *sb = inode->i_sb;
if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)) ||
!(OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL))
return 0;
cpos = pos >> OCFS2_SB(sb)->s_clustersize_bits;
clusters = ocfs2_clusters_for_bytes(sb, pos + count) - cpos;
while (clusters) {
ret = ocfs2_get_clusters(inode, cpos, &phys_cpos, &extent_len,
&extent_flags);
if (ret < 0) {
mlog_errno(ret);
goto out;
}
if (phys_cpos && (extent_flags & OCFS2_EXT_REFCOUNTED)) {
ret = 1;
break;
}
if (extent_len > clusters)
extent_len = clusters;
clusters -= extent_len;
cpos += extent_len;
}
out:
return ret;
}
static int ocfs2_prepare_inode_for_refcount(struct inode *inode,
loff_t pos, size_t count,
int *meta_level)
{
int ret;
struct buffer_head *di_bh = NULL;
u32 cpos = pos >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
u32 clusters =
ocfs2_clusters_for_bytes(inode->i_sb, pos + count) - cpos;
ret = ocfs2_inode_lock(inode, &di_bh, 1);
if (ret) {
mlog_errno(ret);
goto out;
}
*meta_level = 1;
ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters);
if (ret)
mlog_errno(ret);
out:
brelse(di_bh);
return ret;
}
static int ocfs2_prepare_inode_for_write(struct dentry *dentry, static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
loff_t *ppos, loff_t *ppos,
size_t count, size_t count,
...@@ -1712,6 +1777,22 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, ...@@ -1712,6 +1777,22 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
end = saved_pos + count; end = saved_pos + count;
ret = ocfs2_check_range_for_refcount(inode, saved_pos, count);
if (ret == 1) {
ocfs2_inode_unlock(inode, meta_level);
meta_level = -1;
ret = ocfs2_prepare_inode_for_refcount(inode,
saved_pos,
count,
&meta_level);
}
if (ret < 0) {
mlog_errno(ret);
goto out_unlock;
}
/* /*
* Skip the O_DIRECT checks if we don't need * Skip the O_DIRECT checks if we don't need
* them. * them.
...@@ -1758,7 +1839,8 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, ...@@ -1758,7 +1839,8 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
*ppos = saved_pos; *ppos = saved_pos;
out_unlock: out_unlock:
ocfs2_inode_unlock(inode, meta_level); if (meta_level >= 0)
ocfs2_inode_unlock(inode, meta_level);
out: out:
return ret; return ret;
......
...@@ -69,4 +69,6 @@ int ocfs2_update_inode_atime(struct inode *inode, ...@@ -69,4 +69,6 @@ int ocfs2_update_inode_atime(struct inode *inode,
int ocfs2_change_file_space(struct file *file, unsigned int cmd, int ocfs2_change_file_space(struct file *file, unsigned int cmd,
struct ocfs2_space_resv *sr); struct ocfs2_space_resv *sr);
int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos,
size_t count);
#endif /* OCFS2_FILE_H */ #endif /* OCFS2_FILE_H */
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