aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2009-09-20 22:38:17 -0400
committerJoel Becker <joel.becker@oracle.com>2009-09-22 23:09:49 -0400
commit09bf27a000209e9e8c9c048b4c50f6bb0dd857bb (patch)
tree605522b8c41d70d26705dfe4cc9149b6a10724a6
parent0fe9b66c65f3ff227da45381afe7612f91e32740 (diff)
ocfs2: Implement ocfs2_reflink.
Implement ocfs2_reflink. Signed-off-by: Tao Ma <tao.ma@oracle.com>
-rw-r--r--fs/ocfs2/refcounttree.c123
1 files changed, 123 insertions, 0 deletions
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 5d88e76f223a..7a8a384d8ad1 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -33,6 +33,7 @@
33#include "extent_map.h" 33#include "extent_map.h"
34#include "aops.h" 34#include "aops.h"
35#include "xattr.h" 35#include "xattr.h"
36#include "namei.h"
36 37
37#include <linux/bio.h> 38#include <linux/bio.h>
38#include <linux/blkdev.h> 39#include <linux/blkdev.h>
@@ -4022,3 +4023,125 @@ out:
4022 4023
4023 return ret; 4024 return ret;
4024} 4025}
4026
4027static int __ocfs2_reflink(struct dentry *old_dentry,
4028 struct buffer_head *old_bh,
4029 struct inode *new_inode,
4030 bool preserve)
4031{
4032 int ret;
4033 struct inode *inode = old_dentry->d_inode;
4034 struct buffer_head *new_bh = NULL;
4035
4036 ret = filemap_fdatawrite(inode->i_mapping);
4037 if (ret) {
4038 mlog_errno(ret);
4039 goto out;
4040 }
4041
4042 ret = ocfs2_attach_refcount_tree(inode, old_bh);
4043 if (ret) {
4044 mlog_errno(ret);
4045 goto out;
4046 }
4047
4048 mutex_lock(&new_inode->i_mutex);
4049 ret = ocfs2_inode_lock(new_inode, &new_bh, 1);
4050 if (ret) {
4051 mlog_errno(ret);
4052 goto out_unlock;
4053 }
4054
4055 ret = ocfs2_create_reflink_node(inode, old_bh,
4056 new_inode, new_bh, preserve);
4057 if (ret) {
4058 mlog_errno(ret);
4059 goto inode_unlock;
4060 }
4061
4062 if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_XATTR_FL) {
4063 ret = ocfs2_reflink_xattrs(inode, old_bh,
4064 new_inode, new_bh,
4065 preserve);
4066 if (ret)
4067 mlog_errno(ret);
4068 }
4069inode_unlock:
4070 ocfs2_inode_unlock(new_inode, 1);
4071 brelse(new_bh);
4072out_unlock:
4073 mutex_unlock(&new_inode->i_mutex);
4074out:
4075 if (!ret) {
4076 ret = filemap_fdatawait(inode->i_mapping);
4077 if (ret)
4078 mlog_errno(ret);
4079 }
4080 return ret;
4081}
4082
4083static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir,
4084 struct dentry *new_dentry, bool preserve)
4085{
4086 int error;
4087 struct inode *inode = old_dentry->d_inode;
4088 struct buffer_head *old_bh = NULL;
4089 struct inode *new_orphan_inode = NULL;
4090
4091 if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)))
4092 return -EOPNOTSUPP;
4093
4094 error = ocfs2_create_inode_in_orphan(dir, inode->i_mode,
4095 &new_orphan_inode);
4096 if (error) {
4097 mlog_errno(error);
4098 goto out;
4099 }
4100
4101 error = ocfs2_inode_lock(inode, &old_bh, 1);
4102 if (error) {
4103 mlog_errno(error);
4104 goto out;
4105 }
4106
4107 down_write(&OCFS2_I(inode)->ip_xattr_sem);
4108 down_write(&OCFS2_I(inode)->ip_alloc_sem);
4109 error = __ocfs2_reflink(old_dentry, old_bh,
4110 new_orphan_inode, preserve);
4111 up_write(&OCFS2_I(inode)->ip_alloc_sem);
4112 up_write(&OCFS2_I(inode)->ip_xattr_sem);
4113
4114 ocfs2_inode_unlock(inode, 1);
4115 brelse(old_bh);
4116
4117 if (error) {
4118 mlog_errno(error);
4119 goto out;
4120 }
4121
4122 /* If the security isn't preserved, we need to re-initialize them. */
4123 if (!preserve) {
4124 error = ocfs2_init_security_and_acl(dir, new_orphan_inode);
4125 if (error)
4126 mlog_errno(error);
4127 }
4128out:
4129 if (!error) {
4130 error = ocfs2_mv_orphaned_inode_to_new(dir, new_orphan_inode,
4131 new_dentry);
4132 if (error)
4133 mlog_errno(error);
4134 }
4135
4136 if (new_orphan_inode) {
4137 /*
4138 * We need to open_unlock the inode no matter whether we
4139 * succeed or not, so that other nodes can delete it later.
4140 */
4141 ocfs2_open_unlock(new_orphan_inode);
4142 if (error)
4143 iput(new_orphan_inode);
4144 }
4145
4146 return error;
4147}