ocfs2: Implement ocfs2_reflink.
Implement ocfs2_reflink. Signed-off-by: Tao Ma <tao.ma@oracle.com>
This commit is contained in:
parent
0fe9b66c65
commit
09bf27a000
1 changed files with 123 additions and 0 deletions
|
@ -33,6 +33,7 @@
|
|||
#include "extent_map.h"
|
||||
#include "aops.h"
|
||||
#include "xattr.h"
|
||||
#include "namei.h"
|
||||
|
||||
#include <linux/bio.h>
|
||||
#include <linux/blkdev.h>
|
||||
|
@ -4022,3 +4023,125 @@ static int ocfs2_create_reflink_node(struct inode *s_inode,
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __ocfs2_reflink(struct dentry *old_dentry,
|
||||
struct buffer_head *old_bh,
|
||||
struct inode *new_inode,
|
||||
bool preserve)
|
||||
{
|
||||
int ret;
|
||||
struct inode *inode = old_dentry->d_inode;
|
||||
struct buffer_head *new_bh = NULL;
|
||||
|
||||
ret = filemap_fdatawrite(inode->i_mapping);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ocfs2_attach_refcount_tree(inode, old_bh);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&new_inode->i_mutex);
|
||||
ret = ocfs2_inode_lock(new_inode, &new_bh, 1);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = ocfs2_create_reflink_node(inode, old_bh,
|
||||
new_inode, new_bh, preserve);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto inode_unlock;
|
||||
}
|
||||
|
||||
if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_XATTR_FL) {
|
||||
ret = ocfs2_reflink_xattrs(inode, old_bh,
|
||||
new_inode, new_bh,
|
||||
preserve);
|
||||
if (ret)
|
||||
mlog_errno(ret);
|
||||
}
|
||||
inode_unlock:
|
||||
ocfs2_inode_unlock(new_inode, 1);
|
||||
brelse(new_bh);
|
||||
out_unlock:
|
||||
mutex_unlock(&new_inode->i_mutex);
|
||||
out:
|
||||
if (!ret) {
|
||||
ret = filemap_fdatawait(inode->i_mapping);
|
||||
if (ret)
|
||||
mlog_errno(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir,
|
||||
struct dentry *new_dentry, bool preserve)
|
||||
{
|
||||
int error;
|
||||
struct inode *inode = old_dentry->d_inode;
|
||||
struct buffer_head *old_bh = NULL;
|
||||
struct inode *new_orphan_inode = NULL;
|
||||
|
||||
if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
error = ocfs2_create_inode_in_orphan(dir, inode->i_mode,
|
||||
&new_orphan_inode);
|
||||
if (error) {
|
||||
mlog_errno(error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = ocfs2_inode_lock(inode, &old_bh, 1);
|
||||
if (error) {
|
||||
mlog_errno(error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
down_write(&OCFS2_I(inode)->ip_xattr_sem);
|
||||
down_write(&OCFS2_I(inode)->ip_alloc_sem);
|
||||
error = __ocfs2_reflink(old_dentry, old_bh,
|
||||
new_orphan_inode, preserve);
|
||||
up_write(&OCFS2_I(inode)->ip_alloc_sem);
|
||||
up_write(&OCFS2_I(inode)->ip_xattr_sem);
|
||||
|
||||
ocfs2_inode_unlock(inode, 1);
|
||||
brelse(old_bh);
|
||||
|
||||
if (error) {
|
||||
mlog_errno(error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If the security isn't preserved, we need to re-initialize them. */
|
||||
if (!preserve) {
|
||||
error = ocfs2_init_security_and_acl(dir, new_orphan_inode);
|
||||
if (error)
|
||||
mlog_errno(error);
|
||||
}
|
||||
out:
|
||||
if (!error) {
|
||||
error = ocfs2_mv_orphaned_inode_to_new(dir, new_orphan_inode,
|
||||
new_dentry);
|
||||
if (error)
|
||||
mlog_errno(error);
|
||||
}
|
||||
|
||||
if (new_orphan_inode) {
|
||||
/*
|
||||
* We need to open_unlock the inode no matter whether we
|
||||
* succeed or not, so that other nodes can delete it later.
|
||||
*/
|
||||
ocfs2_open_unlock(new_orphan_inode);
|
||||
if (error)
|
||||
iput(new_orphan_inode);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue