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-rc3-djwa @ Mon Jul 31 20:08:17 PDT 2023 Lines: 278 336 82.7 %
Date: 2023-07-31 20:08:17 Functions: 25 30 83.3 %

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

Generated by: LCOV version 1.14