]>
Commit | Line | Data |
---|---|---|
7336d0e6 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
b3b94faa DT |
2 | /* |
3 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | |
3a8a9a10 | 4 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
b3b94faa DT |
5 | */ |
6 | ||
b3b94faa DT |
7 | #include <linux/slab.h> |
8 | #include <linux/spinlock.h> | |
9 | #include <linux/completion.h> | |
10 | #include <linux/buffer_head.h> | |
11 | #include <linux/xattr.h> | |
5c676f6d | 12 | #include <linux/gfs2_ondisk.h> |
e01580bf | 13 | #include <linux/posix_acl_xattr.h> |
7c0f6ba6 | 14 | #include <linux/uaccess.h> |
b3b94faa DT |
15 | |
16 | #include "gfs2.h" | |
5c676f6d | 17 | #include "incore.h" |
b3b94faa | 18 | #include "acl.h" |
307cf6e6 | 19 | #include "xattr.h" |
b3b94faa DT |
20 | #include "glock.h" |
21 | #include "inode.h" | |
22 | #include "meta_io.h" | |
23 | #include "quota.h" | |
24 | #include "rgrp.h" | |
27c3b415 | 25 | #include "super.h" |
b3b94faa | 26 | #include "trans.h" |
5c676f6d | 27 | #include "util.h" |
b3b94faa DT |
28 | |
29 | /** | |
30 | * ea_calc_size - returns the acutal number of bytes the request will take up | |
31 | * (not counting any unstuffed data blocks) | |
32 | * @sdp: | |
33 | * @er: | |
34 | * @size: | |
35 | * | |
36 | * Returns: 1 if the EA should be stuffed | |
37 | */ | |
38 | ||
40b78a32 | 39 | static int ea_calc_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize, |
b3b94faa DT |
40 | unsigned int *size) |
41 | { | |
40b78a32 SW |
42 | unsigned int jbsize = sdp->sd_jbsize; |
43 | ||
44 | /* Stuffed */ | |
45 | *size = ALIGN(sizeof(struct gfs2_ea_header) + nsize + dsize, 8); | |
46 | ||
47 | if (*size <= jbsize) | |
b3b94faa DT |
48 | return 1; |
49 | ||
40b78a32 SW |
50 | /* Unstuffed */ |
51 | *size = ALIGN(sizeof(struct gfs2_ea_header) + nsize + | |
52 | (sizeof(__be64) * DIV_ROUND_UP(dsize, jbsize)), 8); | |
b3b94faa DT |
53 | |
54 | return 0; | |
55 | } | |
56 | ||
40b78a32 | 57 | static int ea_check_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize) |
b3b94faa DT |
58 | { |
59 | unsigned int size; | |
60 | ||
40b78a32 | 61 | if (dsize > GFS2_EA_MAX_DATA_LEN) |
b3b94faa DT |
62 | return -ERANGE; |
63 | ||
40b78a32 | 64 | ea_calc_size(sdp, nsize, dsize, &size); |
b3b94faa DT |
65 | |
66 | /* This can only happen with 512 byte blocks */ | |
67 | if (size > sdp->sd_jbsize) | |
68 | return -ERANGE; | |
69 | ||
70 | return 0; | |
71 | } | |
72 | ||
cca195c5 | 73 | typedef int (*ea_call_t) (struct gfs2_inode *ip, struct buffer_head *bh, |
b3b94faa | 74 | struct gfs2_ea_header *ea, |
cca195c5 | 75 | struct gfs2_ea_header *prev, void *private); |
b3b94faa DT |
76 | |
77 | static int ea_foreach_i(struct gfs2_inode *ip, struct buffer_head *bh, | |
78 | ea_call_t ea_call, void *data) | |
79 | { | |
80 | struct gfs2_ea_header *ea, *prev = NULL; | |
81 | int error = 0; | |
82 | ||
feaa7bba | 83 | if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_EA)) |
b3b94faa DT |
84 | return -EIO; |
85 | ||
86 | for (ea = GFS2_EA_BH2FIRST(bh);; prev = ea, ea = GFS2_EA2NEXT(ea)) { | |
87 | if (!GFS2_EA_REC_LEN(ea)) | |
88 | goto fail; | |
cca195c5 SW |
89 | if (!(bh->b_data <= (char *)ea && (char *)GFS2_EA2NEXT(ea) <= |
90 | bh->b_data + bh->b_size)) | |
b3b94faa DT |
91 | goto fail; |
92 | if (!GFS2_EATYPE_VALID(ea->ea_type)) | |
93 | goto fail; | |
94 | ||
95 | error = ea_call(ip, bh, ea, prev, data); | |
96 | if (error) | |
97 | return error; | |
98 | ||
99 | if (GFS2_EA_IS_LAST(ea)) { | |
100 | if ((char *)GFS2_EA2NEXT(ea) != | |
101 | bh->b_data + bh->b_size) | |
102 | goto fail; | |
103 | break; | |
104 | } | |
105 | } | |
106 | ||
107 | return error; | |
108 | ||
a91ea69f | 109 | fail: |
b3b94faa DT |
110 | gfs2_consist_inode(ip); |
111 | return -EIO; | |
112 | } | |
113 | ||
114 | static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) | |
115 | { | |
116 | struct buffer_head *bh, *eabh; | |
b44b84d7 | 117 | __be64 *eablk, *end; |
b3b94faa DT |
118 | int error; |
119 | ||
c8d57703 | 120 | error = gfs2_meta_read(ip->i_gl, ip->i_eattr, DIO_WAIT, 0, &bh); |
b3b94faa DT |
121 | if (error) |
122 | return error; | |
123 | ||
383f01fb | 124 | if (!(ip->i_diskflags & GFS2_DIF_EA_INDIRECT)) { |
b3b94faa DT |
125 | error = ea_foreach_i(ip, bh, ea_call, data); |
126 | goto out; | |
127 | } | |
128 | ||
feaa7bba | 129 | if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_IN)) { |
b3b94faa DT |
130 | error = -EIO; |
131 | goto out; | |
132 | } | |
133 | ||
b44b84d7 | 134 | eablk = (__be64 *)(bh->b_data + sizeof(struct gfs2_meta_header)); |
feaa7bba | 135 | end = eablk + GFS2_SB(&ip->i_inode)->sd_inptrs; |
b3b94faa DT |
136 | |
137 | for (; eablk < end; eablk++) { | |
cd915493 | 138 | u64 bn; |
b3b94faa DT |
139 | |
140 | if (!*eablk) | |
141 | break; | |
142 | bn = be64_to_cpu(*eablk); | |
143 | ||
c8d57703 | 144 | error = gfs2_meta_read(ip->i_gl, bn, DIO_WAIT, 0, &eabh); |
b3b94faa DT |
145 | if (error) |
146 | break; | |
147 | error = ea_foreach_i(ip, eabh, ea_call, data); | |
148 | brelse(eabh); | |
149 | if (error) | |
150 | break; | |
151 | } | |
a91ea69f | 152 | out: |
b3b94faa | 153 | brelse(bh); |
b3b94faa DT |
154 | return error; |
155 | } | |
156 | ||
157 | struct ea_find { | |
40b78a32 SW |
158 | int type; |
159 | const char *name; | |
160 | size_t namel; | |
b3b94faa DT |
161 | struct gfs2_ea_location *ef_el; |
162 | }; | |
163 | ||
164 | static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh, | |
165 | struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, | |
166 | void *private) | |
167 | { | |
168 | struct ea_find *ef = private; | |
b3b94faa DT |
169 | |
170 | if (ea->ea_type == GFS2_EATYPE_UNUSED) | |
171 | return 0; | |
172 | ||
40b78a32 SW |
173 | if (ea->ea_type == ef->type) { |
174 | if (ea->ea_name_len == ef->namel && | |
175 | !memcmp(GFS2_EA2NAME(ea), ef->name, ea->ea_name_len)) { | |
b3b94faa DT |
176 | struct gfs2_ea_location *el = ef->ef_el; |
177 | get_bh(bh); | |
178 | el->el_bh = bh; | |
179 | el->el_ea = ea; | |
180 | el->el_prev = prev; | |
181 | return 1; | |
182 | } | |
183 | } | |
184 | ||
b3b94faa DT |
185 | return 0; |
186 | } | |
187 | ||
479c427d SW |
188 | static int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, |
189 | struct gfs2_ea_location *el) | |
b3b94faa DT |
190 | { |
191 | struct ea_find ef; | |
192 | int error; | |
193 | ||
40b78a32 SW |
194 | ef.type = type; |
195 | ef.name = name; | |
196 | ef.namel = strlen(name); | |
b3b94faa DT |
197 | ef.ef_el = el; |
198 | ||
199 | memset(el, 0, sizeof(struct gfs2_ea_location)); | |
200 | ||
201 | error = ea_foreach(ip, ea_find_i, &ef); | |
202 | if (error > 0) | |
203 | return 0; | |
204 | ||
205 | return error; | |
206 | } | |
207 | ||
208 | /** | |
209 | * ea_dealloc_unstuffed - | |
210 | * @ip: | |
211 | * @bh: | |
212 | * @ea: | |
213 | * @prev: | |
214 | * @private: | |
215 | * | |
216 | * Take advantage of the fact that all unstuffed blocks are | |
217 | * allocated from the same RG. But watch, this may not always | |
218 | * be true. | |
219 | * | |
220 | * Returns: errno | |
221 | */ | |
222 | ||
223 | static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, | |
224 | struct gfs2_ea_header *ea, | |
225 | struct gfs2_ea_header *prev, void *private) | |
226 | { | |
227 | int *leave = private; | |
feaa7bba | 228 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
b3b94faa DT |
229 | struct gfs2_rgrpd *rgd; |
230 | struct gfs2_holder rg_gh; | |
b44b84d7 AV |
231 | __be64 *dataptrs; |
232 | u64 bn = 0; | |
cd915493 | 233 | u64 bstart = 0; |
b3b94faa DT |
234 | unsigned int blen = 0; |
235 | unsigned int blks = 0; | |
236 | unsigned int x; | |
237 | int error; | |
238 | ||
5e2f7d61 BP |
239 | error = gfs2_rindex_update(sdp); |
240 | if (error) | |
241 | return error; | |
242 | ||
b3b94faa DT |
243 | if (GFS2_EA_IS_STUFFED(ea)) |
244 | return 0; | |
245 | ||
246 | dataptrs = GFS2_EA2DATAPTRS(ea); | |
cca195c5 | 247 | for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) { |
b3b94faa DT |
248 | if (*dataptrs) { |
249 | blks++; | |
250 | bn = be64_to_cpu(*dataptrs); | |
251 | } | |
cca195c5 | 252 | } |
b3b94faa DT |
253 | if (!blks) |
254 | return 0; | |
255 | ||
66fc061b | 256 | rgd = gfs2_blk2rgrpd(sdp, bn, 1); |
b3b94faa DT |
257 | if (!rgd) { |
258 | gfs2_consist_inode(ip); | |
259 | return -EIO; | |
260 | } | |
261 | ||
262 | error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh); | |
263 | if (error) | |
264 | return error; | |
265 | ||
bb8d8a6f | 266 | error = gfs2_trans_begin(sdp, rgd->rd_length + RES_DINODE + |
cca195c5 | 267 | RES_EATTR + RES_STATFS + RES_QUOTA, blks); |
b3b94faa DT |
268 | if (error) |
269 | goto out_gunlock; | |
270 | ||
350a9b0a | 271 | gfs2_trans_add_meta(ip->i_gl, bh); |
b3b94faa DT |
272 | |
273 | dataptrs = GFS2_EA2DATAPTRS(ea); | |
274 | for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) { | |
275 | if (!*dataptrs) | |
276 | break; | |
277 | bn = be64_to_cpu(*dataptrs); | |
278 | ||
279 | if (bstart + blen == bn) | |
280 | blen++; | |
281 | else { | |
282 | if (bstart) | |
0ddeded4 | 283 | gfs2_free_meta(ip, rgd, bstart, blen); |
b3b94faa DT |
284 | bstart = bn; |
285 | blen = 1; | |
286 | } | |
287 | ||
288 | *dataptrs = 0; | |
77658aad | 289 | gfs2_add_inode_blocks(&ip->i_inode, -1); |
b3b94faa DT |
290 | } |
291 | if (bstart) | |
0ddeded4 | 292 | gfs2_free_meta(ip, rgd, bstart, blen); |
b3b94faa DT |
293 | |
294 | if (prev && !leave) { | |
cd915493 | 295 | u32 len; |
b3b94faa DT |
296 | |
297 | len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea); | |
298 | prev->ea_rec_len = cpu_to_be32(len); | |
299 | ||
300 | if (GFS2_EA_IS_LAST(ea)) | |
301 | prev->ea_flags |= GFS2_EAFLAG_LAST; | |
302 | } else { | |
303 | ea->ea_type = GFS2_EATYPE_UNUSED; | |
304 | ea->ea_num_ptrs = 0; | |
305 | } | |
306 | ||
6862c44e | 307 | ip->i_inode.i_ctime = current_time(&ip->i_inode); |
937d3305 | 308 | __mark_inode_dirty(&ip->i_inode, I_DIRTY_DATASYNC); |
b3b94faa DT |
309 | |
310 | gfs2_trans_end(sdp); | |
311 | ||
a91ea69f | 312 | out_gunlock: |
b3b94faa | 313 | gfs2_glock_dq_uninit(&rg_gh); |
b3b94faa DT |
314 | return error; |
315 | } | |
316 | ||
317 | static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, | |
318 | struct gfs2_ea_header *ea, | |
319 | struct gfs2_ea_header *prev, int leave) | |
320 | { | |
b3b94faa DT |
321 | int error; |
322 | ||
8e2e0047 BP |
323 | error = gfs2_rindex_update(GFS2_SB(&ip->i_inode)); |
324 | if (error) | |
325 | return error; | |
326 | ||
f4108a60 | 327 | error = gfs2_quota_hold(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE); |
b3b94faa DT |
328 | if (error) |
329 | goto out_alloc; | |
330 | ||
cca195c5 | 331 | error = ea_dealloc_unstuffed(ip, bh, ea, prev, (leave) ? &error : NULL); |
b3b94faa | 332 | |
b3b94faa | 333 | gfs2_quota_unhold(ip); |
a91ea69f | 334 | out_alloc: |
b3b94faa DT |
335 | return error; |
336 | } | |
337 | ||
b3b94faa DT |
338 | struct ea_list { |
339 | struct gfs2_ea_request *ei_er; | |
340 | unsigned int ei_size; | |
341 | }; | |
342 | ||
343 | static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, | |
344 | struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, | |
345 | void *private) | |
346 | { | |
347 | struct ea_list *ei = private; | |
348 | struct gfs2_ea_request *er = ei->ei_er; | |
21e2156f AG |
349 | unsigned int ea_size; |
350 | char *prefix; | |
351 | unsigned int l; | |
b3b94faa DT |
352 | |
353 | if (ea->ea_type == GFS2_EATYPE_UNUSED) | |
354 | return 0; | |
355 | ||
21e2156f AG |
356 | switch (ea->ea_type) { |
357 | case GFS2_EATYPE_USR: | |
358 | prefix = "user."; | |
359 | l = 5; | |
360 | break; | |
361 | case GFS2_EATYPE_SYS: | |
362 | prefix = "system."; | |
363 | l = 7; | |
364 | break; | |
365 | case GFS2_EATYPE_SECURITY: | |
366 | prefix = "security."; | |
367 | l = 9; | |
368 | break; | |
369 | default: | |
370 | BUG(); | |
371 | } | |
b3b94faa | 372 | |
21e2156f AG |
373 | ea_size = l + ea->ea_name_len + 1; |
374 | if (er->er_data_len) { | |
b3b94faa DT |
375 | if (ei->ei_size + ea_size > er->er_data_len) |
376 | return -ERANGE; | |
377 | ||
90cdd208 SW |
378 | memcpy(er->er_data + ei->ei_size, prefix, l); |
379 | memcpy(er->er_data + ei->ei_size + l, GFS2_EA2NAME(ea), | |
b3b94faa | 380 | ea->ea_name_len); |
21e2156f | 381 | er->er_data[ei->ei_size + ea_size - 1] = 0; |
b3b94faa DT |
382 | } |
383 | ||
384 | ei->ei_size += ea_size; | |
385 | ||
386 | return 0; | |
387 | } | |
388 | ||
389 | /** | |
40b78a32 SW |
390 | * gfs2_listxattr - List gfs2 extended attributes |
391 | * @dentry: The dentry whose inode we are interested in | |
392 | * @buffer: The buffer to write the results | |
393 | * @size: The size of the buffer | |
b3b94faa DT |
394 | * |
395 | * Returns: actual size of data on success, -errno on error | |
396 | */ | |
397 | ||
40b78a32 | 398 | ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) |
b3b94faa | 399 | { |
2b0143b5 | 400 | struct gfs2_inode *ip = GFS2_I(d_inode(dentry)); |
40b78a32 | 401 | struct gfs2_ea_request er; |
b3b94faa DT |
402 | struct gfs2_holder i_gh; |
403 | int error; | |
404 | ||
40b78a32 SW |
405 | memset(&er, 0, sizeof(struct gfs2_ea_request)); |
406 | if (size) { | |
407 | er.er_data = buffer; | |
408 | er.er_data_len = size; | |
b3b94faa DT |
409 | } |
410 | ||
cca195c5 | 411 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); |
b3b94faa DT |
412 | if (error) |
413 | return error; | |
414 | ||
3767ac21 | 415 | if (ip->i_eattr) { |
40b78a32 | 416 | struct ea_list ei = { .ei_er = &er, .ei_size = 0 }; |
b3b94faa DT |
417 | |
418 | error = ea_foreach(ip, ea_list_i, &ei); | |
419 | if (!error) | |
420 | error = ei.ei_size; | |
421 | } | |
422 | ||
423 | gfs2_glock_dq_uninit(&i_gh); | |
424 | ||
425 | return error; | |
426 | } | |
427 | ||
428 | /** | |
1f981697 SW |
429 | * ea_iter_unstuffed - copies the unstuffed xattr data to/from the |
430 | * request buffer | |
cca195c5 SW |
431 | * @ip: The GFS2 inode |
432 | * @ea: The extended attribute header structure | |
1f981697 SW |
433 | * @din: The data to be copied in |
434 | * @dout: The data to be copied out (one of din,dout will be NULL) | |
b3b94faa DT |
435 | * |
436 | * Returns: errno | |
437 | */ | |
438 | ||
1f981697 SW |
439 | static int gfs2_iter_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, |
440 | const char *din, char *dout) | |
b3b94faa | 441 | { |
feaa7bba | 442 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
b3b94faa DT |
443 | struct buffer_head **bh; |
444 | unsigned int amount = GFS2_EA_DATA_LEN(ea); | |
5c676f6d | 445 | unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize); |
b44b84d7 | 446 | __be64 *dataptrs = GFS2_EA2DATAPTRS(ea); |
b3b94faa DT |
447 | unsigned int x; |
448 | int error = 0; | |
1f981697 SW |
449 | unsigned char *pos; |
450 | unsigned cp_size; | |
b3b94faa | 451 | |
16c5f06f | 452 | bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_NOFS); |
b3b94faa DT |
453 | if (!bh) |
454 | return -ENOMEM; | |
455 | ||
456 | for (x = 0; x < nptrs; x++) { | |
c8d57703 | 457 | error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0, 0, |
7276b3b0 | 458 | bh + x); |
b3b94faa DT |
459 | if (error) { |
460 | while (x--) | |
461 | brelse(bh[x]); | |
462 | goto out; | |
463 | } | |
464 | dataptrs++; | |
465 | } | |
466 | ||
467 | for (x = 0; x < nptrs; x++) { | |
7276b3b0 | 468 | error = gfs2_meta_wait(sdp, bh[x]); |
b3b94faa DT |
469 | if (error) { |
470 | for (; x < nptrs; x++) | |
471 | brelse(bh[x]); | |
472 | goto out; | |
473 | } | |
474 | if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) { | |
475 | for (; x < nptrs; x++) | |
476 | brelse(bh[x]); | |
477 | error = -EIO; | |
478 | goto out; | |
479 | } | |
480 | ||
1f981697 SW |
481 | pos = bh[x]->b_data + sizeof(struct gfs2_meta_header); |
482 | cp_size = (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize; | |
b3b94faa | 483 | |
1f981697 SW |
484 | if (dout) { |
485 | memcpy(dout, pos, cp_size); | |
486 | dout += sdp->sd_jbsize; | |
487 | } | |
488 | ||
489 | if (din) { | |
350a9b0a | 490 | gfs2_trans_add_meta(ip->i_gl, bh[x]); |
1f981697 SW |
491 | memcpy(pos, din, cp_size); |
492 | din += sdp->sd_jbsize; | |
493 | } | |
b3b94faa | 494 | |
1f981697 | 495 | amount -= sdp->sd_jbsize; |
b3b94faa DT |
496 | brelse(bh[x]); |
497 | } | |
498 | ||
a91ea69f | 499 | out: |
b3b94faa | 500 | kfree(bh); |
b3b94faa DT |
501 | return error; |
502 | } | |
503 | ||
479c427d SW |
504 | static int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, |
505 | char *data, size_t size) | |
b3b94faa | 506 | { |
40b78a32 SW |
507 | int ret; |
508 | size_t len = GFS2_EA_DATA_LEN(el->el_ea); | |
509 | if (len > size) | |
510 | return -ERANGE; | |
511 | ||
b3b94faa | 512 | if (GFS2_EA_IS_STUFFED(el->el_ea)) { |
40b78a32 SW |
513 | memcpy(data, GFS2_EA2DATA(el->el_ea), len); |
514 | return len; | |
515 | } | |
1f981697 | 516 | ret = gfs2_iter_unstuffed(ip, el->el_ea, NULL, data); |
40b78a32 SW |
517 | if (ret < 0) |
518 | return ret; | |
519 | return len; | |
b3b94faa DT |
520 | } |
521 | ||
479c427d SW |
522 | int gfs2_xattr_acl_get(struct gfs2_inode *ip, const char *name, char **ppdata) |
523 | { | |
524 | struct gfs2_ea_location el; | |
525 | int error; | |
526 | int len; | |
527 | char *data; | |
528 | ||
529 | error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, name, &el); | |
530 | if (error) | |
531 | return error; | |
532 | if (!el.el_ea) | |
533 | goto out; | |
534 | if (!GFS2_EA_DATA_LEN(el.el_ea)) | |
535 | goto out; | |
536 | ||
537 | len = GFS2_EA_DATA_LEN(el.el_ea); | |
538 | data = kmalloc(len, GFP_NOFS); | |
539 | error = -ENOMEM; | |
540 | if (data == NULL) | |
541 | goto out; | |
542 | ||
543 | error = gfs2_ea_get_copy(ip, &el, data, len); | |
114b80ce SW |
544 | if (error < 0) |
545 | kfree(data); | |
546 | else | |
547 | *ppdata = data; | |
479c427d SW |
548 | out: |
549 | brelse(el.el_bh); | |
550 | return error; | |
551 | } | |
552 | ||
b3b94faa | 553 | /** |
40b78a32 SW |
554 | * gfs2_xattr_get - Get a GFS2 extended attribute |
555 | * @inode: The inode | |
40b78a32 SW |
556 | * @name: The name of the extended attribute |
557 | * @buffer: The buffer to write the result into | |
558 | * @size: The size of the buffer | |
431547b3 | 559 | * @type: The type of extended attribute |
b3b94faa DT |
560 | * |
561 | * Returns: actual size of data on success, -errno on error | |
562 | */ | |
1a39ba99 AV |
563 | static int __gfs2_xattr_get(struct inode *inode, const char *name, |
564 | void *buffer, size_t size, int type) | |
b3b94faa | 565 | { |
b296821a | 566 | struct gfs2_inode *ip = GFS2_I(inode); |
b3b94faa DT |
567 | struct gfs2_ea_location el; |
568 | int error; | |
569 | ||
3767ac21 | 570 | if (!ip->i_eattr) |
b3b94faa | 571 | return -ENODATA; |
40b78a32 SW |
572 | if (strlen(name) > GFS2_EA_MAX_NAME_LEN) |
573 | return -EINVAL; | |
b3b94faa | 574 | |
40b78a32 | 575 | error = gfs2_ea_find(ip, type, name, &el); |
b3b94faa DT |
576 | if (error) |
577 | return error; | |
578 | if (!el.el_ea) | |
579 | return -ENODATA; | |
86d00636 | 580 | if (size) |
40b78a32 SW |
581 | error = gfs2_ea_get_copy(ip, &el, buffer, size); |
582 | else | |
b3b94faa | 583 | error = GFS2_EA_DATA_LEN(el.el_ea); |
b3b94faa DT |
584 | brelse(el.el_bh); |
585 | ||
586 | return error; | |
587 | } | |
588 | ||
1a39ba99 AV |
589 | static int gfs2_xattr_get(const struct xattr_handler *handler, |
590 | struct dentry *unused, struct inode *inode, | |
591 | const char *name, void *buffer, size_t size) | |
592 | { | |
593 | struct gfs2_inode *ip = GFS2_I(inode); | |
594 | struct gfs2_holder gh; | |
1a39ba99 AV |
595 | int ret; |
596 | ||
597 | /* During lookup, SELinux calls this function with the glock locked. */ | |
598 | ||
599 | if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { | |
600 | ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); | |
601 | if (ret) | |
602 | return ret; | |
d0920a9c AG |
603 | } else { |
604 | gfs2_holder_mark_uninitialized(&gh); | |
1a39ba99 AV |
605 | } |
606 | ret = __gfs2_xattr_get(inode, name, buffer, size, handler->flags); | |
d0920a9c | 607 | if (gfs2_holder_initialized(&gh)) |
1a39ba99 AV |
608 | gfs2_glock_dq_uninit(&gh); |
609 | return ret; | |
610 | } | |
611 | ||
b3b94faa DT |
612 | /** |
613 | * ea_alloc_blk - allocates a new block for extended attributes. | |
614 | * @ip: A pointer to the inode that's getting extended attributes | |
cca195c5 | 615 | * @bhp: Pointer to pointer to a struct buffer_head |
b3b94faa DT |
616 | * |
617 | * Returns: errno | |
618 | */ | |
619 | ||
620 | static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) | |
621 | { | |
feaa7bba | 622 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
b3b94faa | 623 | struct gfs2_ea_header *ea; |
b45e41d7 | 624 | unsigned int n = 1; |
cd915493 | 625 | u64 block; |
09010978 | 626 | int error; |
b3b94faa | 627 | |
6e87ed0f | 628 | error = gfs2_alloc_blocks(ip, &block, &n, 0, NULL); |
09010978 SW |
629 | if (error) |
630 | return error; | |
fbb27873 | 631 | gfs2_trans_remove_revoke(sdp, block, 1); |
b3b94faa | 632 | *bhp = gfs2_meta_new(ip->i_gl, block); |
350a9b0a | 633 | gfs2_trans_add_meta(ip->i_gl, *bhp); |
b3b94faa DT |
634 | gfs2_metatype_set(*bhp, GFS2_METATYPE_EA, GFS2_FORMAT_EA); |
635 | gfs2_buffer_clear_tail(*bhp, sizeof(struct gfs2_meta_header)); | |
636 | ||
637 | ea = GFS2_EA_BH2FIRST(*bhp); | |
638 | ea->ea_rec_len = cpu_to_be32(sdp->sd_jbsize); | |
639 | ea->ea_type = GFS2_EATYPE_UNUSED; | |
640 | ea->ea_flags = GFS2_EAFLAG_LAST; | |
641 | ea->ea_num_ptrs = 0; | |
642 | ||
77658aad | 643 | gfs2_add_inode_blocks(&ip->i_inode, 1); |
b3b94faa DT |
644 | |
645 | return 0; | |
646 | } | |
647 | ||
648 | /** | |
649 | * ea_write - writes the request info to an ea, creating new blocks if | |
650 | * necessary | |
cca195c5 SW |
651 | * @ip: inode that is being modified |
652 | * @ea: the location of the new ea in a block | |
b3b94faa DT |
653 | * @er: the write request |
654 | * | |
655 | * Note: does not update ea_rec_len or the GFS2_EAFLAG_LAST bin of ea_flags | |
656 | * | |
657 | * returns : errno | |
658 | */ | |
659 | ||
660 | static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, | |
661 | struct gfs2_ea_request *er) | |
662 | { | |
feaa7bba | 663 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
09010978 | 664 | int error; |
b3b94faa DT |
665 | |
666 | ea->ea_data_len = cpu_to_be32(er->er_data_len); | |
667 | ea->ea_name_len = er->er_name_len; | |
668 | ea->ea_type = er->er_type; | |
669 | ea->__pad = 0; | |
670 | ||
671 | memcpy(GFS2_EA2NAME(ea), er->er_name, er->er_name_len); | |
672 | ||
673 | if (GFS2_EAREQ_SIZE_STUFFED(er) <= sdp->sd_jbsize) { | |
674 | ea->ea_num_ptrs = 0; | |
675 | memcpy(GFS2_EA2DATA(ea), er->er_data, er->er_data_len); | |
676 | } else { | |
b44b84d7 | 677 | __be64 *dataptr = GFS2_EA2DATAPTRS(ea); |
b3b94faa DT |
678 | const char *data = er->er_data; |
679 | unsigned int data_len = er->er_data_len; | |
680 | unsigned int copy; | |
681 | unsigned int x; | |
682 | ||
5c676f6d | 683 | ea->ea_num_ptrs = DIV_ROUND_UP(er->er_data_len, sdp->sd_jbsize); |
b3b94faa DT |
684 | for (x = 0; x < ea->ea_num_ptrs; x++) { |
685 | struct buffer_head *bh; | |
cd915493 | 686 | u64 block; |
b3b94faa | 687 | int mh_size = sizeof(struct gfs2_meta_header); |
b45e41d7 | 688 | unsigned int n = 1; |
b3b94faa | 689 | |
6e87ed0f | 690 | error = gfs2_alloc_blocks(ip, &block, &n, 0, NULL); |
09010978 SW |
691 | if (error) |
692 | return error; | |
fbb27873 | 693 | gfs2_trans_remove_revoke(sdp, block, 1); |
b3b94faa | 694 | bh = gfs2_meta_new(ip->i_gl, block); |
350a9b0a | 695 | gfs2_trans_add_meta(ip->i_gl, bh); |
b3b94faa DT |
696 | gfs2_metatype_set(bh, GFS2_METATYPE_ED, GFS2_FORMAT_ED); |
697 | ||
77658aad | 698 | gfs2_add_inode_blocks(&ip->i_inode, 1); |
b3b94faa | 699 | |
cca195c5 SW |
700 | copy = data_len > sdp->sd_jbsize ? sdp->sd_jbsize : |
701 | data_len; | |
b3b94faa DT |
702 | memcpy(bh->b_data + mh_size, data, copy); |
703 | if (copy < sdp->sd_jbsize) | |
704 | memset(bh->b_data + mh_size + copy, 0, | |
705 | sdp->sd_jbsize - copy); | |
706 | ||
cca195c5 | 707 | *dataptr++ = cpu_to_be64(bh->b_blocknr); |
b3b94faa DT |
708 | data += copy; |
709 | data_len -= copy; | |
710 | ||
711 | brelse(bh); | |
712 | } | |
713 | ||
714 | gfs2_assert_withdraw(sdp, !data_len); | |
715 | } | |
716 | ||
717 | return 0; | |
718 | } | |
719 | ||
720 | typedef int (*ea_skeleton_call_t) (struct gfs2_inode *ip, | |
cca195c5 | 721 | struct gfs2_ea_request *er, void *private); |
b3b94faa DT |
722 | |
723 | static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |
724 | unsigned int blks, | |
cca195c5 | 725 | ea_skeleton_call_t skeleton_call, void *private) |
b3b94faa | 726 | { |
7b9cff46 | 727 | struct gfs2_alloc_parms ap = { .target = blks }; |
b3b94faa DT |
728 | int error; |
729 | ||
8e2e0047 BP |
730 | error = gfs2_rindex_update(GFS2_SB(&ip->i_inode)); |
731 | if (error) | |
732 | return error; | |
733 | ||
b8fbf471 | 734 | error = gfs2_quota_lock_check(ip, &ap); |
b3b94faa | 735 | if (error) |
5407e242 | 736 | return error; |
b3b94faa | 737 | |
7b9cff46 | 738 | error = gfs2_inplace_reserve(ip, &ap); |
b3b94faa DT |
739 | if (error) |
740 | goto out_gunlock_q; | |
741 | ||
feaa7bba | 742 | error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), |
71f890f7 | 743 | blks + gfs2_rg_blocks(ip, blks) + |
b3b94faa DT |
744 | RES_DINODE + RES_STATFS + RES_QUOTA, 0); |
745 | if (error) | |
746 | goto out_ipres; | |
747 | ||
748 | error = skeleton_call(ip, er, private); | |
749 | if (error) | |
750 | goto out_end_trans; | |
751 | ||
6862c44e | 752 | ip->i_inode.i_ctime = current_time(&ip->i_inode); |
937d3305 | 753 | __mark_inode_dirty(&ip->i_inode, I_DIRTY_DATASYNC); |
b3b94faa | 754 | |
a91ea69f | 755 | out_end_trans: |
feaa7bba | 756 | gfs2_trans_end(GFS2_SB(&ip->i_inode)); |
a91ea69f | 757 | out_ipres: |
b3b94faa | 758 | gfs2_inplace_release(ip); |
a91ea69f | 759 | out_gunlock_q: |
b3b94faa | 760 | gfs2_quota_unlock(ip); |
b3b94faa DT |
761 | return error; |
762 | } | |
763 | ||
764 | static int ea_init_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |
765 | void *private) | |
766 | { | |
767 | struct buffer_head *bh; | |
768 | int error; | |
769 | ||
770 | error = ea_alloc_blk(ip, &bh); | |
771 | if (error) | |
772 | return error; | |
773 | ||
3767ac21 | 774 | ip->i_eattr = bh->b_blocknr; |
b3b94faa DT |
775 | error = ea_write(ip, GFS2_EA_BH2FIRST(bh), er); |
776 | ||
777 | brelse(bh); | |
778 | ||
779 | return error; | |
780 | } | |
781 | ||
782 | /** | |
783 | * ea_init - initializes a new eattr block | |
784 | * @ip: | |
785 | * @er: | |
786 | * | |
787 | * Returns: errno | |
788 | */ | |
789 | ||
40b78a32 SW |
790 | static int ea_init(struct gfs2_inode *ip, int type, const char *name, |
791 | const void *data, size_t size) | |
b3b94faa | 792 | { |
40b78a32 | 793 | struct gfs2_ea_request er; |
feaa7bba | 794 | unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize; |
b3b94faa DT |
795 | unsigned int blks = 1; |
796 | ||
40b78a32 SW |
797 | er.er_type = type; |
798 | er.er_name = name; | |
799 | er.er_name_len = strlen(name); | |
800 | er.er_data = (void *)data; | |
801 | er.er_data_len = size; | |
802 | ||
803 | if (GFS2_EAREQ_SIZE_STUFFED(&er) > jbsize) | |
804 | blks += DIV_ROUND_UP(er.er_data_len, jbsize); | |
b3b94faa | 805 | |
40b78a32 | 806 | return ea_alloc_skeleton(ip, &er, blks, ea_init_i, NULL); |
b3b94faa DT |
807 | } |
808 | ||
809 | static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea) | |
810 | { | |
cd915493 | 811 | u32 ea_size = GFS2_EA_SIZE(ea); |
568f4c96 SW |
812 | struct gfs2_ea_header *new = (struct gfs2_ea_header *)((char *)ea + |
813 | ea_size); | |
cd915493 | 814 | u32 new_size = GFS2_EA_REC_LEN(ea) - ea_size; |
b3b94faa DT |
815 | int last = ea->ea_flags & GFS2_EAFLAG_LAST; |
816 | ||
817 | ea->ea_rec_len = cpu_to_be32(ea_size); | |
818 | ea->ea_flags ^= last; | |
819 | ||
820 | new->ea_rec_len = cpu_to_be32(new_size); | |
821 | new->ea_flags = last; | |
822 | ||
823 | return new; | |
824 | } | |
825 | ||
826 | static void ea_set_remove_stuffed(struct gfs2_inode *ip, | |
827 | struct gfs2_ea_location *el) | |
828 | { | |
829 | struct gfs2_ea_header *ea = el->el_ea; | |
830 | struct gfs2_ea_header *prev = el->el_prev; | |
cd915493 | 831 | u32 len; |
b3b94faa | 832 | |
350a9b0a | 833 | gfs2_trans_add_meta(ip->i_gl, el->el_bh); |
b3b94faa DT |
834 | |
835 | if (!prev || !GFS2_EA_IS_STUFFED(ea)) { | |
836 | ea->ea_type = GFS2_EATYPE_UNUSED; | |
837 | return; | |
838 | } else if (GFS2_EA2NEXT(prev) != ea) { | |
839 | prev = GFS2_EA2NEXT(prev); | |
feaa7bba | 840 | gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), GFS2_EA2NEXT(prev) == ea); |
b3b94faa DT |
841 | } |
842 | ||
843 | len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea); | |
844 | prev->ea_rec_len = cpu_to_be32(len); | |
845 | ||
846 | if (GFS2_EA_IS_LAST(ea)) | |
847 | prev->ea_flags |= GFS2_EAFLAG_LAST; | |
848 | } | |
849 | ||
850 | struct ea_set { | |
851 | int ea_split; | |
852 | ||
853 | struct gfs2_ea_request *es_er; | |
854 | struct gfs2_ea_location *es_el; | |
855 | ||
856 | struct buffer_head *es_bh; | |
857 | struct gfs2_ea_header *es_ea; | |
858 | }; | |
859 | ||
860 | static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, | |
861 | struct gfs2_ea_header *ea, struct ea_set *es) | |
862 | { | |
863 | struct gfs2_ea_request *er = es->es_er; | |
b3b94faa DT |
864 | int error; |
865 | ||
feaa7bba | 866 | error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + 2 * RES_EATTR, 0); |
b3b94faa DT |
867 | if (error) |
868 | return error; | |
869 | ||
350a9b0a | 870 | gfs2_trans_add_meta(ip->i_gl, bh); |
b3b94faa DT |
871 | |
872 | if (es->ea_split) | |
873 | ea = ea_split_ea(ea); | |
874 | ||
875 | ea_write(ip, ea, er); | |
876 | ||
877 | if (es->es_el) | |
878 | ea_set_remove_stuffed(ip, es->es_el); | |
879 | ||
078cd827 | 880 | ip->i_inode.i_ctime = current_time(&ip->i_inode); |
937d3305 | 881 | __mark_inode_dirty(&ip->i_inode, I_DIRTY_DATASYNC); |
6862c44e | 882 | |
feaa7bba | 883 | gfs2_trans_end(GFS2_SB(&ip->i_inode)); |
b3b94faa DT |
884 | return error; |
885 | } | |
886 | ||
887 | static int ea_set_simple_alloc(struct gfs2_inode *ip, | |
888 | struct gfs2_ea_request *er, void *private) | |
889 | { | |
890 | struct ea_set *es = private; | |
891 | struct gfs2_ea_header *ea = es->es_ea; | |
892 | int error; | |
893 | ||
350a9b0a | 894 | gfs2_trans_add_meta(ip->i_gl, es->es_bh); |
b3b94faa DT |
895 | |
896 | if (es->ea_split) | |
897 | ea = ea_split_ea(ea); | |
898 | ||
899 | error = ea_write(ip, ea, er); | |
900 | if (error) | |
901 | return error; | |
902 | ||
903 | if (es->es_el) | |
904 | ea_set_remove_stuffed(ip, es->es_el); | |
905 | ||
906 | return 0; | |
907 | } | |
908 | ||
909 | static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh, | |
910 | struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, | |
911 | void *private) | |
912 | { | |
913 | struct ea_set *es = private; | |
914 | unsigned int size; | |
915 | int stuffed; | |
916 | int error; | |
917 | ||
40b78a32 SW |
918 | stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er->er_name_len, |
919 | es->es_er->er_data_len, &size); | |
b3b94faa DT |
920 | |
921 | if (ea->ea_type == GFS2_EATYPE_UNUSED) { | |
922 | if (GFS2_EA_REC_LEN(ea) < size) | |
923 | return 0; | |
924 | if (!GFS2_EA_IS_STUFFED(ea)) { | |
925 | error = ea_remove_unstuffed(ip, bh, ea, prev, 1); | |
926 | if (error) | |
927 | return error; | |
928 | } | |
929 | es->ea_split = 0; | |
930 | } else if (GFS2_EA_REC_LEN(ea) - GFS2_EA_SIZE(ea) >= size) | |
931 | es->ea_split = 1; | |
932 | else | |
933 | return 0; | |
934 | ||
935 | if (stuffed) { | |
936 | error = ea_set_simple_noalloc(ip, bh, ea, es); | |
937 | if (error) | |
938 | return error; | |
939 | } else { | |
940 | unsigned int blks; | |
941 | ||
942 | es->es_bh = bh; | |
943 | es->es_ea = ea; | |
5c676f6d | 944 | blks = 2 + DIV_ROUND_UP(es->es_er->er_data_len, |
feaa7bba | 945 | GFS2_SB(&ip->i_inode)->sd_jbsize); |
b3b94faa DT |
946 | |
947 | error = ea_alloc_skeleton(ip, es->es_er, blks, | |
948 | ea_set_simple_alloc, es); | |
949 | if (error) | |
950 | return error; | |
951 | } | |
952 | ||
953 | return 1; | |
954 | } | |
955 | ||
956 | static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |
957 | void *private) | |
958 | { | |
feaa7bba | 959 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
b3b94faa | 960 | struct buffer_head *indbh, *newbh; |
b44b84d7 | 961 | __be64 *eablk; |
b3b94faa DT |
962 | int error; |
963 | int mh_size = sizeof(struct gfs2_meta_header); | |
964 | ||
383f01fb | 965 | if (ip->i_diskflags & GFS2_DIF_EA_INDIRECT) { |
b44b84d7 | 966 | __be64 *end; |
b3b94faa | 967 | |
c8d57703 | 968 | error = gfs2_meta_read(ip->i_gl, ip->i_eattr, DIO_WAIT, 0, |
7276b3b0 | 969 | &indbh); |
b3b94faa DT |
970 | if (error) |
971 | return error; | |
972 | ||
973 | if (gfs2_metatype_check(sdp, indbh, GFS2_METATYPE_IN)) { | |
974 | error = -EIO; | |
975 | goto out; | |
976 | } | |
977 | ||
b44b84d7 | 978 | eablk = (__be64 *)(indbh->b_data + mh_size); |
b3b94faa DT |
979 | end = eablk + sdp->sd_inptrs; |
980 | ||
981 | for (; eablk < end; eablk++) | |
982 | if (!*eablk) | |
983 | break; | |
984 | ||
985 | if (eablk == end) { | |
986 | error = -ENOSPC; | |
987 | goto out; | |
988 | } | |
989 | ||
350a9b0a | 990 | gfs2_trans_add_meta(ip->i_gl, indbh); |
b3b94faa | 991 | } else { |
cd915493 | 992 | u64 blk; |
b45e41d7 | 993 | unsigned int n = 1; |
6e87ed0f | 994 | error = gfs2_alloc_blocks(ip, &blk, &n, 0, NULL); |
09010978 SW |
995 | if (error) |
996 | return error; | |
fbb27873 | 997 | gfs2_trans_remove_revoke(sdp, blk, 1); |
b3b94faa | 998 | indbh = gfs2_meta_new(ip->i_gl, blk); |
350a9b0a | 999 | gfs2_trans_add_meta(ip->i_gl, indbh); |
b3b94faa DT |
1000 | gfs2_metatype_set(indbh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); |
1001 | gfs2_buffer_clear_tail(indbh, mh_size); | |
1002 | ||
b44b84d7 | 1003 | eablk = (__be64 *)(indbh->b_data + mh_size); |
3767ac21 SW |
1004 | *eablk = cpu_to_be64(ip->i_eattr); |
1005 | ip->i_eattr = blk; | |
383f01fb | 1006 | ip->i_diskflags |= GFS2_DIF_EA_INDIRECT; |
77658aad | 1007 | gfs2_add_inode_blocks(&ip->i_inode, 1); |
b3b94faa DT |
1008 | |
1009 | eablk++; | |
1010 | } | |
1011 | ||
1012 | error = ea_alloc_blk(ip, &newbh); | |
1013 | if (error) | |
1014 | goto out; | |
1015 | ||
cd915493 | 1016 | *eablk = cpu_to_be64((u64)newbh->b_blocknr); |
b3b94faa DT |
1017 | error = ea_write(ip, GFS2_EA_BH2FIRST(newbh), er); |
1018 | brelse(newbh); | |
1019 | if (error) | |
1020 | goto out; | |
1021 | ||
1022 | if (private) | |
cca195c5 | 1023 | ea_set_remove_stuffed(ip, private); |
b3b94faa | 1024 | |
a91ea69f | 1025 | out: |
b3b94faa | 1026 | brelse(indbh); |
b3b94faa DT |
1027 | return error; |
1028 | } | |
1029 | ||
40b78a32 SW |
1030 | static int ea_set_i(struct gfs2_inode *ip, int type, const char *name, |
1031 | const void *value, size_t size, struct gfs2_ea_location *el) | |
b3b94faa | 1032 | { |
40b78a32 | 1033 | struct gfs2_ea_request er; |
b3b94faa DT |
1034 | struct ea_set es; |
1035 | unsigned int blks = 2; | |
1036 | int error; | |
1037 | ||
40b78a32 SW |
1038 | er.er_type = type; |
1039 | er.er_name = name; | |
1040 | er.er_data = (void *)value; | |
1041 | er.er_name_len = strlen(name); | |
1042 | er.er_data_len = size; | |
1043 | ||
b3b94faa | 1044 | memset(&es, 0, sizeof(struct ea_set)); |
40b78a32 | 1045 | es.es_er = &er; |
b3b94faa DT |
1046 | es.es_el = el; |
1047 | ||
1048 | error = ea_foreach(ip, ea_set_simple, &es); | |
1049 | if (error > 0) | |
1050 | return 0; | |
1051 | if (error) | |
1052 | return error; | |
1053 | ||
383f01fb | 1054 | if (!(ip->i_diskflags & GFS2_DIF_EA_INDIRECT)) |
b3b94faa | 1055 | blks++; |
40b78a32 SW |
1056 | if (GFS2_EAREQ_SIZE_STUFFED(&er) > GFS2_SB(&ip->i_inode)->sd_jbsize) |
1057 | blks += DIV_ROUND_UP(er.er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize); | |
b3b94faa | 1058 | |
40b78a32 | 1059 | return ea_alloc_skeleton(ip, &er, blks, ea_set_block, el); |
b3b94faa DT |
1060 | } |
1061 | ||
1062 | static int ea_set_remove_unstuffed(struct gfs2_inode *ip, | |
1063 | struct gfs2_ea_location *el) | |
1064 | { | |
1065 | if (el->el_prev && GFS2_EA2NEXT(el->el_prev) != el->el_ea) { | |
1066 | el->el_prev = GFS2_EA2NEXT(el->el_prev); | |
feaa7bba | 1067 | gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), |
b3b94faa DT |
1068 | GFS2_EA2NEXT(el->el_prev) == el->el_ea); |
1069 | } | |
1070 | ||
86d00636 | 1071 | return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev, 0); |
b3b94faa DT |
1072 | } |
1073 | ||
b3b94faa DT |
1074 | static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) |
1075 | { | |
1076 | struct gfs2_ea_header *ea = el->el_ea; | |
1077 | struct gfs2_ea_header *prev = el->el_prev; | |
b3b94faa DT |
1078 | int error; |
1079 | ||
feaa7bba | 1080 | error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0); |
b3b94faa DT |
1081 | if (error) |
1082 | return error; | |
1083 | ||
350a9b0a | 1084 | gfs2_trans_add_meta(ip->i_gl, el->el_bh); |
b3b94faa DT |
1085 | |
1086 | if (prev) { | |
cd915493 | 1087 | u32 len; |
b3b94faa DT |
1088 | |
1089 | len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea); | |
1090 | prev->ea_rec_len = cpu_to_be32(len); | |
1091 | ||
1092 | if (GFS2_EA_IS_LAST(ea)) | |
1093 | prev->ea_flags |= GFS2_EAFLAG_LAST; | |
40b78a32 | 1094 | } else { |
b3b94faa | 1095 | ea->ea_type = GFS2_EATYPE_UNUSED; |
40b78a32 | 1096 | } |
b3b94faa | 1097 | |
6862c44e | 1098 | ip->i_inode.i_ctime = current_time(&ip->i_inode); |
937d3305 | 1099 | __mark_inode_dirty(&ip->i_inode, I_DIRTY_DATASYNC); |
b3b94faa | 1100 | |
feaa7bba | 1101 | gfs2_trans_end(GFS2_SB(&ip->i_inode)); |
b3b94faa DT |
1102 | |
1103 | return error; | |
1104 | } | |
1105 | ||
40b78a32 SW |
1106 | /** |
1107 | * gfs2_xattr_remove - Remove a GFS2 extended attribute | |
431547b3 | 1108 | * @ip: The inode |
40b78a32 SW |
1109 | * @type: The type of the extended attribute |
1110 | * @name: The name of the extended attribute | |
1111 | * | |
1112 | * This is not called directly by the VFS since we use the (common) | |
1113 | * scheme of making a "set with NULL data" mean a remove request. Note | |
1114 | * that this is different from a set with zero length data. | |
1115 | * | |
1116 | * Returns: 0, or errno on failure | |
1117 | */ | |
1118 | ||
431547b3 | 1119 | static int gfs2_xattr_remove(struct gfs2_inode *ip, int type, const char *name) |
b3b94faa DT |
1120 | { |
1121 | struct gfs2_ea_location el; | |
1122 | int error; | |
1123 | ||
3767ac21 | 1124 | if (!ip->i_eattr) |
b3b94faa DT |
1125 | return -ENODATA; |
1126 | ||
40b78a32 | 1127 | error = gfs2_ea_find(ip, type, name, &el); |
b3b94faa DT |
1128 | if (error) |
1129 | return error; | |
1130 | if (!el.el_ea) | |
1131 | return -ENODATA; | |
1132 | ||
1133 | if (GFS2_EA_IS_STUFFED(el.el_ea)) | |
1134 | error = ea_remove_stuffed(ip, &el); | |
1135 | else | |
40b78a32 | 1136 | error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, 0); |
b3b94faa DT |
1137 | |
1138 | brelse(el.el_bh); | |
1139 | ||
1140 | return error; | |
1141 | } | |
1142 | ||
1143 | /** | |
431547b3 CH |
1144 | * __gfs2_xattr_set - Set (or remove) a GFS2 extended attribute |
1145 | * @ip: The inode | |
40b78a32 SW |
1146 | * @name: The name of the extended attribute |
1147 | * @value: The value of the extended attribute (NULL for remove) | |
1148 | * @size: The size of the @value argument | |
1149 | * @flags: Create or Replace | |
431547b3 | 1150 | * @type: The type of the extended attribute |
b3b94faa | 1151 | * |
40b78a32 SW |
1152 | * See gfs2_xattr_remove() for details of the removal of xattrs. |
1153 | * | |
1154 | * Returns: 0 or errno on failure | |
b3b94faa DT |
1155 | */ |
1156 | ||
431547b3 CH |
1157 | int __gfs2_xattr_set(struct inode *inode, const char *name, |
1158 | const void *value, size_t size, int flags, int type) | |
b3b94faa | 1159 | { |
40b78a32 | 1160 | struct gfs2_inode *ip = GFS2_I(inode); |
431547b3 | 1161 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
40b78a32 SW |
1162 | struct gfs2_ea_location el; |
1163 | unsigned int namel = strlen(name); | |
b3b94faa DT |
1164 | int error; |
1165 | ||
40b78a32 SW |
1166 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) |
1167 | return -EPERM; | |
1168 | if (namel > GFS2_EA_MAX_NAME_LEN) | |
1169 | return -ERANGE; | |
b3b94faa | 1170 | |
54aae14b EF |
1171 | if (value == NULL) { |
1172 | error = gfs2_xattr_remove(ip, type, name); | |
1173 | if (error == -ENODATA && !(flags & XATTR_REPLACE)) | |
1174 | error = 0; | |
1175 | return error; | |
1176 | } | |
40b78a32 SW |
1177 | |
1178 | if (ea_check_size(sdp, namel, size)) | |
1179 | return -ERANGE; | |
1180 | ||
1181 | if (!ip->i_eattr) { | |
1182 | if (flags & XATTR_REPLACE) | |
1183 | return -ENODATA; | |
1184 | return ea_init(ip, type, name, value, size); | |
1185 | } | |
1186 | ||
1187 | error = gfs2_ea_find(ip, type, name, &el); | |
b3b94faa DT |
1188 | if (error) |
1189 | return error; | |
1190 | ||
40b78a32 SW |
1191 | if (el.el_ea) { |
1192 | if (ip->i_diskflags & GFS2_DIF_APPENDONLY) { | |
1193 | brelse(el.el_bh); | |
1194 | return -EPERM; | |
1195 | } | |
b3b94faa | 1196 | |
40b78a32 SW |
1197 | error = -EEXIST; |
1198 | if (!(flags & XATTR_CREATE)) { | |
1199 | int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea); | |
1200 | error = ea_set_i(ip, type, name, value, size, &el); | |
1201 | if (!error && unstuffed) | |
1202 | ea_set_remove_unstuffed(ip, &el); | |
1203 | } | |
1204 | ||
1205 | brelse(el.el_bh); | |
1206 | return error; | |
1207 | } | |
1208 | ||
1209 | error = -ENODATA; | |
1210 | if (!(flags & XATTR_REPLACE)) | |
1211 | error = ea_set_i(ip, type, name, value, size, NULL); | |
b3b94faa DT |
1212 | |
1213 | return error; | |
1214 | } | |
1215 | ||
d9a82a04 | 1216 | static int gfs2_xattr_set(const struct xattr_handler *handler, |
59301226 AV |
1217 | struct dentry *unused, struct inode *inode, |
1218 | const char *name, const void *value, | |
1219 | size_t size, int flags) | |
431547b3 | 1220 | { |
1a39ba99 AV |
1221 | struct gfs2_inode *ip = GFS2_I(inode); |
1222 | struct gfs2_holder gh; | |
1223 | int ret; | |
1224 | ||
2fba46a0 | 1225 | ret = gfs2_qa_get(ip); |
1a39ba99 AV |
1226 | if (ret) |
1227 | return ret; | |
1228 | ||
d0920a9c AG |
1229 | /* May be called from gfs_setattr with the glock locked. */ |
1230 | ||
1231 | if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { | |
1232 | ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); | |
1233 | if (ret) | |
2fba46a0 | 1234 | goto out; |
d0920a9c | 1235 | } else { |
2fba46a0 BP |
1236 | if (WARN_ON_ONCE(ip->i_gl->gl_state != LM_ST_EXCLUSIVE)) { |
1237 | ret = -EIO; | |
1238 | goto out; | |
1239 | } | |
d0920a9c AG |
1240 | gfs2_holder_mark_uninitialized(&gh); |
1241 | } | |
1a39ba99 | 1242 | ret = __gfs2_xattr_set(inode, name, value, size, flags, handler->flags); |
d0920a9c AG |
1243 | if (gfs2_holder_initialized(&gh)) |
1244 | gfs2_glock_dq_uninit(&gh); | |
2fba46a0 BP |
1245 | out: |
1246 | gfs2_qa_put(ip); | |
1a39ba99 | 1247 | return ret; |
431547b3 CH |
1248 | } |
1249 | ||
b3b94faa DT |
1250 | static int ea_dealloc_indirect(struct gfs2_inode *ip) |
1251 | { | |
feaa7bba | 1252 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
b3b94faa | 1253 | struct gfs2_rgrp_list rlist; |
0ddeded4 | 1254 | struct gfs2_rgrpd *rgd; |
b3b94faa | 1255 | struct buffer_head *indbh, *dibh; |
b44b84d7 | 1256 | __be64 *eablk, *end; |
b3b94faa | 1257 | unsigned int rg_blocks = 0; |
cd915493 | 1258 | u64 bstart = 0; |
b3b94faa DT |
1259 | unsigned int blen = 0; |
1260 | unsigned int blks = 0; | |
1261 | unsigned int x; | |
1262 | int error; | |
1263 | ||
5e2f7d61 BP |
1264 | error = gfs2_rindex_update(sdp); |
1265 | if (error) | |
1266 | return error; | |
1267 | ||
b3b94faa DT |
1268 | memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); |
1269 | ||
c8d57703 | 1270 | error = gfs2_meta_read(ip->i_gl, ip->i_eattr, DIO_WAIT, 0, &indbh); |
b3b94faa DT |
1271 | if (error) |
1272 | return error; | |
1273 | ||
1274 | if (gfs2_metatype_check(sdp, indbh, GFS2_METATYPE_IN)) { | |
1275 | error = -EIO; | |
1276 | goto out; | |
1277 | } | |
1278 | ||
b44b84d7 | 1279 | eablk = (__be64 *)(indbh->b_data + sizeof(struct gfs2_meta_header)); |
b3b94faa DT |
1280 | end = eablk + sdp->sd_inptrs; |
1281 | ||
1282 | for (; eablk < end; eablk++) { | |
cd915493 | 1283 | u64 bn; |
b3b94faa DT |
1284 | |
1285 | if (!*eablk) | |
1286 | break; | |
1287 | bn = be64_to_cpu(*eablk); | |
1288 | ||
1289 | if (bstart + blen == bn) | |
1290 | blen++; | |
1291 | else { | |
1292 | if (bstart) | |
70b0c365 | 1293 | gfs2_rlist_add(ip, &rlist, bstart); |
b3b94faa DT |
1294 | bstart = bn; |
1295 | blen = 1; | |
1296 | } | |
1297 | blks++; | |
1298 | } | |
1299 | if (bstart) | |
70b0c365 | 1300 | gfs2_rlist_add(ip, &rlist, bstart); |
b3b94faa DT |
1301 | else |
1302 | goto out; | |
1303 | ||
c3abc29e | 1304 | gfs2_rlist_alloc(&rlist); |
b3b94faa DT |
1305 | |
1306 | for (x = 0; x < rlist.rl_rgrps; x++) { | |
0ddeded4 | 1307 | rgd = gfs2_glock2rgrp(rlist.rl_ghs[x].gh_gl); |
bb8d8a6f | 1308 | rg_blocks += rgd->rd_length; |
b3b94faa DT |
1309 | } |
1310 | ||
1311 | error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs); | |
1312 | if (error) | |
1313 | goto out_rlist_free; | |
1314 | ||
cca195c5 SW |
1315 | error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE + RES_INDIRECT + |
1316 | RES_STATFS + RES_QUOTA, blks); | |
b3b94faa DT |
1317 | if (error) |
1318 | goto out_gunlock; | |
1319 | ||
350a9b0a | 1320 | gfs2_trans_add_meta(ip->i_gl, indbh); |
b3b94faa | 1321 | |
b44b84d7 | 1322 | eablk = (__be64 *)(indbh->b_data + sizeof(struct gfs2_meta_header)); |
b3b94faa | 1323 | bstart = 0; |
0ddeded4 | 1324 | rgd = NULL; |
b3b94faa DT |
1325 | blen = 0; |
1326 | ||
1327 | for (; eablk < end; eablk++) { | |
cd915493 | 1328 | u64 bn; |
b3b94faa DT |
1329 | |
1330 | if (!*eablk) | |
1331 | break; | |
1332 | bn = be64_to_cpu(*eablk); | |
1333 | ||
1334 | if (bstart + blen == bn) | |
1335 | blen++; | |
1336 | else { | |
1337 | if (bstart) | |
0ddeded4 | 1338 | gfs2_free_meta(ip, rgd, bstart, blen); |
b3b94faa | 1339 | bstart = bn; |
0ddeded4 | 1340 | rgd = gfs2_blk2rgrpd(sdp, bstart, true); |
b3b94faa DT |
1341 | blen = 1; |
1342 | } | |
1343 | ||
1344 | *eablk = 0; | |
77658aad | 1345 | gfs2_add_inode_blocks(&ip->i_inode, -1); |
b3b94faa DT |
1346 | } |
1347 | if (bstart) | |
0ddeded4 | 1348 | gfs2_free_meta(ip, rgd, bstart, blen); |
b3b94faa | 1349 | |
383f01fb | 1350 | ip->i_diskflags &= ~GFS2_DIF_EA_INDIRECT; |
b3b94faa DT |
1351 | |
1352 | error = gfs2_meta_inode_buffer(ip, &dibh); | |
1353 | if (!error) { | |
350a9b0a | 1354 | gfs2_trans_add_meta(ip->i_gl, dibh); |
539e5d6b | 1355 | gfs2_dinode_out(ip, dibh->b_data); |
b3b94faa DT |
1356 | brelse(dibh); |
1357 | } | |
1358 | ||
1359 | gfs2_trans_end(sdp); | |
1360 | ||
a91ea69f | 1361 | out_gunlock: |
b3b94faa | 1362 | gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); |
a91ea69f | 1363 | out_rlist_free: |
b3b94faa | 1364 | gfs2_rlist_free(&rlist); |
a91ea69f | 1365 | out: |
b3b94faa | 1366 | brelse(indbh); |
b3b94faa DT |
1367 | return error; |
1368 | } | |
1369 | ||
1370 | static int ea_dealloc_block(struct gfs2_inode *ip) | |
1371 | { | |
feaa7bba | 1372 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
b3b94faa DT |
1373 | struct gfs2_rgrpd *rgd; |
1374 | struct buffer_head *dibh; | |
564e12b1 | 1375 | struct gfs2_holder gh; |
b3b94faa DT |
1376 | int error; |
1377 | ||
5e2f7d61 BP |
1378 | error = gfs2_rindex_update(sdp); |
1379 | if (error) | |
1380 | return error; | |
1381 | ||
66fc061b | 1382 | rgd = gfs2_blk2rgrpd(sdp, ip->i_eattr, 1); |
b3b94faa DT |
1383 | if (!rgd) { |
1384 | gfs2_consist_inode(ip); | |
1385 | return -EIO; | |
1386 | } | |
1387 | ||
564e12b1 | 1388 | error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &gh); |
b3b94faa DT |
1389 | if (error) |
1390 | return error; | |
1391 | ||
cca195c5 SW |
1392 | error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_DINODE + RES_STATFS + |
1393 | RES_QUOTA, 1); | |
b3b94faa DT |
1394 | if (error) |
1395 | goto out_gunlock; | |
1396 | ||
0ddeded4 | 1397 | gfs2_free_meta(ip, rgd, ip->i_eattr, 1); |
b3b94faa | 1398 | |
3767ac21 | 1399 | ip->i_eattr = 0; |
77658aad | 1400 | gfs2_add_inode_blocks(&ip->i_inode, -1); |
b3b94faa DT |
1401 | |
1402 | error = gfs2_meta_inode_buffer(ip, &dibh); | |
1403 | if (!error) { | |
350a9b0a | 1404 | gfs2_trans_add_meta(ip->i_gl, dibh); |
539e5d6b | 1405 | gfs2_dinode_out(ip, dibh->b_data); |
b3b94faa DT |
1406 | brelse(dibh); |
1407 | } | |
1408 | ||
1409 | gfs2_trans_end(sdp); | |
1410 | ||
a91ea69f | 1411 | out_gunlock: |
564e12b1 | 1412 | gfs2_glock_dq_uninit(&gh); |
b3b94faa DT |
1413 | return error; |
1414 | } | |
1415 | ||
1416 | /** | |
1417 | * gfs2_ea_dealloc - deallocate the extended attribute fork | |
1418 | * @ip: the inode | |
1419 | * | |
1420 | * Returns: errno | |
1421 | */ | |
1422 | ||
1423 | int gfs2_ea_dealloc(struct gfs2_inode *ip) | |
1424 | { | |
b3b94faa DT |
1425 | int error; |
1426 | ||
8e2e0047 BP |
1427 | error = gfs2_rindex_update(GFS2_SB(&ip->i_inode)); |
1428 | if (error) | |
1429 | return error; | |
1430 | ||
f4108a60 | 1431 | error = gfs2_quota_hold(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE); |
b3b94faa | 1432 | if (error) |
5407e242 | 1433 | return error; |
b3b94faa | 1434 | |
b3b94faa DT |
1435 | error = ea_foreach(ip, ea_dealloc_unstuffed, NULL); |
1436 | if (error) | |
8339ee54 | 1437 | goto out_quota; |
b3b94faa | 1438 | |
383f01fb | 1439 | if (ip->i_diskflags & GFS2_DIF_EA_INDIRECT) { |
b3b94faa DT |
1440 | error = ea_dealloc_indirect(ip); |
1441 | if (error) | |
8339ee54 | 1442 | goto out_quota; |
b3b94faa DT |
1443 | } |
1444 | ||
1445 | error = ea_dealloc_block(ip); | |
1446 | ||
a91ea69f | 1447 | out_quota: |
b3b94faa | 1448 | gfs2_quota_unhold(ip); |
b3b94faa DT |
1449 | return error; |
1450 | } | |
1451 | ||
b7bb0a12 | 1452 | static const struct xattr_handler gfs2_xattr_user_handler = { |
40b78a32 | 1453 | .prefix = XATTR_USER_PREFIX, |
431547b3 CH |
1454 | .flags = GFS2_EATYPE_USR, |
1455 | .get = gfs2_xattr_get, | |
1456 | .set = gfs2_xattr_set, | |
40b78a32 SW |
1457 | }; |
1458 | ||
b7bb0a12 | 1459 | static const struct xattr_handler gfs2_xattr_security_handler = { |
40b78a32 | 1460 | .prefix = XATTR_SECURITY_PREFIX, |
431547b3 CH |
1461 | .flags = GFS2_EATYPE_SECURITY, |
1462 | .get = gfs2_xattr_get, | |
1463 | .set = gfs2_xattr_set, | |
40b78a32 SW |
1464 | }; |
1465 | ||
b7bb0a12 | 1466 | const struct xattr_handler *gfs2_xattr_handlers[] = { |
40b78a32 SW |
1467 | &gfs2_xattr_user_handler, |
1468 | &gfs2_xattr_security_handler, | |
e01580bf CH |
1469 | &posix_acl_access_xattr_handler, |
1470 | &posix_acl_default_xattr_handler, | |
40b78a32 SW |
1471 | NULL, |
1472 | }; | |
1473 |