]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Tiger Yang <tiger.yang@oracle.com> |
2 | Date: Fri, 14 Nov 2008 11:16:41 +0800 | |
3 | Subject: ocfs2: add ocfs2_init_security in during file create | |
4 | Patch-mainline: 2.6.29 | |
5 | ||
6 | Security attributes must be set when creating a new inode. | |
7 | ||
8 | We do this in three steps. | |
9 | ||
10 | - First, get security xattr's name and value by security_operation | |
11 | ||
12 | - Calculate and reserve the meta data and clusters needed by this security | |
13 | xattr before starting transaction | |
14 | ||
15 | - Finally, we set it before add_entry | |
16 | ||
17 | Signed-off-by: Tiger Yang <tiger.yang@oracle.com> | |
18 | Signed-off-by: Mark Fasheh <mfasheh@suse.com> | |
19 | --- | |
20 | fs/ocfs2/namei.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++------ | |
21 | fs/ocfs2/xattr.c | 70 +++++++++++++++++++++++++++++++++++ | |
22 | fs/ocfs2/xattr.h | 17 +++++++++ | |
23 | 3 files changed, 182 insertions(+), 12 deletions(-) | |
24 | ||
25 | diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c | |
26 | index e8ff0ba..40da46b 100644 | |
27 | --- a/fs/ocfs2/namei.c | |
28 | +++ b/fs/ocfs2/namei.c | |
29 | @@ -229,6 +229,12 @@ static int ocfs2_mknod(struct inode *dir, | |
30 | struct inode *inode = NULL; | |
31 | struct ocfs2_alloc_context *inode_ac = NULL; | |
32 | struct ocfs2_alloc_context *data_ac = NULL; | |
33 | + struct ocfs2_alloc_context *xattr_ac = NULL; | |
34 | + int want_clusters = 0; | |
35 | + int xattr_credits = 0; | |
36 | + struct ocfs2_security_xattr_info si = { | |
37 | + .enable = 1, | |
38 | + }; | |
39 | ||
40 | mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry, mode, | |
41 | (unsigned long)dev, dentry->d_name.len, | |
42 | @@ -285,17 +291,39 @@ static int ocfs2_mknod(struct inode *dir, | |
43 | goto leave; | |
44 | } | |
45 | ||
46 | - /* Reserve a cluster if creating an extent based directory. */ | |
47 | - if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) { | |
48 | - status = ocfs2_reserve_clusters(osb, 1, &data_ac); | |
49 | + /* get security xattr */ | |
50 | + status = ocfs2_init_security_get(inode, dir, &si); | |
51 | + if (status) { | |
52 | + if (status == -EOPNOTSUPP) | |
53 | + si.enable = 0; | |
54 | + else { | |
55 | + mlog_errno(status); | |
56 | + goto leave; | |
57 | + } | |
58 | + } | |
59 | + | |
60 | + /* calculate meta data/clusters for setting security xattr */ | |
61 | + if (si.enable) { | |
62 | + status = ocfs2_calc_security_init(dir, &si, &want_clusters, | |
63 | + &xattr_credits, &xattr_ac); | |
64 | if (status < 0) { | |
65 | - if (status != -ENOSPC) | |
66 | - mlog_errno(status); | |
67 | + mlog_errno(status); | |
68 | goto leave; | |
69 | } | |
70 | } | |
71 | ||
72 | - handle = ocfs2_start_trans(osb, OCFS2_MKNOD_CREDITS); | |
73 | + /* Reserve a cluster if creating an extent based directory. */ | |
74 | + if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) | |
75 | + want_clusters += 1; | |
76 | + | |
77 | + status = ocfs2_reserve_clusters(osb, want_clusters, &data_ac); | |
78 | + if (status < 0) { | |
79 | + if (status != -ENOSPC) | |
80 | + mlog_errno(status); | |
81 | + goto leave; | |
82 | + } | |
83 | + | |
84 | + handle = ocfs2_start_trans(osb, OCFS2_MKNOD_CREDITS + xattr_credits); | |
85 | if (IS_ERR(handle)) { | |
86 | status = PTR_ERR(handle); | |
87 | handle = NULL; | |
88 | @@ -335,6 +363,15 @@ static int ocfs2_mknod(struct inode *dir, | |
89 | inc_nlink(dir); | |
90 | } | |
91 | ||
92 | + if (si.enable) { | |
93 | + status = ocfs2_init_security_set(handle, inode, new_fe_bh, &si, | |
94 | + xattr_ac, data_ac); | |
95 | + if (status < 0) { | |
96 | + mlog_errno(status); | |
97 | + goto leave; | |
98 | + } | |
99 | + } | |
100 | + | |
101 | status = ocfs2_add_entry(handle, dentry, inode, | |
102 | OCFS2_I(inode)->ip_blkno, parent_fe_bh, | |
103 | de_bh); | |
104 | @@ -366,6 +403,8 @@ leave: | |
105 | brelse(new_fe_bh); | |
106 | brelse(de_bh); | |
107 | brelse(parent_fe_bh); | |
108 | + kfree(si.name); | |
109 | + kfree(si.value); | |
110 | ||
111 | if ((status < 0) && inode) { | |
112 | clear_nlink(inode); | |
113 | @@ -378,6 +417,9 @@ leave: | |
114 | if (data_ac) | |
115 | ocfs2_free_alloc_context(data_ac); | |
116 | ||
117 | + if (xattr_ac) | |
118 | + ocfs2_free_alloc_context(xattr_ac); | |
119 | + | |
120 | mlog_exit(status); | |
121 | ||
122 | return status; | |
123 | @@ -1508,6 +1550,12 @@ static int ocfs2_symlink(struct inode *dir, | |
124 | handle_t *handle = NULL; | |
125 | struct ocfs2_alloc_context *inode_ac = NULL; | |
126 | struct ocfs2_alloc_context *data_ac = NULL; | |
127 | + struct ocfs2_alloc_context *xattr_ac = NULL; | |
128 | + int want_clusters = 0; | |
129 | + int xattr_credits = 0; | |
130 | + struct ocfs2_security_xattr_info si = { | |
131 | + .enable = 1, | |
132 | + }; | |
133 | ||
134 | mlog_entry("(0x%p, 0x%p, symname='%s' actual='%.*s')\n", dir, | |
135 | dentry, symname, dentry->d_name.len, dentry->d_name.name); | |
136 | @@ -1561,17 +1609,39 @@ static int ocfs2_symlink(struct inode *dir, | |
137 | goto bail; | |
138 | } | |
139 | ||
140 | - /* don't reserve bitmap space for fast symlinks. */ | |
141 | - if (l > ocfs2_fast_symlink_chars(sb)) { | |
142 | - status = ocfs2_reserve_clusters(osb, 1, &data_ac); | |
143 | + /* get security xattr */ | |
144 | + status = ocfs2_init_security_get(inode, dir, &si); | |
145 | + if (status) { | |
146 | + if (status == -EOPNOTSUPP) | |
147 | + si.enable = 0; | |
148 | + else { | |
149 | + mlog_errno(status); | |
150 | + goto bail; | |
151 | + } | |
152 | + } | |
153 | + | |
154 | + /* calculate meta data/clusters for setting security xattr */ | |
155 | + if (si.enable) { | |
156 | + status = ocfs2_calc_security_init(dir, &si, &want_clusters, | |
157 | + &xattr_credits, &xattr_ac); | |
158 | if (status < 0) { | |
159 | - if (status != -ENOSPC) | |
160 | - mlog_errno(status); | |
161 | + mlog_errno(status); | |
162 | goto bail; | |
163 | } | |
164 | } | |
165 | ||
166 | - handle = ocfs2_start_trans(osb, credits); | |
167 | + /* don't reserve bitmap space for fast symlinks. */ | |
168 | + if (l > ocfs2_fast_symlink_chars(sb)) | |
169 | + want_clusters += 1; | |
170 | + | |
171 | + status = ocfs2_reserve_clusters(osb, want_clusters, &data_ac); | |
172 | + if (status < 0) { | |
173 | + if (status != -ENOSPC) | |
174 | + mlog_errno(status); | |
175 | + goto bail; | |
176 | + } | |
177 | + | |
178 | + handle = ocfs2_start_trans(osb, credits + xattr_credits); | |
179 | if (IS_ERR(handle)) { | |
180 | status = PTR_ERR(handle); | |
181 | handle = NULL; | |
182 | @@ -1632,6 +1702,15 @@ static int ocfs2_symlink(struct inode *dir, | |
183 | } | |
184 | } | |
185 | ||
186 | + if (si.enable) { | |
187 | + status = ocfs2_init_security_set(handle, inode, new_fe_bh, &si, | |
188 | + xattr_ac, data_ac); | |
189 | + if (status < 0) { | |
190 | + mlog_errno(status); | |
191 | + goto bail; | |
192 | + } | |
193 | + } | |
194 | + | |
195 | status = ocfs2_add_entry(handle, dentry, inode, | |
196 | le64_to_cpu(fe->i_blkno), parent_fe_bh, | |
197 | de_bh); | |
198 | @@ -1658,10 +1737,14 @@ bail: | |
199 | brelse(new_fe_bh); | |
200 | brelse(parent_fe_bh); | |
201 | brelse(de_bh); | |
202 | + kfree(si.name); | |
203 | + kfree(si.value); | |
204 | if (inode_ac) | |
205 | ocfs2_free_alloc_context(inode_ac); | |
206 | if (data_ac) | |
207 | ocfs2_free_alloc_context(data_ac); | |
208 | + if (xattr_ac) | |
209 | + ocfs2_free_alloc_context(xattr_ac); | |
210 | if ((status < 0) && inode) { | |
211 | clear_nlink(inode); | |
212 | iput(inode); | |
213 | diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c | |
214 | index db03162..2cab0d6 100644 | |
215 | --- a/fs/ocfs2/xattr.c | |
216 | +++ b/fs/ocfs2/xattr.c | |
217 | @@ -81,6 +81,9 @@ struct ocfs2_xattr_set_ctxt { | |
218 | ||
219 | #define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) | |
220 | #define OCFS2_XATTR_INLINE_SIZE 80 | |
221 | +#define OCFS2_XATTR_FREE_IN_IBODY (OCFS2_MIN_XATTR_INLINE_SIZE \ | |
222 | + - sizeof(struct ocfs2_xattr_header) \ | |
223 | + - sizeof(__u32)) | |
224 | ||
225 | static struct ocfs2_xattr_def_value_root def_xv = { | |
226 | .xv.xr_list.l_count = cpu_to_le16(1), | |
227 | @@ -343,6 +346,52 @@ static void ocfs2_xattr_hash_entry(struct inode *inode, | |
228 | return; | |
229 | } | |
230 | ||
231 | +static int ocfs2_xattr_entry_real_size(int name_len, size_t value_len) | |
232 | +{ | |
233 | + int size = 0; | |
234 | + | |
235 | + if (value_len <= OCFS2_XATTR_INLINE_SIZE) | |
236 | + size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_SIZE(value_len); | |
237 | + else | |
238 | + size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE; | |
239 | + size += sizeof(struct ocfs2_xattr_entry); | |
240 | + | |
241 | + return size; | |
242 | +} | |
243 | + | |
244 | +int ocfs2_calc_security_init(struct inode *dir, | |
245 | + struct ocfs2_security_xattr_info *si, | |
246 | + int *want_clusters, | |
247 | + int *xattr_credits, | |
248 | + struct ocfs2_alloc_context **xattr_ac) | |
249 | +{ | |
250 | + int ret = 0; | |
251 | + struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); | |
252 | + int s_size = ocfs2_xattr_entry_real_size(strlen(si->name), | |
253 | + si->value_len); | |
254 | + | |
255 | + /* | |
256 | + * The max space of security xattr taken inline is | |
257 | + * 256(name) + 80(value) + 16(entry) = 352 bytes, | |
258 | + * So reserve one metadata block for it is ok. | |
259 | + */ | |
260 | + if (dir->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE || | |
261 | + s_size > OCFS2_XATTR_FREE_IN_IBODY) { | |
262 | + ret = ocfs2_reserve_new_metadata_blocks(osb, 1, xattr_ac); | |
263 | + if (ret) { | |
264 | + mlog_errno(ret); | |
265 | + return ret; | |
266 | + } | |
267 | + *xattr_credits += OCFS2_XATTR_BLOCK_CREATE_CREDITS; | |
268 | + } | |
269 | + | |
270 | + /* reserve clusters for xattr value which will be set in B tree*/ | |
271 | + if (si->value_len > OCFS2_XATTR_INLINE_SIZE) | |
272 | + *want_clusters += ocfs2_clusters_for_bytes(dir->i_sb, | |
273 | + si->value_len); | |
274 | + return ret; | |
275 | +} | |
276 | + | |
277 | static int ocfs2_xattr_extend_allocation(struct inode *inode, | |
278 | u32 clusters_to_add, | |
279 | struct buffer_head *xattr_bh, | |
280 | @@ -5016,6 +5065,27 @@ static int ocfs2_xattr_security_set(struct inode *inode, const char *name, | |
281 | size, flags); | |
282 | } | |
283 | ||
284 | +int ocfs2_init_security_get(struct inode *inode, | |
285 | + struct inode *dir, | |
286 | + struct ocfs2_security_xattr_info *si) | |
287 | +{ | |
288 | + return security_inode_init_security(inode, dir, &si->name, &si->value, | |
289 | + &si->value_len); | |
290 | +} | |
291 | + | |
292 | +int ocfs2_init_security_set(handle_t *handle, | |
293 | + struct inode *inode, | |
294 | + struct buffer_head *di_bh, | |
295 | + struct ocfs2_security_xattr_info *si, | |
296 | + struct ocfs2_alloc_context *xattr_ac, | |
297 | + struct ocfs2_alloc_context *data_ac) | |
298 | +{ | |
299 | + return ocfs2_xattr_set_handle(handle, inode, di_bh, | |
300 | + OCFS2_XATTR_INDEX_SECURITY, | |
301 | + si->name, si->value, si->value_len, 0, | |
302 | + xattr_ac, data_ac); | |
303 | +} | |
304 | + | |
305 | struct xattr_handler ocfs2_xattr_security_handler = { | |
306 | .prefix = XATTR_SECURITY_PREFIX, | |
307 | .list = ocfs2_xattr_security_list, | |
308 | diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h | |
309 | index 55c5256..188ef6b 100644 | |
310 | --- a/fs/ocfs2/xattr.h | |
311 | +++ b/fs/ocfs2/xattr.h | |
312 | @@ -30,6 +30,13 @@ enum ocfs2_xattr_type { | |
313 | OCFS2_XATTR_MAX | |
314 | }; | |
315 | ||
316 | +struct ocfs2_security_xattr_info { | |
317 | + int enable; | |
318 | + char *name; | |
319 | + void *value; | |
320 | + size_t value_len; | |
321 | +}; | |
322 | + | |
323 | extern struct xattr_handler ocfs2_xattr_user_handler; | |
324 | extern struct xattr_handler ocfs2_xattr_trusted_handler; | |
325 | extern struct xattr_handler ocfs2_xattr_security_handler; | |
326 | @@ -43,5 +50,15 @@ int ocfs2_xattr_set_handle(handle_t *, struct inode *, struct buffer_head *, | |
327 | struct ocfs2_alloc_context *, | |
328 | struct ocfs2_alloc_context *); | |
329 | int ocfs2_xattr_remove(struct inode *, struct buffer_head *); | |
330 | +int ocfs2_init_security_get(struct inode *, struct inode *, | |
331 | + struct ocfs2_security_xattr_info *); | |
332 | +int ocfs2_init_security_set(handle_t *, struct inode *, | |
333 | + struct buffer_head *, | |
334 | + struct ocfs2_security_xattr_info *, | |
335 | + struct ocfs2_alloc_context *, | |
336 | + struct ocfs2_alloc_context *); | |
337 | +int ocfs2_calc_security_init(struct inode *, | |
338 | + struct ocfs2_security_xattr_info *, | |
339 | + int *, int *, struct ocfs2_alloc_context **); | |
340 | ||
341 | #endif /* OCFS2_XATTR_H */ | |
342 | -- | |
343 | 1.5.6 | |
344 |