1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2022 Oracle. All Rights Reserved.
4 * Author: Allison Henderson <allison.henderson@oracle.com>
5 */
6
7 #include "xfs_platform.h"
8 #include "xfs_fs.h"
9 #include "xfs_format.h"
10 #include "xfs_trans_resv.h"
11 #include "xfs_shared.h"
12 #include "xfs_mount.h"
13 #include "xfs_defer.h"
14 #include "xfs_log_format.h"
15 #include "xfs_trans.h"
16 #include "xfs_bmap_btree.h"
17 #include "xfs_trans_priv.h"
18 #include "xfs_log.h"
19 #include "xfs_inode.h"
20 #include "xfs_da_format.h"
21 #include "xfs_da_btree.h"
22 #include "xfs_attr.h"
23 #include "xfs_attr_item.h"
24 #include "xfs_trace.h"
25 #include "xfs_trans_space.h"
26 #include "xfs_errortag.h"
27 #include "xfs_error.h"
28 #include "xfs_log_priv.h"
29 #include "xfs_log_recover.h"
30 #include "xfs_parent.h"
31
32 struct kmem_cache *xfs_attri_cache;
33 struct kmem_cache *xfs_attrd_cache;
34
35 static const struct xfs_item_ops xfs_attri_item_ops;
36 static const struct xfs_item_ops xfs_attrd_item_ops;
37
ATTRI_ITEM(struct xfs_log_item * lip)38 static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)
39 {
40 return container_of(lip, struct xfs_attri_log_item, attri_item);
41 }
42
43 /*
44 * Shared xattr name/value buffers for logged extended attribute operations
45 *
46 * When logging updates to extended attributes, we can create quite a few
47 * attribute log intent items for a single xattr update. To avoid cycling the
48 * memory allocator and memcpy overhead, the name (and value, for setxattr)
49 * are kept in a refcounted object that is shared across all related log items
50 * and the upper-level deferred work state structure. The shared buffer has
51 * a control structure, followed by the name, and then the value.
52 */
53
54 static inline struct xfs_attri_log_nameval *
xfs_attri_log_nameval_get(struct xfs_attri_log_nameval * nv)55 xfs_attri_log_nameval_get(
56 struct xfs_attri_log_nameval *nv)
57 {
58 if (!refcount_inc_not_zero(&nv->refcount))
59 return NULL;
60 return nv;
61 }
62
63 static inline void
xfs_attri_log_nameval_put(struct xfs_attri_log_nameval * nv)64 xfs_attri_log_nameval_put(
65 struct xfs_attri_log_nameval *nv)
66 {
67 if (!nv)
68 return;
69 if (refcount_dec_and_test(&nv->refcount))
70 kvfree(nv);
71 }
72
73 static inline struct xfs_attri_log_nameval *
xfs_attri_log_nameval_alloc(const void * name,unsigned int name_len,const void * new_name,unsigned int new_name_len,const void * value,unsigned int value_len,const void * new_value,unsigned int new_value_len)74 xfs_attri_log_nameval_alloc(
75 const void *name,
76 unsigned int name_len,
77 const void *new_name,
78 unsigned int new_name_len,
79 const void *value,
80 unsigned int value_len,
81 const void *new_value,
82 unsigned int new_value_len)
83 {
84 struct xfs_attri_log_nameval *nv;
85
86 /*
87 * This could be over 64kB in length, so we have to use kvmalloc() for
88 * this. But kvmalloc() utterly sucks, so we use our own version.
89 */
90 nv = xlog_kvmalloc(sizeof(struct xfs_attri_log_nameval) +
91 name_len + new_name_len + value_len +
92 new_value_len);
93
94 nv->name.iov_base = nv + 1;
95 nv->name.iov_len = name_len;
96 memcpy(nv->name.iov_base, name, name_len);
97
98 if (new_name_len) {
99 nv->new_name.iov_base = nv->name.iov_base + name_len;
100 nv->new_name.iov_len = new_name_len;
101 memcpy(nv->new_name.iov_base, new_name, new_name_len);
102 } else {
103 nv->new_name.iov_base = NULL;
104 nv->new_name.iov_len = 0;
105 }
106
107 if (value_len) {
108 nv->value.iov_base = nv->name.iov_base + name_len + new_name_len;
109 nv->value.iov_len = value_len;
110 memcpy(nv->value.iov_base, value, value_len);
111 } else {
112 nv->value.iov_base = NULL;
113 nv->value.iov_len = 0;
114 }
115
116 if (new_value_len) {
117 nv->new_value.iov_base = nv->name.iov_base + name_len +
118 new_name_len + value_len;
119 nv->new_value.iov_len = new_value_len;
120 memcpy(nv->new_value.iov_base, new_value, new_value_len);
121 } else {
122 nv->new_value.iov_base = NULL;
123 nv->new_value.iov_len = 0;
124 }
125
126 refcount_set(&nv->refcount, 1);
127 return nv;
128 }
129
130 STATIC void
xfs_attri_item_free(struct xfs_attri_log_item * attrip)131 xfs_attri_item_free(
132 struct xfs_attri_log_item *attrip)
133 {
134 kvfree(attrip->attri_item.li_lv_shadow);
135 xfs_attri_log_nameval_put(attrip->attri_nameval);
136 kmem_cache_free(xfs_attri_cache, attrip);
137 }
138
139 /*
140 * Freeing the attrip requires that we remove it from the AIL if it has already
141 * been placed there. However, the ATTRI may not yet have been placed in the
142 * AIL when called by xfs_attri_release() from ATTRD processing due to the
143 * ordering of committed vs unpin operations in bulk insert operations. Hence
144 * the reference count to ensure only the last caller frees the ATTRI.
145 */
146 STATIC void
xfs_attri_release(struct xfs_attri_log_item * attrip)147 xfs_attri_release(
148 struct xfs_attri_log_item *attrip)
149 {
150 ASSERT(atomic_read(&attrip->attri_refcount) > 0);
151 if (!atomic_dec_and_test(&attrip->attri_refcount))
152 return;
153
154 xfs_trans_ail_delete(&attrip->attri_item, 0);
155 xfs_attri_item_free(attrip);
156 }
157
158 STATIC void
xfs_attri_item_size(struct xfs_log_item * lip,int * nvecs,int * nbytes)159 xfs_attri_item_size(
160 struct xfs_log_item *lip,
161 int *nvecs,
162 int *nbytes)
163 {
164 struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip);
165 struct xfs_attri_log_nameval *nv = attrip->attri_nameval;
166
167 *nvecs += 2;
168 *nbytes += sizeof(struct xfs_attri_log_format) +
169 xlog_calc_iovec_len(nv->name.iov_len);
170
171 if (nv->new_name.iov_len) {
172 *nvecs += 1;
173 *nbytes += xlog_calc_iovec_len(nv->new_name.iov_len);
174 }
175
176 if (nv->value.iov_len) {
177 *nvecs += 1;
178 *nbytes += xlog_calc_iovec_len(nv->value.iov_len);
179 }
180
181 if (nv->new_value.iov_len) {
182 *nvecs += 1;
183 *nbytes += xlog_calc_iovec_len(nv->new_value.iov_len);
184 }
185 }
186
187 /*
188 * This is called to fill in the log iovecs for the given attri log
189 * item. We use 1 iovec for the attri_format_item, 1 for the name, and
190 * another for the value if it is present
191 */
192 STATIC void
xfs_attri_item_format(struct xfs_log_item * lip,struct xlog_format_buf * lfb)193 xfs_attri_item_format(
194 struct xfs_log_item *lip,
195 struct xlog_format_buf *lfb)
196 {
197 struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip);
198 struct xfs_attri_log_nameval *nv = attrip->attri_nameval;
199
200 attrip->attri_format.alfi_type = XFS_LI_ATTRI;
201 attrip->attri_format.alfi_size = 1;
202
203 /*
204 * This size accounting must be done before copying the attrip into the
205 * iovec. If we do it after, the wrong size will be recorded to the log
206 * and we trip across assertion checks for bad region sizes later during
207 * the log recovery.
208 */
209
210 ASSERT(nv->name.iov_len > 0);
211 attrip->attri_format.alfi_size++;
212
213 if (nv->new_name.iov_len > 0)
214 attrip->attri_format.alfi_size++;
215
216 if (nv->value.iov_len > 0)
217 attrip->attri_format.alfi_size++;
218
219 if (nv->new_value.iov_len > 0)
220 attrip->attri_format.alfi_size++;
221
222 xlog_format_copy(lfb, XLOG_REG_TYPE_ATTRI_FORMAT, &attrip->attri_format,
223 sizeof(struct xfs_attri_log_format));
224
225 xlog_format_copy(lfb, XLOG_REG_TYPE_ATTR_NAME, nv->name.iov_base,
226 nv->name.iov_len);
227
228 if (nv->new_name.iov_len > 0)
229 xlog_format_copy(lfb, XLOG_REG_TYPE_ATTR_NEWNAME,
230 nv->new_name.iov_base, nv->new_name.iov_len);
231
232 if (nv->value.iov_len > 0)
233 xlog_format_copy(lfb, XLOG_REG_TYPE_ATTR_VALUE,
234 nv->value.iov_base, nv->value.iov_len);
235
236 if (nv->new_value.iov_len > 0)
237 xlog_format_copy(lfb, XLOG_REG_TYPE_ATTR_NEWVALUE,
238 nv->new_value.iov_base, nv->new_value.iov_len);
239 }
240
241 /*
242 * The unpin operation is the last place an ATTRI is manipulated in the log. It
243 * is either inserted in the AIL or aborted in the event of a log I/O error. In
244 * either case, the ATTRI transaction has been successfully committed to make
245 * it this far. Therefore, we expect whoever committed the ATTRI to either
246 * construct and commit the ATTRD or drop the ATTRD's reference in the event of
247 * error. Simply drop the log's ATTRI reference now that the log is done with
248 * it.
249 */
250 STATIC void
xfs_attri_item_unpin(struct xfs_log_item * lip,int remove)251 xfs_attri_item_unpin(
252 struct xfs_log_item *lip,
253 int remove)
254 {
255 xfs_attri_release(ATTRI_ITEM(lip));
256 }
257
258
259 STATIC void
xfs_attri_item_release(struct xfs_log_item * lip)260 xfs_attri_item_release(
261 struct xfs_log_item *lip)
262 {
263 xfs_attri_release(ATTRI_ITEM(lip));
264 }
265
266 /*
267 * Allocate and initialize an attri item. Caller may allocate an additional
268 * trailing buffer for name and value
269 */
270 STATIC struct xfs_attri_log_item *
xfs_attri_init(struct xfs_mount * mp,struct xfs_attri_log_nameval * nv)271 xfs_attri_init(
272 struct xfs_mount *mp,
273 struct xfs_attri_log_nameval *nv)
274 {
275 struct xfs_attri_log_item *attrip;
276
277 attrip = kmem_cache_zalloc(xfs_attri_cache, GFP_KERNEL | __GFP_NOFAIL);
278
279 /*
280 * Grab an extra reference to the name/value buffer for this log item.
281 * The caller retains its own reference!
282 */
283 attrip->attri_nameval = xfs_attri_log_nameval_get(nv);
284 ASSERT(attrip->attri_nameval);
285
286 xfs_log_item_init(mp, &attrip->attri_item, XFS_LI_ATTRI,
287 &xfs_attri_item_ops);
288 attrip->attri_format.alfi_id = (uintptr_t)(void *)attrip;
289 atomic_set(&attrip->attri_refcount, 2);
290
291 return attrip;
292 }
293
ATTRD_ITEM(struct xfs_log_item * lip)294 static inline struct xfs_attrd_log_item *ATTRD_ITEM(struct xfs_log_item *lip)
295 {
296 return container_of(lip, struct xfs_attrd_log_item, attrd_item);
297 }
298
299 STATIC void
xfs_attrd_item_free(struct xfs_attrd_log_item * attrdp)300 xfs_attrd_item_free(struct xfs_attrd_log_item *attrdp)
301 {
302 kvfree(attrdp->attrd_item.li_lv_shadow);
303 kmem_cache_free(xfs_attrd_cache, attrdp);
304 }
305
306 STATIC void
xfs_attrd_item_size(struct xfs_log_item * lip,int * nvecs,int * nbytes)307 xfs_attrd_item_size(
308 struct xfs_log_item *lip,
309 int *nvecs,
310 int *nbytes)
311 {
312 *nvecs += 1;
313 *nbytes += sizeof(struct xfs_attrd_log_format);
314 }
315
316 /*
317 * This is called to fill in the log iovecs for the given attrd log item. We use
318 * only 1 iovec for the attrd_format, and we point that at the attr_log_format
319 * structure embedded in the attrd item.
320 */
321 STATIC void
xfs_attrd_item_format(struct xfs_log_item * lip,struct xlog_format_buf * lfb)322 xfs_attrd_item_format(
323 struct xfs_log_item *lip,
324 struct xlog_format_buf *lfb)
325 {
326 struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip);
327
328 attrdp->attrd_format.alfd_type = XFS_LI_ATTRD;
329 attrdp->attrd_format.alfd_size = 1;
330
331 xlog_format_copy(lfb, XLOG_REG_TYPE_ATTRD_FORMAT,
332 &attrdp->attrd_format,
333 sizeof(struct xfs_attrd_log_format));
334 }
335
336 /*
337 * The ATTRD is either committed or aborted if the transaction is canceled. If
338 * the transaction is canceled, drop our reference to the ATTRI and free the
339 * ATTRD.
340 */
341 STATIC void
xfs_attrd_item_release(struct xfs_log_item * lip)342 xfs_attrd_item_release(
343 struct xfs_log_item *lip)
344 {
345 struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip);
346
347 xfs_attri_release(attrdp->attrd_attrip);
348 xfs_attrd_item_free(attrdp);
349 }
350
351 static struct xfs_log_item *
xfs_attrd_item_intent(struct xfs_log_item * lip)352 xfs_attrd_item_intent(
353 struct xfs_log_item *lip)
354 {
355 return &ATTRD_ITEM(lip)->attrd_attrip->attri_item;
356 }
357
358 static inline unsigned int
xfs_attr_log_item_op(const struct xfs_attri_log_format * attrp)359 xfs_attr_log_item_op(const struct xfs_attri_log_format *attrp)
360 {
361 return attrp->alfi_op_flags & XFS_ATTRI_OP_FLAGS_TYPE_MASK;
362 }
363
364 /* Log an attr to the intent item. */
365 STATIC void
xfs_attr_log_item(struct xfs_trans * tp,struct xfs_attri_log_item * attrip,const struct xfs_attr_intent * attr)366 xfs_attr_log_item(
367 struct xfs_trans *tp,
368 struct xfs_attri_log_item *attrip,
369 const struct xfs_attr_intent *attr)
370 {
371 struct xfs_attri_log_format *attrp;
372 struct xfs_attri_log_nameval *nv = attr->xattri_nameval;
373 struct xfs_da_args *args = attr->xattri_da_args;
374
375 /*
376 * At this point the xfs_attr_intent has been constructed, and we've
377 * created the log intent. Fill in the attri log item and log format
378 * structure with fields from this xfs_attr_intent
379 */
380 attrp = &attrip->attri_format;
381 attrp->alfi_ino = args->dp->i_ino;
382 ASSERT(!(attr->xattri_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK));
383 attrp->alfi_op_flags = attr->xattri_op_flags;
384 attrp->alfi_value_len = nv->value.iov_len;
385
386 switch (xfs_attr_log_item_op(attrp)) {
387 case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:
388 ASSERT(nv->value.iov_len == nv->new_value.iov_len);
389
390 attrp->alfi_igen = VFS_I(args->dp)->i_generation;
391 attrp->alfi_old_name_len = nv->name.iov_len;
392 attrp->alfi_new_name_len = nv->new_name.iov_len;
393 break;
394 case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:
395 case XFS_ATTRI_OP_FLAGS_PPTR_SET:
396 attrp->alfi_igen = VFS_I(args->dp)->i_generation;
397 fallthrough;
398 default:
399 attrp->alfi_name_len = nv->name.iov_len;
400 break;
401 }
402
403 ASSERT(!(args->attr_filter & ~XFS_ATTRI_FILTER_MASK));
404 attrp->alfi_attr_filter = args->attr_filter;
405 }
406
407 /* Get an ATTRI. */
408 static struct xfs_log_item *
xfs_attr_create_intent(struct xfs_trans * tp,struct list_head * items,unsigned int count,bool sort)409 xfs_attr_create_intent(
410 struct xfs_trans *tp,
411 struct list_head *items,
412 unsigned int count,
413 bool sort)
414 {
415 struct xfs_mount *mp = tp->t_mountp;
416 struct xfs_attri_log_item *attrip;
417 struct xfs_attr_intent *attr;
418 struct xfs_da_args *args;
419
420 ASSERT(count == 1);
421
422 /*
423 * Each attr item only performs one attribute operation at a time, so
424 * this is a list of one
425 */
426 attr = list_first_entry_or_null(items, struct xfs_attr_intent,
427 xattri_list);
428 args = attr->xattri_da_args;
429
430 if (!(args->op_flags & XFS_DA_OP_LOGGED))
431 return NULL;
432
433 /*
434 * Create a buffer to store the attribute name and value. This buffer
435 * will be shared between the higher level deferred xattr work state
436 * and the lower level xattr log items.
437 */
438 if (!attr->xattri_nameval) {
439 /*
440 * Transfer our reference to the name/value buffer to the
441 * deferred work state structure.
442 */
443 attr->xattri_nameval = xfs_attri_log_nameval_alloc(
444 args->name, args->namelen,
445 args->new_name, args->new_namelen,
446 args->value, args->valuelen,
447 args->new_value, args->new_valuelen);
448 }
449
450 attrip = xfs_attri_init(mp, attr->xattri_nameval);
451 xfs_attr_log_item(tp, attrip, attr);
452
453 return &attrip->attri_item;
454 }
455
456 static inline void
xfs_attr_free_item(struct xfs_attr_intent * attr)457 xfs_attr_free_item(
458 struct xfs_attr_intent *attr)
459 {
460 if (attr->xattri_da_state)
461 xfs_da_state_free(attr->xattri_da_state);
462 xfs_attri_log_nameval_put(attr->xattri_nameval);
463 if (attr->xattri_da_args->op_flags & XFS_DA_OP_RECOVERY)
464 kfree(attr);
465 else
466 kmem_cache_free(xfs_attr_intent_cache, attr);
467 }
468
attri_entry(const struct list_head * e)469 static inline struct xfs_attr_intent *attri_entry(const struct list_head *e)
470 {
471 return list_entry(e, struct xfs_attr_intent, xattri_list);
472 }
473
474 /* Process an attr. */
475 STATIC int
xfs_attr_finish_item(struct xfs_trans * tp,struct xfs_log_item * done,struct list_head * item,struct xfs_btree_cur ** state)476 xfs_attr_finish_item(
477 struct xfs_trans *tp,
478 struct xfs_log_item *done,
479 struct list_head *item,
480 struct xfs_btree_cur **state)
481 {
482 struct xfs_attr_intent *attr = attri_entry(item);
483 struct xfs_da_args *args;
484 int error;
485
486 args = attr->xattri_da_args;
487
488 /* Reset trans after EAGAIN cycle since the transaction is new */
489 args->trans = tp;
490
491 if (XFS_TEST_ERROR(args->dp->i_mount, XFS_ERRTAG_LARP)) {
492 error = -EIO;
493 goto out;
494 }
495
496 /* If an attr removal is trivially complete, we're done. */
497 if (attr->xattri_op_flags == XFS_ATTRI_OP_FLAGS_REMOVE &&
498 !xfs_inode_hasattr(args->dp)) {
499 error = 0;
500 goto out;
501 }
502
503 error = xfs_attr_set_iter(attr);
504 if (!error && attr->xattri_dela_state != XFS_DAS_DONE)
505 return -EAGAIN;
506
507 out:
508 xfs_attr_free_item(attr);
509 return error;
510 }
511
512 /* Abort all pending ATTRs. */
513 STATIC void
xfs_attr_abort_intent(struct xfs_log_item * intent)514 xfs_attr_abort_intent(
515 struct xfs_log_item *intent)
516 {
517 xfs_attri_release(ATTRI_ITEM(intent));
518 }
519
520 /* Cancel an attr */
521 STATIC void
xfs_attr_cancel_item(struct list_head * item)522 xfs_attr_cancel_item(
523 struct list_head *item)
524 {
525 struct xfs_attr_intent *attr = attri_entry(item);
526
527 xfs_attr_free_item(attr);
528 }
529
530 STATIC bool
xfs_attri_item_match(struct xfs_log_item * lip,uint64_t intent_id)531 xfs_attri_item_match(
532 struct xfs_log_item *lip,
533 uint64_t intent_id)
534 {
535 return ATTRI_ITEM(lip)->attri_format.alfi_id == intent_id;
536 }
537
538 static inline bool
xfs_attri_validate_namelen(unsigned int namelen)539 xfs_attri_validate_namelen(unsigned int namelen)
540 {
541 return namelen > 0 && namelen <= XATTR_NAME_MAX;
542 }
543
544 /* Is this recovered ATTRI format ok? */
545 static inline bool
xfs_attri_validate(struct xfs_mount * mp,struct xfs_attri_log_format * attrp)546 xfs_attri_validate(
547 struct xfs_mount *mp,
548 struct xfs_attri_log_format *attrp)
549 {
550 unsigned int op = xfs_attr_log_item_op(attrp);
551
552 if (attrp->alfi_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK)
553 return false;
554
555 if (attrp->alfi_attr_filter & ~XFS_ATTRI_FILTER_MASK)
556 return false;
557
558 if (!xfs_attr_check_namespace(attrp->alfi_attr_filter &
559 XFS_ATTR_NSP_ONDISK_MASK))
560 return false;
561
562 switch (op) {
563 case XFS_ATTRI_OP_FLAGS_PPTR_SET:
564 case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:
565 if (!xfs_has_parent(mp))
566 return false;
567 if (attrp->alfi_value_len != sizeof(struct xfs_parent_rec))
568 return false;
569 if (!xfs_attri_validate_namelen(attrp->alfi_name_len))
570 return false;
571 if (!(attrp->alfi_attr_filter & XFS_ATTR_PARENT))
572 return false;
573 break;
574 case XFS_ATTRI_OP_FLAGS_SET:
575 case XFS_ATTRI_OP_FLAGS_REPLACE:
576 if (!xfs_is_using_logged_xattrs(mp))
577 return false;
578 if (attrp->alfi_value_len > XATTR_SIZE_MAX)
579 return false;
580 if (!xfs_attri_validate_namelen(attrp->alfi_name_len))
581 return false;
582 break;
583 case XFS_ATTRI_OP_FLAGS_REMOVE:
584 if (!xfs_is_using_logged_xattrs(mp))
585 return false;
586 if (attrp->alfi_value_len != 0)
587 return false;
588 if (!xfs_attri_validate_namelen(attrp->alfi_name_len))
589 return false;
590 break;
591 case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:
592 if (!xfs_has_parent(mp))
593 return false;
594 if (!xfs_attri_validate_namelen(attrp->alfi_old_name_len))
595 return false;
596 if (!xfs_attri_validate_namelen(attrp->alfi_new_name_len))
597 return false;
598 if (attrp->alfi_value_len != sizeof(struct xfs_parent_rec))
599 return false;
600 if (!(attrp->alfi_attr_filter & XFS_ATTR_PARENT))
601 return false;
602 break;
603 default:
604 return false;
605 }
606
607 return xfs_verify_ino(mp, attrp->alfi_ino);
608 }
609
610 static int
xfs_attri_iread_extents(struct xfs_inode * ip)611 xfs_attri_iread_extents(
612 struct xfs_inode *ip)
613 {
614 struct xfs_trans *tp;
615 int error;
616
617 tp = xfs_trans_alloc_empty(ip->i_mount);
618 xfs_ilock(ip, XFS_ILOCK_EXCL);
619 error = xfs_iread_extents(tp, ip, XFS_ATTR_FORK);
620 xfs_iunlock(ip, XFS_ILOCK_EXCL);
621 xfs_trans_cancel(tp);
622
623 return error;
624 }
625
626 static inline struct xfs_attr_intent *
xfs_attri_recover_work(struct xfs_mount * mp,struct xfs_defer_pending * dfp,struct xfs_attri_log_format * attrp,struct xfs_inode ** ipp,struct xfs_attri_log_nameval * nv)627 xfs_attri_recover_work(
628 struct xfs_mount *mp,
629 struct xfs_defer_pending *dfp,
630 struct xfs_attri_log_format *attrp,
631 struct xfs_inode **ipp,
632 struct xfs_attri_log_nameval *nv)
633 {
634 struct xfs_attr_intent *attr;
635 struct xfs_da_args *args;
636 struct xfs_inode *ip;
637 int local;
638 int error;
639
640 /*
641 * Parent pointer attr items record the generation but regular logged
642 * xattrs do not; select the right iget function.
643 */
644 switch (xfs_attr_log_item_op(attrp)) {
645 case XFS_ATTRI_OP_FLAGS_PPTR_SET:
646 case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:
647 case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:
648 error = xlog_recover_iget_handle(mp, attrp->alfi_ino,
649 attrp->alfi_igen, &ip);
650 break;
651 default:
652 error = xlog_recover_iget(mp, attrp->alfi_ino, &ip);
653 break;
654 }
655 if (error) {
656 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, attrp,
657 sizeof(*attrp));
658 return ERR_PTR(-EFSCORRUPTED);
659 }
660
661 if (xfs_inode_has_attr_fork(ip)) {
662 error = xfs_attri_iread_extents(ip);
663 if (error) {
664 xfs_irele(ip);
665 return ERR_PTR(error);
666 }
667 }
668
669 attr = kzalloc(sizeof(struct xfs_attr_intent) +
670 sizeof(struct xfs_da_args), GFP_KERNEL | __GFP_NOFAIL);
671 args = (struct xfs_da_args *)(attr + 1);
672
673 attr->xattri_da_args = args;
674 attr->xattri_op_flags = xfs_attr_log_item_op(attrp);
675
676 /*
677 * We're reconstructing the deferred work state structure from the
678 * recovered log item. Grab a reference to the name/value buffer and
679 * attach it to the new work state.
680 */
681 attr->xattri_nameval = xfs_attri_log_nameval_get(nv);
682 ASSERT(attr->xattri_nameval);
683
684 args->dp = ip;
685 args->geo = mp->m_attr_geo;
686 args->whichfork = XFS_ATTR_FORK;
687 args->name = nv->name.iov_base;
688 args->namelen = nv->name.iov_len;
689 args->new_name = nv->new_name.iov_base;
690 args->new_namelen = nv->new_name.iov_len;
691 args->value = nv->value.iov_base;
692 args->valuelen = nv->value.iov_len;
693 args->new_value = nv->new_value.iov_base;
694 args->new_valuelen = nv->new_value.iov_len;
695 args->attr_filter = attrp->alfi_attr_filter & XFS_ATTRI_FILTER_MASK;
696 args->op_flags = XFS_DA_OP_RECOVERY | XFS_DA_OP_OKNOENT |
697 XFS_DA_OP_LOGGED;
698 args->owner = args->dp->i_ino;
699 xfs_attr_sethash(args);
700
701 switch (xfs_attr_intent_op(attr)) {
702 case XFS_ATTRI_OP_FLAGS_PPTR_SET:
703 case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:
704 case XFS_ATTRI_OP_FLAGS_SET:
705 case XFS_ATTRI_OP_FLAGS_REPLACE:
706 args->total = xfs_attr_calc_size(args, &local);
707 if (xfs_inode_hasattr(args->dp))
708 attr->xattri_dela_state = xfs_attr_init_replace_state(args);
709 else
710 attr->xattri_dela_state = xfs_attr_init_add_state(args);
711 break;
712 case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:
713 case XFS_ATTRI_OP_FLAGS_REMOVE:
714 attr->xattri_dela_state = xfs_attr_init_remove_state(args);
715 break;
716 }
717
718 xfs_defer_add_item(dfp, &attr->xattri_list);
719 *ipp = ip;
720 return attr;
721 }
722
723 /*
724 * Process an attr intent item that was recovered from the log. We need to
725 * delete the attr that it describes.
726 */
727 STATIC int
xfs_attr_recover_work(struct xfs_defer_pending * dfp,struct list_head * capture_list)728 xfs_attr_recover_work(
729 struct xfs_defer_pending *dfp,
730 struct list_head *capture_list)
731 {
732 struct xfs_log_item *lip = dfp->dfp_intent;
733 struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip);
734 struct xfs_attr_intent *attr;
735 struct xfs_mount *mp = lip->li_log->l_mp;
736 struct xfs_inode *ip = NULL;
737 struct xfs_da_args *args;
738 struct xfs_trans *tp;
739 struct xfs_trans_res resv;
740 struct xfs_attri_log_format *attrp;
741 struct xfs_attri_log_nameval *nv = attrip->attri_nameval;
742 int error;
743 unsigned int total = 0;
744
745 /*
746 * First check the validity of the attr described by the ATTRI. If any
747 * are bad, then assume that all are bad and just toss the ATTRI.
748 */
749 attrp = &attrip->attri_format;
750 if (!xfs_attri_validate(mp, attrp) ||
751 !xfs_attr_namecheck(attrp->alfi_attr_filter, nv->name.iov_base,
752 nv->name.iov_len))
753 return -EFSCORRUPTED;
754
755 attr = xfs_attri_recover_work(mp, dfp, attrp, &ip, nv);
756 if (IS_ERR(attr))
757 return PTR_ERR(attr);
758 args = attr->xattri_da_args;
759
760 switch (xfs_attr_intent_op(attr)) {
761 case XFS_ATTRI_OP_FLAGS_PPTR_SET:
762 case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:
763 case XFS_ATTRI_OP_FLAGS_SET:
764 case XFS_ATTRI_OP_FLAGS_REPLACE:
765 resv = xfs_attr_set_resv(args);
766 total = args->total;
767 break;
768 case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:
769 case XFS_ATTRI_OP_FLAGS_REMOVE:
770 resv = M_RES(mp)->tr_attrrm;
771 total = XFS_ATTRRM_SPACE_RES(mp);
772 break;
773 }
774 resv = xlog_recover_resv(&resv);
775 error = xfs_trans_alloc(mp, &resv, total, 0, XFS_TRANS_RESERVE, &tp);
776 if (error)
777 return error;
778 args->trans = tp;
779
780 xfs_ilock(ip, XFS_ILOCK_EXCL);
781 xfs_trans_ijoin(tp, ip, 0);
782
783 error = xlog_recover_finish_intent(tp, dfp);
784 if (error == -EFSCORRUPTED)
785 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
786 &attrip->attri_format,
787 sizeof(attrip->attri_format));
788 if (error)
789 goto out_cancel;
790
791 error = xfs_defer_ops_capture_and_commit(tp, capture_list);
792 out_unlock:
793 xfs_iunlock(ip, XFS_ILOCK_EXCL);
794 xfs_irele(ip);
795 return error;
796 out_cancel:
797 xfs_trans_cancel(tp);
798 goto out_unlock;
799 }
800
801 /* Re-log an intent item to push the log tail forward. */
802 static struct xfs_log_item *
xfs_attr_relog_intent(struct xfs_trans * tp,struct xfs_log_item * intent,struct xfs_log_item * done_item)803 xfs_attr_relog_intent(
804 struct xfs_trans *tp,
805 struct xfs_log_item *intent,
806 struct xfs_log_item *done_item)
807 {
808 struct xfs_attri_log_item *old_attrip;
809 struct xfs_attri_log_item *new_attrip;
810 struct xfs_attri_log_format *new_attrp;
811 struct xfs_attri_log_format *old_attrp;
812
813 old_attrip = ATTRI_ITEM(intent);
814 old_attrp = &old_attrip->attri_format;
815
816 /*
817 * Create a new log item that shares the same name/value buffer as the
818 * old log item.
819 */
820 new_attrip = xfs_attri_init(tp->t_mountp, old_attrip->attri_nameval);
821 new_attrp = &new_attrip->attri_format;
822
823 new_attrp->alfi_ino = old_attrp->alfi_ino;
824 new_attrp->alfi_igen = old_attrp->alfi_igen;
825 new_attrp->alfi_op_flags = old_attrp->alfi_op_flags;
826 new_attrp->alfi_value_len = old_attrp->alfi_value_len;
827
828 switch (xfs_attr_log_item_op(old_attrp)) {
829 case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:
830 new_attrp->alfi_new_name_len = old_attrp->alfi_new_name_len;
831 new_attrp->alfi_old_name_len = old_attrp->alfi_old_name_len;
832 break;
833 default:
834 new_attrp->alfi_name_len = old_attrp->alfi_name_len;
835 break;
836 }
837
838 new_attrp->alfi_attr_filter = old_attrp->alfi_attr_filter;
839
840 return &new_attrip->attri_item;
841 }
842
843 /* Get an ATTRD so we can process all the attrs. */
844 static struct xfs_log_item *
xfs_attr_create_done(struct xfs_trans * tp,struct xfs_log_item * intent,unsigned int count)845 xfs_attr_create_done(
846 struct xfs_trans *tp,
847 struct xfs_log_item *intent,
848 unsigned int count)
849 {
850 struct xfs_attri_log_item *attrip;
851 struct xfs_attrd_log_item *attrdp;
852
853 attrip = ATTRI_ITEM(intent);
854
855 attrdp = kmem_cache_zalloc(xfs_attrd_cache, GFP_KERNEL | __GFP_NOFAIL);
856
857 xfs_log_item_init(tp->t_mountp, &attrdp->attrd_item, XFS_LI_ATTRD,
858 &xfs_attrd_item_ops);
859 attrdp->attrd_attrip = attrip;
860 attrdp->attrd_format.alfd_alf_id = attrip->attri_format.alfi_id;
861
862 return &attrdp->attrd_item;
863 }
864
865 void
xfs_attr_defer_add(struct xfs_da_args * args,enum xfs_attr_defer_op op)866 xfs_attr_defer_add(
867 struct xfs_da_args *args,
868 enum xfs_attr_defer_op op)
869 {
870 struct xfs_attr_intent *new;
871 unsigned int log_op = 0;
872 bool is_pptr = args->attr_filter & XFS_ATTR_PARENT;
873
874 if (is_pptr) {
875 ASSERT(xfs_has_parent(args->dp->i_mount));
876 ASSERT((args->attr_filter & ~XFS_ATTR_PARENT) == 0);
877 ASSERT(args->op_flags & XFS_DA_OP_LOGGED);
878 ASSERT(args->valuelen == sizeof(struct xfs_parent_rec));
879 }
880
881 new = kmem_cache_zalloc(xfs_attr_intent_cache,
882 GFP_NOFS | __GFP_NOFAIL);
883 new->xattri_da_args = args;
884
885 /* Compute log operation from the higher level op and namespace. */
886 switch (op) {
887 case XFS_ATTR_DEFER_SET:
888 if (is_pptr)
889 log_op = XFS_ATTRI_OP_FLAGS_PPTR_SET;
890 else
891 log_op = XFS_ATTRI_OP_FLAGS_SET;
892 break;
893 case XFS_ATTR_DEFER_REPLACE:
894 if (is_pptr)
895 log_op = XFS_ATTRI_OP_FLAGS_PPTR_REPLACE;
896 else
897 log_op = XFS_ATTRI_OP_FLAGS_REPLACE;
898 break;
899 case XFS_ATTR_DEFER_REMOVE:
900 if (is_pptr)
901 log_op = XFS_ATTRI_OP_FLAGS_PPTR_REMOVE;
902 else
903 log_op = XFS_ATTRI_OP_FLAGS_REMOVE;
904 break;
905 default:
906 ASSERT(0);
907 break;
908 }
909 new->xattri_op_flags = log_op;
910
911 /* Set up initial attr operation state. */
912 switch (log_op) {
913 case XFS_ATTRI_OP_FLAGS_PPTR_SET:
914 case XFS_ATTRI_OP_FLAGS_SET:
915 new->xattri_dela_state = xfs_attr_init_add_state(args);
916 break;
917 case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:
918 ASSERT(args->new_valuelen == args->valuelen);
919 new->xattri_dela_state = xfs_attr_init_replace_state(args);
920 break;
921 case XFS_ATTRI_OP_FLAGS_REPLACE:
922 new->xattri_dela_state = xfs_attr_init_replace_state(args);
923 break;
924 case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:
925 case XFS_ATTRI_OP_FLAGS_REMOVE:
926 new->xattri_dela_state = xfs_attr_init_remove_state(args);
927 break;
928 }
929
930 xfs_defer_add(args->trans, &new->xattri_list, &xfs_attr_defer_type);
931 trace_xfs_attr_defer_add(new->xattri_dela_state, args->dp);
932 }
933
934 const struct xfs_defer_op_type xfs_attr_defer_type = {
935 .name = "attr",
936 .max_items = 1,
937 .create_intent = xfs_attr_create_intent,
938 .abort_intent = xfs_attr_abort_intent,
939 .create_done = xfs_attr_create_done,
940 .finish_item = xfs_attr_finish_item,
941 .cancel_item = xfs_attr_cancel_item,
942 .recover_work = xfs_attr_recover_work,
943 .relog_intent = xfs_attr_relog_intent,
944 };
945
946 static inline void *
xfs_attri_validate_name_iovec(struct xfs_mount * mp,struct xfs_attri_log_format * attri_formatp,const struct kvec * iovec,unsigned int name_len)947 xfs_attri_validate_name_iovec(
948 struct xfs_mount *mp,
949 struct xfs_attri_log_format *attri_formatp,
950 const struct kvec *iovec,
951 unsigned int name_len)
952 {
953 if (iovec->iov_len != xlog_calc_iovec_len(name_len)) {
954 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
955 attri_formatp, sizeof(*attri_formatp));
956 return NULL;
957 }
958
959 if (!xfs_attr_namecheck(attri_formatp->alfi_attr_filter, iovec->iov_base,
960 name_len)) {
961 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
962 attri_formatp, sizeof(*attri_formatp));
963 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
964 iovec->iov_base, iovec->iov_len);
965 return NULL;
966 }
967
968 return iovec->iov_base;
969 }
970
971 static inline void *
xfs_attri_validate_value_iovec(struct xfs_mount * mp,struct xfs_attri_log_format * attri_formatp,const struct kvec * iovec,unsigned int value_len)972 xfs_attri_validate_value_iovec(
973 struct xfs_mount *mp,
974 struct xfs_attri_log_format *attri_formatp,
975 const struct kvec *iovec,
976 unsigned int value_len)
977 {
978 if (iovec->iov_len != xlog_calc_iovec_len(value_len)) {
979 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
980 attri_formatp, sizeof(*attri_formatp));
981 return NULL;
982 }
983
984 if ((attri_formatp->alfi_attr_filter & XFS_ATTR_PARENT) &&
985 !xfs_parent_valuecheck(mp, iovec->iov_base, value_len)) {
986 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
987 attri_formatp, sizeof(*attri_formatp));
988 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
989 iovec->iov_base, iovec->iov_len);
990 return NULL;
991 }
992
993 return iovec->iov_base;
994 }
995
996 STATIC int
xlog_recover_attri_commit_pass2(struct xlog * log,struct list_head * buffer_list,struct xlog_recover_item * item,xfs_lsn_t lsn)997 xlog_recover_attri_commit_pass2(
998 struct xlog *log,
999 struct list_head *buffer_list,
1000 struct xlog_recover_item *item,
1001 xfs_lsn_t lsn)
1002 {
1003 struct xfs_mount *mp = log->l_mp;
1004 struct xfs_attri_log_item *attrip;
1005 struct xfs_attri_log_format *attri_formatp;
1006 struct xfs_attri_log_nameval *nv;
1007 const void *attr_name;
1008 const void *attr_value = NULL;
1009 const void *attr_new_name = NULL;
1010 const void *attr_new_value = NULL;
1011 size_t len;
1012 unsigned int name_len = 0;
1013 unsigned int value_len = 0;
1014 unsigned int new_name_len = 0;
1015 unsigned int new_value_len = 0;
1016 unsigned int op, i = 0;
1017
1018 /* Validate xfs_attri_log_format before the large memory allocation */
1019 len = sizeof(struct xfs_attri_log_format);
1020 if (item->ri_buf[i].iov_len != len) {
1021 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
1022 item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
1023 return -EFSCORRUPTED;
1024 }
1025
1026 attri_formatp = item->ri_buf[i].iov_base;
1027 if (!xfs_attri_validate(mp, attri_formatp)) {
1028 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
1029 attri_formatp, len);
1030 return -EFSCORRUPTED;
1031 }
1032
1033 /* Check the number of log iovecs makes sense for the op code. */
1034 op = xfs_attr_log_item_op(attri_formatp);
1035 switch (op) {
1036 case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:
1037 case XFS_ATTRI_OP_FLAGS_PPTR_SET:
1038 /* Log item, attr name, attr value */
1039 if (item->ri_total != 3) {
1040 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
1041 attri_formatp, len);
1042 return -EFSCORRUPTED;
1043 }
1044 name_len = attri_formatp->alfi_name_len;
1045 value_len = attri_formatp->alfi_value_len;
1046 break;
1047 case XFS_ATTRI_OP_FLAGS_SET:
1048 case XFS_ATTRI_OP_FLAGS_REPLACE:
1049 /* Log item, attr name, optional attr value */
1050 if (item->ri_total != 2 + !!attri_formatp->alfi_value_len) {
1051 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
1052 attri_formatp, len);
1053 return -EFSCORRUPTED;
1054 }
1055 name_len = attri_formatp->alfi_name_len;
1056 value_len = attri_formatp->alfi_value_len;
1057 break;
1058 case XFS_ATTRI_OP_FLAGS_REMOVE:
1059 /* Log item, attr name */
1060 if (item->ri_total != 2) {
1061 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
1062 attri_formatp, len);
1063 return -EFSCORRUPTED;
1064 }
1065 name_len = attri_formatp->alfi_name_len;
1066 break;
1067 case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:
1068 /*
1069 * Log item, attr name, new attr name, attr value, new attr
1070 * value
1071 */
1072 if (item->ri_total != 5) {
1073 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
1074 attri_formatp, len);
1075 return -EFSCORRUPTED;
1076 }
1077 name_len = attri_formatp->alfi_old_name_len;
1078 new_name_len = attri_formatp->alfi_new_name_len;
1079 new_value_len = value_len = attri_formatp->alfi_value_len;
1080 break;
1081 default:
1082 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
1083 attri_formatp, len);
1084 return -EFSCORRUPTED;
1085 }
1086 i++;
1087
1088 /* Validate the attr name */
1089 attr_name = xfs_attri_validate_name_iovec(mp, attri_formatp,
1090 &item->ri_buf[i], name_len);
1091 if (!attr_name)
1092 return -EFSCORRUPTED;
1093 i++;
1094
1095 /* Validate the new attr name */
1096 if (new_name_len > 0) {
1097 attr_new_name = xfs_attri_validate_name_iovec(mp,
1098 attri_formatp, &item->ri_buf[i],
1099 new_name_len);
1100 if (!attr_new_name)
1101 return -EFSCORRUPTED;
1102 i++;
1103 }
1104
1105 /* Validate the attr value, if present */
1106 if (value_len != 0) {
1107 attr_value = xfs_attri_validate_value_iovec(mp, attri_formatp,
1108 &item->ri_buf[i], value_len);
1109 if (!attr_value)
1110 return -EFSCORRUPTED;
1111 i++;
1112 }
1113
1114 /* Validate the new attr value, if present */
1115 if (new_value_len != 0) {
1116 attr_new_value = xfs_attri_validate_value_iovec(mp,
1117 attri_formatp, &item->ri_buf[i],
1118 new_value_len);
1119 if (!attr_new_value)
1120 return -EFSCORRUPTED;
1121 i++;
1122 }
1123
1124 /*
1125 * Make sure we got the correct number of buffers for the operation
1126 * that we just loaded.
1127 */
1128 if (i != item->ri_total) {
1129 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
1130 attri_formatp, len);
1131 return -EFSCORRUPTED;
1132 }
1133
1134 /*
1135 * Memory alloc failure will cause replay to abort. We attach the
1136 * name/value buffer to the recovered incore log item and drop our
1137 * reference.
1138 */
1139 nv = xfs_attri_log_nameval_alloc(attr_name, name_len,
1140 attr_new_name, new_name_len,
1141 attr_value, value_len,
1142 attr_new_value, new_value_len);
1143
1144 attrip = xfs_attri_init(mp, nv);
1145 memcpy(&attrip->attri_format, attri_formatp, len);
1146
1147 xlog_recover_intent_item(log, &attrip->attri_item, lsn,
1148 &xfs_attr_defer_type);
1149 xfs_attri_log_nameval_put(nv);
1150 return 0;
1151 }
1152
1153 /*
1154 * This routine is called when an ATTRD format structure is found in a committed
1155 * transaction in the log. Its purpose is to cancel the corresponding ATTRI if
1156 * it was still in the log. To do this it searches the AIL for the ATTRI with
1157 * an id equal to that in the ATTRD format structure. If we find it we drop
1158 * the ATTRD reference, which removes the ATTRI from the AIL and frees it.
1159 */
1160 STATIC int
xlog_recover_attrd_commit_pass2(struct xlog * log,struct list_head * buffer_list,struct xlog_recover_item * item,xfs_lsn_t lsn)1161 xlog_recover_attrd_commit_pass2(
1162 struct xlog *log,
1163 struct list_head *buffer_list,
1164 struct xlog_recover_item *item,
1165 xfs_lsn_t lsn)
1166 {
1167 struct xfs_attrd_log_format *attrd_formatp;
1168
1169 attrd_formatp = item->ri_buf[0].iov_base;
1170 if (item->ri_buf[0].iov_len != sizeof(struct xfs_attrd_log_format)) {
1171 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
1172 item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
1173 return -EFSCORRUPTED;
1174 }
1175
1176 xlog_recover_release_intent(log, XFS_LI_ATTRI,
1177 attrd_formatp->alfd_alf_id);
1178 return 0;
1179 }
1180
1181 static const struct xfs_item_ops xfs_attri_item_ops = {
1182 .flags = XFS_ITEM_INTENT,
1183 .iop_size = xfs_attri_item_size,
1184 .iop_format = xfs_attri_item_format,
1185 .iop_unpin = xfs_attri_item_unpin,
1186 .iop_release = xfs_attri_item_release,
1187 .iop_match = xfs_attri_item_match,
1188 };
1189
1190 const struct xlog_recover_item_ops xlog_attri_item_ops = {
1191 .item_type = XFS_LI_ATTRI,
1192 .commit_pass2 = xlog_recover_attri_commit_pass2,
1193 };
1194
1195 static const struct xfs_item_ops xfs_attrd_item_ops = {
1196 .flags = XFS_ITEM_RELEASE_WHEN_COMMITTED |
1197 XFS_ITEM_INTENT_DONE,
1198 .iop_size = xfs_attrd_item_size,
1199 .iop_format = xfs_attrd_item_format,
1200 .iop_release = xfs_attrd_item_release,
1201 .iop_intent = xfs_attrd_item_intent,
1202 };
1203
1204 const struct xlog_recover_item_ops xlog_attrd_item_ops = {
1205 .item_type = XFS_LI_ATTRD,
1206 .commit_pass2 = xlog_recover_attrd_commit_pass2,
1207 };
1208