diff options
Diffstat (limited to 'fs/ocfs2')
-rw-r--r-- | fs/ocfs2/refcounttree.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 5d88e76f223..7a8a384d8ad 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 | |||
4027 | static 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 | } | ||
4069 | inode_unlock: | ||
4070 | ocfs2_inode_unlock(new_inode, 1); | ||
4071 | brelse(new_bh); | ||
4072 | out_unlock: | ||
4073 | mutex_unlock(&new_inode->i_mutex); | ||
4074 | out: | ||
4075 | if (!ret) { | ||
4076 | ret = filemap_fdatawait(inode->i_mapping); | ||
4077 | if (ret) | ||
4078 | mlog_errno(ret); | ||
4079 | } | ||
4080 | return ret; | ||
4081 | } | ||
4082 | |||
4083 | static 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 | } | ||
4128 | out: | ||
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 | } | ||