hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/fs/xfs/libxfs/xfs_attr.c
....@@ -9,23 +9,18 @@
99 #include "xfs_format.h"
1010 #include "xfs_log_format.h"
1111 #include "xfs_trans_resv.h"
12
-#include "xfs_bit.h"
1312 #include "xfs_mount.h"
1413 #include "xfs_defer.h"
1514 #include "xfs_da_format.h"
1615 #include "xfs_da_btree.h"
1716 #include "xfs_attr_sf.h"
1817 #include "xfs_inode.h"
19
-#include "xfs_alloc.h"
2018 #include "xfs_trans.h"
21
-#include "xfs_inode_item.h"
2219 #include "xfs_bmap.h"
23
-#include "xfs_bmap_util.h"
2420 #include "xfs_bmap_btree.h"
2521 #include "xfs_attr.h"
2622 #include "xfs_attr_leaf.h"
2723 #include "xfs_attr_remote.h"
28
-#include "xfs_error.h"
2924 #include "xfs_quota.h"
3025 #include "xfs_trans_space.h"
3126 #include "xfs_trace.h"
....@@ -51,6 +46,7 @@
5146 STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
5247 STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
5348 STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
49
+STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
5450
5551 /*
5652 * Internal routines when attribute list is more than one block.
....@@ -58,42 +54,18 @@
5854 STATIC int xfs_attr_node_get(xfs_da_args_t *args);
5955 STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
6056 STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
57
+STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
58
+ struct xfs_da_state **state);
6159 STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
6260 STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
63
-
64
-
65
-STATIC int
66
-xfs_attr_args_init(
67
- struct xfs_da_args *args,
68
- struct xfs_inode *dp,
69
- const unsigned char *name,
70
- int flags)
71
-{
72
-
73
- if (!name)
74
- return -EINVAL;
75
-
76
- memset(args, 0, sizeof(*args));
77
- args->geo = dp->i_mount->m_attr_geo;
78
- args->whichfork = XFS_ATTR_FORK;
79
- args->dp = dp;
80
- args->flags = flags;
81
- args->name = name;
82
- args->namelen = strlen((const char *)name);
83
- if (args->namelen >= MAXNAMELEN)
84
- return -EFAULT; /* match IRIX behaviour */
85
-
86
- args->hashval = xfs_da_hashname(args->name, args->namelen);
87
- return 0;
88
-}
8961
9062 int
9163 xfs_inode_hasattr(
9264 struct xfs_inode *ip)
9365 {
9466 if (!XFS_IFORK_Q(ip) ||
95
- (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
96
- ip->i_d.di_anextents == 0))
67
+ (ip->i_afp->if_format == XFS_DINODE_FMT_EXTENTS &&
68
+ ip->i_afp->if_nextents == 0))
9769 return 0;
9870 return 1;
9971 }
....@@ -102,57 +74,66 @@
10274 * Overall external interface routines.
10375 *========================================================================*/
10476
105
-/* Retrieve an extended attribute and its value. Must have ilock. */
77
+/*
78
+ * Retrieve an extended attribute and its value. Must have ilock.
79
+ * Returns 0 on successful retrieval, otherwise an error.
80
+ */
10681 int
10782 xfs_attr_get_ilocked(
108
- struct xfs_inode *ip,
10983 struct xfs_da_args *args)
11084 {
111
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
85
+ ASSERT(xfs_isilocked(args->dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
11286
113
- if (!xfs_inode_hasattr(ip))
87
+ if (!xfs_inode_hasattr(args->dp))
11488 return -ENOATTR;
115
- else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
89
+
90
+ if (args->dp->i_afp->if_format == XFS_DINODE_FMT_LOCAL)
11691 return xfs_attr_shortform_getvalue(args);
117
- else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK))
92
+ if (xfs_bmap_one_block(args->dp, XFS_ATTR_FORK))
11893 return xfs_attr_leaf_get(args);
119
- else
120
- return xfs_attr_node_get(args);
94
+ return xfs_attr_node_get(args);
12195 }
12296
123
-/* Retrieve an extended attribute by name, and its value. */
97
+/*
98
+ * Retrieve an extended attribute by name, and its value if requested.
99
+ *
100
+ * If args->valuelen is zero, then the caller does not want the value, just an
101
+ * indication whether the attribute exists and the size of the value if it
102
+ * exists. The size is returned in args.valuelen.
103
+ *
104
+ * If args->value is NULL but args->valuelen is non-zero, allocate the buffer
105
+ * for the value after existence of the attribute has been determined. The
106
+ * caller always has to free args->value if it is set, no matter if this
107
+ * function was successful or not.
108
+ *
109
+ * If the attribute is found, but exceeds the size limit set by the caller in
110
+ * args->valuelen, return -ERANGE with the size of the attribute that was found
111
+ * in args->valuelen.
112
+ */
124113 int
125114 xfs_attr_get(
126
- struct xfs_inode *ip,
127
- const unsigned char *name,
128
- unsigned char *value,
129
- int *valuelenp,
130
- int flags)
115
+ struct xfs_da_args *args)
131116 {
132
- struct xfs_da_args args;
133117 uint lock_mode;
134118 int error;
135119
136
- XFS_STATS_INC(ip->i_mount, xs_attr_get);
120
+ XFS_STATS_INC(args->dp->i_mount, xs_attr_get);
137121
138
- if (XFS_FORCED_SHUTDOWN(ip->i_mount))
122
+ if (XFS_FORCED_SHUTDOWN(args->dp->i_mount))
139123 return -EIO;
140124
141
- error = xfs_attr_args_init(&args, ip, name, flags);
142
- if (error)
143
- return error;
125
+ args->geo = args->dp->i_mount->m_attr_geo;
126
+ args->whichfork = XFS_ATTR_FORK;
127
+ args->hashval = xfs_da_hashname(args->name, args->namelen);
144128
145
- args.value = value;
146
- args.valuelen = *valuelenp;
147129 /* Entirely possible to look up a name which doesn't exist */
148
- args.op_flags = XFS_DA_OP_OKNOENT;
130
+ args->op_flags = XFS_DA_OP_OKNOENT;
149131
150
- lock_mode = xfs_ilock_attr_map_shared(ip);
151
- error = xfs_attr_get_ilocked(ip, &args);
152
- xfs_iunlock(ip, lock_mode);
132
+ lock_mode = xfs_ilock_attr_map_shared(args->dp);
133
+ error = xfs_attr_get_ilocked(args);
134
+ xfs_iunlock(args->dp, lock_mode);
153135
154
- *valuelenp = args.valuelen;
155
- return error == -EEXIST ? 0 : error;
136
+ return error;
156137 }
157138
158139 /*
....@@ -197,8 +178,13 @@
197178 struct xfs_da_args *args)
198179 {
199180
200
- struct xfs_mount *mp = dp->i_mount;
201
- int error, error2;
181
+ int error;
182
+
183
+ /*
184
+ * Build initial attribute list (if required).
185
+ */
186
+ if (dp->i_afp->if_format == XFS_DINODE_FMT_EXTENTS)
187
+ xfs_attr_shortform_create(args);
202188
203189 error = xfs_attr_shortform_addname(args);
204190 if (error == -ENOSPC)
....@@ -208,15 +194,73 @@
208194 * Commit the shortform mods, and we're done.
209195 * NOTE: this is also the error path (EEXIST, etc).
210196 */
211
- if (!error && (args->flags & ATTR_KERNOTIME) == 0)
197
+ if (!error && !(args->op_flags & XFS_DA_OP_NOTIME))
212198 xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
213199
214
- if (mp->m_flags & XFS_MOUNT_WSYNC)
200
+ if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
215201 xfs_trans_set_sync(args->trans);
216202
217
- error2 = xfs_trans_commit(args->trans);
218
- args->trans = NULL;
219
- return error ? error : error2;
203
+ return error;
204
+}
205
+
206
+/*
207
+ * Check to see if the attr should be upgraded from non-existent or shortform to
208
+ * single-leaf-block attribute list.
209
+ */
210
+static inline bool
211
+xfs_attr_is_shortform(
212
+ struct xfs_inode *ip)
213
+{
214
+ return ip->i_afp->if_format == XFS_DINODE_FMT_LOCAL ||
215
+ (ip->i_afp->if_format == XFS_DINODE_FMT_EXTENTS &&
216
+ ip->i_afp->if_nextents == 0);
217
+}
218
+
219
+/*
220
+ * Attempts to set an attr in shortform, or converts short form to leaf form if
221
+ * there is not enough room. If the attr is set, the transaction is committed
222
+ * and set to NULL.
223
+ */
224
+STATIC int
225
+xfs_attr_set_shortform(
226
+ struct xfs_da_args *args,
227
+ struct xfs_buf **leaf_bp)
228
+{
229
+ struct xfs_inode *dp = args->dp;
230
+ int error, error2 = 0;
231
+
232
+ /*
233
+ * Try to add the attr to the attribute list in the inode.
234
+ */
235
+ error = xfs_attr_try_sf_addname(dp, args);
236
+ if (error != -ENOSPC) {
237
+ error2 = xfs_trans_commit(args->trans);
238
+ args->trans = NULL;
239
+ return error ? error : error2;
240
+ }
241
+ /*
242
+ * It won't fit in the shortform, transform to a leaf block. GROT:
243
+ * another possible req'mt for a double-split btree op.
244
+ */
245
+ error = xfs_attr_shortform_to_leaf(args, leaf_bp);
246
+ if (error)
247
+ return error;
248
+
249
+ /*
250
+ * Prevent the leaf buffer from being unlocked so that a concurrent AIL
251
+ * push cannot grab the half-baked leaf buffer and run into problems
252
+ * with the write verifier. Once we're done rolling the transaction we
253
+ * can release the hold and add the attr to the leaf.
254
+ */
255
+ xfs_trans_bhold(args->trans, *leaf_bp);
256
+ error = xfs_defer_finish(&args->trans);
257
+ xfs_trans_bhold_release(args->trans, *leaf_bp);
258
+ if (error) {
259
+ xfs_trans_brelse(args->trans, *leaf_bp);
260
+ return error;
261
+ }
262
+
263
+ return 0;
220264 }
221265
222266 /*
....@@ -228,58 +272,91 @@
228272 {
229273 struct xfs_inode *dp = args->dp;
230274 struct xfs_buf *leaf_bp = NULL;
231
- int error;
275
+ int error = 0;
232276
233277 /*
234
- * If the attribute list is non-existent or a shortform list,
235
- * upgrade it to a single-leaf-block attribute list.
278
+ * If the attribute list is already in leaf format, jump straight to
279
+ * leaf handling. Otherwise, try to add the attribute to the shortform
280
+ * list; if there's no room then convert the list to leaf format and try
281
+ * again.
236282 */
237
- if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
238
- (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
239
- dp->i_d.di_anextents == 0)) {
283
+ if (xfs_attr_is_shortform(dp)) {
240284
241285 /*
242
- * Build initial attribute list (if required).
286
+ * If the attr was successfully set in shortform, the
287
+ * transaction is committed and set to NULL. Otherwise, is it
288
+ * converted from shortform to leaf, and the transaction is
289
+ * retained.
243290 */
244
- if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
245
- xfs_attr_shortform_create(args);
291
+ error = xfs_attr_set_shortform(args, &leaf_bp);
292
+ if (error || !args->trans)
293
+ return error;
294
+ }
246295
247
- /*
248
- * Try to add the attr to the attribute list in the inode.
249
- */
250
- error = xfs_attr_try_sf_addname(dp, args);
296
+ if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
297
+ error = xfs_attr_leaf_addname(args);
251298 if (error != -ENOSPC)
252299 return error;
253300
254301 /*
255
- * It won't fit in the shortform, transform to a leaf block.
256
- * GROT: another possible req'mt for a double-split btree op.
302
+ * Promote the attribute list to the Btree format.
257303 */
258
- error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
304
+ error = xfs_attr3_leaf_to_node(args);
259305 if (error)
260306 return error;
261307
262308 /*
263
- * Prevent the leaf buffer from being unlocked so that a
264
- * concurrent AIL push cannot grab the half-baked leaf
265
- * buffer and run into problems with the write verifier.
266
- * Once we're done rolling the transaction we can release
267
- * the hold and add the attr to the leaf.
309
+ * Finish any deferred work items and roll the transaction once
310
+ * more. The goal here is to call node_addname with the inode
311
+ * and transaction in the same state (inode locked and joined,
312
+ * transaction clean) no matter how we got to this step.
268313 */
269
- xfs_trans_bhold(args->trans, leaf_bp);
270314 error = xfs_defer_finish(&args->trans);
271
- xfs_trans_bhold_release(args->trans, leaf_bp);
272
- if (error) {
273
- xfs_trans_brelse(args->trans, leaf_bp);
315
+ if (error)
274316 return error;
275
- }
317
+
318
+ /*
319
+ * Commit the current trans (including the inode) and
320
+ * start a new one.
321
+ */
322
+ error = xfs_trans_roll_inode(&args->trans, dp);
323
+ if (error)
324
+ return error;
276325 }
277326
278
- if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
279
- error = xfs_attr_leaf_addname(args);
280
- else
281
- error = xfs_attr_node_addname(args);
327
+ error = xfs_attr_node_addname(args);
282328 return error;
329
+}
330
+
331
+/*
332
+ * Return EEXIST if attr is found, or ENOATTR if not
333
+ */
334
+int
335
+xfs_has_attr(
336
+ struct xfs_da_args *args)
337
+{
338
+ struct xfs_inode *dp = args->dp;
339
+ struct xfs_buf *bp = NULL;
340
+ int error;
341
+
342
+ if (!xfs_inode_hasattr(dp))
343
+ return -ENOATTR;
344
+
345
+ if (dp->i_afp->if_format == XFS_DINODE_FMT_LOCAL) {
346
+ ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
347
+ return xfs_attr_sf_findname(args, NULL, NULL);
348
+ }
349
+
350
+ if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
351
+ error = xfs_attr_leaf_hasname(args, &bp);
352
+
353
+ if (bp)
354
+ xfs_trans_brelse(args->trans, bp);
355
+
356
+ return error;
357
+ }
358
+
359
+ return xfs_attr_node_hasname(args, NULL);
283360 }
284361
285362 /*
....@@ -294,7 +371,7 @@
294371
295372 if (!xfs_inode_hasattr(dp)) {
296373 error = -ENOATTR;
297
- } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
374
+ } else if (dp->i_afp->if_format == XFS_DINODE_FMT_LOCAL) {
298375 ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
299376 error = xfs_attr_shortform_remove(args);
300377 } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
....@@ -306,79 +383,115 @@
306383 return error;
307384 }
308385
386
+/*
387
+ * Note: If args->value is NULL the attribute will be removed, just like the
388
+ * Linux ->setattr API.
389
+ */
309390 int
310391 xfs_attr_set(
311
- struct xfs_inode *dp,
312
- const unsigned char *name,
313
- unsigned char *value,
314
- int valuelen,
315
- int flags)
392
+ struct xfs_da_args *args)
316393 {
394
+ struct xfs_inode *dp = args->dp;
317395 struct xfs_mount *mp = dp->i_mount;
318
- struct xfs_da_args args;
319396 struct xfs_trans_res tres;
320
- int rsvd = (flags & ATTR_ROOT) != 0;
397
+ bool rsvd = (args->attr_filter & XFS_ATTR_ROOT);
321398 int error, local;
322
-
323
- XFS_STATS_INC(mp, xs_attr_set);
399
+ unsigned int total;
324400
325401 if (XFS_FORCED_SHUTDOWN(dp->i_mount))
326402 return -EIO;
327
-
328
- error = xfs_attr_args_init(&args, dp, name, flags);
329
- if (error)
330
- return error;
331
-
332
- args.value = value;
333
- args.valuelen = valuelen;
334
- args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
335
- args.total = xfs_attr_calc_size(&args, &local);
336403
337404 error = xfs_qm_dqattach(dp);
338405 if (error)
339406 return error;
340407
408
+ args->geo = mp->m_attr_geo;
409
+ args->whichfork = XFS_ATTR_FORK;
410
+ args->hashval = xfs_da_hashname(args->name, args->namelen);
411
+
341412 /*
342
- * If the inode doesn't have an attribute fork, add one.
343
- * (inode must not be locked when we call this routine)
413
+ * We have no control over the attribute names that userspace passes us
414
+ * to remove, so we have to allow the name lookup prior to attribute
415
+ * removal to fail as well.
344416 */
345
- if (XFS_IFORK_Q(dp) == 0) {
346
- int sf_size = sizeof(xfs_attr_sf_hdr_t) +
347
- XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
417
+ args->op_flags = XFS_DA_OP_OKNOENT;
348418
349
- error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
350
- if (error)
351
- return error;
419
+ if (args->value) {
420
+ XFS_STATS_INC(mp, xs_attr_set);
421
+
422
+ args->op_flags |= XFS_DA_OP_ADDNAME;
423
+ args->total = xfs_attr_calc_size(args, &local);
424
+
425
+ /*
426
+ * If the inode doesn't have an attribute fork, add one.
427
+ * (inode must not be locked when we call this routine)
428
+ */
429
+ if (XFS_IFORK_Q(dp) == 0) {
430
+ int sf_size = sizeof(struct xfs_attr_sf_hdr) +
431
+ xfs_attr_sf_entsize_byname(args->namelen,
432
+ args->valuelen);
433
+
434
+ error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
435
+ if (error)
436
+ return error;
437
+ }
438
+
439
+ tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
440
+ M_RES(mp)->tr_attrsetrt.tr_logres *
441
+ args->total;
442
+ tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
443
+ tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
444
+ total = args->total;
445
+ } else {
446
+ XFS_STATS_INC(mp, xs_attr_remove);
447
+
448
+ tres = M_RES(mp)->tr_attrrm;
449
+ total = XFS_ATTRRM_SPACE_RES(mp);
352450 }
353
-
354
- tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
355
- M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
356
- tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
357
- tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
358451
359452 /*
360453 * Root fork attributes can use reserved data blocks for this
361454 * operation if necessary
362455 */
363
- error = xfs_trans_alloc(mp, &tres, args.total, 0,
364
- rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
456
+ error = xfs_trans_alloc(mp, &tres, total, 0,
457
+ rsvd ? XFS_TRANS_RESERVE : 0, &args->trans);
365458 if (error)
366459 return error;
367460
368461 xfs_ilock(dp, XFS_ILOCK_EXCL);
369
- error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0,
370
- rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
371
- XFS_QMOPT_RES_REGBLKS);
372
- if (error)
373
- goto out_trans_cancel;
462
+ xfs_trans_ijoin(args->trans, dp, 0);
463
+ if (args->value) {
464
+ unsigned int quota_flags = XFS_QMOPT_RES_REGBLKS;
374465
375
- xfs_trans_ijoin(args.trans, dp, 0);
376
- error = xfs_attr_set_args(&args);
377
- if (error)
378
- goto out_trans_cancel;
379
- if (!args.trans) {
466
+ if (rsvd)
467
+ quota_flags |= XFS_QMOPT_FORCE_RES;
468
+ error = xfs_trans_reserve_quota_nblks(args->trans, dp,
469
+ args->total, 0, quota_flags);
470
+ if (error)
471
+ goto out_trans_cancel;
472
+
473
+ error = xfs_has_attr(args);
474
+ if (error == -EEXIST && (args->attr_flags & XATTR_CREATE))
475
+ goto out_trans_cancel;
476
+ if (error == -ENOATTR && (args->attr_flags & XATTR_REPLACE))
477
+ goto out_trans_cancel;
478
+ if (error != -ENOATTR && error != -EEXIST)
479
+ goto out_trans_cancel;
480
+
481
+ error = xfs_attr_set_args(args);
482
+ if (error)
483
+ goto out_trans_cancel;
380484 /* shortform attribute has already been committed */
381
- goto out_unlock;
485
+ if (!args->trans)
486
+ goto out_unlock;
487
+ } else {
488
+ error = xfs_has_attr(args);
489
+ if (error != -EEXIST)
490
+ goto out_trans_cancel;
491
+
492
+ error = xfs_attr_remove_args(args);
493
+ if (error)
494
+ goto out_trans_cancel;
382495 }
383496
384497 /*
....@@ -386,111 +499,37 @@
386499 * transaction goes to disk before returning to the user.
387500 */
388501 if (mp->m_flags & XFS_MOUNT_WSYNC)
389
- xfs_trans_set_sync(args.trans);
502
+ xfs_trans_set_sync(args->trans);
390503
391
- if ((flags & ATTR_KERNOTIME) == 0)
392
- xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
504
+ if (!(args->op_flags & XFS_DA_OP_NOTIME))
505
+ xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
393506
394507 /*
395508 * Commit the last in the sequence of transactions.
396509 */
397
- xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
398
- error = xfs_trans_commit(args.trans);
510
+ xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
511
+ error = xfs_trans_commit(args->trans);
399512 out_unlock:
400513 xfs_iunlock(dp, XFS_ILOCK_EXCL);
401514 return error;
402515
403516 out_trans_cancel:
404
- if (args.trans)
405
- xfs_trans_cancel(args.trans);
517
+ if (args->trans)
518
+ xfs_trans_cancel(args->trans);
406519 goto out_unlock;
407
-}
408
-
409
-/*
410
- * Generic handler routine to remove a name from an attribute list.
411
- * Transitions attribute list from Btree to shortform as necessary.
412
- */
413
-int
414
-xfs_attr_remove(
415
- struct xfs_inode *dp,
416
- const unsigned char *name,
417
- int flags)
418
-{
419
- struct xfs_mount *mp = dp->i_mount;
420
- struct xfs_da_args args;
421
- int error;
422
-
423
- XFS_STATS_INC(mp, xs_attr_remove);
424
-
425
- if (XFS_FORCED_SHUTDOWN(dp->i_mount))
426
- return -EIO;
427
-
428
- error = xfs_attr_args_init(&args, dp, name, flags);
429
- if (error)
430
- return error;
431
-
432
- /*
433
- * we have no control over the attribute names that userspace passes us
434
- * to remove, so we have to allow the name lookup prior to attribute
435
- * removal to fail.
436
- */
437
- args.op_flags = XFS_DA_OP_OKNOENT;
438
-
439
- error = xfs_qm_dqattach(dp);
440
- if (error)
441
- return error;
442
-
443
- /*
444
- * Root fork attributes can use reserved data blocks for this
445
- * operation if necessary
446
- */
447
- error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
448
- XFS_ATTRRM_SPACE_RES(mp), 0,
449
- (flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
450
- &args.trans);
451
- if (error)
452
- return error;
453
-
454
- xfs_ilock(dp, XFS_ILOCK_EXCL);
455
- /*
456
- * No need to make quota reservations here. We expect to release some
457
- * blocks not allocate in the common case.
458
- */
459
- xfs_trans_ijoin(args.trans, dp, 0);
460
-
461
- error = xfs_attr_remove_args(&args);
462
- if (error)
463
- goto out;
464
-
465
- /*
466
- * If this is a synchronous mount, make sure that the
467
- * transaction goes to disk before returning to the user.
468
- */
469
- if (mp->m_flags & XFS_MOUNT_WSYNC)
470
- xfs_trans_set_sync(args.trans);
471
-
472
- if ((flags & ATTR_KERNOTIME) == 0)
473
- xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
474
-
475
- /*
476
- * Commit the last in the sequence of transactions.
477
- */
478
- xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
479
- error = xfs_trans_commit(args.trans);
480
- xfs_iunlock(dp, XFS_ILOCK_EXCL);
481
-
482
- return error;
483
-
484
-out:
485
- if (args.trans)
486
- xfs_trans_cancel(args.trans);
487
- xfs_iunlock(dp, XFS_ILOCK_EXCL);
488
- return error;
489520 }
490521
491522 /*========================================================================
492523 * External routines when attribute list is inside the inode
493524 *========================================================================*/
525
+
526
+static inline int xfs_attr_sf_totsize(struct xfs_inode *dp)
527
+{
528
+ struct xfs_attr_shortform *sf;
529
+
530
+ sf = (struct xfs_attr_shortform *)dp->i_afp->if_u1.if_data;
531
+ return be16_to_cpu(sf->hdr.totsize);
532
+}
494533
495534 /*
496535 * Add a name to the shortform attribute list structure
....@@ -504,10 +543,10 @@
504543 trace_xfs_attr_sf_addname(args);
505544
506545 retval = xfs_attr_shortform_lookup(args);
507
- if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
546
+ if (retval == -ENOATTR && (args->attr_flags & XATTR_REPLACE))
508547 return retval;
509
- } else if (retval == -EEXIST) {
510
- if (args->flags & ATTR_CREATE)
548
+ if (retval == -EEXIST) {
549
+ if (args->attr_flags & XATTR_CREATE)
511550 return retval;
512551 retval = xfs_attr_shortform_remove(args);
513552 if (retval)
....@@ -517,15 +556,15 @@
517556 * that the leaf format add routine won't trip over the attr
518557 * not being around.
519558 */
520
- args->flags &= ~ATTR_REPLACE;
559
+ args->attr_flags &= ~XATTR_REPLACE;
521560 }
522561
523562 if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
524563 args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
525564 return -ENOSPC;
526565
527
- newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
528
- newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
566
+ newsize = xfs_attr_sf_totsize(args->dp);
567
+ newsize += xfs_attr_sf_entsize_byname(args->namelen, args->valuelen);
529568
530569 forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
531570 if (!forkoff)
....@@ -540,54 +579,65 @@
540579 * External routines when attribute list is one block
541580 *========================================================================*/
542581
543
-/*
544
- * Add a name to the leaf attribute list structure
545
- *
546
- * This leaf block cannot have a "remote" value, we only call this routine
547
- * if bmap_one_block() says there is only one block (ie: no remote blks).
548
- */
549
-STATIC int
550
-xfs_attr_leaf_addname(
582
+/* Store info about a remote block */
583
+STATIC void
584
+xfs_attr_save_rmt_blk(
551585 struct xfs_da_args *args)
552586 {
553
- struct xfs_inode *dp;
554
- struct xfs_buf *bp;
555
- int retval, error, forkoff;
587
+ args->blkno2 = args->blkno;
588
+ args->index2 = args->index;
589
+ args->rmtblkno2 = args->rmtblkno;
590
+ args->rmtblkcnt2 = args->rmtblkcnt;
591
+ args->rmtvaluelen2 = args->rmtvaluelen;
592
+}
556593
557
- trace_xfs_attr_leaf_addname(args);
594
+/* Set stored info about a remote block */
595
+STATIC void
596
+xfs_attr_restore_rmt_blk(
597
+ struct xfs_da_args *args)
598
+{
599
+ args->blkno = args->blkno2;
600
+ args->index = args->index2;
601
+ args->rmtblkno = args->rmtblkno2;
602
+ args->rmtblkcnt = args->rmtblkcnt2;
603
+ args->rmtvaluelen = args->rmtvaluelen2;
604
+}
558605
559
- /*
560
- * Read the (only) block in the attribute list in.
561
- */
562
- dp = args->dp;
563
- args->blkno = 0;
564
- error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
565
- if (error)
566
- return error;
606
+/*
607
+ * Tries to add an attribute to an inode in leaf form
608
+ *
609
+ * This function is meant to execute as part of a delayed operation and leaves
610
+ * the transaction handling to the caller. On success the attribute is added
611
+ * and the inode and transaction are left dirty. If there is not enough space,
612
+ * the attr data is converted to node format and -ENOSPC is returned. Caller is
613
+ * responsible for handling the dirty inode and transaction or adding the attr
614
+ * in node format.
615
+ */
616
+STATIC int
617
+xfs_attr_leaf_try_add(
618
+ struct xfs_da_args *args,
619
+ struct xfs_buf *bp)
620
+{
621
+ int retval;
567622
568623 /*
569624 * Look up the given attribute in the leaf block. Figure out if
570625 * the given flags produce an error or call for an atomic rename.
571626 */
572
- retval = xfs_attr3_leaf_lookup_int(bp, args);
573
- if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
574
- xfs_trans_brelse(args->trans, bp);
627
+ retval = xfs_attr_leaf_hasname(args, &bp);
628
+ if (retval != -ENOATTR && retval != -EEXIST)
575629 return retval;
576
- } else if (retval == -EEXIST) {
577
- if (args->flags & ATTR_CREATE) { /* pure create op */
578
- xfs_trans_brelse(args->trans, bp);
579
- return retval;
580
- }
630
+ if (retval == -ENOATTR && (args->attr_flags & XATTR_REPLACE))
631
+ goto out_brelse;
632
+ if (retval == -EEXIST) {
633
+ if (args->attr_flags & XATTR_CREATE)
634
+ goto out_brelse;
581635
582636 trace_xfs_attr_leaf_replace(args);
583637
584638 /* save the attribute state for later removal*/
585639 args->op_flags |= XFS_DA_OP_RENAME; /* an atomic rename */
586
- args->blkno2 = args->blkno; /* set 2nd entry info*/
587
- args->index2 = args->index;
588
- args->rmtblkno2 = args->rmtblkno;
589
- args->rmtblkcnt2 = args->rmtblkcnt;
590
- args->rmtvaluelen2 = args->rmtvaluelen;
640
+ xfs_attr_save_rmt_blk(args);
591641
592642 /*
593643 * clear the remote attr state now that it is saved so that the
....@@ -600,37 +650,35 @@
600650 }
601651
602652 /*
603
- * Add the attribute to the leaf block, transitioning to a Btree
604
- * if required.
653
+ * Add the attribute to the leaf block
605654 */
606
- retval = xfs_attr3_leaf_add(bp, args);
607
- if (retval == -ENOSPC) {
608
- /*
609
- * Promote the attribute list to the Btree format, then
610
- * Commit that transaction so that the node_addname() call
611
- * can manage its own transactions.
612
- */
613
- error = xfs_attr3_leaf_to_node(args);
614
- if (error)
615
- return error;
616
- error = xfs_defer_finish(&args->trans);
617
- if (error)
618
- return error;
655
+ return xfs_attr3_leaf_add(bp, args);
619656
620
- /*
621
- * Commit the current trans (including the inode) and start
622
- * a new one.
623
- */
624
- error = xfs_trans_roll_inode(&args->trans, dp);
625
- if (error)
626
- return error;
657
+out_brelse:
658
+ xfs_trans_brelse(args->trans, bp);
659
+ return retval;
660
+}
627661
628
- /*
629
- * Fob the whole rest of the problem off on the Btree code.
630
- */
631
- error = xfs_attr_node_addname(args);
662
+
663
+/*
664
+ * Add a name to the leaf attribute list structure
665
+ *
666
+ * This leaf block cannot have a "remote" value, we only call this routine
667
+ * if bmap_one_block() says there is only one block (ie: no remote blks).
668
+ */
669
+STATIC int
670
+xfs_attr_leaf_addname(
671
+ struct xfs_da_args *args)
672
+{
673
+ int error, forkoff;
674
+ struct xfs_buf *bp = NULL;
675
+ struct xfs_inode *dp = args->dp;
676
+
677
+ trace_xfs_attr_leaf_addname(args);
678
+
679
+ error = xfs_attr_leaf_try_add(args, bp);
680
+ if (error)
632681 return error;
633
- }
634682
635683 /*
636684 * Commit the transaction that added the attr name so that
....@@ -652,71 +700,92 @@
652700 return error;
653701 }
654702
655
- /*
656
- * If this is an atomic rename operation, we must "flip" the
657
- * incomplete flags on the "new" and "old" attribute/value pairs
658
- * so that one disappears and one appears atomically. Then we
659
- * must remove the "old" attribute/value pair.
660
- */
661
- if (args->op_flags & XFS_DA_OP_RENAME) {
662
- /*
663
- * In a separate transaction, set the incomplete flag on the
664
- * "old" attr and clear the incomplete flag on the "new" attr.
665
- */
666
- error = xfs_attr3_leaf_flipflags(args);
667
- if (error)
668
- return error;
669
-
670
- /*
671
- * Dismantle the "old" attribute/value pair by removing
672
- * a "remote" value (if it exists).
673
- */
674
- args->index = args->index2;
675
- args->blkno = args->blkno2;
676
- args->rmtblkno = args->rmtblkno2;
677
- args->rmtblkcnt = args->rmtblkcnt2;
678
- args->rmtvaluelen = args->rmtvaluelen2;
679
- if (args->rmtblkno) {
680
- error = xfs_attr_rmtval_remove(args);
681
- if (error)
682
- return error;
683
- }
684
-
685
- /*
686
- * Read in the block containing the "old" attr, then
687
- * remove the "old" attr from that block (neat, huh!)
688
- */
689
- error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
690
- -1, &bp);
691
- if (error)
692
- return error;
693
-
694
- xfs_attr3_leaf_remove(bp, args);
695
-
696
- /*
697
- * If the result is small enough, shrink it all into the inode.
698
- */
699
- if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
700
- error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
701
- /* bp is gone due to xfs_da_shrink_inode */
702
- if (error)
703
- return error;
704
- error = xfs_defer_finish(&args->trans);
705
- if (error)
706
- return error;
707
- }
708
-
709
- /*
710
- * Commit the remove and start the next trans in series.
711
- */
712
- error = xfs_trans_roll_inode(&args->trans, dp);
713
-
714
- } else if (args->rmtblkno > 0) {
703
+ if (!(args->op_flags & XFS_DA_OP_RENAME)) {
715704 /*
716705 * Added a "remote" value, just clear the incomplete flag.
717706 */
718
- error = xfs_attr3_leaf_clearflag(args);
707
+ if (args->rmtblkno > 0)
708
+ error = xfs_attr3_leaf_clearflag(args);
709
+
710
+ return error;
719711 }
712
+
713
+ /*
714
+ * If this is an atomic rename operation, we must "flip" the incomplete
715
+ * flags on the "new" and "old" attribute/value pairs so that one
716
+ * disappears and one appears atomically. Then we must remove the "old"
717
+ * attribute/value pair.
718
+ *
719
+ * In a separate transaction, set the incomplete flag on the "old" attr
720
+ * and clear the incomplete flag on the "new" attr.
721
+ */
722
+
723
+ error = xfs_attr3_leaf_flipflags(args);
724
+ if (error)
725
+ return error;
726
+ /*
727
+ * Commit the flag value change and start the next trans in series.
728
+ */
729
+ error = xfs_trans_roll_inode(&args->trans, args->dp);
730
+ if (error)
731
+ return error;
732
+
733
+ /*
734
+ * Dismantle the "old" attribute/value pair by removing a "remote" value
735
+ * (if it exists).
736
+ */
737
+ xfs_attr_restore_rmt_blk(args);
738
+
739
+ if (args->rmtblkno) {
740
+ error = xfs_attr_rmtval_invalidate(args);
741
+ if (error)
742
+ return error;
743
+
744
+ error = xfs_attr_rmtval_remove(args);
745
+ if (error)
746
+ return error;
747
+ }
748
+
749
+ /*
750
+ * Read in the block containing the "old" attr, then remove the "old"
751
+ * attr from that block (neat, huh!)
752
+ */
753
+ error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
754
+ &bp);
755
+ if (error)
756
+ return error;
757
+
758
+ xfs_attr3_leaf_remove(bp, args);
759
+
760
+ /*
761
+ * If the result is small enough, shrink it all into the inode.
762
+ */
763
+ forkoff = xfs_attr_shortform_allfit(bp, dp);
764
+ if (forkoff)
765
+ error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
766
+ /* bp is gone due to xfs_da_shrink_inode */
767
+
768
+ return error;
769
+}
770
+
771
+/*
772
+ * Return EEXIST if attr is found, or ENOATTR if not
773
+ */
774
+STATIC int
775
+xfs_attr_leaf_hasname(
776
+ struct xfs_da_args *args,
777
+ struct xfs_buf **bp)
778
+{
779
+ int error = 0;
780
+
781
+ error = xfs_attr3_leaf_read(args->trans, args->dp, 0, bp);
782
+ if (error)
783
+ return error;
784
+
785
+ error = xfs_attr3_leaf_lookup_int(*bp, args);
786
+ if (error != -ENOATTR && error != -EEXIST)
787
+ xfs_trans_brelse(args->trans, *bp);
788
+
720789 return error;
721790 }
722791
....@@ -740,31 +809,25 @@
740809 * Remove the attribute.
741810 */
742811 dp = args->dp;
743
- args->blkno = 0;
744
- error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
745
- if (error)
746
- return error;
747812
748
- error = xfs_attr3_leaf_lookup_int(bp, args);
813
+ error = xfs_attr_leaf_hasname(args, &bp);
814
+
749815 if (error == -ENOATTR) {
750816 xfs_trans_brelse(args->trans, bp);
751817 return error;
752
- }
818
+ } else if (error != -EEXIST)
819
+ return error;
753820
754821 xfs_attr3_leaf_remove(bp, args);
755822
756823 /*
757824 * If the result is small enough, shrink it all into the inode.
758825 */
759
- if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
760
- error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
826
+ forkoff = xfs_attr_shortform_allfit(bp, dp);
827
+ if (forkoff)
828
+ return xfs_attr3_leaf_to_shortform(bp, args, forkoff);
761829 /* bp is gone due to xfs_da_shrink_inode */
762
- if (error)
763
- return error;
764
- error = xfs_defer_finish(&args->trans);
765
- if (error)
766
- return error;
767
- }
830
+
768831 return 0;
769832 }
770833
....@@ -773,6 +836,8 @@
773836 *
774837 * This leaf block cannot have a "remote" value, we only call this routine
775838 * if bmap_one_block() says there is only one block (ie: no remote blks).
839
+ *
840
+ * Returns 0 on successful retrieval, otherwise an error.
776841 */
777842 STATIC int
778843 xfs_attr_leaf_get(xfs_da_args_t *args)
....@@ -782,22 +847,48 @@
782847
783848 trace_xfs_attr_leaf_get(args);
784849
785
- args->blkno = 0;
786
- error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
787
- if (error)
788
- return error;
850
+ error = xfs_attr_leaf_hasname(args, &bp);
789851
790
- error = xfs_attr3_leaf_lookup_int(bp, args);
791
- if (error != -EEXIST) {
852
+ if (error == -ENOATTR) {
792853 xfs_trans_brelse(args->trans, bp);
793854 return error;
794
- }
855
+ } else if (error != -EEXIST)
856
+ return error;
857
+
858
+
795859 error = xfs_attr3_leaf_getvalue(bp, args);
796860 xfs_trans_brelse(args->trans, bp);
797
- if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) {
798
- error = xfs_attr_rmtval_get(args);
799
- }
800861 return error;
862
+}
863
+
864
+/*
865
+ * Return EEXIST if attr is found, or ENOATTR if not
866
+ * statep: If not null is set to point at the found state. Caller will
867
+ * be responsible for freeing the state in this case.
868
+ */
869
+STATIC int
870
+xfs_attr_node_hasname(
871
+ struct xfs_da_args *args,
872
+ struct xfs_da_state **statep)
873
+{
874
+ struct xfs_da_state *state;
875
+ int retval, error;
876
+
877
+ state = xfs_da_state_alloc(args);
878
+ if (statep != NULL)
879
+ *statep = state;
880
+
881
+ /*
882
+ * Search to see if name exists, and get back a pointer to it.
883
+ */
884
+ error = xfs_da3_node_lookup_int(state, &retval);
885
+ if (error)
886
+ retval = error;
887
+
888
+ if (!statep)
889
+ xfs_da_state_free(state);
890
+
891
+ return retval;
801892 }
802893
803894 /*========================================================================
....@@ -821,7 +912,6 @@
821912 struct xfs_da_state *state;
822913 struct xfs_da_state_blk *blk;
823914 struct xfs_inode *dp;
824
- struct xfs_mount *mp;
825915 int retval, error;
826916
827917 trace_xfs_attr_node_addname(args);
....@@ -830,36 +920,29 @@
830920 * Fill in bucket of arguments/results/context to carry around.
831921 */
832922 dp = args->dp;
833
- mp = dp->i_mount;
834923 restart:
835
- state = xfs_da_state_alloc();
836
- state->args = args;
837
- state->mp = mp;
838
-
839924 /*
840925 * Search to see if name already exists, and get back a pointer
841926 * to where it should go.
842927 */
843
- error = xfs_da3_node_lookup_int(state, &retval);
844
- if (error)
928
+ error = 0;
929
+ retval = xfs_attr_node_hasname(args, &state);
930
+ if (retval != -ENOATTR && retval != -EEXIST)
845931 goto out;
932
+
846933 blk = &state->path.blk[ state->path.active-1 ];
847934 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
848
- if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
935
+ if (retval == -ENOATTR && (args->attr_flags & XATTR_REPLACE))
849936 goto out;
850
- } else if (retval == -EEXIST) {
851
- if (args->flags & ATTR_CREATE)
937
+ if (retval == -EEXIST) {
938
+ if (args->attr_flags & XATTR_CREATE)
852939 goto out;
853940
854941 trace_xfs_attr_node_replace(args);
855942
856943 /* save the attribute state for later removal*/
857944 args->op_flags |= XFS_DA_OP_RENAME; /* atomic rename op */
858
- args->blkno2 = args->blkno; /* set 2nd entry info*/
859
- args->index2 = args->index;
860
- args->rmtblkno2 = args->rmtblkno;
861
- args->rmtblkcnt2 = args->rmtblkcnt;
862
- args->rmtvaluelen2 = args->rmtvaluelen;
945
+ xfs_attr_save_rmt_blk(args);
863946
864947 /*
865948 * clear the remote attr state now that it is saved so that the
....@@ -945,82 +1028,75 @@
9451028 return error;
9461029 }
9471030
948
- /*
949
- * If this is an atomic rename operation, we must "flip" the
950
- * incomplete flags on the "new" and "old" attribute/value pairs
951
- * so that one disappears and one appears atomically. Then we
952
- * must remove the "old" attribute/value pair.
953
- */
954
- if (args->op_flags & XFS_DA_OP_RENAME) {
955
- /*
956
- * In a separate transaction, set the incomplete flag on the
957
- * "old" attr and clear the incomplete flag on the "new" attr.
958
- */
959
- error = xfs_attr3_leaf_flipflags(args);
960
- if (error)
961
- goto out;
962
-
963
- /*
964
- * Dismantle the "old" attribute/value pair by removing
965
- * a "remote" value (if it exists).
966
- */
967
- args->index = args->index2;
968
- args->blkno = args->blkno2;
969
- args->rmtblkno = args->rmtblkno2;
970
- args->rmtblkcnt = args->rmtblkcnt2;
971
- args->rmtvaluelen = args->rmtvaluelen2;
972
- if (args->rmtblkno) {
973
- error = xfs_attr_rmtval_remove(args);
974
- if (error)
975
- return error;
976
- }
977
-
978
- /*
979
- * Re-find the "old" attribute entry after any split ops.
980
- * The INCOMPLETE flag means that we will find the "old"
981
- * attr, not the "new" one.
982
- */
983
- args->flags |= XFS_ATTR_INCOMPLETE;
984
- state = xfs_da_state_alloc();
985
- state->args = args;
986
- state->mp = mp;
987
- state->inleaf = 0;
988
- error = xfs_da3_node_lookup_int(state, &retval);
989
- if (error)
990
- goto out;
991
-
992
- /*
993
- * Remove the name and update the hashvals in the tree.
994
- */
995
- blk = &state->path.blk[ state->path.active-1 ];
996
- ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
997
- error = xfs_attr3_leaf_remove(blk->bp, args);
998
- xfs_da3_fixhashpath(state, &state->path);
999
-
1000
- /*
1001
- * Check to see if the tree needs to be collapsed.
1002
- */
1003
- if (retval && (state->path.active > 1)) {
1004
- error = xfs_da3_join(state);
1005
- if (error)
1006
- goto out;
1007
- error = xfs_defer_finish(&args->trans);
1008
- if (error)
1009
- goto out;
1010
- }
1011
-
1012
- /*
1013
- * Commit and start the next trans in the chain.
1014
- */
1015
- error = xfs_trans_roll_inode(&args->trans, dp);
1016
- if (error)
1017
- goto out;
1018
-
1019
- } else if (args->rmtblkno > 0) {
1031
+ if (!(args->op_flags & XFS_DA_OP_RENAME)) {
10201032 /*
10211033 * Added a "remote" value, just clear the incomplete flag.
10221034 */
1023
- error = xfs_attr3_leaf_clearflag(args);
1035
+ if (args->rmtblkno > 0)
1036
+ error = xfs_attr3_leaf_clearflag(args);
1037
+ retval = error;
1038
+ goto out;
1039
+ }
1040
+
1041
+ /*
1042
+ * If this is an atomic rename operation, we must "flip" the incomplete
1043
+ * flags on the "new" and "old" attribute/value pairs so that one
1044
+ * disappears and one appears atomically. Then we must remove the "old"
1045
+ * attribute/value pair.
1046
+ *
1047
+ * In a separate transaction, set the incomplete flag on the "old" attr
1048
+ * and clear the incomplete flag on the "new" attr.
1049
+ */
1050
+ error = xfs_attr3_leaf_flipflags(args);
1051
+ if (error)
1052
+ goto out;
1053
+ /*
1054
+ * Commit the flag value change and start the next trans in series
1055
+ */
1056
+ error = xfs_trans_roll_inode(&args->trans, args->dp);
1057
+ if (error)
1058
+ goto out;
1059
+
1060
+ /*
1061
+ * Dismantle the "old" attribute/value pair by removing a "remote" value
1062
+ * (if it exists).
1063
+ */
1064
+ xfs_attr_restore_rmt_blk(args);
1065
+
1066
+ if (args->rmtblkno) {
1067
+ error = xfs_attr_rmtval_invalidate(args);
1068
+ if (error)
1069
+ return error;
1070
+
1071
+ error = xfs_attr_rmtval_remove(args);
1072
+ if (error)
1073
+ return error;
1074
+ }
1075
+
1076
+ /*
1077
+ * Re-find the "old" attribute entry after any split ops. The INCOMPLETE
1078
+ * flag means that we will find the "old" attr, not the "new" one.
1079
+ */
1080
+ args->attr_filter |= XFS_ATTR_INCOMPLETE;
1081
+ state = xfs_da_state_alloc(args);
1082
+ state->inleaf = 0;
1083
+ error = xfs_da3_node_lookup_int(state, &retval);
1084
+ if (error)
1085
+ goto out;
1086
+
1087
+ /*
1088
+ * Remove the name and update the hashvals in the tree.
1089
+ */
1090
+ blk = &state->path.blk[state->path.active-1];
1091
+ ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1092
+ error = xfs_attr3_leaf_remove(blk->bp, args);
1093
+ xfs_da3_fixhashpath(state, &state->path);
1094
+
1095
+ /*
1096
+ * Check to see if the tree needs to be collapsed.
1097
+ */
1098
+ if (retval && (state->path.active > 1)) {
1099
+ error = xfs_da3_join(state);
10241100 if (error)
10251101 goto out;
10261102 }
....@@ -1032,6 +1108,114 @@
10321108 if (error)
10331109 return error;
10341110 return retval;
1111
+}
1112
+
1113
+/*
1114
+ * Shrink an attribute from leaf to shortform
1115
+ */
1116
+STATIC int
1117
+xfs_attr_node_shrink(
1118
+ struct xfs_da_args *args,
1119
+ struct xfs_da_state *state)
1120
+{
1121
+ struct xfs_inode *dp = args->dp;
1122
+ int error, forkoff;
1123
+ struct xfs_buf *bp;
1124
+
1125
+ /*
1126
+ * Have to get rid of the copy of this dabuf in the state.
1127
+ */
1128
+ ASSERT(state->path.active == 1);
1129
+ ASSERT(state->path.blk[0].bp);
1130
+ state->path.blk[0].bp = NULL;
1131
+
1132
+ error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
1133
+ if (error)
1134
+ return error;
1135
+
1136
+ forkoff = xfs_attr_shortform_allfit(bp, dp);
1137
+ if (forkoff) {
1138
+ error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
1139
+ /* bp is gone due to xfs_da_shrink_inode */
1140
+ } else
1141
+ xfs_trans_brelse(args->trans, bp);
1142
+
1143
+ return error;
1144
+}
1145
+
1146
+/*
1147
+ * Mark an attribute entry INCOMPLETE and save pointers to the relevant buffers
1148
+ * for later deletion of the entry.
1149
+ */
1150
+STATIC int
1151
+xfs_attr_leaf_mark_incomplete(
1152
+ struct xfs_da_args *args,
1153
+ struct xfs_da_state *state)
1154
+{
1155
+ int error;
1156
+
1157
+ /*
1158
+ * Fill in disk block numbers in the state structure
1159
+ * so that we can get the buffers back after we commit
1160
+ * several transactions in the following calls.
1161
+ */
1162
+ error = xfs_attr_fillstate(state);
1163
+ if (error)
1164
+ return error;
1165
+
1166
+ /*
1167
+ * Mark the attribute as INCOMPLETE
1168
+ */
1169
+ return xfs_attr3_leaf_setflag(args);
1170
+}
1171
+
1172
+/*
1173
+ * Initial setup for xfs_attr_node_removename. Make sure the attr is there and
1174
+ * the blocks are valid. Attr keys with remote blocks will be marked
1175
+ * incomplete.
1176
+ */
1177
+STATIC
1178
+int xfs_attr_node_removename_setup(
1179
+ struct xfs_da_args *args,
1180
+ struct xfs_da_state **state)
1181
+{
1182
+ int error;
1183
+
1184
+ error = xfs_attr_node_hasname(args, state);
1185
+ if (error != -EEXIST)
1186
+ return error;
1187
+
1188
+ ASSERT((*state)->path.blk[(*state)->path.active - 1].bp != NULL);
1189
+ ASSERT((*state)->path.blk[(*state)->path.active - 1].magic ==
1190
+ XFS_ATTR_LEAF_MAGIC);
1191
+
1192
+ if (args->rmtblkno > 0) {
1193
+ error = xfs_attr_leaf_mark_incomplete(args, *state);
1194
+ if (error)
1195
+ return error;
1196
+
1197
+ return xfs_attr_rmtval_invalidate(args);
1198
+ }
1199
+
1200
+ return 0;
1201
+}
1202
+
1203
+STATIC int
1204
+xfs_attr_node_remove_rmt(
1205
+ struct xfs_da_args *args,
1206
+ struct xfs_da_state *state)
1207
+{
1208
+ int error = 0;
1209
+
1210
+ error = xfs_attr_rmtval_remove(args);
1211
+ if (error)
1212
+ return error;
1213
+
1214
+ /*
1215
+ * Refill the state structure with buffers, the prior calls released our
1216
+ * buffers.
1217
+ */
1218
+ return xfs_attr_refillstate(state);
10351219 }
10361220
10371221 /*
....@@ -1047,64 +1231,22 @@
10471231 {
10481232 struct xfs_da_state *state;
10491233 struct xfs_da_state_blk *blk;
1050
- struct xfs_inode *dp;
1051
- struct xfs_buf *bp;
1052
- int retval, error, forkoff;
1234
+ int retval, error;
1235
+ struct xfs_inode *dp = args->dp;
10531236
10541237 trace_xfs_attr_node_removename(args);
10551238
1056
- /*
1057
- * Tie a string around our finger to remind us where we are.
1058
- */
1059
- dp = args->dp;
1060
- state = xfs_da_state_alloc();
1061
- state->args = args;
1062
- state->mp = dp->i_mount;
1063
-
1064
- /*
1065
- * Search to see if name exists, and get back a pointer to it.
1066
- */
1067
- error = xfs_da3_node_lookup_int(state, &retval);
1068
- if (error || (retval != -EEXIST)) {
1069
- if (error == 0)
1070
- error = retval;
1239
+ error = xfs_attr_node_removename_setup(args, &state);
1240
+ if (error)
10711241 goto out;
1072
- }
10731242
10741243 /*
10751244 * If there is an out-of-line value, de-allocate the blocks.
10761245 * This is done before we remove the attribute so that we don't
10771246 * overflow the maximum size of a transaction and/or hit a deadlock.
10781247 */
1079
- blk = &state->path.blk[ state->path.active-1 ];
1080
- ASSERT(blk->bp != NULL);
1081
- ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
10821248 if (args->rmtblkno > 0) {
1083
- /*
1084
- * Fill in disk block numbers in the state structure
1085
- * so that we can get the buffers back after we commit
1086
- * several transactions in the following calls.
1087
- */
1088
- error = xfs_attr_fillstate(state);
1089
- if (error)
1090
- goto out;
1091
-
1092
- /*
1093
- * Mark the attribute as INCOMPLETE, then bunmapi() the
1094
- * remote value.
1095
- */
1096
- error = xfs_attr3_leaf_setflag(args);
1097
- if (error)
1098
- goto out;
1099
- error = xfs_attr_rmtval_remove(args);
1100
- if (error)
1101
- goto out;
1102
-
1103
- /*
1104
- * Refill the state structure with buffers, the prior calls
1105
- * released our buffers.
1106
- */
1107
- error = xfs_attr_refillstate(state);
1249
+ error = xfs_attr_node_remove_rmt(args, state);
11081250 if (error)
11091251 goto out;
11101252 }
....@@ -1138,33 +1280,12 @@
11381280 /*
11391281 * If the result is small enough, push it all into the inode.
11401282 */
1141
- if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
1142
- /*
1143
- * Have to get rid of the copy of this dabuf in the state.
1144
- */
1145
- ASSERT(state->path.active == 1);
1146
- ASSERT(state->path.blk[0].bp);
1147
- state->path.blk[0].bp = NULL;
1148
-
1149
- error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
1150
- if (error)
1151
- goto out;
1152
-
1153
- if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
1154
- error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
1155
- /* bp is gone due to xfs_da_shrink_inode */
1156
- if (error)
1157
- goto out;
1158
- error = xfs_defer_finish(&args->trans);
1159
- if (error)
1160
- goto out;
1161
- } else
1162
- xfs_trans_brelse(args->trans, bp);
1163
- }
1164
- error = 0;
1283
+ if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
1284
+ error = xfs_attr_node_shrink(args, state);
11651285
11661286 out:
1167
- xfs_da_state_free(state);
1287
+ if (state)
1288
+ xfs_da_state_free(state);
11681289 return error;
11691290 }
11701291
....@@ -1239,10 +1360,9 @@
12391360 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
12401361 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
12411362 if (blk->disk_blkno) {
1242
- error = xfs_da3_node_read(state->args->trans,
1243
- state->args->dp,
1244
- blk->blkno, blk->disk_blkno,
1245
- &blk->bp, XFS_ATTR_FORK);
1363
+ error = xfs_da3_node_read_mapped(state->args->trans,
1364
+ state->args->dp, blk->disk_blkno,
1365
+ &blk->bp, XFS_ATTR_FORK);
12461366 if (error)
12471367 return error;
12481368 } else {
....@@ -1258,10 +1378,9 @@
12581378 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
12591379 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
12601380 if (blk->disk_blkno) {
1261
- error = xfs_da3_node_read(state->args->trans,
1262
- state->args->dp,
1263
- blk->blkno, blk->disk_blkno,
1264
- &blk->bp, XFS_ATTR_FORK);
1381
+ error = xfs_da3_node_read_mapped(state->args->trans,
1382
+ state->args->dp, blk->disk_blkno,
1383
+ &blk->bp, XFS_ATTR_FORK);
12651384 if (error)
12661385 return error;
12671386 } else {
....@@ -1273,55 +1392,65 @@
12731392 }
12741393
12751394 /*
1276
- * Look up a filename in a node attribute list.
1395
+ * Retrieve the attribute data from a node attribute list.
12771396 *
12781397 * This routine gets called for any attribute fork that has more than one
12791398 * block, ie: both true Btree attr lists and for single-leaf-blocks with
12801399 * "remote" values taking up more blocks.
1400
+ *
1401
+ * Returns 0 on successful retrieval, otherwise an error.
12811402 */
12821403 STATIC int
1283
-xfs_attr_node_get(xfs_da_args_t *args)
1404
+xfs_attr_node_get(
1405
+ struct xfs_da_args *args)
12841406 {
1285
- xfs_da_state_t *state;
1286
- xfs_da_state_blk_t *blk;
1287
- int error, retval;
1288
- int i;
1407
+ struct xfs_da_state *state;
1408
+ struct xfs_da_state_blk *blk;
1409
+ int i;
1410
+ int error;
12891411
12901412 trace_xfs_attr_node_get(args);
1291
-
1292
- state = xfs_da_state_alloc();
1293
- state->args = args;
1294
- state->mp = args->dp->i_mount;
12951413
12961414 /*
12971415 * Search to see if name exists, and get back a pointer to it.
12981416 */
1299
- error = xfs_da3_node_lookup_int(state, &retval);
1300
- if (error) {
1301
- retval = error;
1302
- } else if (retval == -EEXIST) {
1303
- blk = &state->path.blk[ state->path.active-1 ];
1304
- ASSERT(blk->bp != NULL);
1305
- ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1417
+ error = xfs_attr_node_hasname(args, &state);
1418
+ if (error != -EEXIST)
1419
+ goto out_release;
13061420
1307
- /*
1308
- * Get the value, local or "remote"
1309
- */
1310
- retval = xfs_attr3_leaf_getvalue(blk->bp, args);
1311
- if (!retval && (args->rmtblkno > 0)
1312
- && !(args->flags & ATTR_KERNOVAL)) {
1313
- retval = xfs_attr_rmtval_get(args);
1314
- }
1315
- }
1421
+ /*
1422
+ * Get the value, local or "remote"
1423
+ */
1424
+ blk = &state->path.blk[state->path.active - 1];
1425
+ error = xfs_attr3_leaf_getvalue(blk->bp, args);
13161426
13171427 /*
13181428 * If not in a transaction, we have to release all the buffers.
13191429 */
1320
- for (i = 0; i < state->path.active; i++) {
1430
+out_release:
1431
+ for (i = 0; state != NULL && i < state->path.active; i++) {
13211432 xfs_trans_brelse(args->trans, state->path.blk[i].bp);
13221433 state->path.blk[i].bp = NULL;
13231434 }
13241435
1325
- xfs_da_state_free(state);
1326
- return retval;
1436
+ if (state)
1437
+ xfs_da_state_free(state);
1438
+ return error;
1439
+}
1440
+
1441
+/* Returns true if the attribute entry name is valid. */
1442
+bool
1443
+xfs_attr_namecheck(
1444
+ const void *name,
1445
+ size_t length)
1446
+{
1447
+ /*
1448
+ * MAXNAMELEN includes the trailing null, but (name/length) leave it
1449
+ * out, so use >= for the length check.
1450
+ */
1451
+ if (length >= MAXNAMELEN)
1452
+ return false;
1453
+
1454
+ /* There shouldn't be any nulls here */
1455
+ return !memchr(name, 0, length);
13271456 }