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 "extent_map.h"
|
||||||
#include "aops.h"
|
#include "aops.h"
|
||||||
#include "xattr.h"
|
#include "xattr.h"
|
||||||
|
#include "namei.h"
|
||||||
|
|
||||||
#include <linux/bio.h>
|
#include <linux/bio.h>
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
|
@ -4022,3 +4023,125 @@ static int ocfs2_create_reflink_node(struct inode *s_inode,
|
||||||
|
|
||||||
return ret;
|
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…
Add table
Reference in a new issue