aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2009-08-17 23:47:56 -0400
committerJoel Becker <joel.becker@oracle.com>2009-09-22 23:09:49 -0400
commit0fe9b66c65f3ff227da45381afe7612f91e32740 (patch)
tree14d95c15065419825adb4f0f0a26a5416a64259e /fs/ocfs2
parentbc13d347574fc0a8a666bc0f4cc2b635d202e372 (diff)
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>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r--fs/ocfs2/refcounttree.c38
-rw-r--r--fs/ocfs2/xattr.c98
-rw-r--r--fs/ocfs2/xattr.h5
3 files changed, 119 insertions, 22 deletions
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 47df8c5cd3c5..5d88e76f223a 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -3904,7 +3904,8 @@ out:
3904static int ocfs2_complete_reflink(struct inode *s_inode, 3904static int ocfs2_complete_reflink(struct inode *s_inode,
3905 struct buffer_head *s_bh, 3905 struct buffer_head *s_bh,
3906 struct inode *t_inode, 3906 struct inode *t_inode,
3907 struct buffer_head *t_bh) 3907 struct buffer_head *t_bh,
3908 bool preserve)
3908{ 3909{
3909 int ret; 3910 int ret;
3910 handle_t *handle; 3911 handle_t *handle;
@@ -3939,22 +3940,26 @@ static int ocfs2_complete_reflink(struct inode *s_inode,
3939 di->i_size = s_di->i_size; 3940 di->i_size = s_di->i_size;
3940 di->i_dyn_features = s_di->i_dyn_features; 3941 di->i_dyn_features = s_di->i_dyn_features;
3941 di->i_attr = s_di->i_attr; 3942 di->i_attr = s_di->i_attr;
3942 di->i_uid = s_di->i_uid;
3943 di->i_gid = s_di->i_gid;
3944 di->i_mode = s_di->i_mode;
3945 3943
3946 /* 3944 if (preserve) {
3947 * update time. 3945 di->i_uid = s_di->i_uid;
3948 * we want mtime to appear identical to the source and update ctime. 3946 di->i_gid = s_di->i_gid;
3949 */ 3947 di->i_mode = s_di->i_mode;
3950 t_inode->i_ctime = CURRENT_TIME; 3948
3949 /*
3950 * update time.
3951 * we want mtime to appear identical to the source and
3952 * update ctime.
3953 */
3954 t_inode->i_ctime = CURRENT_TIME;
3951 3955
3952 di->i_ctime = cpu_to_le64(t_inode->i_ctime.tv_sec); 3956 di->i_ctime = cpu_to_le64(t_inode->i_ctime.tv_sec);
3953 di->i_ctime_nsec = cpu_to_le32(t_inode->i_ctime.tv_nsec); 3957 di->i_ctime_nsec = cpu_to_le32(t_inode->i_ctime.tv_nsec);
3954 3958
3955 t_inode->i_mtime = s_inode->i_mtime; 3959 t_inode->i_mtime = s_inode->i_mtime;
3956 di->i_mtime = s_di->i_mtime; 3960 di->i_mtime = s_di->i_mtime;
3957 di->i_mtime_nsec = s_di->i_mtime_nsec; 3961 di->i_mtime_nsec = s_di->i_mtime_nsec;
3962 }
3958 3963
3959 ocfs2_journal_dirty(handle, t_bh); 3964 ocfs2_journal_dirty(handle, t_bh);
3960 3965
@@ -3966,7 +3971,8 @@ out_commit:
3966static int ocfs2_create_reflink_node(struct inode *s_inode, 3971static int ocfs2_create_reflink_node(struct inode *s_inode,
3967 struct buffer_head *s_bh, 3972 struct buffer_head *s_bh,
3968 struct inode *t_inode, 3973 struct inode *t_inode,
3969 struct buffer_head *t_bh) 3974 struct buffer_head *t_bh,
3975 bool preserve)
3970{ 3976{
3971 int ret; 3977 int ret;
3972 struct buffer_head *ref_root_bh = NULL; 3978 struct buffer_head *ref_root_bh = NULL;
@@ -4001,7 +4007,7 @@ static int ocfs2_create_reflink_node(struct inode *s_inode,
4001 goto out_unlock_refcount; 4007 goto out_unlock_refcount;
4002 } 4008 }
4003 4009
4004 ret = ocfs2_complete_reflink(s_inode, s_bh, t_inode, t_bh); 4010 ret = ocfs2_complete_reflink(s_inode, s_bh, t_inode, t_bh, preserve);
4005 if (ret) 4011 if (ret)
4006 mlog_errno(ret); 4012 mlog_errno(ret);
4007 4013
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index 8d1a0abc105c..fe3419068df2 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -56,6 +56,7 @@
56#include "super.h" 56#include "super.h"
57#include "xattr.h" 57#include "xattr.h"
58#include "refcounttree.h" 58#include "refcounttree.h"
59#include "acl.h"
59 60
60struct ocfs2_xattr_def_value_root { 61struct ocfs2_xattr_def_value_root {
61 struct ocfs2_xattr_value_root xv; 62 struct ocfs2_xattr_value_root xv;
@@ -204,6 +205,8 @@ static int ocfs2_get_xattr_tree_value_root(struct super_block *sb,
204 int offset, 205 int offset,
205 struct ocfs2_xattr_value_root **xv, 206 struct ocfs2_xattr_value_root **xv,
206 struct buffer_head **bh); 207 struct buffer_head **bh);
208static int ocfs2_xattr_security_set(struct inode *inode, const char *name,
209 const void *value, size_t size, int flags);
207 210
208static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb) 211static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb)
209{ 212{
@@ -5994,6 +5997,7 @@ out:
5994 return ret; 5997 return ret;
5995} 5998}
5996 5999
6000typedef int (should_xattr_reflinked)(struct ocfs2_xattr_entry *xe);
5997/* 6001/*
5998 * Store the information we need in xattr reflink. 6002 * Store the information we need in xattr reflink.
5999 * old_bh and new_bh are inode bh for the old and new inode. 6003 * old_bh and new_bh are inode bh for the old and new inode.
@@ -6006,6 +6010,7 @@ struct ocfs2_xattr_reflink {
6006 struct ocfs2_caching_info *ref_ci; 6010 struct ocfs2_caching_info *ref_ci;
6007 struct buffer_head *ref_root_bh; 6011 struct buffer_head *ref_root_bh;
6008 struct ocfs2_cached_dealloc_ctxt *dealloc; 6012 struct ocfs2_cached_dealloc_ctxt *dealloc;
6013 should_xattr_reflinked *xattr_reflinked;
6009}; 6014};
6010 6015
6011/* 6016/*
@@ -6147,6 +6152,9 @@ out:
6147 * NOTE: 6152 * NOTE:
6148 * Before we call this function, the caller has memcpy the xattr in 6153 * Before we call this function, the caller has memcpy the xattr in
6149 * old_xh to the new_xh. 6154 * old_xh to the new_xh.
6155 *
6156 * If args.xattr_reflinked is set, call it to decide whether the xe should
6157 * be reflinked or not. If not, remove it from the new xattr header.
6150 */ 6158 */
6151static int ocfs2_reflink_xattr_header(handle_t *handle, 6159static int ocfs2_reflink_xattr_header(handle_t *handle,
6152 struct ocfs2_xattr_reflink *args, 6160 struct ocfs2_xattr_reflink *args,
@@ -6159,10 +6167,10 @@ static int ocfs2_reflink_xattr_header(handle_t *handle,
6159 get_xattr_value_root *func, 6167 get_xattr_value_root *func,
6160 void *para) 6168 void *para)
6161{ 6169{
6162 int ret = 0, i; 6170 int ret = 0, i, j;
6163 struct super_block *sb = args->old_inode->i_sb; 6171 struct super_block *sb = args->old_inode->i_sb;
6164 struct buffer_head *value_bh; 6172 struct buffer_head *value_bh;
6165 struct ocfs2_xattr_entry *xe; 6173 struct ocfs2_xattr_entry *xe, *last;
6166 struct ocfs2_xattr_value_root *xv, *new_xv; 6174 struct ocfs2_xattr_value_root *xv, *new_xv;
6167 struct ocfs2_extent_tree data_et; 6175 struct ocfs2_extent_tree data_et;
6168 u32 clusters, cpos, p_cluster, num_clusters; 6176 u32 clusters, cpos, p_cluster, num_clusters;
@@ -6170,9 +6178,30 @@ static int ocfs2_reflink_xattr_header(handle_t *handle,
6170 6178
6171 mlog(0, "reflink xattr in container %llu, count = %u\n", 6179 mlog(0, "reflink xattr in container %llu, count = %u\n",
6172 (unsigned long long)old_bh->b_blocknr, le16_to_cpu(xh->xh_count)); 6180 (unsigned long long)old_bh->b_blocknr, le16_to_cpu(xh->xh_count));
6173 for (i = 0; i < le16_to_cpu(xh->xh_count); i++) { 6181
6182 last = &new_xh->xh_entries[le16_to_cpu(new_xh->xh_count)];
6183 for (i = 0, j = 0; i < le16_to_cpu(xh->xh_count); i++, j++) {
6174 xe = &xh->xh_entries[i]; 6184 xe = &xh->xh_entries[i];
6175 6185
6186 if (args->xattr_reflinked && !args->xattr_reflinked(xe)) {
6187 xe = &new_xh->xh_entries[j];
6188
6189 le16_add_cpu(&new_xh->xh_count, -1);
6190 if (new_xh->xh_count) {
6191 memmove(xe, xe + 1,
6192 (void *)last - (void *)xe);
6193 memset(last, 0,
6194 sizeof(struct ocfs2_xattr_entry));
6195 }
6196
6197 /*
6198 * We don't want j to increase in the next round since
6199 * it is already moved ahead.
6200 */
6201 j--;
6202 continue;
6203 }
6204
6176 if (ocfs2_xattr_is_local(xe)) 6205 if (ocfs2_xattr_is_local(xe))
6177 continue; 6206 continue;
6178 6207
@@ -6182,7 +6211,7 @@ static int ocfs2_reflink_xattr_header(handle_t *handle,
6182 break; 6211 break;
6183 } 6212 }
6184 6213
6185 ret = func(sb, new_bh, new_xh, i, &new_xv, &value_bh, para); 6214 ret = func(sb, new_bh, new_xh, j, &new_xv, &value_bh, para);
6186 if (ret) { 6215 if (ret) {
6187 mlog_errno(ret); 6216 mlog_errno(ret);
6188 break; 6217 break;
@@ -6847,10 +6876,20 @@ out:
6847 return ret; 6876 return ret;
6848} 6877}
6849 6878
6879static int ocfs2_reflink_xattr_no_security(struct ocfs2_xattr_entry *xe)
6880{
6881 int type = ocfs2_xattr_get_type(xe);
6882
6883 return type != OCFS2_XATTR_INDEX_SECURITY &&
6884 type != OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS &&
6885 type != OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
6886}
6887
6850int ocfs2_reflink_xattrs(struct inode *old_inode, 6888int ocfs2_reflink_xattrs(struct inode *old_inode,
6851 struct buffer_head *old_bh, 6889 struct buffer_head *old_bh,
6852 struct inode *new_inode, 6890 struct inode *new_inode,
6853 struct buffer_head *new_bh) 6891 struct buffer_head *new_bh,
6892 bool preserve_security)
6854{ 6893{
6855 int ret; 6894 int ret;
6856 struct ocfs2_xattr_reflink args; 6895 struct ocfs2_xattr_reflink args;
@@ -6878,6 +6917,10 @@ int ocfs2_reflink_xattrs(struct inode *old_inode,
6878 args.ref_ci = &ref_tree->rf_ci; 6917 args.ref_ci = &ref_tree->rf_ci;
6879 args.ref_root_bh = ref_root_bh; 6918 args.ref_root_bh = ref_root_bh;
6880 args.dealloc = &dealloc; 6919 args.dealloc = &dealloc;
6920 if (preserve_security)
6921 args.xattr_reflinked = NULL;
6922 else
6923 args.xattr_reflinked = ocfs2_reflink_xattr_no_security;
6881 6924
6882 if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) { 6925 if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
6883 ret = ocfs2_reflink_xattr_inline(&args); 6926 ret = ocfs2_reflink_xattr_inline(&args);
@@ -6918,6 +6961,51 @@ out:
6918} 6961}
6919 6962
6920/* 6963/*
6964 * Initialize security and acl for a already created inode.
6965 * Used for reflink a non-preserve-security file.
6966 *
6967 * It uses common api like ocfs2_xattr_set, so the caller
6968 * must not hold any lock expect i_mutex.
6969 */
6970int ocfs2_init_security_and_acl(struct inode *dir,
6971 struct inode *inode)
6972{
6973 int ret = 0;
6974 struct buffer_head *dir_bh = NULL;
6975 struct ocfs2_security_xattr_info si = {
6976 .enable = 1,
6977 };
6978
6979 ret = ocfs2_init_security_get(inode, dir, &si);
6980 if (!ret) {
6981 ret = ocfs2_xattr_security_set(inode, si.name,
6982 si.value, si.value_len,
6983 XATTR_CREATE);
6984 if (ret) {
6985 mlog_errno(ret);
6986 goto leave;
6987 }
6988 } else if (ret != -EOPNOTSUPP) {
6989 mlog_errno(ret);
6990 goto leave;
6991 }
6992
6993 ret = ocfs2_inode_lock(dir, &dir_bh, 0);
6994 if (ret) {
6995 mlog_errno(ret);
6996 goto leave;
6997 }
6998
6999 ret = ocfs2_init_acl(NULL, inode, dir, NULL, dir_bh, NULL, NULL);
7000 if (ret)
7001 mlog_errno(ret);
7002
7003 ocfs2_inode_unlock(dir, 0);
7004 brelse(dir_bh);
7005leave:
7006 return ret;
7007}
7008/*
6921 * 'security' attributes support 7009 * 'security' attributes support
6922 */ 7010 */
6923static size_t ocfs2_xattr_security_list(struct inode *inode, char *list, 7011static size_t ocfs2_xattr_security_list(struct inode *inode, char *list,
diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h
index 4f913053d5ee..08e36389f56d 100644
--- a/fs/ocfs2/xattr.h
+++ b/fs/ocfs2/xattr.h
@@ -93,5 +93,8 @@ int ocfs2_xattr_attach_refcount_tree(struct inode *inode,
93int ocfs2_reflink_xattrs(struct inode *old_inode, 93int ocfs2_reflink_xattrs(struct inode *old_inode,
94 struct buffer_head *old_bh, 94 struct buffer_head *old_bh,
95 struct inode *new_inode, 95 struct inode *new_inode,
96 struct buffer_head *new_bh); 96 struct buffer_head *new_bh,
97 bool preserve_security);
98int ocfs2_init_security_and_acl(struct inode *dir,
99 struct inode *inode);
97#endif /* OCFS2_XATTR_H */ 100#endif /* OCFS2_XATTR_H */