ocfs2: Add preserve to reflink.
reflink has 2 options for the destination file: 1. snapshot: reflink will attempt to preserve ownership, permissions, and all other security state in order to create a full snapshot. 2. new file: it will acquire the data extent sharing but will see the file's security state and attributes initialized as a new file. So add the option to ocfs2. Signed-off-by: Tao Ma <tao.ma@oracle.com>
This commit is contained in:
parent
bc13d34757
commit
0fe9b66c65
|
@ -3904,7 +3904,8 @@ out:
|
||||||
static int ocfs2_complete_reflink(struct inode *s_inode,
|
static int ocfs2_complete_reflink(struct inode *s_inode,
|
||||||
struct buffer_head *s_bh,
|
struct buffer_head *s_bh,
|
||||||
struct inode *t_inode,
|
struct inode *t_inode,
|
||||||
struct buffer_head *t_bh)
|
struct buffer_head *t_bh,
|
||||||
|
bool preserve)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
handle_t *handle;
|
handle_t *handle;
|
||||||
|
@ -3939,13 +3940,16 @@ static int ocfs2_complete_reflink(struct inode *s_inode,
|
||||||
di->i_size = s_di->i_size;
|
di->i_size = s_di->i_size;
|
||||||
di->i_dyn_features = s_di->i_dyn_features;
|
di->i_dyn_features = s_di->i_dyn_features;
|
||||||
di->i_attr = s_di->i_attr;
|
di->i_attr = s_di->i_attr;
|
||||||
|
|
||||||
|
if (preserve) {
|
||||||
di->i_uid = s_di->i_uid;
|
di->i_uid = s_di->i_uid;
|
||||||
di->i_gid = s_di->i_gid;
|
di->i_gid = s_di->i_gid;
|
||||||
di->i_mode = s_di->i_mode;
|
di->i_mode = s_di->i_mode;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* update time.
|
* update time.
|
||||||
* we want mtime to appear identical to the source and update ctime.
|
* we want mtime to appear identical to the source and
|
||||||
|
* update ctime.
|
||||||
*/
|
*/
|
||||||
t_inode->i_ctime = CURRENT_TIME;
|
t_inode->i_ctime = CURRENT_TIME;
|
||||||
|
|
||||||
|
@ -3955,6 +3959,7 @@ static int ocfs2_complete_reflink(struct inode *s_inode,
|
||||||
t_inode->i_mtime = s_inode->i_mtime;
|
t_inode->i_mtime = s_inode->i_mtime;
|
||||||
di->i_mtime = s_di->i_mtime;
|
di->i_mtime = s_di->i_mtime;
|
||||||
di->i_mtime_nsec = s_di->i_mtime_nsec;
|
di->i_mtime_nsec = s_di->i_mtime_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
ocfs2_journal_dirty(handle, t_bh);
|
ocfs2_journal_dirty(handle, t_bh);
|
||||||
|
|
||||||
|
@ -3966,7 +3971,8 @@ out_commit:
|
||||||
static int ocfs2_create_reflink_node(struct inode *s_inode,
|
static int ocfs2_create_reflink_node(struct inode *s_inode,
|
||||||
struct buffer_head *s_bh,
|
struct buffer_head *s_bh,
|
||||||
struct inode *t_inode,
|
struct inode *t_inode,
|
||||||
struct buffer_head *t_bh)
|
struct buffer_head *t_bh,
|
||||||
|
bool preserve)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct buffer_head *ref_root_bh = NULL;
|
struct buffer_head *ref_root_bh = NULL;
|
||||||
|
@ -4001,7 +4007,7 @@ static int ocfs2_create_reflink_node(struct inode *s_inode,
|
||||||
goto out_unlock_refcount;
|
goto out_unlock_refcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ocfs2_complete_reflink(s_inode, s_bh, t_inode, t_bh);
|
ret = ocfs2_complete_reflink(s_inode, s_bh, t_inode, t_bh, preserve);
|
||||||
if (ret)
|
if (ret)
|
||||||
mlog_errno(ret);
|
mlog_errno(ret);
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
#include "super.h"
|
#include "super.h"
|
||||||
#include "xattr.h"
|
#include "xattr.h"
|
||||||
#include "refcounttree.h"
|
#include "refcounttree.h"
|
||||||
|
#include "acl.h"
|
||||||
|
|
||||||
struct ocfs2_xattr_def_value_root {
|
struct ocfs2_xattr_def_value_root {
|
||||||
struct ocfs2_xattr_value_root xv;
|
struct ocfs2_xattr_value_root xv;
|
||||||
|
@ -204,6 +205,8 @@ static int ocfs2_get_xattr_tree_value_root(struct super_block *sb,
|
||||||
int offset,
|
int offset,
|
||||||
struct ocfs2_xattr_value_root **xv,
|
struct ocfs2_xattr_value_root **xv,
|
||||||
struct buffer_head **bh);
|
struct buffer_head **bh);
|
||||||
|
static int ocfs2_xattr_security_set(struct inode *inode, const char *name,
|
||||||
|
const void *value, size_t size, int flags);
|
||||||
|
|
||||||
static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb)
|
static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb)
|
||||||
{
|
{
|
||||||
|
@ -5994,6 +5997,7 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef int (should_xattr_reflinked)(struct ocfs2_xattr_entry *xe);
|
||||||
/*
|
/*
|
||||||
* Store the information we need in xattr reflink.
|
* Store the information we need in xattr reflink.
|
||||||
* old_bh and new_bh are inode bh for the old and new inode.
|
* old_bh and new_bh are inode bh for the old and new inode.
|
||||||
|
@ -6006,6 +6010,7 @@ struct ocfs2_xattr_reflink {
|
||||||
struct ocfs2_caching_info *ref_ci;
|
struct ocfs2_caching_info *ref_ci;
|
||||||
struct buffer_head *ref_root_bh;
|
struct buffer_head *ref_root_bh;
|
||||||
struct ocfs2_cached_dealloc_ctxt *dealloc;
|
struct ocfs2_cached_dealloc_ctxt *dealloc;
|
||||||
|
should_xattr_reflinked *xattr_reflinked;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -6147,6 +6152,9 @@ out:
|
||||||
* NOTE:
|
* NOTE:
|
||||||
* Before we call this function, the caller has memcpy the xattr in
|
* Before we call this function, the caller has memcpy the xattr in
|
||||||
* old_xh to the new_xh.
|
* old_xh to the new_xh.
|
||||||
|
*
|
||||||
|
* If args.xattr_reflinked is set, call it to decide whether the xe should
|
||||||
|
* be reflinked or not. If not, remove it from the new xattr header.
|
||||||
*/
|
*/
|
||||||
static int ocfs2_reflink_xattr_header(handle_t *handle,
|
static int ocfs2_reflink_xattr_header(handle_t *handle,
|
||||||
struct ocfs2_xattr_reflink *args,
|
struct ocfs2_xattr_reflink *args,
|
||||||
|
@ -6159,10 +6167,10 @@ static int ocfs2_reflink_xattr_header(handle_t *handle,
|
||||||
get_xattr_value_root *func,
|
get_xattr_value_root *func,
|
||||||
void *para)
|
void *para)
|
||||||
{
|
{
|
||||||
int ret = 0, i;
|
int ret = 0, i, j;
|
||||||
struct super_block *sb = args->old_inode->i_sb;
|
struct super_block *sb = args->old_inode->i_sb;
|
||||||
struct buffer_head *value_bh;
|
struct buffer_head *value_bh;
|
||||||
struct ocfs2_xattr_entry *xe;
|
struct ocfs2_xattr_entry *xe, *last;
|
||||||
struct ocfs2_xattr_value_root *xv, *new_xv;
|
struct ocfs2_xattr_value_root *xv, *new_xv;
|
||||||
struct ocfs2_extent_tree data_et;
|
struct ocfs2_extent_tree data_et;
|
||||||
u32 clusters, cpos, p_cluster, num_clusters;
|
u32 clusters, cpos, p_cluster, num_clusters;
|
||||||
|
@ -6170,9 +6178,30 @@ static int ocfs2_reflink_xattr_header(handle_t *handle,
|
||||||
|
|
||||||
mlog(0, "reflink xattr in container %llu, count = %u\n",
|
mlog(0, "reflink xattr in container %llu, count = %u\n",
|
||||||
(unsigned long long)old_bh->b_blocknr, le16_to_cpu(xh->xh_count));
|
(unsigned long long)old_bh->b_blocknr, le16_to_cpu(xh->xh_count));
|
||||||
for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
|
|
||||||
|
last = &new_xh->xh_entries[le16_to_cpu(new_xh->xh_count)];
|
||||||
|
for (i = 0, j = 0; i < le16_to_cpu(xh->xh_count); i++, j++) {
|
||||||
xe = &xh->xh_entries[i];
|
xe = &xh->xh_entries[i];
|
||||||
|
|
||||||
|
if (args->xattr_reflinked && !args->xattr_reflinked(xe)) {
|
||||||
|
xe = &new_xh->xh_entries[j];
|
||||||
|
|
||||||
|
le16_add_cpu(&new_xh->xh_count, -1);
|
||||||
|
if (new_xh->xh_count) {
|
||||||
|
memmove(xe, xe + 1,
|
||||||
|
(void *)last - (void *)xe);
|
||||||
|
memset(last, 0,
|
||||||
|
sizeof(struct ocfs2_xattr_entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't want j to increase in the next round since
|
||||||
|
* it is already moved ahead.
|
||||||
|
*/
|
||||||
|
j--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (ocfs2_xattr_is_local(xe))
|
if (ocfs2_xattr_is_local(xe))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -6182,7 +6211,7 @@ static int ocfs2_reflink_xattr_header(handle_t *handle,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = func(sb, new_bh, new_xh, i, &new_xv, &value_bh, para);
|
ret = func(sb, new_bh, new_xh, j, &new_xv, &value_bh, para);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
mlog_errno(ret);
|
mlog_errno(ret);
|
||||||
break;
|
break;
|
||||||
|
@ -6847,10 +6876,20 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ocfs2_reflink_xattr_no_security(struct ocfs2_xattr_entry *xe)
|
||||||
|
{
|
||||||
|
int type = ocfs2_xattr_get_type(xe);
|
||||||
|
|
||||||
|
return type != OCFS2_XATTR_INDEX_SECURITY &&
|
||||||
|
type != OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS &&
|
||||||
|
type != OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
int ocfs2_reflink_xattrs(struct inode *old_inode,
|
int ocfs2_reflink_xattrs(struct inode *old_inode,
|
||||||
struct buffer_head *old_bh,
|
struct buffer_head *old_bh,
|
||||||
struct inode *new_inode,
|
struct inode *new_inode,
|
||||||
struct buffer_head *new_bh)
|
struct buffer_head *new_bh,
|
||||||
|
bool preserve_security)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct ocfs2_xattr_reflink args;
|
struct ocfs2_xattr_reflink args;
|
||||||
|
@ -6878,6 +6917,10 @@ int ocfs2_reflink_xattrs(struct inode *old_inode,
|
||||||
args.ref_ci = &ref_tree->rf_ci;
|
args.ref_ci = &ref_tree->rf_ci;
|
||||||
args.ref_root_bh = ref_root_bh;
|
args.ref_root_bh = ref_root_bh;
|
||||||
args.dealloc = &dealloc;
|
args.dealloc = &dealloc;
|
||||||
|
if (preserve_security)
|
||||||
|
args.xattr_reflinked = NULL;
|
||||||
|
else
|
||||||
|
args.xattr_reflinked = ocfs2_reflink_xattr_no_security;
|
||||||
|
|
||||||
if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
|
if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
|
||||||
ret = ocfs2_reflink_xattr_inline(&args);
|
ret = ocfs2_reflink_xattr_inline(&args);
|
||||||
|
@ -6917,6 +6960,51 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize security and acl for a already created inode.
|
||||||
|
* Used for reflink a non-preserve-security file.
|
||||||
|
*
|
||||||
|
* It uses common api like ocfs2_xattr_set, so the caller
|
||||||
|
* must not hold any lock expect i_mutex.
|
||||||
|
*/
|
||||||
|
int ocfs2_init_security_and_acl(struct inode *dir,
|
||||||
|
struct inode *inode)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct buffer_head *dir_bh = NULL;
|
||||||
|
struct ocfs2_security_xattr_info si = {
|
||||||
|
.enable = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = ocfs2_init_security_get(inode, dir, &si);
|
||||||
|
if (!ret) {
|
||||||
|
ret = ocfs2_xattr_security_set(inode, si.name,
|
||||||
|
si.value, si.value_len,
|
||||||
|
XATTR_CREATE);
|
||||||
|
if (ret) {
|
||||||
|
mlog_errno(ret);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
} else if (ret != -EOPNOTSUPP) {
|
||||||
|
mlog_errno(ret);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ocfs2_inode_lock(dir, &dir_bh, 0);
|
||||||
|
if (ret) {
|
||||||
|
mlog_errno(ret);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ocfs2_init_acl(NULL, inode, dir, NULL, dir_bh, NULL, NULL);
|
||||||
|
if (ret)
|
||||||
|
mlog_errno(ret);
|
||||||
|
|
||||||
|
ocfs2_inode_unlock(dir, 0);
|
||||||
|
brelse(dir_bh);
|
||||||
|
leave:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* 'security' attributes support
|
* 'security' attributes support
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -93,5 +93,8 @@ int ocfs2_xattr_attach_refcount_tree(struct inode *inode,
|
||||||
int ocfs2_reflink_xattrs(struct inode *old_inode,
|
int ocfs2_reflink_xattrs(struct inode *old_inode,
|
||||||
struct buffer_head *old_bh,
|
struct buffer_head *old_bh,
|
||||||
struct inode *new_inode,
|
struct inode *new_inode,
|
||||||
struct buffer_head *new_bh);
|
struct buffer_head *new_bh,
|
||||||
|
bool preserve_security);
|
||||||
|
int ocfs2_init_security_and_acl(struct inode *dir,
|
||||||
|
struct inode *inode);
|
||||||
#endif /* OCFS2_XATTR_H */
|
#endif /* OCFS2_XATTR_H */
|
||||||
|
|
Loading…
Reference in a new issue