diff options
author | Dave Chinner <dchinner@redhat.com> | 2014-06-25 00:57:53 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2014-06-25 00:57:53 -0400 |
commit | 30f712c9dd69348aa51351d5cb6d366bf4fae31d (patch) | |
tree | 9b246ca3986b784d8f9f6841466dfd4c90909e47 /fs/xfs/xfs_attr.c | |
parent | 84be0ffc9043f7c56044294eb775a2200452c76d (diff) |
libxfs: move source files
Move all the source files that are shared with userspace into
libxfs/. This is done as one big chunk simpy to get it done
quickly
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs/xfs_attr.c')
-rw-r--r-- | fs/xfs/xfs_attr.c | 1459 |
1 files changed, 0 insertions, 1459 deletions
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c deleted file mode 100644 index 7d95b16f0919..000000000000 --- a/fs/xfs/xfs_attr.c +++ /dev/null | |||
@@ -1,1459 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it would be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write the Free Software Foundation, | ||
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
17 | */ | ||
18 | #include "xfs.h" | ||
19 | #include "xfs_fs.h" | ||
20 | #include "xfs_shared.h" | ||
21 | #include "xfs_format.h" | ||
22 | #include "xfs_log_format.h" | ||
23 | #include "xfs_trans_resv.h" | ||
24 | #include "xfs_bit.h" | ||
25 | #include "xfs_sb.h" | ||
26 | #include "xfs_ag.h" | ||
27 | #include "xfs_mount.h" | ||
28 | #include "xfs_da_format.h" | ||
29 | #include "xfs_da_btree.h" | ||
30 | #include "xfs_attr_sf.h" | ||
31 | #include "xfs_inode.h" | ||
32 | #include "xfs_alloc.h" | ||
33 | #include "xfs_trans.h" | ||
34 | #include "xfs_inode_item.h" | ||
35 | #include "xfs_bmap.h" | ||
36 | #include "xfs_bmap_util.h" | ||
37 | #include "xfs_bmap_btree.h" | ||
38 | #include "xfs_attr.h" | ||
39 | #include "xfs_attr_leaf.h" | ||
40 | #include "xfs_attr_remote.h" | ||
41 | #include "xfs_error.h" | ||
42 | #include "xfs_quota.h" | ||
43 | #include "xfs_trans_space.h" | ||
44 | #include "xfs_trace.h" | ||
45 | #include "xfs_dinode.h" | ||
46 | |||
47 | /* | ||
48 | * xfs_attr.c | ||
49 | * | ||
50 | * Provide the external interfaces to manage attribute lists. | ||
51 | */ | ||
52 | |||
53 | /*======================================================================== | ||
54 | * Function prototypes for the kernel. | ||
55 | *========================================================================*/ | ||
56 | |||
57 | /* | ||
58 | * Internal routines when attribute list fits inside the inode. | ||
59 | */ | ||
60 | STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args); | ||
61 | |||
62 | /* | ||
63 | * Internal routines when attribute list is one block. | ||
64 | */ | ||
65 | STATIC int xfs_attr_leaf_get(xfs_da_args_t *args); | ||
66 | STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); | ||
67 | STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); | ||
68 | |||
69 | /* | ||
70 | * Internal routines when attribute list is more than one block. | ||
71 | */ | ||
72 | STATIC int xfs_attr_node_get(xfs_da_args_t *args); | ||
73 | STATIC int xfs_attr_node_addname(xfs_da_args_t *args); | ||
74 | STATIC int xfs_attr_node_removename(xfs_da_args_t *args); | ||
75 | STATIC int xfs_attr_fillstate(xfs_da_state_t *state); | ||
76 | STATIC int xfs_attr_refillstate(xfs_da_state_t *state); | ||
77 | |||
78 | |||
79 | STATIC int | ||
80 | xfs_attr_args_init( | ||
81 | struct xfs_da_args *args, | ||
82 | struct xfs_inode *dp, | ||
83 | const unsigned char *name, | ||
84 | int flags) | ||
85 | { | ||
86 | |||
87 | if (!name) | ||
88 | return EINVAL; | ||
89 | |||
90 | memset(args, 0, sizeof(*args)); | ||
91 | args->geo = dp->i_mount->m_attr_geo; | ||
92 | args->whichfork = XFS_ATTR_FORK; | ||
93 | args->dp = dp; | ||
94 | args->flags = flags; | ||
95 | args->name = name; | ||
96 | args->namelen = strlen((const char *)name); | ||
97 | if (args->namelen >= MAXNAMELEN) | ||
98 | return EFAULT; /* match IRIX behaviour */ | ||
99 | |||
100 | args->hashval = xfs_da_hashname(args->name, args->namelen); | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | int | ||
105 | xfs_inode_hasattr( | ||
106 | struct xfs_inode *ip) | ||
107 | { | ||
108 | if (!XFS_IFORK_Q(ip) || | ||
109 | (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
110 | ip->i_d.di_anextents == 0)) | ||
111 | return 0; | ||
112 | return 1; | ||
113 | } | ||
114 | |||
115 | /*======================================================================== | ||
116 | * Overall external interface routines. | ||
117 | *========================================================================*/ | ||
118 | |||
119 | int | ||
120 | xfs_attr_get( | ||
121 | struct xfs_inode *ip, | ||
122 | const unsigned char *name, | ||
123 | unsigned char *value, | ||
124 | int *valuelenp, | ||
125 | int flags) | ||
126 | { | ||
127 | struct xfs_da_args args; | ||
128 | uint lock_mode; | ||
129 | int error; | ||
130 | |||
131 | XFS_STATS_INC(xs_attr_get); | ||
132 | |||
133 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | ||
134 | return EIO; | ||
135 | |||
136 | if (!xfs_inode_hasattr(ip)) | ||
137 | return ENOATTR; | ||
138 | |||
139 | error = xfs_attr_args_init(&args, ip, name, flags); | ||
140 | if (error) | ||
141 | return error; | ||
142 | |||
143 | args.value = value; | ||
144 | args.valuelen = *valuelenp; | ||
145 | |||
146 | lock_mode = xfs_ilock_attr_map_shared(ip); | ||
147 | if (!xfs_inode_hasattr(ip)) | ||
148 | error = ENOATTR; | ||
149 | else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) | ||
150 | error = xfs_attr_shortform_getvalue(&args); | ||
151 | else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) | ||
152 | error = xfs_attr_leaf_get(&args); | ||
153 | else | ||
154 | error = xfs_attr_node_get(&args); | ||
155 | xfs_iunlock(ip, lock_mode); | ||
156 | |||
157 | *valuelenp = args.valuelen; | ||
158 | return error == EEXIST ? 0 : error; | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * Calculate how many blocks we need for the new attribute, | ||
163 | */ | ||
164 | STATIC int | ||
165 | xfs_attr_calc_size( | ||
166 | struct xfs_da_args *args, | ||
167 | int *local) | ||
168 | { | ||
169 | struct xfs_mount *mp = args->dp->i_mount; | ||
170 | int size; | ||
171 | int nblks; | ||
172 | |||
173 | /* | ||
174 | * Determine space new attribute will use, and if it would be | ||
175 | * "local" or "remote" (note: local != inline). | ||
176 | */ | ||
177 | size = xfs_attr_leaf_newentsize(args, local); | ||
178 | nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); | ||
179 | if (*local) { | ||
180 | if (size > (args->geo->blksize / 2)) { | ||
181 | /* Double split possible */ | ||
182 | nblks *= 2; | ||
183 | } | ||
184 | } else { | ||
185 | /* | ||
186 | * Out of line attribute, cannot double split, but | ||
187 | * make room for the attribute value itself. | ||
188 | */ | ||
189 | uint dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen); | ||
190 | nblks += dblocks; | ||
191 | nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); | ||
192 | } | ||
193 | |||
194 | return nblks; | ||
195 | } | ||
196 | |||
197 | int | ||
198 | xfs_attr_set( | ||
199 | struct xfs_inode *dp, | ||
200 | const unsigned char *name, | ||
201 | unsigned char *value, | ||
202 | int valuelen, | ||
203 | int flags) | ||
204 | { | ||
205 | struct xfs_mount *mp = dp->i_mount; | ||
206 | struct xfs_da_args args; | ||
207 | struct xfs_bmap_free flist; | ||
208 | struct xfs_trans_res tres; | ||
209 | xfs_fsblock_t firstblock; | ||
210 | int rsvd = (flags & ATTR_ROOT) != 0; | ||
211 | int error, err2, committed, local; | ||
212 | |||
213 | XFS_STATS_INC(xs_attr_set); | ||
214 | |||
215 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) | ||
216 | return EIO; | ||
217 | |||
218 | error = xfs_attr_args_init(&args, dp, name, flags); | ||
219 | if (error) | ||
220 | return error; | ||
221 | |||
222 | args.value = value; | ||
223 | args.valuelen = valuelen; | ||
224 | args.firstblock = &firstblock; | ||
225 | args.flist = &flist; | ||
226 | args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; | ||
227 | args.total = xfs_attr_calc_size(&args, &local); | ||
228 | |||
229 | error = xfs_qm_dqattach(dp, 0); | ||
230 | if (error) | ||
231 | return error; | ||
232 | |||
233 | /* | ||
234 | * If the inode doesn't have an attribute fork, add one. | ||
235 | * (inode must not be locked when we call this routine) | ||
236 | */ | ||
237 | if (XFS_IFORK_Q(dp) == 0) { | ||
238 | int sf_size = sizeof(xfs_attr_sf_hdr_t) + | ||
239 | XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen); | ||
240 | |||
241 | error = xfs_bmap_add_attrfork(dp, sf_size, rsvd); | ||
242 | if (error) | ||
243 | return error; | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * Start our first transaction of the day. | ||
248 | * | ||
249 | * All future transactions during this code must be "chained" off | ||
250 | * this one via the trans_dup() call. All transactions will contain | ||
251 | * the inode, and the inode will always be marked with trans_ihold(). | ||
252 | * Since the inode will be locked in all transactions, we must log | ||
253 | * the inode in every transaction to let it float upward through | ||
254 | * the log. | ||
255 | */ | ||
256 | args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET); | ||
257 | |||
258 | /* | ||
259 | * Root fork attributes can use reserved data blocks for this | ||
260 | * operation if necessary | ||
261 | */ | ||
262 | |||
263 | if (rsvd) | ||
264 | args.trans->t_flags |= XFS_TRANS_RESERVE; | ||
265 | |||
266 | tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres + | ||
267 | M_RES(mp)->tr_attrsetrt.tr_logres * args.total; | ||
268 | tres.tr_logcount = XFS_ATTRSET_LOG_COUNT; | ||
269 | tres.tr_logflags = XFS_TRANS_PERM_LOG_RES; | ||
270 | error = xfs_trans_reserve(args.trans, &tres, args.total, 0); | ||
271 | if (error) { | ||
272 | xfs_trans_cancel(args.trans, 0); | ||
273 | return error; | ||
274 | } | ||
275 | xfs_ilock(dp, XFS_ILOCK_EXCL); | ||
276 | |||
277 | error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0, | ||
278 | rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : | ||
279 | XFS_QMOPT_RES_REGBLKS); | ||
280 | if (error) { | ||
281 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | ||
282 | xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES); | ||
283 | return error; | ||
284 | } | ||
285 | |||
286 | xfs_trans_ijoin(args.trans, dp, 0); | ||
287 | |||
288 | /* | ||
289 | * If the attribute list is non-existent or a shortform list, | ||
290 | * upgrade it to a single-leaf-block attribute list. | ||
291 | */ | ||
292 | if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL || | ||
293 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
294 | dp->i_d.di_anextents == 0)) { | ||
295 | |||
296 | /* | ||
297 | * Build initial attribute list (if required). | ||
298 | */ | ||
299 | if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) | ||
300 | xfs_attr_shortform_create(&args); | ||
301 | |||
302 | /* | ||
303 | * Try to add the attr to the attribute list in | ||
304 | * the inode. | ||
305 | */ | ||
306 | error = xfs_attr_shortform_addname(&args); | ||
307 | if (error != ENOSPC) { | ||
308 | /* | ||
309 | * Commit the shortform mods, and we're done. | ||
310 | * NOTE: this is also the error path (EEXIST, etc). | ||
311 | */ | ||
312 | ASSERT(args.trans != NULL); | ||
313 | |||
314 | /* | ||
315 | * If this is a synchronous mount, make sure that | ||
316 | * the transaction goes to disk before returning | ||
317 | * to the user. | ||
318 | */ | ||
319 | if (mp->m_flags & XFS_MOUNT_WSYNC) | ||
320 | xfs_trans_set_sync(args.trans); | ||
321 | |||
322 | if (!error && (flags & ATTR_KERNOTIME) == 0) { | ||
323 | xfs_trans_ichgtime(args.trans, dp, | ||
324 | XFS_ICHGTIME_CHG); | ||
325 | } | ||
326 | err2 = xfs_trans_commit(args.trans, | ||
327 | XFS_TRANS_RELEASE_LOG_RES); | ||
328 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | ||
329 | |||
330 | return error ? error : err2; | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * It won't fit in the shortform, transform to a leaf block. | ||
335 | * GROT: another possible req'mt for a double-split btree op. | ||
336 | */ | ||
337 | xfs_bmap_init(args.flist, args.firstblock); | ||
338 | error = xfs_attr_shortform_to_leaf(&args); | ||
339 | if (!error) { | ||
340 | error = xfs_bmap_finish(&args.trans, args.flist, | ||
341 | &committed); | ||
342 | } | ||
343 | if (error) { | ||
344 | ASSERT(committed); | ||
345 | args.trans = NULL; | ||
346 | xfs_bmap_cancel(&flist); | ||
347 | goto out; | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * bmap_finish() may have committed the last trans and started | ||
352 | * a new one. We need the inode to be in all transactions. | ||
353 | */ | ||
354 | if (committed) | ||
355 | xfs_trans_ijoin(args.trans, dp, 0); | ||
356 | |||
357 | /* | ||
358 | * Commit the leaf transformation. We'll need another (linked) | ||
359 | * transaction to add the new attribute to the leaf. | ||
360 | */ | ||
361 | |||
362 | error = xfs_trans_roll(&args.trans, dp); | ||
363 | if (error) | ||
364 | goto out; | ||
365 | |||
366 | } | ||
367 | |||
368 | if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) | ||
369 | error = xfs_attr_leaf_addname(&args); | ||
370 | else | ||
371 | error = xfs_attr_node_addname(&args); | ||
372 | if (error) | ||
373 | goto out; | ||
374 | |||
375 | /* | ||
376 | * If this is a synchronous mount, make sure that the | ||
377 | * transaction goes to disk before returning to the user. | ||
378 | */ | ||
379 | if (mp->m_flags & XFS_MOUNT_WSYNC) | ||
380 | xfs_trans_set_sync(args.trans); | ||
381 | |||
382 | if ((flags & ATTR_KERNOTIME) == 0) | ||
383 | xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG); | ||
384 | |||
385 | /* | ||
386 | * Commit the last in the sequence of transactions. | ||
387 | */ | ||
388 | xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); | ||
389 | error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES); | ||
390 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | ||
391 | |||
392 | return error; | ||
393 | |||
394 | out: | ||
395 | if (args.trans) { | ||
396 | xfs_trans_cancel(args.trans, | ||
397 | XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); | ||
398 | } | ||
399 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | ||
400 | return error; | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * Generic handler routine to remove a name from an attribute list. | ||
405 | * Transitions attribute list from Btree to shortform as necessary. | ||
406 | */ | ||
407 | int | ||
408 | xfs_attr_remove( | ||
409 | struct xfs_inode *dp, | ||
410 | const unsigned char *name, | ||
411 | int flags) | ||
412 | { | ||
413 | struct xfs_mount *mp = dp->i_mount; | ||
414 | struct xfs_da_args args; | ||
415 | struct xfs_bmap_free flist; | ||
416 | xfs_fsblock_t firstblock; | ||
417 | int error; | ||
418 | |||
419 | XFS_STATS_INC(xs_attr_remove); | ||
420 | |||
421 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) | ||
422 | return EIO; | ||
423 | |||
424 | if (!xfs_inode_hasattr(dp)) | ||
425 | return ENOATTR; | ||
426 | |||
427 | error = xfs_attr_args_init(&args, dp, name, flags); | ||
428 | if (error) | ||
429 | return error; | ||
430 | |||
431 | args.firstblock = &firstblock; | ||
432 | args.flist = &flist; | ||
433 | |||
434 | /* | ||
435 | * we have no control over the attribute names that userspace passes us | ||
436 | * to remove, so we have to allow the name lookup prior to attribute | ||
437 | * removal to fail. | ||
438 | */ | ||
439 | args.op_flags = XFS_DA_OP_OKNOENT; | ||
440 | |||
441 | error = xfs_qm_dqattach(dp, 0); | ||
442 | if (error) | ||
443 | return error; | ||
444 | |||
445 | /* | ||
446 | * Start our first transaction of the day. | ||
447 | * | ||
448 | * All future transactions during this code must be "chained" off | ||
449 | * this one via the trans_dup() call. All transactions will contain | ||
450 | * the inode, and the inode will always be marked with trans_ihold(). | ||
451 | * Since the inode will be locked in all transactions, we must log | ||
452 | * the inode in every transaction to let it float upward through | ||
453 | * the log. | ||
454 | */ | ||
455 | args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM); | ||
456 | |||
457 | /* | ||
458 | * Root fork attributes can use reserved data blocks for this | ||
459 | * operation if necessary | ||
460 | */ | ||
461 | |||
462 | if (flags & ATTR_ROOT) | ||
463 | args.trans->t_flags |= XFS_TRANS_RESERVE; | ||
464 | |||
465 | error = xfs_trans_reserve(args.trans, &M_RES(mp)->tr_attrrm, | ||
466 | XFS_ATTRRM_SPACE_RES(mp), 0); | ||
467 | if (error) { | ||
468 | xfs_trans_cancel(args.trans, 0); | ||
469 | return error; | ||
470 | } | ||
471 | |||
472 | xfs_ilock(dp, XFS_ILOCK_EXCL); | ||
473 | /* | ||
474 | * No need to make quota reservations here. We expect to release some | ||
475 | * blocks not allocate in the common case. | ||
476 | */ | ||
477 | xfs_trans_ijoin(args.trans, dp, 0); | ||
478 | |||
479 | if (!xfs_inode_hasattr(dp)) { | ||
480 | error = ENOATTR; | ||
481 | } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | ||
482 | ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); | ||
483 | error = xfs_attr_shortform_remove(&args); | ||
484 | } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { | ||
485 | error = xfs_attr_leaf_removename(&args); | ||
486 | } else { | ||
487 | error = xfs_attr_node_removename(&args); | ||
488 | } | ||
489 | |||
490 | if (error) | ||
491 | goto out; | ||
492 | |||
493 | /* | ||
494 | * If this is a synchronous mount, make sure that the | ||
495 | * transaction goes to disk before returning to the user. | ||
496 | */ | ||
497 | if (mp->m_flags & XFS_MOUNT_WSYNC) | ||
498 | xfs_trans_set_sync(args.trans); | ||
499 | |||
500 | if ((flags & ATTR_KERNOTIME) == 0) | ||
501 | xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG); | ||
502 | |||
503 | /* | ||
504 | * Commit the last in the sequence of transactions. | ||
505 | */ | ||
506 | xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); | ||
507 | error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES); | ||
508 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | ||
509 | |||
510 | return error; | ||
511 | |||
512 | out: | ||
513 | if (args.trans) { | ||
514 | xfs_trans_cancel(args.trans, | ||
515 | XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); | ||
516 | } | ||
517 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | ||
518 | return error; | ||
519 | } | ||
520 | |||
521 | /*======================================================================== | ||
522 | * External routines when attribute list is inside the inode | ||
523 | *========================================================================*/ | ||
524 | |||
525 | /* | ||
526 | * Add a name to the shortform attribute list structure | ||
527 | * This is the external routine. | ||
528 | */ | ||
529 | STATIC int | ||
530 | xfs_attr_shortform_addname(xfs_da_args_t *args) | ||
531 | { | ||
532 | int newsize, forkoff, retval; | ||
533 | |||
534 | trace_xfs_attr_sf_addname(args); | ||
535 | |||
536 | retval = xfs_attr_shortform_lookup(args); | ||
537 | if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { | ||
538 | return retval; | ||
539 | } else if (retval == EEXIST) { | ||
540 | if (args->flags & ATTR_CREATE) | ||
541 | return retval; | ||
542 | retval = xfs_attr_shortform_remove(args); | ||
543 | ASSERT(retval == 0); | ||
544 | } | ||
545 | |||
546 | if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX || | ||
547 | args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX) | ||
548 | return ENOSPC; | ||
549 | |||
550 | newsize = XFS_ATTR_SF_TOTSIZE(args->dp); | ||
551 | newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); | ||
552 | |||
553 | forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize); | ||
554 | if (!forkoff) | ||
555 | return ENOSPC; | ||
556 | |||
557 | xfs_attr_shortform_add(args, forkoff); | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | |||
562 | /*======================================================================== | ||
563 | * External routines when attribute list is one block | ||
564 | *========================================================================*/ | ||
565 | |||
566 | /* | ||
567 | * Add a name to the leaf attribute list structure | ||
568 | * | ||
569 | * This leaf block cannot have a "remote" value, we only call this routine | ||
570 | * if bmap_one_block() says there is only one block (ie: no remote blks). | ||
571 | */ | ||
572 | STATIC int | ||
573 | xfs_attr_leaf_addname(xfs_da_args_t *args) | ||
574 | { | ||
575 | xfs_inode_t *dp; | ||
576 | struct xfs_buf *bp; | ||
577 | int retval, error, committed, forkoff; | ||
578 | |||
579 | trace_xfs_attr_leaf_addname(args); | ||
580 | |||
581 | /* | ||
582 | * Read the (only) block in the attribute list in. | ||
583 | */ | ||
584 | dp = args->dp; | ||
585 | args->blkno = 0; | ||
586 | error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); | ||
587 | if (error) | ||
588 | return error; | ||
589 | |||
590 | /* | ||
591 | * Look up the given attribute in the leaf block. Figure out if | ||
592 | * the given flags produce an error or call for an atomic rename. | ||
593 | */ | ||
594 | retval = xfs_attr3_leaf_lookup_int(bp, args); | ||
595 | if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { | ||
596 | xfs_trans_brelse(args->trans, bp); | ||
597 | return retval; | ||
598 | } else if (retval == EEXIST) { | ||
599 | if (args->flags & ATTR_CREATE) { /* pure create op */ | ||
600 | xfs_trans_brelse(args->trans, bp); | ||
601 | return retval; | ||
602 | } | ||
603 | |||
604 | trace_xfs_attr_leaf_replace(args); | ||
605 | |||
606 | /* save the attribute state for later removal*/ | ||
607 | args->op_flags |= XFS_DA_OP_RENAME; /* an atomic rename */ | ||
608 | args->blkno2 = args->blkno; /* set 2nd entry info*/ | ||
609 | args->index2 = args->index; | ||
610 | args->rmtblkno2 = args->rmtblkno; | ||
611 | args->rmtblkcnt2 = args->rmtblkcnt; | ||
612 | args->rmtvaluelen2 = args->rmtvaluelen; | ||
613 | |||
614 | /* | ||
615 | * clear the remote attr state now that it is saved so that the | ||
616 | * values reflect the state of the attribute we are about to | ||
617 | * add, not the attribute we just found and will remove later. | ||
618 | */ | ||
619 | args->rmtblkno = 0; | ||
620 | args->rmtblkcnt = 0; | ||
621 | args->rmtvaluelen = 0; | ||
622 | } | ||
623 | |||
624 | /* | ||
625 | * Add the attribute to the leaf block, transitioning to a Btree | ||
626 | * if required. | ||
627 | */ | ||
628 | retval = xfs_attr3_leaf_add(bp, args); | ||
629 | if (retval == ENOSPC) { | ||
630 | /* | ||
631 | * Promote the attribute list to the Btree format, then | ||
632 | * Commit that transaction so that the node_addname() call | ||
633 | * can manage its own transactions. | ||
634 | */ | ||
635 | xfs_bmap_init(args->flist, args->firstblock); | ||
636 | error = xfs_attr3_leaf_to_node(args); | ||
637 | if (!error) { | ||
638 | error = xfs_bmap_finish(&args->trans, args->flist, | ||
639 | &committed); | ||
640 | } | ||
641 | if (error) { | ||
642 | ASSERT(committed); | ||
643 | args->trans = NULL; | ||
644 | xfs_bmap_cancel(args->flist); | ||
645 | return error; | ||
646 | } | ||
647 | |||
648 | /* | ||
649 | * bmap_finish() may have committed the last trans and started | ||
650 | * a new one. We need the inode to be in all transactions. | ||
651 | */ | ||
652 | if (committed) | ||
653 | xfs_trans_ijoin(args->trans, dp, 0); | ||
654 | |||
655 | /* | ||
656 | * Commit the current trans (including the inode) and start | ||
657 | * a new one. | ||
658 | */ | ||
659 | error = xfs_trans_roll(&args->trans, dp); | ||
660 | if (error) | ||
661 | return error; | ||
662 | |||
663 | /* | ||
664 | * Fob the whole rest of the problem off on the Btree code. | ||
665 | */ | ||
666 | error = xfs_attr_node_addname(args); | ||
667 | return error; | ||
668 | } | ||
669 | |||
670 | /* | ||
671 | * Commit the transaction that added the attr name so that | ||
672 | * later routines can manage their own transactions. | ||
673 | */ | ||
674 | error = xfs_trans_roll(&args->trans, dp); | ||
675 | if (error) | ||
676 | return error; | ||
677 | |||
678 | /* | ||
679 | * If there was an out-of-line value, allocate the blocks we | ||
680 | * identified for its storage and copy the value. This is done | ||
681 | * after we create the attribute so that we don't overflow the | ||
682 | * maximum size of a transaction and/or hit a deadlock. | ||
683 | */ | ||
684 | if (args->rmtblkno > 0) { | ||
685 | error = xfs_attr_rmtval_set(args); | ||
686 | if (error) | ||
687 | return error; | ||
688 | } | ||
689 | |||
690 | /* | ||
691 | * If this is an atomic rename operation, we must "flip" the | ||
692 | * incomplete flags on the "new" and "old" attribute/value pairs | ||
693 | * so that one disappears and one appears atomically. Then we | ||
694 | * must remove the "old" attribute/value pair. | ||
695 | */ | ||
696 | if (args->op_flags & XFS_DA_OP_RENAME) { | ||
697 | /* | ||
698 | * In a separate transaction, set the incomplete flag on the | ||
699 | * "old" attr and clear the incomplete flag on the "new" attr. | ||
700 | */ | ||
701 | error = xfs_attr3_leaf_flipflags(args); | ||
702 | if (error) | ||
703 | return error; | ||
704 | |||
705 | /* | ||
706 | * Dismantle the "old" attribute/value pair by removing | ||
707 | * a "remote" value (if it exists). | ||
708 | */ | ||
709 | args->index = args->index2; | ||
710 | args->blkno = args->blkno2; | ||
711 | args->rmtblkno = args->rmtblkno2; | ||
712 | args->rmtblkcnt = args->rmtblkcnt2; | ||
713 | args->rmtvaluelen = args->rmtvaluelen2; | ||
714 | if (args->rmtblkno) { | ||
715 | error = xfs_attr_rmtval_remove(args); | ||
716 | if (error) | ||
717 | return error; | ||
718 | } | ||
719 | |||
720 | /* | ||
721 | * Read in the block containing the "old" attr, then | ||
722 | * remove the "old" attr from that block (neat, huh!) | ||
723 | */ | ||
724 | error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, | ||
725 | -1, &bp); | ||
726 | if (error) | ||
727 | return error; | ||
728 | |||
729 | xfs_attr3_leaf_remove(bp, args); | ||
730 | |||
731 | /* | ||
732 | * If the result is small enough, shrink it all into the inode. | ||
733 | */ | ||
734 | if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { | ||
735 | xfs_bmap_init(args->flist, args->firstblock); | ||
736 | error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); | ||
737 | /* bp is gone due to xfs_da_shrink_inode */ | ||
738 | if (!error) { | ||
739 | error = xfs_bmap_finish(&args->trans, | ||
740 | args->flist, | ||
741 | &committed); | ||
742 | } | ||
743 | if (error) { | ||
744 | ASSERT(committed); | ||
745 | args->trans = NULL; | ||
746 | xfs_bmap_cancel(args->flist); | ||
747 | return error; | ||
748 | } | ||
749 | |||
750 | /* | ||
751 | * bmap_finish() may have committed the last trans | ||
752 | * and started a new one. We need the inode to be | ||
753 | * in all transactions. | ||
754 | */ | ||
755 | if (committed) | ||
756 | xfs_trans_ijoin(args->trans, dp, 0); | ||
757 | } | ||
758 | |||
759 | /* | ||
760 | * Commit the remove and start the next trans in series. | ||
761 | */ | ||
762 | error = xfs_trans_roll(&args->trans, dp); | ||
763 | |||
764 | } else if (args->rmtblkno > 0) { | ||
765 | /* | ||
766 | * Added a "remote" value, just clear the incomplete flag. | ||
767 | */ | ||
768 | error = xfs_attr3_leaf_clearflag(args); | ||
769 | } | ||
770 | return error; | ||
771 | } | ||
772 | |||
773 | /* | ||
774 | * Remove a name from the leaf attribute list structure | ||
775 | * | ||
776 | * This leaf block cannot have a "remote" value, we only call this routine | ||
777 | * if bmap_one_block() says there is only one block (ie: no remote blks). | ||
778 | */ | ||
779 | STATIC int | ||
780 | xfs_attr_leaf_removename(xfs_da_args_t *args) | ||
781 | { | ||
782 | xfs_inode_t *dp; | ||
783 | struct xfs_buf *bp; | ||
784 | int error, committed, forkoff; | ||
785 | |||
786 | trace_xfs_attr_leaf_removename(args); | ||
787 | |||
788 | /* | ||
789 | * Remove the attribute. | ||
790 | */ | ||
791 | dp = args->dp; | ||
792 | args->blkno = 0; | ||
793 | error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); | ||
794 | if (error) | ||
795 | return error; | ||
796 | |||
797 | error = xfs_attr3_leaf_lookup_int(bp, args); | ||
798 | if (error == ENOATTR) { | ||
799 | xfs_trans_brelse(args->trans, bp); | ||
800 | return error; | ||
801 | } | ||
802 | |||
803 | xfs_attr3_leaf_remove(bp, args); | ||
804 | |||
805 | /* | ||
806 | * If the result is small enough, shrink it all into the inode. | ||
807 | */ | ||
808 | if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { | ||
809 | xfs_bmap_init(args->flist, args->firstblock); | ||
810 | error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); | ||
811 | /* bp is gone due to xfs_da_shrink_inode */ | ||
812 | if (!error) { | ||
813 | error = xfs_bmap_finish(&args->trans, args->flist, | ||
814 | &committed); | ||
815 | } | ||
816 | if (error) { | ||
817 | ASSERT(committed); | ||
818 | args->trans = NULL; | ||
819 | xfs_bmap_cancel(args->flist); | ||
820 | return error; | ||
821 | } | ||
822 | |||
823 | /* | ||
824 | * bmap_finish() may have committed the last trans and started | ||
825 | * a new one. We need the inode to be in all transactions. | ||
826 | */ | ||
827 | if (committed) | ||
828 | xfs_trans_ijoin(args->trans, dp, 0); | ||
829 | } | ||
830 | return 0; | ||
831 | } | ||
832 | |||
833 | /* | ||
834 | * Look up a name in a leaf attribute list structure. | ||
835 | * | ||
836 | * This leaf block cannot have a "remote" value, we only call this routine | ||
837 | * if bmap_one_block() says there is only one block (ie: no remote blks). | ||
838 | */ | ||
839 | STATIC int | ||
840 | xfs_attr_leaf_get(xfs_da_args_t *args) | ||
841 | { | ||
842 | struct xfs_buf *bp; | ||
843 | int error; | ||
844 | |||
845 | trace_xfs_attr_leaf_get(args); | ||
846 | |||
847 | args->blkno = 0; | ||
848 | error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); | ||
849 | if (error) | ||
850 | return error; | ||
851 | |||
852 | error = xfs_attr3_leaf_lookup_int(bp, args); | ||
853 | if (error != EEXIST) { | ||
854 | xfs_trans_brelse(args->trans, bp); | ||
855 | return error; | ||
856 | } | ||
857 | error = xfs_attr3_leaf_getvalue(bp, args); | ||
858 | xfs_trans_brelse(args->trans, bp); | ||
859 | if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) { | ||
860 | error = xfs_attr_rmtval_get(args); | ||
861 | } | ||
862 | return error; | ||
863 | } | ||
864 | |||
865 | /*======================================================================== | ||
866 | * External routines when attribute list size > geo->blksize | ||
867 | *========================================================================*/ | ||
868 | |||
869 | /* | ||
870 | * Add a name to a Btree-format attribute list. | ||
871 | * | ||
872 | * This will involve walking down the Btree, and may involve splitting | ||
873 | * leaf nodes and even splitting intermediate nodes up to and including | ||
874 | * the root node (a special case of an intermediate node). | ||
875 | * | ||
876 | * "Remote" attribute values confuse the issue and atomic rename operations | ||
877 | * add a whole extra layer of confusion on top of that. | ||
878 | */ | ||
879 | STATIC int | ||
880 | xfs_attr_node_addname(xfs_da_args_t *args) | ||
881 | { | ||
882 | xfs_da_state_t *state; | ||
883 | xfs_da_state_blk_t *blk; | ||
884 | xfs_inode_t *dp; | ||
885 | xfs_mount_t *mp; | ||
886 | int committed, retval, error; | ||
887 | |||
888 | trace_xfs_attr_node_addname(args); | ||
889 | |||
890 | /* | ||
891 | * Fill in bucket of arguments/results/context to carry around. | ||
892 | */ | ||
893 | dp = args->dp; | ||
894 | mp = dp->i_mount; | ||
895 | restart: | ||
896 | state = xfs_da_state_alloc(); | ||
897 | state->args = args; | ||
898 | state->mp = mp; | ||
899 | |||
900 | /* | ||
901 | * Search to see if name already exists, and get back a pointer | ||
902 | * to where it should go. | ||
903 | */ | ||
904 | error = xfs_da3_node_lookup_int(state, &retval); | ||
905 | if (error) | ||
906 | goto out; | ||
907 | blk = &state->path.blk[ state->path.active-1 ]; | ||
908 | ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); | ||
909 | if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { | ||
910 | goto out; | ||
911 | } else if (retval == EEXIST) { | ||
912 | if (args->flags & ATTR_CREATE) | ||
913 | goto out; | ||
914 | |||
915 | trace_xfs_attr_node_replace(args); | ||
916 | |||
917 | /* save the attribute state for later removal*/ | ||
918 | args->op_flags |= XFS_DA_OP_RENAME; /* atomic rename op */ | ||
919 | args->blkno2 = args->blkno; /* set 2nd entry info*/ | ||
920 | args->index2 = args->index; | ||
921 | args->rmtblkno2 = args->rmtblkno; | ||
922 | args->rmtblkcnt2 = args->rmtblkcnt; | ||
923 | args->rmtvaluelen2 = args->rmtvaluelen; | ||
924 | |||
925 | /* | ||
926 | * clear the remote attr state now that it is saved so that the | ||
927 | * values reflect the state of the attribute we are about to | ||
928 | * add, not the attribute we just found and will remove later. | ||
929 | */ | ||
930 | args->rmtblkno = 0; | ||
931 | args->rmtblkcnt = 0; | ||
932 | args->rmtvaluelen = 0; | ||
933 | } | ||
934 | |||
935 | retval = xfs_attr3_leaf_add(blk->bp, state->args); | ||
936 | if (retval == ENOSPC) { | ||
937 | if (state->path.active == 1) { | ||
938 | /* | ||
939 | * Its really a single leaf node, but it had | ||
940 | * out-of-line values so it looked like it *might* | ||
941 | * have been a b-tree. | ||
942 | */ | ||
943 | xfs_da_state_free(state); | ||
944 | state = NULL; | ||
945 | xfs_bmap_init(args->flist, args->firstblock); | ||
946 | error = xfs_attr3_leaf_to_node(args); | ||
947 | if (!error) { | ||
948 | error = xfs_bmap_finish(&args->trans, | ||
949 | args->flist, | ||
950 | &committed); | ||
951 | } | ||
952 | if (error) { | ||
953 | ASSERT(committed); | ||
954 | args->trans = NULL; | ||
955 | xfs_bmap_cancel(args->flist); | ||
956 | goto out; | ||
957 | } | ||
958 | |||
959 | /* | ||
960 | * bmap_finish() may have committed the last trans | ||
961 | * and started a new one. We need the inode to be | ||
962 | * in all transactions. | ||
963 | */ | ||
964 | if (committed) | ||
965 | xfs_trans_ijoin(args->trans, dp, 0); | ||
966 | |||
967 | /* | ||
968 | * Commit the node conversion and start the next | ||
969 | * trans in the chain. | ||
970 | */ | ||
971 | error = xfs_trans_roll(&args->trans, dp); | ||
972 | if (error) | ||
973 | goto out; | ||
974 | |||
975 | goto restart; | ||
976 | } | ||
977 | |||
978 | /* | ||
979 | * Split as many Btree elements as required. | ||
980 | * This code tracks the new and old attr's location | ||
981 | * in the index/blkno/rmtblkno/rmtblkcnt fields and | ||
982 | * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields. | ||
983 | */ | ||
984 | xfs_bmap_init(args->flist, args->firstblock); | ||
985 | error = xfs_da3_split(state); | ||
986 | if (!error) { | ||
987 | error = xfs_bmap_finish(&args->trans, args->flist, | ||
988 | &committed); | ||
989 | } | ||
990 | if (error) { | ||
991 | ASSERT(committed); | ||
992 | args->trans = NULL; | ||
993 | xfs_bmap_cancel(args->flist); | ||
994 | goto out; | ||
995 | } | ||
996 | |||
997 | /* | ||
998 | * bmap_finish() may have committed the last trans and started | ||
999 | * a new one. We need the inode to be in all transactions. | ||
1000 | */ | ||
1001 | if (committed) | ||
1002 | xfs_trans_ijoin(args->trans, dp, 0); | ||
1003 | } else { | ||
1004 | /* | ||
1005 | * Addition succeeded, update Btree hashvals. | ||
1006 | */ | ||
1007 | xfs_da3_fixhashpath(state, &state->path); | ||
1008 | } | ||
1009 | |||
1010 | /* | ||
1011 | * Kill the state structure, we're done with it and need to | ||
1012 | * allow the buffers to come back later. | ||
1013 | */ | ||
1014 | xfs_da_state_free(state); | ||
1015 | state = NULL; | ||
1016 | |||
1017 | /* | ||
1018 | * Commit the leaf addition or btree split and start the next | ||
1019 | * trans in the chain. | ||
1020 | */ | ||
1021 | error = xfs_trans_roll(&args->trans, dp); | ||
1022 | if (error) | ||
1023 | goto out; | ||
1024 | |||
1025 | /* | ||
1026 | * If there was an out-of-line value, allocate the blocks we | ||
1027 | * identified for its storage and copy the value. This is done | ||
1028 | * after we create the attribute so that we don't overflow the | ||
1029 | * maximum size of a transaction and/or hit a deadlock. | ||
1030 | */ | ||
1031 | if (args->rmtblkno > 0) { | ||
1032 | error = xfs_attr_rmtval_set(args); | ||
1033 | if (error) | ||
1034 | return error; | ||
1035 | } | ||
1036 | |||
1037 | /* | ||
1038 | * If this is an atomic rename operation, we must "flip" the | ||
1039 | * incomplete flags on the "new" and "old" attribute/value pairs | ||
1040 | * so that one disappears and one appears atomically. Then we | ||
1041 | * must remove the "old" attribute/value pair. | ||
1042 | */ | ||
1043 | if (args->op_flags & XFS_DA_OP_RENAME) { | ||
1044 | /* | ||
1045 | * In a separate transaction, set the incomplete flag on the | ||
1046 | * "old" attr and clear the incomplete flag on the "new" attr. | ||
1047 | */ | ||
1048 | error = xfs_attr3_leaf_flipflags(args); | ||
1049 | if (error) | ||
1050 | goto out; | ||
1051 | |||
1052 | /* | ||
1053 | * Dismantle the "old" attribute/value pair by removing | ||
1054 | * a "remote" value (if it exists). | ||
1055 | */ | ||
1056 | args->index = args->index2; | ||
1057 | args->blkno = args->blkno2; | ||
1058 | args->rmtblkno = args->rmtblkno2; | ||
1059 | args->rmtblkcnt = args->rmtblkcnt2; | ||
1060 | args->rmtvaluelen = args->rmtvaluelen2; | ||
1061 | if (args->rmtblkno) { | ||
1062 | error = xfs_attr_rmtval_remove(args); | ||
1063 | if (error) | ||
1064 | return error; | ||
1065 | } | ||
1066 | |||
1067 | /* | ||
1068 | * Re-find the "old" attribute entry after any split ops. | ||
1069 | * The INCOMPLETE flag means that we will find the "old" | ||
1070 | * attr, not the "new" one. | ||
1071 | */ | ||
1072 | args->flags |= XFS_ATTR_INCOMPLETE; | ||
1073 | state = xfs_da_state_alloc(); | ||
1074 | state->args = args; | ||
1075 | state->mp = mp; | ||
1076 | state->inleaf = 0; | ||
1077 | error = xfs_da3_node_lookup_int(state, &retval); | ||
1078 | if (error) | ||
1079 | goto out; | ||
1080 | |||
1081 | /* | ||
1082 | * Remove the name and update the hashvals in the tree. | ||
1083 | */ | ||
1084 | blk = &state->path.blk[ state->path.active-1 ]; | ||
1085 | ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); | ||
1086 | error = xfs_attr3_leaf_remove(blk->bp, args); | ||
1087 | xfs_da3_fixhashpath(state, &state->path); | ||
1088 | |||
1089 | /* | ||
1090 | * Check to see if the tree needs to be collapsed. | ||
1091 | */ | ||
1092 | if (retval && (state->path.active > 1)) { | ||
1093 | xfs_bmap_init(args->flist, args->firstblock); | ||
1094 | error = xfs_da3_join(state); | ||
1095 | if (!error) { | ||
1096 | error = xfs_bmap_finish(&args->trans, | ||
1097 | args->flist, | ||
1098 | &committed); | ||
1099 | } | ||
1100 | if (error) { | ||
1101 | ASSERT(committed); | ||
1102 | args->trans = NULL; | ||
1103 | xfs_bmap_cancel(args->flist); | ||
1104 | goto out; | ||
1105 | } | ||
1106 | |||
1107 | /* | ||
1108 | * bmap_finish() may have committed the last trans | ||
1109 | * and started a new one. We need the inode to be | ||
1110 | * in all transactions. | ||
1111 | */ | ||
1112 | if (committed) | ||
1113 | xfs_trans_ijoin(args->trans, dp, 0); | ||
1114 | } | ||
1115 | |||
1116 | /* | ||
1117 | * Commit and start the next trans in the chain. | ||
1118 | */ | ||
1119 | error = xfs_trans_roll(&args->trans, dp); | ||
1120 | if (error) | ||
1121 | goto out; | ||
1122 | |||
1123 | } else if (args->rmtblkno > 0) { | ||
1124 | /* | ||
1125 | * Added a "remote" value, just clear the incomplete flag. | ||
1126 | */ | ||
1127 | error = xfs_attr3_leaf_clearflag(args); | ||
1128 | if (error) | ||
1129 | goto out; | ||
1130 | } | ||
1131 | retval = error = 0; | ||
1132 | |||
1133 | out: | ||
1134 | if (state) | ||
1135 | xfs_da_state_free(state); | ||
1136 | if (error) | ||
1137 | return error; | ||
1138 | return retval; | ||
1139 | } | ||
1140 | |||
1141 | /* | ||
1142 | * Remove a name from a B-tree attribute list. | ||
1143 | * | ||
1144 | * This will involve walking down the Btree, and may involve joining | ||
1145 | * leaf nodes and even joining intermediate nodes up to and including | ||
1146 | * the root node (a special case of an intermediate node). | ||
1147 | */ | ||
1148 | STATIC int | ||
1149 | xfs_attr_node_removename(xfs_da_args_t *args) | ||
1150 | { | ||
1151 | xfs_da_state_t *state; | ||
1152 | xfs_da_state_blk_t *blk; | ||
1153 | xfs_inode_t *dp; | ||
1154 | struct xfs_buf *bp; | ||
1155 | int retval, error, committed, forkoff; | ||
1156 | |||
1157 | trace_xfs_attr_node_removename(args); | ||
1158 | |||
1159 | /* | ||
1160 | * Tie a string around our finger to remind us where we are. | ||
1161 | */ | ||
1162 | dp = args->dp; | ||
1163 | state = xfs_da_state_alloc(); | ||
1164 | state->args = args; | ||
1165 | state->mp = dp->i_mount; | ||
1166 | |||
1167 | /* | ||
1168 | * Search to see if name exists, and get back a pointer to it. | ||
1169 | */ | ||
1170 | error = xfs_da3_node_lookup_int(state, &retval); | ||
1171 | if (error || (retval != EEXIST)) { | ||
1172 | if (error == 0) | ||
1173 | error = retval; | ||
1174 | goto out; | ||
1175 | } | ||
1176 | |||
1177 | /* | ||
1178 | * If there is an out-of-line value, de-allocate the blocks. | ||
1179 | * This is done before we remove the attribute so that we don't | ||
1180 | * overflow the maximum size of a transaction and/or hit a deadlock. | ||
1181 | */ | ||
1182 | blk = &state->path.blk[ state->path.active-1 ]; | ||
1183 | ASSERT(blk->bp != NULL); | ||
1184 | ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); | ||
1185 | if (args->rmtblkno > 0) { | ||
1186 | /* | ||
1187 | * Fill in disk block numbers in the state structure | ||
1188 | * so that we can get the buffers back after we commit | ||
1189 | * several transactions in the following calls. | ||
1190 | */ | ||
1191 | error = xfs_attr_fillstate(state); | ||
1192 | if (error) | ||
1193 | goto out; | ||
1194 | |||
1195 | /* | ||
1196 | * Mark the attribute as INCOMPLETE, then bunmapi() the | ||
1197 | * remote value. | ||
1198 | */ | ||
1199 | error = xfs_attr3_leaf_setflag(args); | ||
1200 | if (error) | ||
1201 | goto out; | ||
1202 | error = xfs_attr_rmtval_remove(args); | ||
1203 | if (error) | ||
1204 | goto out; | ||
1205 | |||
1206 | /* | ||
1207 | * Refill the state structure with buffers, the prior calls | ||
1208 | * released our buffers. | ||
1209 | */ | ||
1210 | error = xfs_attr_refillstate(state); | ||
1211 | if (error) | ||
1212 | goto out; | ||
1213 | } | ||
1214 | |||
1215 | /* | ||
1216 | * Remove the name and update the hashvals in the tree. | ||
1217 | */ | ||
1218 | blk = &state->path.blk[ state->path.active-1 ]; | ||
1219 | ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); | ||
1220 | retval = xfs_attr3_leaf_remove(blk->bp, args); | ||
1221 | xfs_da3_fixhashpath(state, &state->path); | ||
1222 | |||
1223 | /* | ||
1224 | * Check to see if the tree needs to be collapsed. | ||
1225 | */ | ||
1226 | if (retval && (state->path.active > 1)) { | ||
1227 | xfs_bmap_init(args->flist, args->firstblock); | ||
1228 | error = xfs_da3_join(state); | ||
1229 | if (!error) { | ||
1230 | error = xfs_bmap_finish(&args->trans, args->flist, | ||
1231 | &committed); | ||
1232 | } | ||
1233 | if (error) { | ||
1234 | ASSERT(committed); | ||
1235 | args->trans = NULL; | ||
1236 | xfs_bmap_cancel(args->flist); | ||
1237 | goto out; | ||
1238 | } | ||
1239 | |||
1240 | /* | ||
1241 | * bmap_finish() may have committed the last trans and started | ||
1242 | * a new one. We need the inode to be in all transactions. | ||
1243 | */ | ||
1244 | if (committed) | ||
1245 | xfs_trans_ijoin(args->trans, dp, 0); | ||
1246 | |||
1247 | /* | ||
1248 | * Commit the Btree join operation and start a new trans. | ||
1249 | */ | ||
1250 | error = xfs_trans_roll(&args->trans, dp); | ||
1251 | if (error) | ||
1252 | goto out; | ||
1253 | } | ||
1254 | |||
1255 | /* | ||
1256 | * If the result is small enough, push it all into the inode. | ||
1257 | */ | ||
1258 | if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { | ||
1259 | /* | ||
1260 | * Have to get rid of the copy of this dabuf in the state. | ||
1261 | */ | ||
1262 | ASSERT(state->path.active == 1); | ||
1263 | ASSERT(state->path.blk[0].bp); | ||
1264 | state->path.blk[0].bp = NULL; | ||
1265 | |||
1266 | error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp); | ||
1267 | if (error) | ||
1268 | goto out; | ||
1269 | |||
1270 | if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { | ||
1271 | xfs_bmap_init(args->flist, args->firstblock); | ||
1272 | error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); | ||
1273 | /* bp is gone due to xfs_da_shrink_inode */ | ||
1274 | if (!error) { | ||
1275 | error = xfs_bmap_finish(&args->trans, | ||
1276 | args->flist, | ||
1277 | &committed); | ||
1278 | } | ||
1279 | if (error) { | ||
1280 | ASSERT(committed); | ||
1281 | args->trans = NULL; | ||
1282 | xfs_bmap_cancel(args->flist); | ||
1283 | goto out; | ||
1284 | } | ||
1285 | |||
1286 | /* | ||
1287 | * bmap_finish() may have committed the last trans | ||
1288 | * and started a new one. We need the inode to be | ||
1289 | * in all transactions. | ||
1290 | */ | ||
1291 | if (committed) | ||
1292 | xfs_trans_ijoin(args->trans, dp, 0); | ||
1293 | } else | ||
1294 | xfs_trans_brelse(args->trans, bp); | ||
1295 | } | ||
1296 | error = 0; | ||
1297 | |||
1298 | out: | ||
1299 | xfs_da_state_free(state); | ||
1300 | return error; | ||
1301 | } | ||
1302 | |||
1303 | /* | ||
1304 | * Fill in the disk block numbers in the state structure for the buffers | ||
1305 | * that are attached to the state structure. | ||
1306 | * This is done so that we can quickly reattach ourselves to those buffers | ||
1307 | * after some set of transaction commits have released these buffers. | ||
1308 | */ | ||
1309 | STATIC int | ||
1310 | xfs_attr_fillstate(xfs_da_state_t *state) | ||
1311 | { | ||
1312 | xfs_da_state_path_t *path; | ||
1313 | xfs_da_state_blk_t *blk; | ||
1314 | int level; | ||
1315 | |||
1316 | trace_xfs_attr_fillstate(state->args); | ||
1317 | |||
1318 | /* | ||
1319 | * Roll down the "path" in the state structure, storing the on-disk | ||
1320 | * block number for those buffers in the "path". | ||
1321 | */ | ||
1322 | path = &state->path; | ||
1323 | ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); | ||
1324 | for (blk = path->blk, level = 0; level < path->active; blk++, level++) { | ||
1325 | if (blk->bp) { | ||
1326 | blk->disk_blkno = XFS_BUF_ADDR(blk->bp); | ||
1327 | blk->bp = NULL; | ||
1328 | } else { | ||
1329 | blk->disk_blkno = 0; | ||
1330 | } | ||
1331 | } | ||
1332 | |||
1333 | /* | ||
1334 | * Roll down the "altpath" in the state structure, storing the on-disk | ||
1335 | * block number for those buffers in the "altpath". | ||
1336 | */ | ||
1337 | path = &state->altpath; | ||
1338 | ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); | ||
1339 | for (blk = path->blk, level = 0; level < path->active; blk++, level++) { | ||
1340 | if (blk->bp) { | ||
1341 | blk->disk_blkno = XFS_BUF_ADDR(blk->bp); | ||
1342 | blk->bp = NULL; | ||
1343 | } else { | ||
1344 | blk->disk_blkno = 0; | ||
1345 | } | ||
1346 | } | ||
1347 | |||
1348 | return 0; | ||
1349 | } | ||
1350 | |||
1351 | /* | ||
1352 | * Reattach the buffers to the state structure based on the disk block | ||
1353 | * numbers stored in the state structure. | ||
1354 | * This is done after some set of transaction commits have released those | ||
1355 | * buffers from our grip. | ||
1356 | */ | ||
1357 | STATIC int | ||
1358 | xfs_attr_refillstate(xfs_da_state_t *state) | ||
1359 | { | ||
1360 | xfs_da_state_path_t *path; | ||
1361 | xfs_da_state_blk_t *blk; | ||
1362 | int level, error; | ||
1363 | |||
1364 | trace_xfs_attr_refillstate(state->args); | ||
1365 | |||
1366 | /* | ||
1367 | * Roll down the "path" in the state structure, storing the on-disk | ||
1368 | * block number for those buffers in the "path". | ||
1369 | */ | ||
1370 | path = &state->path; | ||
1371 | ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); | ||
1372 | for (blk = path->blk, level = 0; level < path->active; blk++, level++) { | ||
1373 | if (blk->disk_blkno) { | ||
1374 | error = xfs_da3_node_read(state->args->trans, | ||
1375 | state->args->dp, | ||
1376 | blk->blkno, blk->disk_blkno, | ||
1377 | &blk->bp, XFS_ATTR_FORK); | ||
1378 | if (error) | ||
1379 | return error; | ||
1380 | } else { | ||
1381 | blk->bp = NULL; | ||
1382 | } | ||
1383 | } | ||
1384 | |||
1385 | /* | ||
1386 | * Roll down the "altpath" in the state structure, storing the on-disk | ||
1387 | * block number for those buffers in the "altpath". | ||
1388 | */ | ||
1389 | path = &state->altpath; | ||
1390 | ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); | ||
1391 | for (blk = path->blk, level = 0; level < path->active; blk++, level++) { | ||
1392 | if (blk->disk_blkno) { | ||
1393 | error = xfs_da3_node_read(state->args->trans, | ||
1394 | state->args->dp, | ||
1395 | blk->blkno, blk->disk_blkno, | ||
1396 | &blk->bp, XFS_ATTR_FORK); | ||
1397 | if (error) | ||
1398 | return error; | ||
1399 | } else { | ||
1400 | blk->bp = NULL; | ||
1401 | } | ||
1402 | } | ||
1403 | |||
1404 | return 0; | ||
1405 | } | ||
1406 | |||
1407 | /* | ||
1408 | * Look up a filename in a node attribute list. | ||
1409 | * | ||
1410 | * This routine gets called for any attribute fork that has more than one | ||
1411 | * block, ie: both true Btree attr lists and for single-leaf-blocks with | ||
1412 | * "remote" values taking up more blocks. | ||
1413 | */ | ||
1414 | STATIC int | ||
1415 | xfs_attr_node_get(xfs_da_args_t *args) | ||
1416 | { | ||
1417 | xfs_da_state_t *state; | ||
1418 | xfs_da_state_blk_t *blk; | ||
1419 | int error, retval; | ||
1420 | int i; | ||
1421 | |||
1422 | trace_xfs_attr_node_get(args); | ||
1423 | |||
1424 | state = xfs_da_state_alloc(); | ||
1425 | state->args = args; | ||
1426 | state->mp = args->dp->i_mount; | ||
1427 | |||
1428 | /* | ||
1429 | * Search to see if name exists, and get back a pointer to it. | ||
1430 | */ | ||
1431 | error = xfs_da3_node_lookup_int(state, &retval); | ||
1432 | if (error) { | ||
1433 | retval = error; | ||
1434 | } else if (retval == EEXIST) { | ||
1435 | blk = &state->path.blk[ state->path.active-1 ]; | ||
1436 | ASSERT(blk->bp != NULL); | ||
1437 | ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); | ||
1438 | |||
1439 | /* | ||
1440 | * Get the value, local or "remote" | ||
1441 | */ | ||
1442 | retval = xfs_attr3_leaf_getvalue(blk->bp, args); | ||
1443 | if (!retval && (args->rmtblkno > 0) | ||
1444 | && !(args->flags & ATTR_KERNOVAL)) { | ||
1445 | retval = xfs_attr_rmtval_get(args); | ||
1446 | } | ||
1447 | } | ||
1448 | |||
1449 | /* | ||
1450 | * If not in a transaction, we have to release all the buffers. | ||
1451 | */ | ||
1452 | for (i = 0; i < state->path.active; i++) { | ||
1453 | xfs_trans_brelse(args->trans, state->path.blk[i].bp); | ||
1454 | state->path.blk[i].bp = NULL; | ||
1455 | } | ||
1456 | |||
1457 | xfs_da_state_free(state); | ||
1458 | return retval; | ||
1459 | } | ||