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-xfsa @ Mon Jul 31 20:08:27 PDT 2023 Lines: 428 482 88.8 %
Date: 2023-07-31 20:08:27 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   187609659 : xfs_attri_log_nameval_get(
      58             :         struct xfs_attri_log_nameval    *nv)
      59             : {
      60   187609659 :         if (!refcount_inc_not_zero(&nv->refcount))
      61           0 :                 return NULL;
      62             :         return nv;
      63             : }
      64             : 
      65             : static inline void
      66   607892456 : xfs_attri_log_nameval_put(
      67             :         struct xfs_attri_log_nameval    *nv)
      68             : {
      69   607892456 :         if (!nv)
      70             :                 return;
      71   335185840 :         if (refcount_dec_and_test(&nv->refcount))
      72   147639093 :                 kvfree(nv);
      73             : }
      74             : 
      75             : static inline struct xfs_attri_log_nameval *
      76   147614648 : 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   147614648 :         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   147614648 :         nv = xlog_kvmalloc(sizeof(struct xfs_attri_log_nameval) +
      93   147614648 :                                         name_len + new_name_len + value_len +
      94             :                                         new_value_len);
      95             : 
      96   147622625 :         nv->name.i_addr = nv + 1;
      97   147622625 :         nv->name.i_len = name_len;
      98   147622625 :         nv->name.i_type = XLOG_REG_TYPE_ATTR_NAME;
      99   295245250 :         memcpy(nv->name.i_addr, name, name_len);
     100             : 
     101   147622625 :         if (new_name_len) {
     102    39781938 :                 nv->new_name.i_addr = nv->name.i_addr + name_len;
     103    39781938 :                 nv->new_name.i_len = new_name_len;
     104    79563876 :                 memcpy(nv->new_name.i_addr, new_name, new_name_len);
     105             :         } else {
     106   107840687 :                 nv->new_name.i_addr = NULL;
     107   107840687 :                 nv->new_name.i_len = 0;
     108             :         }
     109   147622625 :         nv->new_name.i_type = XLOG_REG_TYPE_ATTR_NEWNAME;
     110             : 
     111   147622625 :         if (value_len) {
     112   147620403 :                 nv->value.i_addr = nv->name.i_addr + name_len + new_name_len;
     113   147620403 :                 nv->value.i_len = value_len;
     114   295240806 :                 memcpy(nv->value.i_addr, value, value_len);
     115             :         } else {
     116        2222 :                 nv->value.i_addr = NULL;
     117        2222 :                 nv->value.i_len = 0;
     118             :         }
     119   147622625 :         nv->value.i_type = XLOG_REG_TYPE_ATTR_VALUE;
     120             : 
     121   147622625 :         if (new_value_len) {
     122    39781931 :                 nv->new_value.i_addr = nv->name.i_addr + name_len +
     123    39781931 :                                                 new_name_len + value_len;
     124    39781931 :                 nv->new_value.i_len = new_value_len;
     125    79563862 :                 memcpy(nv->new_value.i_addr, new_value, new_value_len);
     126             :         } else {
     127   107840694 :                 nv->new_value.i_addr = NULL;
     128   107840694 :                 nv->new_value.i_len = 0;
     129             :         }
     130   147622625 :         nv->new_value.i_type = XLOG_REG_TYPE_ATTR_NEWVALUE;
     131             : 
     132   147622625 :         refcount_set(&nv->refcount, 1);
     133   147622625 :         return nv;
     134             : }
     135             : 
     136             : STATIC void
     137   187643476 : xfs_attri_item_free(
     138             :         struct xfs_attri_log_item       *attrip)
     139             : {
     140   187643476 :         kmem_free(attrip->attri_item.li_lv_shadow);
     141   187642650 :         xfs_attri_log_nameval_put(attrip->attri_nameval);
     142   187642947 :         kmem_cache_free(xfs_attri_cache, attrip);
     143   187643111 : }
     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   375196088 : xfs_attri_release(
     154             :         struct xfs_attri_log_item       *attrip)
     155             : {
     156   375196088 :         ASSERT(atomic_read(&attrip->attri_refcount) > 0);
     157   750446769 :         if (!atomic_dec_and_test(&attrip->attri_refcount))
     158             :                 return;
     159             : 
     160   187643050 :         xfs_trans_ail_delete(&attrip->attri_item, 0);
     161   187643581 :         xfs_attri_item_free(attrip);
     162             : }
     163             : 
     164             : STATIC void
     165   187639278 : xfs_attri_item_size(
     166             :         struct xfs_log_item             *lip,
     167             :         int                             *nvecs,
     168             :         int                             *nbytes)
     169             : {
     170   187639278 :         struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
     171   187639278 :         struct xfs_attri_log_nameval    *nv = attrip->attri_nameval;
     172             : 
     173   187639278 :         *nvecs += 2;
     174   187639278 :         *nbytes += sizeof(struct xfs_attri_log_format) +
     175   187639278 :                         xlog_calc_iovec_len(nv->name.i_len);
     176             : 
     177   187639278 :         if (nv->new_name.i_len) {
     178    79708525 :                 *nvecs += 1;
     179    79708525 :                 *nbytes += xlog_calc_iovec_len(nv->new_name.i_len);
     180             :         }
     181             : 
     182   187639278 :         if (nv->value.i_len) {
     183   187639502 :                 *nvecs += 1;
     184   187639502 :                 *nbytes += xlog_calc_iovec_len(nv->value.i_len);
     185             :         }
     186             : 
     187   187639278 :         if (nv->new_value.i_len) {
     188    79708526 :                 *nvecs += 1;
     189    79708526 :                 *nbytes += xlog_calc_iovec_len(nv->new_value.i_len);
     190             :         }
     191   187639278 : }
     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   187641199 : xfs_attri_item_format(
     200             :         struct xfs_log_item             *lip,
     201             :         struct xfs_log_vec              *lv)
     202             : {
     203   187641199 :         struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
     204   187641199 :         struct xfs_log_iovec            *vecp = NULL;
     205   187641199 :         struct xfs_attri_log_nameval    *nv = attrip->attri_nameval;
     206             : 
     207   187641199 :         attrip->attri_format.alfi_type = XFS_LI_ATTRI;
     208   187641199 :         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   187641199 :         ASSERT(nv->name.i_len > 0);
     218   187641199 :         attrip->attri_format.alfi_size++;
     219             : 
     220   187641199 :         if (nv->new_name.i_len > 0)
     221    79708546 :                 attrip->attri_format.alfi_size++;
     222             : 
     223   187641199 :         if (nv->value.i_len > 0)
     224   187640380 :                 attrip->attri_format.alfi_size++;
     225             : 
     226   187641199 :         if (nv->new_value.i_len > 0)
     227    79708550 :                 attrip->attri_format.alfi_size++;
     228             : 
     229   187641199 :         xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT,
     230   187641199 :                         &attrip->attri_format,
     231             :                         sizeof(struct xfs_attri_log_format));
     232   187640642 :         xlog_copy_from_iovec(lv, &vecp, &nv->name);
     233             : 
     234   187640723 :         if (nv->new_name.i_len > 0)
     235    79708556 :                 xlog_copy_from_iovec(lv, &vecp, &nv->new_name);
     236             : 
     237   187640718 :         if (nv->value.i_len > 0)
     238   187640744 :                 xlog_copy_from_iovec(lv, &vecp, &nv->value);
     239             : 
     240   187640448 :         if (nv->new_value.i_len > 0)
     241    79708556 :                 xlog_copy_from_iovec(lv, &vecp, &nv->new_value);
     242   187640440 : }
     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   187640706 : xfs_attri_item_unpin(
     255             :         struct xfs_log_item     *lip,
     256             :         int                     remove)
     257             : {
     258   187640706 :         xfs_attri_release(ATTRI_ITEM(lip));
     259   187641526 : }
     260             : 
     261             : 
     262             : STATIC void
     263        1631 : xfs_attri_item_release(
     264             :         struct xfs_log_item     *lip)
     265             : {
     266        1631 :         xfs_attri_release(ATTRI_ITEM(lip));
     267        1631 : }
     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   187621071 : xfs_attri_init(
     275             :         struct xfs_mount                *mp,
     276             :         struct xfs_attri_log_nameval    *nv)
     277             : {
     278   187621071 :         struct xfs_attri_log_item       *attrip;
     279             : 
     280   187621071 :         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   187611450 :         attrip->attri_nameval = xfs_attri_log_nameval_get(nv);
     287   187613082 :         ASSERT(attrip->attri_nameval);
     288             : 
     289   187613082 :         xfs_log_item_init(mp, &attrip->attri_item, XFS_LI_ATTRI,
     290             :                           &xfs_attri_item_ops);
     291   187622674 :         attrip->attri_format.alfi_id = (uintptr_t)(void *)attrip;
     292   187622674 :         atomic_set(&attrip->attri_refcount, 2);
     293             : 
     294   187622674 :         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   187640980 : xfs_attrd_item_free(struct xfs_attrd_log_item *attrdp)
     304             : {
     305   187640980 :         kmem_free(attrdp->attrd_item.li_lv_shadow);
     306   187641193 :         kmem_cache_free(xfs_attrd_cache, attrdp);
     307   187640947 : }
     308             : 
     309             : STATIC void
     310   187640296 : xfs_attrd_item_size(
     311             :         struct xfs_log_item             *lip,
     312             :         int                             *nvecs,
     313             :         int                             *nbytes)
     314             : {
     315   187640296 :         *nvecs += 1;
     316   187640296 :         *nbytes += sizeof(struct xfs_attrd_log_format);
     317   187640296 : }
     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       56662 : xfs_attrd_item_format(
     326             :         struct xfs_log_item     *lip,
     327             :         struct xfs_log_vec      *lv)
     328             : {
     329       56662 :         struct xfs_attrd_log_item       *attrdp = ATTRD_ITEM(lip);
     330       56662 :         struct xfs_log_iovec            *vecp = NULL;
     331             : 
     332       56662 :         attrdp->attrd_format.alfd_type = XFS_LI_ATTRD;
     333       56662 :         attrdp->attrd_format.alfd_size = 1;
     334             : 
     335       56662 :         xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT,
     336       56662 :                         &attrdp->attrd_format,
     337             :                         sizeof(struct xfs_attrd_log_format));
     338       56662 : }
     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   187640814 : xfs_attrd_item_release(
     347             :         struct xfs_log_item             *lip)
     348             : {
     349   187640814 :         struct xfs_attrd_log_item       *attrdp = ATTRD_ITEM(lip);
     350             : 
     351   187640814 :         xfs_attri_release(attrdp->attrd_attrip);
     352   187640950 :         xfs_attrd_item_free(attrdp);
     353   187640953 : }
     354             : 
     355             : static struct xfs_log_item *
     356   187639365 : xfs_attrd_item_intent(
     357             :         struct xfs_log_item     *lip)
     358             : {
     359   187639365 :         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   544011200 : xfs_xattri_finish_update(
     370             :         struct xfs_attr_intent          *attr,
     371             :         struct xfs_attrd_log_item       *attrdp)
     372             : {
     373   544011200 :         struct xfs_da_args              *args = attr->xattri_da_args;
     374   544011200 :         int                             error;
     375             : 
     376   544011200 :         if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_LARP)) {
     377          56 :                 error = -EIO;
     378          56 :                 goto out;
     379             :         }
     380             : 
     381   544110911 :         error = xfs_attr_set_iter(attr);
     382   544095520 :         if (!error && attr->xattri_dela_state != XFS_DAS_DONE)
     383   123708648 :                 error = -EAGAIN;
     384   420386872 : 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   544095576 :         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   544095576 :         if (attrdp)
     398   187631128 :                 set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags);
     399             : 
     400   544103632 :         return error;
     401             : }
     402             : 
     403             : static inline unsigned int
     404             : xfs_attr_log_item_op(const struct xfs_attri_log_format *attrp)
     405             : {
     406   187631126 :         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   187615994 : 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   187615994 :         struct xfs_attri_log_format     *attrp;
     417             : 
     418   187615994 :         tp->t_flags |= XFS_TRANS_DIRTY;
     419   187615994 :         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   187626287 :         attrp = &attrip->attri_format;
     427   187626287 :         attrp->alfi_ino = attr->xattri_da_args->dp->i_ino;
     428   187626287 :         ASSERT(!(attr->xattri_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK));
     429   187626287 :         attrp->alfi_op_flags = attr->xattri_op_flags;
     430   187626287 :         attrp->alfi_value_len = attr->xattri_nameval->value.i_len;
     431             : 
     432   187626287 :         if (xfs_attr_log_item_op(attrp) == XFS_ATTRI_OP_FLAGS_NVREPLACE) {
     433    79708370 :                 attrp->alfi_old_name_len = attr->xattri_nameval->name.i_len;
     434    79708370 :                 attrp->alfi_new_name_len = attr->xattri_nameval->new_name.i_len;
     435    79708370 :                 attrp->alfi_new_value_len = attr->xattri_nameval->new_value.i_len;
     436             :         } else {
     437   107917917 :                 attrp->alfi_name_len = attr->xattri_nameval->name.i_len;
     438             :         }
     439             : 
     440   187626287 :         ASSERT(!(attr->xattri_da_args->attr_filter & ~XFS_ATTRI_FILTER_MASK));
     441   187626287 :         attrp->alfi_attr_filter = attr->xattri_da_args->attr_filter;
     442   187626287 : }
     443             : 
     444             : /* Get an ATTRI. */
     445             : static struct xfs_log_item *
     446   544025022 : xfs_attr_create_intent(
     447             :         struct xfs_trans                *tp,
     448             :         struct list_head                *items,
     449             :         unsigned int                    count,
     450             :         bool                            sort)
     451             : {
     452   544025022 :         struct xfs_mount                *mp = tp->t_mountp;
     453   544025022 :         struct xfs_attri_log_item       *attrip;
     454   544025022 :         struct xfs_attr_intent          *attr;
     455   544025022 :         struct xfs_da_args              *args;
     456             : 
     457   544025022 :         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   544025022 :         attr = list_first_entry_or_null(items, struct xfs_attr_intent,
     464             :                         xattri_list);
     465   544025022 :         args = attr->xattri_da_args;
     466             : 
     467   544025022 :         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   187612930 :         if (!attr->xattri_nameval) {
     476             :                 /*
     477             :                  * Transfer our reference to the name/value buffer to the
     478             :                  * deferred work state structure.
     479             :                  */
     480   147613948 :                 attr->xattri_nameval = xfs_attri_log_nameval_alloc(
     481   147618239 :                                 args->name, args->namelen,
     482   147618239 :                                 args->new_name, args->new_namelen,
     483   147618239 :                                 args->value, args->valuelen,
     484   147618239 :                                 args->new_value, args->new_valuelen);
     485             :         }
     486             : 
     487   187608639 :         attrip = xfs_attri_init(mp, attr->xattri_nameval);
     488   187607805 :         xfs_trans_add_item(tp, &attrip->attri_item);
     489   187628290 :         xfs_attr_log_item(tp, attrip, attr);
     490             : 
     491   187628290 :         return &attrip->attri_item;
     492             : }
     493             : 
     494             : static inline void
     495   420367635 : xfs_attr_free_item(
     496             :         struct xfs_attr_intent          *attr)
     497             : {
     498   420367635 :         if (attr->xattri_da_state)
     499     1273869 :                 xfs_da_state_free(attr->xattri_da_state);
     500   420367637 :         xfs_attri_log_nameval_put(attr->xattri_nameval);
     501   420402464 :         if (attr->xattri_da_args->op_flags & XFS_DA_OP_RECOVERY)
     502          94 :                 kmem_free(attr);
     503             :         else
     504   420402370 :                 kmem_cache_free(xfs_attr_intent_cache, attr);
     505   420452739 : }
     506             : 
     507             : /* Process an attr. */
     508             : STATIC int
     509   544011420 : 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   544011420 :         struct xfs_attr_intent          *attr;
     516   544011420 :         struct xfs_attrd_log_item       *done_item = NULL;
     517   544011420 :         int                             error;
     518             : 
     519   544011420 :         attr = container_of(item, struct xfs_attr_intent, xattri_list);
     520   544011420 :         if (done)
     521   187637626 :                 done_item = ATTRD_ITEM(done);
     522             : 
     523             :         /*
     524             :          * Always reset trans after EAGAIN cycle
     525             :          * since the transaction is new
     526             :          */
     527   544011420 :         attr->xattri_da_args->trans = tp;
     528             : 
     529   544011420 :         error = xfs_xattri_finish_update(attr, done_item);
     530   544079252 :         if (error != -EAGAIN)
     531   420401185 :                 xfs_attr_free_item(attr);
     532             : 
     533   544120677 :         return error;
     534             : }
     535             : 
     536             : /* Abort all pending ATTRs. */
     537             : STATIC void
     538          47 : xfs_attr_abort_intent(
     539             :         struct xfs_log_item             *intent)
     540             : {
     541          47 :         xfs_attri_release(ATTRI_ITEM(intent));
     542          47 : }
     543             : 
     544             : /* Cancel an attr */
     545             : STATIC void
     546         310 : xfs_attr_cancel_item(
     547             :         struct list_head                *item)
     548             : {
     549         310 :         struct xfs_attr_intent          *attr;
     550             : 
     551         310 :         attr = container_of(item, struct xfs_attr_intent, xattri_list);
     552         310 :         xfs_attr_free_item(attr);
     553         310 : }
     554             : 
     555             : STATIC bool
     556        1737 : xfs_attri_item_match(
     557             :         struct xfs_log_item     *lip,
     558             :         uint64_t                intent_id)
     559             : {
     560        1737 :         return ATTRI_ITEM(lip)->attri_format.alfi_id == intent_id;
     561             : }
     562             : 
     563             : /* Is this recovered ATTRI format ok? */
     564             : static inline bool
     565        1813 : xfs_attri_validate(
     566             :         struct xfs_mount                *mp,
     567             :         struct xfs_attri_log_format     *attrp)
     568             : {
     569        1813 :         unsigned int                    op = xfs_attr_log_item_op(attrp);
     570             : 
     571        1813 :         if (attrp->alfi_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK)
     572             :                 return false;
     573             : 
     574        1813 :         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        1813 :         switch (op) {
     579          48 :         case XFS_ATTRI_OP_FLAGS_REMOVE:
     580          48 :                 if (attrp->alfi_value_len != 0)
     581             :                         return false;
     582          48 :                 if (attrp->alfi_name_len == 0 ||
     583             :                     attrp->alfi_name_len > XATTR_NAME_MAX)
     584             :                         return false;
     585          48 :                 if (attrp->alfi_new_value_len != 0)
     586             :                         return false;
     587             :                 break;
     588         927 :         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         927 :                 if (attrp->alfi_name_len == 0 ||
     593             :                     attrp->alfi_name_len > XATTR_NAME_MAX)
     594             :                         return false;
     595         927 :                 if (attrp->alfi_value_len > XATTR_SIZE_MAX)
     596             :                         return false;
     597         927 :                 if (attrp->alfi_new_value_len != 0)
     598             :                         return false;
     599             :                 break;
     600         838 :         case XFS_ATTRI_OP_FLAGS_NVREPLACE:
     601         838 :                 if (attrp->alfi_old_name_len == 0 ||
     602             :                     attrp->alfi_old_name_len > XATTR_NAME_MAX)
     603             :                         return false;
     604         838 :                 if (attrp->alfi_new_name_len == 0 ||
     605             :                     attrp->alfi_new_name_len > XATTR_NAME_MAX)
     606             :                         return false;
     607         838 :                 if (attrp->alfi_value_len > XATTR_SIZE_MAX)
     608             :                         return false;
     609         838 :                 if (attrp->alfi_new_value_len > XATTR_SIZE_MAX)
     610             :                         return false;
     611             :                 break;
     612             :         default:
     613             :                 return false;
     614             :         }
     615             : 
     616        1813 :         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          94 : xfs_attri_item_recover(
     625             :         struct xfs_log_item             *lip,
     626             :         struct list_head                *capture_list)
     627             : {
     628          94 :         struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
     629          94 :         struct xfs_attr_intent          *attr;
     630          94 :         struct xfs_mount                *mp = lip->li_log->l_mp;
     631          94 :         struct xfs_inode                *ip;
     632          94 :         struct xfs_da_args              *args;
     633          94 :         struct xfs_trans                *tp;
     634          94 :         struct xfs_trans_res            tres;
     635          94 :         struct xfs_attri_log_format     *attrp;
     636          94 :         struct xfs_attri_log_nameval    *nv = attrip->attri_nameval;
     637          94 :         int                             error;
     638          94 :         int                             total;
     639          94 :         int                             local;
     640          94 :         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          94 :         attrp = &attrip->attri_format;
     647         188 :         if (!xfs_attri_validate(mp, attrp) ||
     648          94 :             !xfs_attr_namecheck(mp, nv->name.i_addr, nv->name.i_len,
     649             :                                 attrp->alfi_attr_filter))
     650           0 :                 return -EFSCORRUPTED;
     651             : 
     652          94 :         error = xlog_recover_iget(mp,  attrp->alfi_ino, &ip);
     653          94 :         if (error)
     654             :                 return error;
     655             : 
     656          94 :         attr = kmem_zalloc(sizeof(struct xfs_attr_intent) +
     657             :                            sizeof(struct xfs_da_args), KM_NOFS);
     658          94 :         args = (struct xfs_da_args *)(attr + 1);
     659             : 
     660          94 :         attr->xattri_da_args = args;
     661          94 :         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          94 :         attr->xattri_nameval = xfs_attri_log_nameval_get(nv);
     669          94 :         ASSERT(attr->xattri_nameval);
     670             : 
     671          94 :         args->dp = ip;
     672          94 :         args->geo = mp->m_attr_geo;
     673          94 :         args->whichfork = XFS_ATTR_FORK;
     674          94 :         args->name = nv->name.i_addr;
     675          94 :         args->namelen = nv->name.i_len;
     676          94 :         args->new_name = nv->new_name.i_addr;
     677          94 :         args->new_namelen = nv->new_name.i_len;
     678          94 :         args->hashval = xfs_da_hashname(args->name, args->namelen);
     679          94 :         args->value = nv->value.i_addr;
     680          94 :         args->valuelen = nv->value.i_len;
     681          94 :         args->new_value = nv->new_value.i_addr;
     682          94 :         args->new_valuelen = nv->new_value.i_len;
     683          94 :         args->attr_filter = attrp->alfi_attr_filter & XFS_ATTRI_FILTER_MASK;
     684          94 :         args->op_flags = XFS_DA_OP_RECOVERY | XFS_DA_OP_OKNOENT |
     685             :                          XFS_DA_OP_LOGGED;
     686          94 :         args->owner = ip->i_ino;
     687             : 
     688         188 :         ASSERT(xfs_sb_version_haslogxattrs(&mp->m_sb));
     689             : 
     690          94 :         switch (xfs_attr_intent_op(attr)) {
     691          26 :         case XFS_ATTRI_OP_FLAGS_NVREPLACE:
     692             :         case XFS_ATTRI_OP_FLAGS_NVSET:
     693          26 :                 args->op_flags |= XFS_DA_OP_NVLOOKUP;
     694          60 :                 fallthrough;
     695          60 :         case XFS_ATTRI_OP_FLAGS_SET:
     696             :         case XFS_ATTRI_OP_FLAGS_REPLACE:
     697          60 :                 args->total = xfs_attr_calc_size(args, &local);
     698          60 :                 if (xfs_inode_hasattr(args->dp))
     699          43 :                         attr->xattri_dela_state = xfs_attr_init_replace_state(args);
     700             :                 else
     701          17 :                         attr->xattri_dela_state = xfs_attr_init_add_state(args);
     702             :                 break;
     703          10 :         case XFS_ATTRI_OP_FLAGS_NVREMOVE:
     704          10 :                 args->op_flags |= XFS_DA_OP_NVLOOKUP;
     705          34 :                 fallthrough;
     706          34 :         case XFS_ATTRI_OP_FLAGS_REMOVE:
     707          34 :                 if (!xfs_inode_hasattr(args->dp))
     708           0 :                         goto out;
     709          34 :                 attr->xattri_dela_state = xfs_attr_init_remove_state(args);
     710          34 :                 break;
     711           0 :         default:
     712           0 :                 ASSERT(0);
     713           0 :                 error = -EFSCORRUPTED;
     714           0 :                 goto out;
     715             :         }
     716             : 
     717          94 :         xfs_init_attr_trans(args, &tres, &total);
     718          94 :         error = xfs_trans_alloc(mp, &tres, total, 0, XFS_TRANS_RESERVE, &tp);
     719          94 :         if (error)
     720           0 :                 goto out;
     721             : 
     722          94 :         args->trans = tp;
     723          94 :         done_item = xfs_trans_get_attrd(tp, attrip);
     724             : 
     725          94 :         xfs_ilock(ip, XFS_ILOCK_EXCL);
     726          94 :         xfs_trans_ijoin(tp, ip, 0);
     727             : 
     728          94 :         error = xfs_xattri_finish_update(attr, done_item);
     729          94 :         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          61 :                 xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_ATTR, &attr->xattri_list);
     735          61 :                 error = xfs_defer_ops_capture_and_commit(tp, capture_list);
     736          61 :                 if (error)
     737           0 :                         goto out_unlock;
     738             : 
     739          61 :                 xfs_iunlock(ip, XFS_ILOCK_EXCL);
     740          61 :                 xfs_irele(ip);
     741          61 :                 return 0;
     742             :         }
     743          33 :         if (error) {
     744           0 :                 xfs_trans_cancel(tp);
     745           0 :                 goto out_unlock;
     746             :         }
     747             : 
     748          33 :         error = xfs_defer_ops_capture_and_commit(tp, capture_list);
     749          33 : out_unlock:
     750          33 :         xfs_iunlock(ip, XFS_ILOCK_EXCL);
     751          33 :         xfs_irele(ip);
     752          33 : out:
     753          33 :         xfs_attr_free_item(attr);
     754          33 :         return error;
     755             : }
     756             : 
     757             : /* Re-log an intent item to push the log tail forward. */
     758             : static struct xfs_log_item *
     759        1213 : xfs_attri_item_relog(
     760             :         struct xfs_log_item             *intent,
     761             :         struct xfs_trans                *tp)
     762             : {
     763        1213 :         struct xfs_attrd_log_item       *attrdp;
     764        1213 :         struct xfs_attri_log_item       *old_attrip;
     765        1213 :         struct xfs_attri_log_item       *new_attrip;
     766        1213 :         struct xfs_attri_log_format     *new_attrp;
     767        1213 :         struct xfs_attri_log_format     *old_attrp;
     768             : 
     769        1213 :         old_attrip = ATTRI_ITEM(intent);
     770        1213 :         old_attrp = &old_attrip->attri_format;
     771             : 
     772        1213 :         tp->t_flags |= XFS_TRANS_DIRTY;
     773        1213 :         attrdp = xfs_trans_get_attrd(tp, old_attrip);
     774        1213 :         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        1213 :         new_attrip = xfs_attri_init(tp->t_mountp, old_attrip->attri_nameval);
     781        1213 :         new_attrp = &new_attrip->attri_format;
     782             : 
     783        1213 :         new_attrp->alfi_ino = old_attrp->alfi_ino;
     784        1213 :         new_attrp->alfi_op_flags = old_attrp->alfi_op_flags;
     785        1213 :         new_attrp->alfi_value_len = old_attrp->alfi_value_len;
     786             : 
     787        1213 :         if (xfs_attr_log_item_op(old_attrp) == XFS_ATTRI_OP_FLAGS_NVREPLACE) {
     788          81 :                 new_attrp->alfi_new_name_len = old_attrp->alfi_new_name_len;
     789          81 :                 new_attrp->alfi_old_name_len = old_attrp->alfi_old_name_len;
     790          81 :                 new_attrp->alfi_new_value_len = old_attrp->alfi_new_value_len;
     791             :         } else {
     792        1132 :                 new_attrp->alfi_name_len = old_attrp->alfi_name_len;
     793             :         }
     794             : 
     795        1213 :         new_attrp->alfi_attr_filter = old_attrp->alfi_attr_filter;
     796             : 
     797        1213 :         xfs_trans_add_item(tp, &new_attrip->attri_item);
     798        1213 :         set_bit(XFS_LI_DIRTY, &new_attrip->attri_item.li_flags);
     799             : 
     800        1213 :         return &new_attrip->attri_item;
     801             : }
     802             : 
     803             : STATIC int
     804        1719 : 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        1719 :         struct xfs_mount                *mp = log->l_mp;
     811        1719 :         struct xfs_attri_log_item       *attrip;
     812        1719 :         struct xfs_attri_log_format     *attri_formatp;
     813        1719 :         struct xfs_attri_log_nameval    *nv;
     814        1719 :         const void                      *attr_name;
     815        1719 :         const void                      *attr_value = NULL;
     816        1719 :         const void                      *attr_new_name = NULL;
     817        1719 :         const void                      *attr_new_value = NULL;
     818        1719 :         size_t                          len;
     819        1719 :         unsigned int                    name_len = 0;
     820        1719 :         unsigned int                    value_len = 0;
     821        1719 :         unsigned int                    new_name_len = 0;
     822        1719 :         unsigned int                    new_value_len = 0;
     823        1719 :         unsigned int                    op, i = 0;
     824             : 
     825             :         /* Validate xfs_attri_log_format before the large memory allocation */
     826        1719 :         len = sizeof(struct xfs_attri_log_format);
     827        1719 :         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        1719 :         attri_formatp = item->ri_buf[i].i_addr;
     834        1719 :         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        1719 :         op = xfs_attr_log_item_op(attri_formatp);
     842        1719 :         switch (op) {
     843         840 :         case XFS_ATTRI_OP_FLAGS_NVSET:
     844             :         case XFS_ATTRI_OP_FLAGS_NVREMOVE:
     845             :                 /* Log item, attr name, optional attr value */
     846         840 :                 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         840 :                 name_len = attri_formatp->alfi_name_len;
     852         840 :                 value_len = attri_formatp->alfi_value_len;
     853         840 :                 break;
     854          34 :         case XFS_ATTRI_OP_FLAGS_SET:
     855             :         case XFS_ATTRI_OP_FLAGS_REPLACE:
     856             :                 /* Log item, attr name, attr value */
     857          34 :                 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          34 :                 name_len = attri_formatp->alfi_name_len;
     863          34 :                 value_len = attri_formatp->alfi_value_len;
     864          34 :                 break;
     865          24 :         case XFS_ATTRI_OP_FLAGS_REMOVE:
     866             :                 /* Log item, attr name */
     867          24 :                 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          24 :                 name_len = attri_formatp->alfi_name_len;
     873          24 :                 break;
     874         821 :         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         821 :                 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         821 :                 name_len = attri_formatp->alfi_old_name_len;
     885         821 :                 new_name_len = attri_formatp->alfi_new_name_len;
     886         821 :                 value_len = attri_formatp->alfi_value_len;
     887         821 :                 new_value_len = attri_formatp->alfi_new_value_len;
     888         821 :                 break;
     889           0 :         default:
     890           0 :                 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
     891             :                                      attri_formatp, len);
     892           0 :                 return -EFSCORRUPTED;
     893             :         }
     894        1719 :         i++;
     895             : 
     896             :         /* Validate the attr name */
     897        1719 :         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        1719 :         attr_name = item->ri_buf[i].i_addr;
     904        1719 :         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        1719 :         i++;
     911             : 
     912             :         /* Validate the new attr name */
     913        1719 :         if (new_name_len > 0) {
     914         821 :                 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         821 :                 attr_new_name = item->ri_buf[i].i_addr;
     922         821 :                 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        1719 :         if (value_len != 0) {
     934        1695 :                 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        1695 :                 attr_value = item->ri_buf[i].i_addr;
     941        3356 :                 if ((attri_formatp->alfi_attr_filter & XFS_ATTR_PARENT) &&
     942        1661 :                     !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        1695 :                 i++;
     949             :         }
     950             : 
     951             :         /* Validate the new attr value, if present */
     952        1719 :         if (new_value_len != 0) {
     953         821 :                 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         821 :                 attr_new_value = item->ri_buf[i].i_addr;
     960        1642 :                 if ((attri_formatp->alfi_attr_filter & XFS_ATTR_PARENT) &&
     961         821 :                     !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         821 :                 i++;
     968             :         }
     969             : 
     970             :         /*
     971             :          * Make sure we got the correct number of buffers for the operation
     972             :          * that we just loaded.
     973             :          */
     974        1719 :         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        1719 :         switch (op) {
     981          24 :         case XFS_ATTRI_OP_FLAGS_REMOVE:
     982             :                 /* Regular remove operations operate only on names. */
     983          24 :                 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         898 :                 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         898 :                 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         821 :         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         821 :                 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         821 :                 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        1719 :         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        1719 :         attrip = xfs_attri_init(mp, nv);
    1037        3438 :         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        1719 :         xfs_trans_ail_insert(log->l_ailp, &attrip->attri_item, lsn);
    1046        1719 :         xfs_attri_release(attrip);
    1047        1719 :         xfs_attri_log_nameval_put(nv);
    1048        1719 :         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   187637592 : xfs_trans_get_attrd(struct xfs_trans            *tp,
    1056             :                   struct xfs_attri_log_item     *attrip)
    1057             : {
    1058   187637592 :         struct xfs_attrd_log_item               *attrdp;
    1059             : 
    1060   187637592 :         ASSERT(tp != NULL);
    1061             : 
    1062   187637592 :         attrdp = kmem_cache_zalloc(xfs_attrd_cache, GFP_NOFS | __GFP_NOFAIL);
    1063             : 
    1064   187635309 :         xfs_log_item_init(tp->t_mountp, &attrdp->attrd_item, XFS_LI_ATTRD,
    1065             :                           &xfs_attrd_item_ops);
    1066   187640431 :         attrdp->attrd_attrip = attrip;
    1067   187640431 :         attrdp->attrd_format.alfd_alf_id = attrip->attri_format.alfi_id;
    1068             : 
    1069   187640431 :         xfs_trans_add_item(tp, &attrdp->attrd_item);
    1070   187640543 :         return attrdp;
    1071             : }
    1072             : 
    1073             : /* Get an ATTRD so we can process all the attrs. */
    1074             : static struct xfs_log_item *
    1075   544008150 : xfs_attr_create_done(
    1076             :         struct xfs_trans                *tp,
    1077             :         struct xfs_log_item             *intent,
    1078             :         unsigned int                    count)
    1079             : {
    1080   544008150 :         if (!intent)
    1081             :                 return NULL;
    1082             : 
    1083   187638530 :         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        1629 : 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        1629 :         struct xfs_attrd_log_format     *attrd_formatp;
    1110             : 
    1111        1629 :         attrd_formatp = item->ri_buf[0].i_addr;
    1112        1629 :         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        1629 :         xlog_recover_release_intent(log, XFS_LI_ATTRI,
    1119             :                                     attrd_formatp->alfd_alf_id);
    1120        1629 :         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