diff options
author | Tao Ma <tao.ma@oracle.com> | 2009-08-17 23:47:56 -0400 |
---|---|---|
committer | Joel Becker <joel.becker@oracle.com> | 2009-09-22 23:09:49 -0400 |
commit | 0fe9b66c65f3ff227da45381afe7612f91e32740 (patch) | |
tree | 14d95c15065419825adb4f0f0a26a5416a64259e /fs/ocfs2 | |
parent | bc13d347574fc0a8a666bc0f4cc2b635d202e372 (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.c | 38 | ||||
-rw-r--r-- | fs/ocfs2/xattr.c | 98 | ||||
-rw-r--r-- | fs/ocfs2/xattr.h | 5 |
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: | |||
3904 | static int ocfs2_complete_reflink(struct inode *s_inode, | 3904 | static 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: | |||
3966 | static int ocfs2_create_reflink_node(struct inode *s_inode, | 3971 | static 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 | ||
60 | struct ocfs2_xattr_def_value_root { | 61 | struct 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); |
208 | static int ocfs2_xattr_security_set(struct inode *inode, const char *name, | ||
209 | const void *value, size_t size, int flags); | ||
207 | 210 | ||
208 | static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb) | 211 | static 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 | ||
6000 | typedef 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 | */ |
6151 | static int ocfs2_reflink_xattr_header(handle_t *handle, | 6159 | static 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 | ||
6879 | static 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 | |||
6850 | int ocfs2_reflink_xattrs(struct inode *old_inode, | 6888 | int 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 | */ | ||
6970 | int 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); | ||
7005 | leave: | ||
7006 | return ret; | ||
7007 | } | ||
7008 | /* | ||
6921 | * 'security' attributes support | 7009 | * 'security' attributes support |
6922 | */ | 7010 | */ |
6923 | static size_t ocfs2_xattr_security_list(struct inode *inode, char *list, | 7011 | static 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, | |||
93 | int ocfs2_reflink_xattrs(struct inode *old_inode, | 93 | int 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); | ||
98 | int ocfs2_init_security_and_acl(struct inode *dir, | ||
99 | struct inode *inode); | ||
97 | #endif /* OCFS2_XATTR_H */ | 100 | #endif /* OCFS2_XATTR_H */ |