LCOV - code coverage report
Current view: top level - fs/xfs - xfs_attr_item.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsx @ Mon Jul 31 20:08:34 PDT 2023 Lines: 428 482 88.8 %
Date: 2023-07-31 20:08:34 Functions: 30 30 100.0 %

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

Generated by: LCOV version 1.14