Merge tag 'mfd-next-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
[platform/kernel/linux-rpi.git] / fs / xfs / xfs_attr_item.c
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.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_inode.h"
26 #include "xfs_trans_space.h"
27 #include "xfs_errortag.h"
28 #include "xfs_error.h"
29 #include "xfs_log_priv.h"
30 #include "xfs_log_recover.h"
31
32 static const struct xfs_item_ops xfs_attri_item_ops;
33 static const struct xfs_item_ops xfs_attrd_item_ops;
34 static struct xfs_attrd_log_item *xfs_trans_get_attrd(struct xfs_trans *tp,
35                                         struct xfs_attri_log_item *attrip);
36
37 static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)
38 {
39         return container_of(lip, struct xfs_attri_log_item, attri_item);
40 }
41
42 STATIC void
43 xfs_attri_item_free(
44         struct xfs_attri_log_item       *attrip)
45 {
46         kmem_free(attrip->attri_item.li_lv_shadow);
47         kvfree(attrip);
48 }
49
50 /*
51  * Freeing the attrip requires that we remove it from the AIL if it has already
52  * been placed there. However, the ATTRI may not yet have been placed in the
53  * AIL when called by xfs_attri_release() from ATTRD processing due to the
54  * ordering of committed vs unpin operations in bulk insert operations. Hence
55  * the reference count to ensure only the last caller frees the ATTRI.
56  */
57 STATIC void
58 xfs_attri_release(
59         struct xfs_attri_log_item       *attrip)
60 {
61         ASSERT(atomic_read(&attrip->attri_refcount) > 0);
62         if (!atomic_dec_and_test(&attrip->attri_refcount))
63                 return;
64
65         xfs_trans_ail_delete(&attrip->attri_item, 0);
66         xfs_attri_item_free(attrip);
67 }
68
69 STATIC void
70 xfs_attri_item_size(
71         struct xfs_log_item             *lip,
72         int                             *nvecs,
73         int                             *nbytes)
74 {
75         struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
76
77         *nvecs += 2;
78         *nbytes += sizeof(struct xfs_attri_log_format) +
79                         xlog_calc_iovec_len(attrip->attri_name_len);
80
81         if (!attrip->attri_value_len)
82                 return;
83
84         *nvecs += 1;
85         *nbytes += xlog_calc_iovec_len(attrip->attri_value_len);
86 }
87
88 /*
89  * This is called to fill in the log iovecs for the given attri log
90  * item. We use  1 iovec for the attri_format_item, 1 for the name, and
91  * another for the value if it is present
92  */
93 STATIC void
94 xfs_attri_item_format(
95         struct xfs_log_item             *lip,
96         struct xfs_log_vec              *lv)
97 {
98         struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
99         struct xfs_log_iovec            *vecp = NULL;
100
101         attrip->attri_format.alfi_type = XFS_LI_ATTRI;
102         attrip->attri_format.alfi_size = 1;
103
104         /*
105          * This size accounting must be done before copying the attrip into the
106          * iovec.  If we do it after, the wrong size will be recorded to the log
107          * and we trip across assertion checks for bad region sizes later during
108          * the log recovery.
109          */
110
111         ASSERT(attrip->attri_name_len > 0);
112         attrip->attri_format.alfi_size++;
113
114         if (attrip->attri_value_len > 0)
115                 attrip->attri_format.alfi_size++;
116
117         xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT,
118                         &attrip->attri_format,
119                         sizeof(struct xfs_attri_log_format));
120         xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NAME,
121                         attrip->attri_name,
122                         attrip->attri_name_len);
123         if (attrip->attri_value_len > 0)
124                 xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_VALUE,
125                                 attrip->attri_value,
126                                 attrip->attri_value_len);
127 }
128
129 /*
130  * The unpin operation is the last place an ATTRI is manipulated in the log. It
131  * is either inserted in the AIL or aborted in the event of a log I/O error. In
132  * either case, the ATTRI transaction has been successfully committed to make
133  * it this far. Therefore, we expect whoever committed the ATTRI to either
134  * construct and commit the ATTRD or drop the ATTRD's reference in the event of
135  * error. Simply drop the log's ATTRI reference now that the log is done with
136  * it.
137  */
138 STATIC void
139 xfs_attri_item_unpin(
140         struct xfs_log_item     *lip,
141         int                     remove)
142 {
143         xfs_attri_release(ATTRI_ITEM(lip));
144 }
145
146
147 STATIC void
148 xfs_attri_item_release(
149         struct xfs_log_item     *lip)
150 {
151         xfs_attri_release(ATTRI_ITEM(lip));
152 }
153
154 /*
155  * Allocate and initialize an attri item.  Caller may allocate an additional
156  * trailing buffer for name and value
157  */
158 STATIC struct xfs_attri_log_item *
159 xfs_attri_init(
160         struct xfs_mount                *mp,
161         uint32_t                        name_len,
162         uint32_t                        value_len)
163
164 {
165         struct xfs_attri_log_item       *attrip;
166         uint32_t                        buffer_size = name_len + value_len;
167
168         if (buffer_size) {
169                 /*
170                  * This could be over 64kB in length, so we have to use
171                  * kvmalloc() for this. But kvmalloc() utterly sucks, so we
172                  * use own version.
173                  */
174                 attrip = xlog_kvmalloc(sizeof(struct xfs_attri_log_item) +
175                                         buffer_size);
176         } else {
177                 attrip = kmem_cache_alloc(xfs_attri_cache,
178                                         GFP_NOFS | __GFP_NOFAIL);
179         }
180         memset(attrip, 0, sizeof(struct xfs_attri_log_item));
181
182         attrip->attri_name_len = name_len;
183         if (name_len)
184                 attrip->attri_name = ((char *)attrip) +
185                                 sizeof(struct xfs_attri_log_item);
186         else
187                 attrip->attri_name = NULL;
188
189         attrip->attri_value_len = value_len;
190         if (value_len)
191                 attrip->attri_value = ((char *)attrip) +
192                                 sizeof(struct xfs_attri_log_item) +
193                                 name_len;
194         else
195                 attrip->attri_value = NULL;
196
197         xfs_log_item_init(mp, &attrip->attri_item, XFS_LI_ATTRI,
198                           &xfs_attri_item_ops);
199         attrip->attri_format.alfi_id = (uintptr_t)(void *)attrip;
200         atomic_set(&attrip->attri_refcount, 2);
201
202         return attrip;
203 }
204
205 /*
206  * Copy an attr format buffer from the given buf, and into the destination attr
207  * format structure.
208  */
209 STATIC int
210 xfs_attri_copy_format(
211         struct xfs_log_iovec            *buf,
212         struct xfs_attri_log_format     *dst_attr_fmt)
213 {
214         struct xfs_attri_log_format     *src_attr_fmt = buf->i_addr;
215         size_t                          len;
216
217         len = sizeof(struct xfs_attri_log_format);
218         if (buf->i_len != len) {
219                 XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
220                 return -EFSCORRUPTED;
221         }
222
223         memcpy((char *)dst_attr_fmt, (char *)src_attr_fmt, len);
224         return 0;
225 }
226
227 static inline struct xfs_attrd_log_item *ATTRD_ITEM(struct xfs_log_item *lip)
228 {
229         return container_of(lip, struct xfs_attrd_log_item, attrd_item);
230 }
231
232 STATIC void
233 xfs_attrd_item_free(struct xfs_attrd_log_item *attrdp)
234 {
235         kmem_free(attrdp->attrd_item.li_lv_shadow);
236         kmem_free(attrdp);
237 }
238
239 STATIC void
240 xfs_attrd_item_size(
241         struct xfs_log_item             *lip,
242         int                             *nvecs,
243         int                             *nbytes)
244 {
245         *nvecs += 1;
246         *nbytes += sizeof(struct xfs_attrd_log_format);
247 }
248
249 /*
250  * This is called to fill in the log iovecs for the given attrd log item. We use
251  * only 1 iovec for the attrd_format, and we point that at the attr_log_format
252  * structure embedded in the attrd item.
253  */
254 STATIC void
255 xfs_attrd_item_format(
256         struct xfs_log_item     *lip,
257         struct xfs_log_vec      *lv)
258 {
259         struct xfs_attrd_log_item       *attrdp = ATTRD_ITEM(lip);
260         struct xfs_log_iovec            *vecp = NULL;
261
262         attrdp->attrd_format.alfd_type = XFS_LI_ATTRD;
263         attrdp->attrd_format.alfd_size = 1;
264
265         xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT,
266                         &attrdp->attrd_format,
267                         sizeof(struct xfs_attrd_log_format));
268 }
269
270 /*
271  * The ATTRD is either committed or aborted if the transaction is canceled. If
272  * the transaction is canceled, drop our reference to the ATTRI and free the
273  * ATTRD.
274  */
275 STATIC void
276 xfs_attrd_item_release(
277         struct xfs_log_item             *lip)
278 {
279         struct xfs_attrd_log_item       *attrdp = ATTRD_ITEM(lip);
280
281         xfs_attri_release(attrdp->attrd_attrip);
282         xfs_attrd_item_free(attrdp);
283 }
284
285 static struct xfs_log_item *
286 xfs_attrd_item_intent(
287         struct xfs_log_item     *lip)
288 {
289         return &ATTRD_ITEM(lip)->attrd_attrip->attri_item;
290 }
291
292 /*
293  * Performs one step of an attribute update intent and marks the attrd item
294  * dirty..  An attr operation may be a set or a remove.  Note that the
295  * transaction is marked dirty regardless of whether the operation succeeds or
296  * fails to support the ATTRI/ATTRD lifecycle rules.
297  */
298 STATIC int
299 xfs_xattri_finish_update(
300         struct xfs_attr_item            *attr,
301         struct xfs_attrd_log_item       *attrdp)
302 {
303         struct xfs_da_args              *args = attr->xattri_da_args;
304         int                             error;
305
306         if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_LARP)) {
307                 error = -EIO;
308                 goto out;
309         }
310
311         error = xfs_attr_set_iter(attr);
312         if (!error && attr->xattri_dela_state != XFS_DAS_DONE)
313                 error = -EAGAIN;
314 out:
315         /*
316          * Mark the transaction dirty, even on error. This ensures the
317          * transaction is aborted, which:
318          *
319          * 1.) releases the ATTRI and frees the ATTRD
320          * 2.) shuts down the filesystem
321          */
322         args->trans->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE;
323
324         /*
325          * attr intent/done items are null when logged attributes are disabled
326          */
327         if (attrdp)
328                 set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags);
329
330         return error;
331 }
332
333 /* Log an attr to the intent item. */
334 STATIC void
335 xfs_attr_log_item(
336         struct xfs_trans                *tp,
337         struct xfs_attri_log_item       *attrip,
338         struct xfs_attr_item            *attr)
339 {
340         struct xfs_attri_log_format     *attrp;
341
342         tp->t_flags |= XFS_TRANS_DIRTY;
343         set_bit(XFS_LI_DIRTY, &attrip->attri_item.li_flags);
344
345         /*
346          * At this point the xfs_attr_item has been constructed, and we've
347          * created the log intent. Fill in the attri log item and log format
348          * structure with fields from this xfs_attr_item
349          */
350         attrp = &attrip->attri_format;
351         attrp->alfi_ino = attr->xattri_da_args->dp->i_ino;
352         attrp->alfi_op_flags = attr->xattri_op_flags;
353         attrp->alfi_value_len = attr->xattri_da_args->valuelen;
354         attrp->alfi_name_len = attr->xattri_da_args->namelen;
355         attrp->alfi_attr_flags = attr->xattri_da_args->attr_filter;
356
357         memcpy(attrip->attri_name, attr->xattri_da_args->name,
358                attr->xattri_da_args->namelen);
359         memcpy(attrip->attri_value, attr->xattri_da_args->value,
360                attr->xattri_da_args->valuelen);
361         attrip->attri_name_len = attr->xattri_da_args->namelen;
362         attrip->attri_value_len = attr->xattri_da_args->valuelen;
363 }
364
365 /* Get an ATTRI. */
366 static struct xfs_log_item *
367 xfs_attr_create_intent(
368         struct xfs_trans                *tp,
369         struct list_head                *items,
370         unsigned int                    count,
371         bool                            sort)
372 {
373         struct xfs_mount                *mp = tp->t_mountp;
374         struct xfs_attri_log_item       *attrip;
375         struct xfs_attr_item            *attr;
376
377         ASSERT(count == 1);
378
379         if (!xfs_sb_version_haslogxattrs(&mp->m_sb))
380                 return NULL;
381
382         /*
383          * Each attr item only performs one attribute operation at a time, so
384          * this is a list of one
385          */
386         list_for_each_entry(attr, items, xattri_list) {
387                 attrip = xfs_attri_init(mp, attr->xattri_da_args->namelen,
388                                         attr->xattri_da_args->valuelen);
389                 if (attrip == NULL)
390                         return NULL;
391
392                 xfs_trans_add_item(tp, &attrip->attri_item);
393                 xfs_attr_log_item(tp, attrip, attr);
394         }
395
396         return &attrip->attri_item;
397 }
398
399 /* Process an attr. */
400 STATIC int
401 xfs_attr_finish_item(
402         struct xfs_trans                *tp,
403         struct xfs_log_item             *done,
404         struct list_head                *item,
405         struct xfs_btree_cur            **state)
406 {
407         struct xfs_attr_item            *attr;
408         struct xfs_attrd_log_item       *done_item = NULL;
409         int                             error;
410
411         attr = container_of(item, struct xfs_attr_item, xattri_list);
412         if (done)
413                 done_item = ATTRD_ITEM(done);
414
415         /*
416          * Always reset trans after EAGAIN cycle
417          * since the transaction is new
418          */
419         attr->xattri_da_args->trans = tp;
420
421         error = xfs_xattri_finish_update(attr, done_item);
422         if (error != -EAGAIN)
423                 kmem_free(attr);
424
425         return error;
426 }
427
428 /* Abort all pending ATTRs. */
429 STATIC void
430 xfs_attr_abort_intent(
431         struct xfs_log_item             *intent)
432 {
433         xfs_attri_release(ATTRI_ITEM(intent));
434 }
435
436 /* Cancel an attr */
437 STATIC void
438 xfs_attr_cancel_item(
439         struct list_head                *item)
440 {
441         struct xfs_attr_item            *attr;
442
443         attr = container_of(item, struct xfs_attr_item, xattri_list);
444         kmem_free(attr);
445 }
446
447 STATIC xfs_lsn_t
448 xfs_attri_item_committed(
449         struct xfs_log_item             *lip,
450         xfs_lsn_t                       lsn)
451 {
452         struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
453
454         /*
455          * The attrip refers to xfs_attr_item memory to log the name and value
456          * with the intent item. This already occurred when the intent was
457          * committed so these fields are no longer accessed. Clear them out of
458          * caution since we're about to free the xfs_attr_item.
459          */
460         attrip->attri_name = NULL;
461         attrip->attri_value = NULL;
462
463         /*
464          * The ATTRI is logged only once and cannot be moved in the log, so
465          * simply return the lsn at which it's been logged.
466          */
467         return lsn;
468 }
469
470 STATIC bool
471 xfs_attri_item_match(
472         struct xfs_log_item     *lip,
473         uint64_t                intent_id)
474 {
475         return ATTRI_ITEM(lip)->attri_format.alfi_id == intent_id;
476 }
477
478 /* Is this recovered ATTRI format ok? */
479 static inline bool
480 xfs_attri_validate(
481         struct xfs_mount                *mp,
482         struct xfs_attri_log_format     *attrp)
483 {
484         unsigned int                    op = attrp->alfi_op_flags &
485                                              XFS_ATTR_OP_FLAGS_TYPE_MASK;
486
487         if (attrp->__pad != 0)
488                 return false;
489
490         /* alfi_op_flags should be either a set or remove */
491         switch (op) {
492         case XFS_ATTR_OP_FLAGS_SET:
493         case XFS_ATTR_OP_FLAGS_REPLACE:
494         case XFS_ATTR_OP_FLAGS_REMOVE:
495                 break;
496         default:
497                 return false;
498         }
499
500         if (attrp->alfi_value_len > XATTR_SIZE_MAX)
501                 return false;
502
503         if ((attrp->alfi_name_len > XATTR_NAME_MAX) ||
504             (attrp->alfi_name_len == 0))
505                 return false;
506
507         return xfs_verify_ino(mp, attrp->alfi_ino);
508 }
509
510 /*
511  * Process an attr intent item that was recovered from the log.  We need to
512  * delete the attr that it describes.
513  */
514 STATIC int
515 xfs_attri_item_recover(
516         struct xfs_log_item             *lip,
517         struct list_head                *capture_list)
518 {
519         struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
520         struct xfs_attr_item            *attr;
521         struct xfs_mount                *mp = lip->li_log->l_mp;
522         struct xfs_inode                *ip;
523         struct xfs_da_args              *args;
524         struct xfs_trans                *tp;
525         struct xfs_trans_res            tres;
526         struct xfs_attri_log_format     *attrp;
527         int                             error, ret = 0;
528         int                             total;
529         int                             local;
530         struct xfs_attrd_log_item       *done_item = NULL;
531
532         /*
533          * First check the validity of the attr described by the ATTRI.  If any
534          * are bad, then assume that all are bad and just toss the ATTRI.
535          */
536         attrp = &attrip->attri_format;
537         if (!xfs_attri_validate(mp, attrp) ||
538             !xfs_attr_namecheck(attrip->attri_name, attrip->attri_name_len))
539                 return -EFSCORRUPTED;
540
541         error = xlog_recover_iget(mp,  attrp->alfi_ino, &ip);
542         if (error)
543                 return error;
544
545         attr = kmem_zalloc(sizeof(struct xfs_attr_item) +
546                            sizeof(struct xfs_da_args), KM_NOFS);
547         args = (struct xfs_da_args *)(attr + 1);
548
549         attr->xattri_da_args = args;
550         attr->xattri_op_flags = attrp->alfi_op_flags;
551
552         args->dp = ip;
553         args->geo = mp->m_attr_geo;
554         args->whichfork = XFS_ATTR_FORK;
555         args->name = attrip->attri_name;
556         args->namelen = attrp->alfi_name_len;
557         args->hashval = xfs_da_hashname(args->name, args->namelen);
558         args->attr_filter = attrp->alfi_attr_flags;
559         args->op_flags = XFS_DA_OP_RECOVERY | XFS_DA_OP_OKNOENT;
560
561         switch (attrp->alfi_op_flags & XFS_ATTR_OP_FLAGS_TYPE_MASK) {
562         case XFS_ATTR_OP_FLAGS_SET:
563         case XFS_ATTR_OP_FLAGS_REPLACE:
564                 args->value = attrip->attri_value;
565                 args->valuelen = attrp->alfi_value_len;
566                 args->total = xfs_attr_calc_size(args, &local);
567                 if (xfs_inode_hasattr(args->dp))
568                         attr->xattri_dela_state = xfs_attr_init_replace_state(args);
569                 else
570                         attr->xattri_dela_state = xfs_attr_init_add_state(args);
571                 break;
572         case XFS_ATTR_OP_FLAGS_REMOVE:
573                 if (!xfs_inode_hasattr(args->dp))
574                         goto out;
575                 attr->xattri_dela_state = xfs_attr_init_remove_state(args);
576                 break;
577         default:
578                 ASSERT(0);
579                 error = -EFSCORRUPTED;
580                 goto out;
581         }
582
583         xfs_init_attr_trans(args, &tres, &total);
584         error = xfs_trans_alloc(mp, &tres, total, 0, XFS_TRANS_RESERVE, &tp);
585         if (error)
586                 goto out;
587
588         args->trans = tp;
589         done_item = xfs_trans_get_attrd(tp, attrip);
590
591         xfs_ilock(ip, XFS_ILOCK_EXCL);
592         xfs_trans_ijoin(tp, ip, 0);
593
594         ret = xfs_xattri_finish_update(attr, done_item);
595         if (ret == -EAGAIN) {
596                 /* There's more work to do, so add it to this transaction */
597                 xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_ATTR, &attr->xattri_list);
598         } else
599                 error = ret;
600
601         if (error) {
602                 xfs_trans_cancel(tp);
603                 goto out_unlock;
604         }
605
606         error = xfs_defer_ops_capture_and_commit(tp, capture_list);
607
608 out_unlock:
609         if (attr->xattri_leaf_bp)
610                 xfs_buf_relse(attr->xattri_leaf_bp);
611
612         xfs_iunlock(ip, XFS_ILOCK_EXCL);
613         xfs_irele(ip);
614 out:
615         if (ret != -EAGAIN)
616                 kmem_free(attr);
617         return error;
618 }
619
620 /* Re-log an intent item to push the log tail forward. */
621 static struct xfs_log_item *
622 xfs_attri_item_relog(
623         struct xfs_log_item             *intent,
624         struct xfs_trans                *tp)
625 {
626         struct xfs_attrd_log_item       *attrdp;
627         struct xfs_attri_log_item       *old_attrip;
628         struct xfs_attri_log_item       *new_attrip;
629         struct xfs_attri_log_format     *new_attrp;
630         struct xfs_attri_log_format     *old_attrp;
631
632         old_attrip = ATTRI_ITEM(intent);
633         old_attrp = &old_attrip->attri_format;
634
635         tp->t_flags |= XFS_TRANS_DIRTY;
636         attrdp = xfs_trans_get_attrd(tp, old_attrip);
637         set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags);
638
639         new_attrip = xfs_attri_init(tp->t_mountp, old_attrp->alfi_name_len,
640                                     old_attrp->alfi_value_len);
641         new_attrp = &new_attrip->attri_format;
642
643         new_attrp->alfi_ino = old_attrp->alfi_ino;
644         new_attrp->alfi_op_flags = old_attrp->alfi_op_flags;
645         new_attrp->alfi_value_len = old_attrp->alfi_value_len;
646         new_attrp->alfi_name_len = old_attrp->alfi_name_len;
647         new_attrp->alfi_attr_flags = old_attrp->alfi_attr_flags;
648
649         memcpy(new_attrip->attri_name, old_attrip->attri_name,
650                 new_attrip->attri_name_len);
651
652         if (new_attrip->attri_value_len > 0)
653                 memcpy(new_attrip->attri_value, old_attrip->attri_value,
654                        new_attrip->attri_value_len);
655
656         xfs_trans_add_item(tp, &new_attrip->attri_item);
657         set_bit(XFS_LI_DIRTY, &new_attrip->attri_item.li_flags);
658
659         return &new_attrip->attri_item;
660 }
661
662 STATIC int
663 xlog_recover_attri_commit_pass2(
664         struct xlog                     *log,
665         struct list_head                *buffer_list,
666         struct xlog_recover_item        *item,
667         xfs_lsn_t                       lsn)
668 {
669         int                             error;
670         struct xfs_mount                *mp = log->l_mp;
671         struct xfs_attri_log_item       *attrip;
672         struct xfs_attri_log_format     *attri_formatp;
673         int                             region = 0;
674
675         attri_formatp = item->ri_buf[region].i_addr;
676
677         /* Validate xfs_attri_log_format */
678         if (!xfs_attri_validate(mp, attri_formatp)) {
679                 XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
680                 return -EFSCORRUPTED;
681         }
682
683         /* memory alloc failure will cause replay to abort */
684         attrip = xfs_attri_init(mp, attri_formatp->alfi_name_len,
685                                 attri_formatp->alfi_value_len);
686         if (attrip == NULL)
687                 return -ENOMEM;
688
689         error = xfs_attri_copy_format(&item->ri_buf[region],
690                                       &attrip->attri_format);
691         if (error)
692                 goto out;
693
694         region++;
695         memcpy(attrip->attri_name, item->ri_buf[region].i_addr,
696                attrip->attri_name_len);
697
698         if (!xfs_attr_namecheck(attrip->attri_name, attrip->attri_name_len)) {
699                 XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
700                 error = -EFSCORRUPTED;
701                 goto out;
702         }
703
704         if (attrip->attri_value_len > 0) {
705                 region++;
706                 memcpy(attrip->attri_value, item->ri_buf[region].i_addr,
707                        attrip->attri_value_len);
708         }
709
710         /*
711          * The ATTRI has two references. One for the ATTRD and one for ATTRI to
712          * ensure it makes it into the AIL. Insert the ATTRI into the AIL
713          * directly and drop the ATTRI reference. Note that
714          * xfs_trans_ail_update() drops the AIL lock.
715          */
716         xfs_trans_ail_insert(log->l_ailp, &attrip->attri_item, lsn);
717         xfs_attri_release(attrip);
718         return 0;
719 out:
720         xfs_attri_item_free(attrip);
721         return error;
722 }
723
724 /*
725  * This routine is called to allocate an "attr free done" log item.
726  */
727 static struct xfs_attrd_log_item *
728 xfs_trans_get_attrd(struct xfs_trans            *tp,
729                   struct xfs_attri_log_item     *attrip)
730 {
731         struct xfs_attrd_log_item               *attrdp;
732
733         ASSERT(tp != NULL);
734
735         attrdp = kmem_cache_zalloc(xfs_attrd_cache, GFP_NOFS | __GFP_NOFAIL);
736
737         xfs_log_item_init(tp->t_mountp, &attrdp->attrd_item, XFS_LI_ATTRD,
738                           &xfs_attrd_item_ops);
739         attrdp->attrd_attrip = attrip;
740         attrdp->attrd_format.alfd_alf_id = attrip->attri_format.alfi_id;
741
742         xfs_trans_add_item(tp, &attrdp->attrd_item);
743         return attrdp;
744 }
745
746 /* Get an ATTRD so we can process all the attrs. */
747 static struct xfs_log_item *
748 xfs_attr_create_done(
749         struct xfs_trans                *tp,
750         struct xfs_log_item             *intent,
751         unsigned int                    count)
752 {
753         if (!intent)
754                 return NULL;
755
756         return &xfs_trans_get_attrd(tp, ATTRI_ITEM(intent))->attrd_item;
757 }
758
759 const struct xfs_defer_op_type xfs_attr_defer_type = {
760         .max_items      = 1,
761         .create_intent  = xfs_attr_create_intent,
762         .abort_intent   = xfs_attr_abort_intent,
763         .create_done    = xfs_attr_create_done,
764         .finish_item    = xfs_attr_finish_item,
765         .cancel_item    = xfs_attr_cancel_item,
766 };
767
768 /*
769  * This routine is called when an ATTRD format structure is found in a committed
770  * transaction in the log. Its purpose is to cancel the corresponding ATTRI if
771  * it was still in the log. To do this it searches the AIL for the ATTRI with
772  * an id equal to that in the ATTRD format structure. If we find it we drop
773  * the ATTRD reference, which removes the ATTRI from the AIL and frees it.
774  */
775 STATIC int
776 xlog_recover_attrd_commit_pass2(
777         struct xlog                     *log,
778         struct list_head                *buffer_list,
779         struct xlog_recover_item        *item,
780         xfs_lsn_t                       lsn)
781 {
782         struct xfs_attrd_log_format     *attrd_formatp;
783
784         attrd_formatp = item->ri_buf[0].i_addr;
785         if (item->ri_buf[0].i_len != sizeof(struct xfs_attrd_log_format)) {
786                 XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
787                 return -EFSCORRUPTED;
788         }
789
790         xlog_recover_release_intent(log, XFS_LI_ATTRI,
791                                     attrd_formatp->alfd_alf_id);
792         return 0;
793 }
794
795 static const struct xfs_item_ops xfs_attri_item_ops = {
796         .flags          = XFS_ITEM_INTENT,
797         .iop_size       = xfs_attri_item_size,
798         .iop_format     = xfs_attri_item_format,
799         .iop_unpin      = xfs_attri_item_unpin,
800         .iop_committed  = xfs_attri_item_committed,
801         .iop_release    = xfs_attri_item_release,
802         .iop_recover    = xfs_attri_item_recover,
803         .iop_match      = xfs_attri_item_match,
804         .iop_relog      = xfs_attri_item_relog,
805 };
806
807 const struct xlog_recover_item_ops xlog_attri_item_ops = {
808         .item_type      = XFS_LI_ATTRI,
809         .commit_pass2   = xlog_recover_attri_commit_pass2,
810 };
811
812 static const struct xfs_item_ops xfs_attrd_item_ops = {
813         .flags          = XFS_ITEM_RELEASE_WHEN_COMMITTED |
814                           XFS_ITEM_INTENT_DONE,
815         .iop_size       = xfs_attrd_item_size,
816         .iop_format     = xfs_attrd_item_format,
817         .iop_release    = xfs_attrd_item_release,
818         .iop_intent     = xfs_attrd_item_intent,
819 };
820
821 const struct xlog_recover_item_ops xlog_attrd_item_ops = {
822         .item_type      = XFS_LI_ATTRD,
823         .commit_pass2   = xlog_recover_attrd_commit_pass2,
824 };