162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2022 Oracle. All Rights Reserved. 462306a36Sopenharmony_ci * Author: Allison Henderson <allison.henderson@oracle.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "xfs.h" 862306a36Sopenharmony_ci#include "xfs_fs.h" 962306a36Sopenharmony_ci#include "xfs_format.h" 1062306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1162306a36Sopenharmony_ci#include "xfs_shared.h" 1262306a36Sopenharmony_ci#include "xfs_mount.h" 1362306a36Sopenharmony_ci#include "xfs_defer.h" 1462306a36Sopenharmony_ci#include "xfs_log_format.h" 1562306a36Sopenharmony_ci#include "xfs_trans.h" 1662306a36Sopenharmony_ci#include "xfs_bmap_btree.h" 1762306a36Sopenharmony_ci#include "xfs_trans_priv.h" 1862306a36Sopenharmony_ci#include "xfs_log.h" 1962306a36Sopenharmony_ci#include "xfs_inode.h" 2062306a36Sopenharmony_ci#include "xfs_da_format.h" 2162306a36Sopenharmony_ci#include "xfs_da_btree.h" 2262306a36Sopenharmony_ci#include "xfs_attr.h" 2362306a36Sopenharmony_ci#include "xfs_attr_item.h" 2462306a36Sopenharmony_ci#include "xfs_trace.h" 2562306a36Sopenharmony_ci#include "xfs_trans_space.h" 2662306a36Sopenharmony_ci#include "xfs_errortag.h" 2762306a36Sopenharmony_ci#include "xfs_error.h" 2862306a36Sopenharmony_ci#include "xfs_log_priv.h" 2962306a36Sopenharmony_ci#include "xfs_log_recover.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistruct kmem_cache *xfs_attri_cache; 3262306a36Sopenharmony_cistruct kmem_cache *xfs_attrd_cache; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic const struct xfs_item_ops xfs_attri_item_ops; 3562306a36Sopenharmony_cistatic const struct xfs_item_ops xfs_attrd_item_ops; 3662306a36Sopenharmony_cistatic struct xfs_attrd_log_item *xfs_trans_get_attrd(struct xfs_trans *tp, 3762306a36Sopenharmony_ci struct xfs_attri_log_item *attrip); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci return container_of(lip, struct xfs_attri_log_item, attri_item); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * Shared xattr name/value buffers for logged extended attribute operations 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * When logging updates to extended attributes, we can create quite a few 4862306a36Sopenharmony_ci * attribute log intent items for a single xattr update. To avoid cycling the 4962306a36Sopenharmony_ci * memory allocator and memcpy overhead, the name (and value, for setxattr) 5062306a36Sopenharmony_ci * are kept in a refcounted object that is shared across all related log items 5162306a36Sopenharmony_ci * and the upper-level deferred work state structure. The shared buffer has 5262306a36Sopenharmony_ci * a control structure, followed by the name, and then the value. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic inline struct xfs_attri_log_nameval * 5662306a36Sopenharmony_cixfs_attri_log_nameval_get( 5762306a36Sopenharmony_ci struct xfs_attri_log_nameval *nv) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci if (!refcount_inc_not_zero(&nv->refcount)) 6062306a36Sopenharmony_ci return NULL; 6162306a36Sopenharmony_ci return nv; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic inline void 6562306a36Sopenharmony_cixfs_attri_log_nameval_put( 6662306a36Sopenharmony_ci struct xfs_attri_log_nameval *nv) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci if (!nv) 6962306a36Sopenharmony_ci return; 7062306a36Sopenharmony_ci if (refcount_dec_and_test(&nv->refcount)) 7162306a36Sopenharmony_ci kvfree(nv); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic inline struct xfs_attri_log_nameval * 7562306a36Sopenharmony_cixfs_attri_log_nameval_alloc( 7662306a36Sopenharmony_ci const void *name, 7762306a36Sopenharmony_ci unsigned int name_len, 7862306a36Sopenharmony_ci const void *value, 7962306a36Sopenharmony_ci unsigned int value_len) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct xfs_attri_log_nameval *nv; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* 8462306a36Sopenharmony_ci * This could be over 64kB in length, so we have to use kvmalloc() for 8562306a36Sopenharmony_ci * this. But kvmalloc() utterly sucks, so we use our own version. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci nv = xlog_kvmalloc(sizeof(struct xfs_attri_log_nameval) + 8862306a36Sopenharmony_ci name_len + value_len); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci nv->name.i_addr = nv + 1; 9162306a36Sopenharmony_ci nv->name.i_len = name_len; 9262306a36Sopenharmony_ci nv->name.i_type = XLOG_REG_TYPE_ATTR_NAME; 9362306a36Sopenharmony_ci memcpy(nv->name.i_addr, name, name_len); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (value_len) { 9662306a36Sopenharmony_ci nv->value.i_addr = nv->name.i_addr + name_len; 9762306a36Sopenharmony_ci nv->value.i_len = value_len; 9862306a36Sopenharmony_ci memcpy(nv->value.i_addr, value, value_len); 9962306a36Sopenharmony_ci } else { 10062306a36Sopenharmony_ci nv->value.i_addr = NULL; 10162306a36Sopenharmony_ci nv->value.i_len = 0; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci nv->value.i_type = XLOG_REG_TYPE_ATTR_VALUE; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci refcount_set(&nv->refcount, 1); 10662306a36Sopenharmony_ci return nv; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ciSTATIC void 11062306a36Sopenharmony_cixfs_attri_item_free( 11162306a36Sopenharmony_ci struct xfs_attri_log_item *attrip) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci kmem_free(attrip->attri_item.li_lv_shadow); 11462306a36Sopenharmony_ci xfs_attri_log_nameval_put(attrip->attri_nameval); 11562306a36Sopenharmony_ci kmem_cache_free(xfs_attri_cache, attrip); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* 11962306a36Sopenharmony_ci * Freeing the attrip requires that we remove it from the AIL if it has already 12062306a36Sopenharmony_ci * been placed there. However, the ATTRI may not yet have been placed in the 12162306a36Sopenharmony_ci * AIL when called by xfs_attri_release() from ATTRD processing due to the 12262306a36Sopenharmony_ci * ordering of committed vs unpin operations in bulk insert operations. Hence 12362306a36Sopenharmony_ci * the reference count to ensure only the last caller frees the ATTRI. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ciSTATIC void 12662306a36Sopenharmony_cixfs_attri_release( 12762306a36Sopenharmony_ci struct xfs_attri_log_item *attrip) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci ASSERT(atomic_read(&attrip->attri_refcount) > 0); 13062306a36Sopenharmony_ci if (!atomic_dec_and_test(&attrip->attri_refcount)) 13162306a36Sopenharmony_ci return; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci xfs_trans_ail_delete(&attrip->attri_item, 0); 13462306a36Sopenharmony_ci xfs_attri_item_free(attrip); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ciSTATIC void 13862306a36Sopenharmony_cixfs_attri_item_size( 13962306a36Sopenharmony_ci struct xfs_log_item *lip, 14062306a36Sopenharmony_ci int *nvecs, 14162306a36Sopenharmony_ci int *nbytes) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip); 14462306a36Sopenharmony_ci struct xfs_attri_log_nameval *nv = attrip->attri_nameval; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci *nvecs += 2; 14762306a36Sopenharmony_ci *nbytes += sizeof(struct xfs_attri_log_format) + 14862306a36Sopenharmony_ci xlog_calc_iovec_len(nv->name.i_len); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (!nv->value.i_len) 15162306a36Sopenharmony_ci return; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci *nvecs += 1; 15462306a36Sopenharmony_ci *nbytes += xlog_calc_iovec_len(nv->value.i_len); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci/* 15862306a36Sopenharmony_ci * This is called to fill in the log iovecs for the given attri log 15962306a36Sopenharmony_ci * item. We use 1 iovec for the attri_format_item, 1 for the name, and 16062306a36Sopenharmony_ci * another for the value if it is present 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ciSTATIC void 16362306a36Sopenharmony_cixfs_attri_item_format( 16462306a36Sopenharmony_ci struct xfs_log_item *lip, 16562306a36Sopenharmony_ci struct xfs_log_vec *lv) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip); 16862306a36Sopenharmony_ci struct xfs_log_iovec *vecp = NULL; 16962306a36Sopenharmony_ci struct xfs_attri_log_nameval *nv = attrip->attri_nameval; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci attrip->attri_format.alfi_type = XFS_LI_ATTRI; 17262306a36Sopenharmony_ci attrip->attri_format.alfi_size = 1; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* 17562306a36Sopenharmony_ci * This size accounting must be done before copying the attrip into the 17662306a36Sopenharmony_ci * iovec. If we do it after, the wrong size will be recorded to the log 17762306a36Sopenharmony_ci * and we trip across assertion checks for bad region sizes later during 17862306a36Sopenharmony_ci * the log recovery. 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci ASSERT(nv->name.i_len > 0); 18262306a36Sopenharmony_ci attrip->attri_format.alfi_size++; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (nv->value.i_len > 0) 18562306a36Sopenharmony_ci attrip->attri_format.alfi_size++; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT, 18862306a36Sopenharmony_ci &attrip->attri_format, 18962306a36Sopenharmony_ci sizeof(struct xfs_attri_log_format)); 19062306a36Sopenharmony_ci xlog_copy_from_iovec(lv, &vecp, &nv->name); 19162306a36Sopenharmony_ci if (nv->value.i_len > 0) 19262306a36Sopenharmony_ci xlog_copy_from_iovec(lv, &vecp, &nv->value); 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci/* 19662306a36Sopenharmony_ci * The unpin operation is the last place an ATTRI is manipulated in the log. It 19762306a36Sopenharmony_ci * is either inserted in the AIL or aborted in the event of a log I/O error. In 19862306a36Sopenharmony_ci * either case, the ATTRI transaction has been successfully committed to make 19962306a36Sopenharmony_ci * it this far. Therefore, we expect whoever committed the ATTRI to either 20062306a36Sopenharmony_ci * construct and commit the ATTRD or drop the ATTRD's reference in the event of 20162306a36Sopenharmony_ci * error. Simply drop the log's ATTRI reference now that the log is done with 20262306a36Sopenharmony_ci * it. 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_ciSTATIC void 20562306a36Sopenharmony_cixfs_attri_item_unpin( 20662306a36Sopenharmony_ci struct xfs_log_item *lip, 20762306a36Sopenharmony_ci int remove) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci xfs_attri_release(ATTRI_ITEM(lip)); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ciSTATIC void 21462306a36Sopenharmony_cixfs_attri_item_release( 21562306a36Sopenharmony_ci struct xfs_log_item *lip) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci xfs_attri_release(ATTRI_ITEM(lip)); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci/* 22162306a36Sopenharmony_ci * Allocate and initialize an attri item. Caller may allocate an additional 22262306a36Sopenharmony_ci * trailing buffer for name and value 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_ciSTATIC struct xfs_attri_log_item * 22562306a36Sopenharmony_cixfs_attri_init( 22662306a36Sopenharmony_ci struct xfs_mount *mp, 22762306a36Sopenharmony_ci struct xfs_attri_log_nameval *nv) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct xfs_attri_log_item *attrip; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci attrip = kmem_cache_zalloc(xfs_attri_cache, GFP_NOFS | __GFP_NOFAIL); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* 23462306a36Sopenharmony_ci * Grab an extra reference to the name/value buffer for this log item. 23562306a36Sopenharmony_ci * The caller retains its own reference! 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_ci attrip->attri_nameval = xfs_attri_log_nameval_get(nv); 23862306a36Sopenharmony_ci ASSERT(attrip->attri_nameval); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci xfs_log_item_init(mp, &attrip->attri_item, XFS_LI_ATTRI, 24162306a36Sopenharmony_ci &xfs_attri_item_ops); 24262306a36Sopenharmony_ci attrip->attri_format.alfi_id = (uintptr_t)(void *)attrip; 24362306a36Sopenharmony_ci atomic_set(&attrip->attri_refcount, 2); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci return attrip; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic inline struct xfs_attrd_log_item *ATTRD_ITEM(struct xfs_log_item *lip) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci return container_of(lip, struct xfs_attrd_log_item, attrd_item); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ciSTATIC void 25462306a36Sopenharmony_cixfs_attrd_item_free(struct xfs_attrd_log_item *attrdp) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci kmem_free(attrdp->attrd_item.li_lv_shadow); 25762306a36Sopenharmony_ci kmem_cache_free(xfs_attrd_cache, attrdp); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ciSTATIC void 26162306a36Sopenharmony_cixfs_attrd_item_size( 26262306a36Sopenharmony_ci struct xfs_log_item *lip, 26362306a36Sopenharmony_ci int *nvecs, 26462306a36Sopenharmony_ci int *nbytes) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci *nvecs += 1; 26762306a36Sopenharmony_ci *nbytes += sizeof(struct xfs_attrd_log_format); 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci/* 27162306a36Sopenharmony_ci * This is called to fill in the log iovecs for the given attrd log item. We use 27262306a36Sopenharmony_ci * only 1 iovec for the attrd_format, and we point that at the attr_log_format 27362306a36Sopenharmony_ci * structure embedded in the attrd item. 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_ciSTATIC void 27662306a36Sopenharmony_cixfs_attrd_item_format( 27762306a36Sopenharmony_ci struct xfs_log_item *lip, 27862306a36Sopenharmony_ci struct xfs_log_vec *lv) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip); 28162306a36Sopenharmony_ci struct xfs_log_iovec *vecp = NULL; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci attrdp->attrd_format.alfd_type = XFS_LI_ATTRD; 28462306a36Sopenharmony_ci attrdp->attrd_format.alfd_size = 1; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT, 28762306a36Sopenharmony_ci &attrdp->attrd_format, 28862306a36Sopenharmony_ci sizeof(struct xfs_attrd_log_format)); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/* 29262306a36Sopenharmony_ci * The ATTRD is either committed or aborted if the transaction is canceled. If 29362306a36Sopenharmony_ci * the transaction is canceled, drop our reference to the ATTRI and free the 29462306a36Sopenharmony_ci * ATTRD. 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_ciSTATIC void 29762306a36Sopenharmony_cixfs_attrd_item_release( 29862306a36Sopenharmony_ci struct xfs_log_item *lip) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci xfs_attri_release(attrdp->attrd_attrip); 30362306a36Sopenharmony_ci xfs_attrd_item_free(attrdp); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic struct xfs_log_item * 30762306a36Sopenharmony_cixfs_attrd_item_intent( 30862306a36Sopenharmony_ci struct xfs_log_item *lip) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci return &ATTRD_ITEM(lip)->attrd_attrip->attri_item; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci/* 31462306a36Sopenharmony_ci * Performs one step of an attribute update intent and marks the attrd item 31562306a36Sopenharmony_ci * dirty.. An attr operation may be a set or a remove. Note that the 31662306a36Sopenharmony_ci * transaction is marked dirty regardless of whether the operation succeeds or 31762306a36Sopenharmony_ci * fails to support the ATTRI/ATTRD lifecycle rules. 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_ciSTATIC int 32062306a36Sopenharmony_cixfs_xattri_finish_update( 32162306a36Sopenharmony_ci struct xfs_attr_intent *attr, 32262306a36Sopenharmony_ci struct xfs_attrd_log_item *attrdp) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct xfs_da_args *args = attr->xattri_da_args; 32562306a36Sopenharmony_ci int error; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_LARP)) { 32862306a36Sopenharmony_ci error = -EIO; 32962306a36Sopenharmony_ci goto out; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci error = xfs_attr_set_iter(attr); 33362306a36Sopenharmony_ci if (!error && attr->xattri_dela_state != XFS_DAS_DONE) 33462306a36Sopenharmony_ci error = -EAGAIN; 33562306a36Sopenharmony_ciout: 33662306a36Sopenharmony_ci /* 33762306a36Sopenharmony_ci * Mark the transaction dirty, even on error. This ensures the 33862306a36Sopenharmony_ci * transaction is aborted, which: 33962306a36Sopenharmony_ci * 34062306a36Sopenharmony_ci * 1.) releases the ATTRI and frees the ATTRD 34162306a36Sopenharmony_ci * 2.) shuts down the filesystem 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_ci args->trans->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* 34662306a36Sopenharmony_ci * attr intent/done items are null when logged attributes are disabled 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci if (attrdp) 34962306a36Sopenharmony_ci set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return error; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci/* Log an attr to the intent item. */ 35562306a36Sopenharmony_ciSTATIC void 35662306a36Sopenharmony_cixfs_attr_log_item( 35762306a36Sopenharmony_ci struct xfs_trans *tp, 35862306a36Sopenharmony_ci struct xfs_attri_log_item *attrip, 35962306a36Sopenharmony_ci const struct xfs_attr_intent *attr) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci struct xfs_attri_log_format *attrp; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci tp->t_flags |= XFS_TRANS_DIRTY; 36462306a36Sopenharmony_ci set_bit(XFS_LI_DIRTY, &attrip->attri_item.li_flags); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* 36762306a36Sopenharmony_ci * At this point the xfs_attr_intent has been constructed, and we've 36862306a36Sopenharmony_ci * created the log intent. Fill in the attri log item and log format 36962306a36Sopenharmony_ci * structure with fields from this xfs_attr_intent 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_ci attrp = &attrip->attri_format; 37262306a36Sopenharmony_ci attrp->alfi_ino = attr->xattri_da_args->dp->i_ino; 37362306a36Sopenharmony_ci ASSERT(!(attr->xattri_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK)); 37462306a36Sopenharmony_ci attrp->alfi_op_flags = attr->xattri_op_flags; 37562306a36Sopenharmony_ci attrp->alfi_value_len = attr->xattri_nameval->value.i_len; 37662306a36Sopenharmony_ci attrp->alfi_name_len = attr->xattri_nameval->name.i_len; 37762306a36Sopenharmony_ci ASSERT(!(attr->xattri_da_args->attr_filter & ~XFS_ATTRI_FILTER_MASK)); 37862306a36Sopenharmony_ci attrp->alfi_attr_filter = attr->xattri_da_args->attr_filter; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci/* Get an ATTRI. */ 38262306a36Sopenharmony_cistatic struct xfs_log_item * 38362306a36Sopenharmony_cixfs_attr_create_intent( 38462306a36Sopenharmony_ci struct xfs_trans *tp, 38562306a36Sopenharmony_ci struct list_head *items, 38662306a36Sopenharmony_ci unsigned int count, 38762306a36Sopenharmony_ci bool sort) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct xfs_mount *mp = tp->t_mountp; 39062306a36Sopenharmony_ci struct xfs_attri_log_item *attrip; 39162306a36Sopenharmony_ci struct xfs_attr_intent *attr; 39262306a36Sopenharmony_ci struct xfs_da_args *args; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci ASSERT(count == 1); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * Each attr item only performs one attribute operation at a time, so 39862306a36Sopenharmony_ci * this is a list of one 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ci attr = list_first_entry_or_null(items, struct xfs_attr_intent, 40162306a36Sopenharmony_ci xattri_list); 40262306a36Sopenharmony_ci args = attr->xattri_da_args; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (!(args->op_flags & XFS_DA_OP_LOGGED)) 40562306a36Sopenharmony_ci return NULL; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* 40862306a36Sopenharmony_ci * Create a buffer to store the attribute name and value. This buffer 40962306a36Sopenharmony_ci * will be shared between the higher level deferred xattr work state 41062306a36Sopenharmony_ci * and the lower level xattr log items. 41162306a36Sopenharmony_ci */ 41262306a36Sopenharmony_ci if (!attr->xattri_nameval) { 41362306a36Sopenharmony_ci /* 41462306a36Sopenharmony_ci * Transfer our reference to the name/value buffer to the 41562306a36Sopenharmony_ci * deferred work state structure. 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_ci attr->xattri_nameval = xfs_attri_log_nameval_alloc(args->name, 41862306a36Sopenharmony_ci args->namelen, args->value, args->valuelen); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci attrip = xfs_attri_init(mp, attr->xattri_nameval); 42262306a36Sopenharmony_ci xfs_trans_add_item(tp, &attrip->attri_item); 42362306a36Sopenharmony_ci xfs_attr_log_item(tp, attrip, attr); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return &attrip->attri_item; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic inline void 42962306a36Sopenharmony_cixfs_attr_free_item( 43062306a36Sopenharmony_ci struct xfs_attr_intent *attr) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci if (attr->xattri_da_state) 43362306a36Sopenharmony_ci xfs_da_state_free(attr->xattri_da_state); 43462306a36Sopenharmony_ci xfs_attri_log_nameval_put(attr->xattri_nameval); 43562306a36Sopenharmony_ci if (attr->xattri_da_args->op_flags & XFS_DA_OP_RECOVERY) 43662306a36Sopenharmony_ci kmem_free(attr); 43762306a36Sopenharmony_ci else 43862306a36Sopenharmony_ci kmem_cache_free(xfs_attr_intent_cache, attr); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/* Process an attr. */ 44262306a36Sopenharmony_ciSTATIC int 44362306a36Sopenharmony_cixfs_attr_finish_item( 44462306a36Sopenharmony_ci struct xfs_trans *tp, 44562306a36Sopenharmony_ci struct xfs_log_item *done, 44662306a36Sopenharmony_ci struct list_head *item, 44762306a36Sopenharmony_ci struct xfs_btree_cur **state) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci struct xfs_attr_intent *attr; 45062306a36Sopenharmony_ci struct xfs_attrd_log_item *done_item = NULL; 45162306a36Sopenharmony_ci int error; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci attr = container_of(item, struct xfs_attr_intent, xattri_list); 45462306a36Sopenharmony_ci if (done) 45562306a36Sopenharmony_ci done_item = ATTRD_ITEM(done); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* 45862306a36Sopenharmony_ci * Always reset trans after EAGAIN cycle 45962306a36Sopenharmony_ci * since the transaction is new 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_ci attr->xattri_da_args->trans = tp; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci error = xfs_xattri_finish_update(attr, done_item); 46462306a36Sopenharmony_ci if (error != -EAGAIN) 46562306a36Sopenharmony_ci xfs_attr_free_item(attr); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci return error; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci/* Abort all pending ATTRs. */ 47162306a36Sopenharmony_ciSTATIC void 47262306a36Sopenharmony_cixfs_attr_abort_intent( 47362306a36Sopenharmony_ci struct xfs_log_item *intent) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci xfs_attri_release(ATTRI_ITEM(intent)); 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci/* Cancel an attr */ 47962306a36Sopenharmony_ciSTATIC void 48062306a36Sopenharmony_cixfs_attr_cancel_item( 48162306a36Sopenharmony_ci struct list_head *item) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci struct xfs_attr_intent *attr; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci attr = container_of(item, struct xfs_attr_intent, xattri_list); 48662306a36Sopenharmony_ci xfs_attr_free_item(attr); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ciSTATIC bool 49062306a36Sopenharmony_cixfs_attri_item_match( 49162306a36Sopenharmony_ci struct xfs_log_item *lip, 49262306a36Sopenharmony_ci uint64_t intent_id) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci return ATTRI_ITEM(lip)->attri_format.alfi_id == intent_id; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci/* Is this recovered ATTRI format ok? */ 49862306a36Sopenharmony_cistatic inline bool 49962306a36Sopenharmony_cixfs_attri_validate( 50062306a36Sopenharmony_ci struct xfs_mount *mp, 50162306a36Sopenharmony_ci struct xfs_attri_log_format *attrp) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci unsigned int op = attrp->alfi_op_flags & 50462306a36Sopenharmony_ci XFS_ATTRI_OP_FLAGS_TYPE_MASK; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (attrp->__pad != 0) 50762306a36Sopenharmony_ci return false; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (attrp->alfi_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK) 51062306a36Sopenharmony_ci return false; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (attrp->alfi_attr_filter & ~XFS_ATTRI_FILTER_MASK) 51362306a36Sopenharmony_ci return false; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* alfi_op_flags should be either a set or remove */ 51662306a36Sopenharmony_ci switch (op) { 51762306a36Sopenharmony_ci case XFS_ATTRI_OP_FLAGS_SET: 51862306a36Sopenharmony_ci case XFS_ATTRI_OP_FLAGS_REPLACE: 51962306a36Sopenharmony_ci case XFS_ATTRI_OP_FLAGS_REMOVE: 52062306a36Sopenharmony_ci break; 52162306a36Sopenharmony_ci default: 52262306a36Sopenharmony_ci return false; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (attrp->alfi_value_len > XATTR_SIZE_MAX) 52662306a36Sopenharmony_ci return false; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if ((attrp->alfi_name_len > XATTR_NAME_MAX) || 52962306a36Sopenharmony_ci (attrp->alfi_name_len == 0)) 53062306a36Sopenharmony_ci return false; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci return xfs_verify_ino(mp, attrp->alfi_ino); 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci/* 53662306a36Sopenharmony_ci * Process an attr intent item that was recovered from the log. We need to 53762306a36Sopenharmony_ci * delete the attr that it describes. 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ciSTATIC int 54062306a36Sopenharmony_cixfs_attri_item_recover( 54162306a36Sopenharmony_ci struct xfs_log_item *lip, 54262306a36Sopenharmony_ci struct list_head *capture_list) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip); 54562306a36Sopenharmony_ci struct xfs_attr_intent *attr; 54662306a36Sopenharmony_ci struct xfs_mount *mp = lip->li_log->l_mp; 54762306a36Sopenharmony_ci struct xfs_inode *ip; 54862306a36Sopenharmony_ci struct xfs_da_args *args; 54962306a36Sopenharmony_ci struct xfs_trans *tp; 55062306a36Sopenharmony_ci struct xfs_trans_res resv; 55162306a36Sopenharmony_ci struct xfs_attri_log_format *attrp; 55262306a36Sopenharmony_ci struct xfs_attri_log_nameval *nv = attrip->attri_nameval; 55362306a36Sopenharmony_ci int error; 55462306a36Sopenharmony_ci int total; 55562306a36Sopenharmony_ci int local; 55662306a36Sopenharmony_ci struct xfs_attrd_log_item *done_item = NULL; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* 55962306a36Sopenharmony_ci * First check the validity of the attr described by the ATTRI. If any 56062306a36Sopenharmony_ci * are bad, then assume that all are bad and just toss the ATTRI. 56162306a36Sopenharmony_ci */ 56262306a36Sopenharmony_ci attrp = &attrip->attri_format; 56362306a36Sopenharmony_ci if (!xfs_attri_validate(mp, attrp) || 56462306a36Sopenharmony_ci !xfs_attr_namecheck(nv->name.i_addr, nv->name.i_len)) 56562306a36Sopenharmony_ci return -EFSCORRUPTED; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci error = xlog_recover_iget(mp, attrp->alfi_ino, &ip); 56862306a36Sopenharmony_ci if (error) 56962306a36Sopenharmony_ci return error; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci attr = kmem_zalloc(sizeof(struct xfs_attr_intent) + 57262306a36Sopenharmony_ci sizeof(struct xfs_da_args), KM_NOFS); 57362306a36Sopenharmony_ci args = (struct xfs_da_args *)(attr + 1); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci attr->xattri_da_args = args; 57662306a36Sopenharmony_ci attr->xattri_op_flags = attrp->alfi_op_flags & 57762306a36Sopenharmony_ci XFS_ATTRI_OP_FLAGS_TYPE_MASK; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* 58062306a36Sopenharmony_ci * We're reconstructing the deferred work state structure from the 58162306a36Sopenharmony_ci * recovered log item. Grab a reference to the name/value buffer and 58262306a36Sopenharmony_ci * attach it to the new work state. 58362306a36Sopenharmony_ci */ 58462306a36Sopenharmony_ci attr->xattri_nameval = xfs_attri_log_nameval_get(nv); 58562306a36Sopenharmony_ci ASSERT(attr->xattri_nameval); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci args->dp = ip; 58862306a36Sopenharmony_ci args->geo = mp->m_attr_geo; 58962306a36Sopenharmony_ci args->whichfork = XFS_ATTR_FORK; 59062306a36Sopenharmony_ci args->name = nv->name.i_addr; 59162306a36Sopenharmony_ci args->namelen = nv->name.i_len; 59262306a36Sopenharmony_ci args->hashval = xfs_da_hashname(args->name, args->namelen); 59362306a36Sopenharmony_ci args->attr_filter = attrp->alfi_attr_filter & XFS_ATTRI_FILTER_MASK; 59462306a36Sopenharmony_ci args->op_flags = XFS_DA_OP_RECOVERY | XFS_DA_OP_OKNOENT | 59562306a36Sopenharmony_ci XFS_DA_OP_LOGGED; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci ASSERT(xfs_sb_version_haslogxattrs(&mp->m_sb)); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci switch (attr->xattri_op_flags) { 60062306a36Sopenharmony_ci case XFS_ATTRI_OP_FLAGS_SET: 60162306a36Sopenharmony_ci case XFS_ATTRI_OP_FLAGS_REPLACE: 60262306a36Sopenharmony_ci args->value = nv->value.i_addr; 60362306a36Sopenharmony_ci args->valuelen = nv->value.i_len; 60462306a36Sopenharmony_ci args->total = xfs_attr_calc_size(args, &local); 60562306a36Sopenharmony_ci if (xfs_inode_hasattr(args->dp)) 60662306a36Sopenharmony_ci attr->xattri_dela_state = xfs_attr_init_replace_state(args); 60762306a36Sopenharmony_ci else 60862306a36Sopenharmony_ci attr->xattri_dela_state = xfs_attr_init_add_state(args); 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci case XFS_ATTRI_OP_FLAGS_REMOVE: 61162306a36Sopenharmony_ci if (!xfs_inode_hasattr(args->dp)) 61262306a36Sopenharmony_ci goto out; 61362306a36Sopenharmony_ci attr->xattri_dela_state = xfs_attr_init_remove_state(args); 61462306a36Sopenharmony_ci break; 61562306a36Sopenharmony_ci default: 61662306a36Sopenharmony_ci ASSERT(0); 61762306a36Sopenharmony_ci error = -EFSCORRUPTED; 61862306a36Sopenharmony_ci goto out; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci xfs_init_attr_trans(args, &resv, &total); 62262306a36Sopenharmony_ci resv = xlog_recover_resv(&resv); 62362306a36Sopenharmony_ci error = xfs_trans_alloc(mp, &resv, total, 0, XFS_TRANS_RESERVE, &tp); 62462306a36Sopenharmony_ci if (error) 62562306a36Sopenharmony_ci goto out; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci args->trans = tp; 62862306a36Sopenharmony_ci done_item = xfs_trans_get_attrd(tp, attrip); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci xfs_ilock(ip, XFS_ILOCK_EXCL); 63162306a36Sopenharmony_ci xfs_trans_ijoin(tp, ip, 0); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci error = xfs_xattri_finish_update(attr, done_item); 63462306a36Sopenharmony_ci if (error == -EAGAIN) { 63562306a36Sopenharmony_ci /* 63662306a36Sopenharmony_ci * There's more work to do, so add the intent item to this 63762306a36Sopenharmony_ci * transaction so that we can continue it later. 63862306a36Sopenharmony_ci */ 63962306a36Sopenharmony_ci xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_ATTR, &attr->xattri_list); 64062306a36Sopenharmony_ci error = xfs_defer_ops_capture_and_commit(tp, capture_list); 64162306a36Sopenharmony_ci if (error) 64262306a36Sopenharmony_ci goto out_unlock; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci xfs_iunlock(ip, XFS_ILOCK_EXCL); 64562306a36Sopenharmony_ci xfs_irele(ip); 64662306a36Sopenharmony_ci return 0; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci if (error) { 64962306a36Sopenharmony_ci xfs_trans_cancel(tp); 65062306a36Sopenharmony_ci goto out_unlock; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci error = xfs_defer_ops_capture_and_commit(tp, capture_list); 65462306a36Sopenharmony_ciout_unlock: 65562306a36Sopenharmony_ci xfs_iunlock(ip, XFS_ILOCK_EXCL); 65662306a36Sopenharmony_ci xfs_irele(ip); 65762306a36Sopenharmony_ciout: 65862306a36Sopenharmony_ci xfs_attr_free_item(attr); 65962306a36Sopenharmony_ci return error; 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci/* Re-log an intent item to push the log tail forward. */ 66362306a36Sopenharmony_cistatic struct xfs_log_item * 66462306a36Sopenharmony_cixfs_attri_item_relog( 66562306a36Sopenharmony_ci struct xfs_log_item *intent, 66662306a36Sopenharmony_ci struct xfs_trans *tp) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci struct xfs_attrd_log_item *attrdp; 66962306a36Sopenharmony_ci struct xfs_attri_log_item *old_attrip; 67062306a36Sopenharmony_ci struct xfs_attri_log_item *new_attrip; 67162306a36Sopenharmony_ci struct xfs_attri_log_format *new_attrp; 67262306a36Sopenharmony_ci struct xfs_attri_log_format *old_attrp; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci old_attrip = ATTRI_ITEM(intent); 67562306a36Sopenharmony_ci old_attrp = &old_attrip->attri_format; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci tp->t_flags |= XFS_TRANS_DIRTY; 67862306a36Sopenharmony_ci attrdp = xfs_trans_get_attrd(tp, old_attrip); 67962306a36Sopenharmony_ci set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci /* 68262306a36Sopenharmony_ci * Create a new log item that shares the same name/value buffer as the 68362306a36Sopenharmony_ci * old log item. 68462306a36Sopenharmony_ci */ 68562306a36Sopenharmony_ci new_attrip = xfs_attri_init(tp->t_mountp, old_attrip->attri_nameval); 68662306a36Sopenharmony_ci new_attrp = &new_attrip->attri_format; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci new_attrp->alfi_ino = old_attrp->alfi_ino; 68962306a36Sopenharmony_ci new_attrp->alfi_op_flags = old_attrp->alfi_op_flags; 69062306a36Sopenharmony_ci new_attrp->alfi_value_len = old_attrp->alfi_value_len; 69162306a36Sopenharmony_ci new_attrp->alfi_name_len = old_attrp->alfi_name_len; 69262306a36Sopenharmony_ci new_attrp->alfi_attr_filter = old_attrp->alfi_attr_filter; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci xfs_trans_add_item(tp, &new_attrip->attri_item); 69562306a36Sopenharmony_ci set_bit(XFS_LI_DIRTY, &new_attrip->attri_item.li_flags); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci return &new_attrip->attri_item; 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ciSTATIC int 70162306a36Sopenharmony_cixlog_recover_attri_commit_pass2( 70262306a36Sopenharmony_ci struct xlog *log, 70362306a36Sopenharmony_ci struct list_head *buffer_list, 70462306a36Sopenharmony_ci struct xlog_recover_item *item, 70562306a36Sopenharmony_ci xfs_lsn_t lsn) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci struct xfs_mount *mp = log->l_mp; 70862306a36Sopenharmony_ci struct xfs_attri_log_item *attrip; 70962306a36Sopenharmony_ci struct xfs_attri_log_format *attri_formatp; 71062306a36Sopenharmony_ci struct xfs_attri_log_nameval *nv; 71162306a36Sopenharmony_ci const void *attr_value = NULL; 71262306a36Sopenharmony_ci const void *attr_name; 71362306a36Sopenharmony_ci size_t len; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci attri_formatp = item->ri_buf[0].i_addr; 71662306a36Sopenharmony_ci attr_name = item->ri_buf[1].i_addr; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* Validate xfs_attri_log_format before the large memory allocation */ 71962306a36Sopenharmony_ci len = sizeof(struct xfs_attri_log_format); 72062306a36Sopenharmony_ci if (item->ri_buf[0].i_len != len) { 72162306a36Sopenharmony_ci XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 72262306a36Sopenharmony_ci item->ri_buf[0].i_addr, item->ri_buf[0].i_len); 72362306a36Sopenharmony_ci return -EFSCORRUPTED; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (!xfs_attri_validate(mp, attri_formatp)) { 72762306a36Sopenharmony_ci XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 72862306a36Sopenharmony_ci item->ri_buf[0].i_addr, item->ri_buf[0].i_len); 72962306a36Sopenharmony_ci return -EFSCORRUPTED; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* Validate the attr name */ 73362306a36Sopenharmony_ci if (item->ri_buf[1].i_len != 73462306a36Sopenharmony_ci xlog_calc_iovec_len(attri_formatp->alfi_name_len)) { 73562306a36Sopenharmony_ci XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 73662306a36Sopenharmony_ci item->ri_buf[0].i_addr, item->ri_buf[0].i_len); 73762306a36Sopenharmony_ci return -EFSCORRUPTED; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (!xfs_attr_namecheck(attr_name, attri_formatp->alfi_name_len)) { 74162306a36Sopenharmony_ci XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 74262306a36Sopenharmony_ci item->ri_buf[1].i_addr, item->ri_buf[1].i_len); 74362306a36Sopenharmony_ci return -EFSCORRUPTED; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* Validate the attr value, if present */ 74762306a36Sopenharmony_ci if (attri_formatp->alfi_value_len != 0) { 74862306a36Sopenharmony_ci if (item->ri_buf[2].i_len != xlog_calc_iovec_len(attri_formatp->alfi_value_len)) { 74962306a36Sopenharmony_ci XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 75062306a36Sopenharmony_ci item->ri_buf[0].i_addr, 75162306a36Sopenharmony_ci item->ri_buf[0].i_len); 75262306a36Sopenharmony_ci return -EFSCORRUPTED; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci attr_value = item->ri_buf[2].i_addr; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci /* 75962306a36Sopenharmony_ci * Memory alloc failure will cause replay to abort. We attach the 76062306a36Sopenharmony_ci * name/value buffer to the recovered incore log item and drop our 76162306a36Sopenharmony_ci * reference. 76262306a36Sopenharmony_ci */ 76362306a36Sopenharmony_ci nv = xfs_attri_log_nameval_alloc(attr_name, 76462306a36Sopenharmony_ci attri_formatp->alfi_name_len, attr_value, 76562306a36Sopenharmony_ci attri_formatp->alfi_value_len); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci attrip = xfs_attri_init(mp, nv); 76862306a36Sopenharmony_ci memcpy(&attrip->attri_format, attri_formatp, len); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci /* 77162306a36Sopenharmony_ci * The ATTRI has two references. One for the ATTRD and one for ATTRI to 77262306a36Sopenharmony_ci * ensure it makes it into the AIL. Insert the ATTRI into the AIL 77362306a36Sopenharmony_ci * directly and drop the ATTRI reference. Note that 77462306a36Sopenharmony_ci * xfs_trans_ail_update() drops the AIL lock. 77562306a36Sopenharmony_ci */ 77662306a36Sopenharmony_ci xfs_trans_ail_insert(log->l_ailp, &attrip->attri_item, lsn); 77762306a36Sopenharmony_ci xfs_attri_release(attrip); 77862306a36Sopenharmony_ci xfs_attri_log_nameval_put(nv); 77962306a36Sopenharmony_ci return 0; 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci/* 78362306a36Sopenharmony_ci * This routine is called to allocate an "attr free done" log item. 78462306a36Sopenharmony_ci */ 78562306a36Sopenharmony_cistatic struct xfs_attrd_log_item * 78662306a36Sopenharmony_cixfs_trans_get_attrd(struct xfs_trans *tp, 78762306a36Sopenharmony_ci struct xfs_attri_log_item *attrip) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci struct xfs_attrd_log_item *attrdp; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci ASSERT(tp != NULL); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci attrdp = kmem_cache_zalloc(xfs_attrd_cache, GFP_NOFS | __GFP_NOFAIL); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci xfs_log_item_init(tp->t_mountp, &attrdp->attrd_item, XFS_LI_ATTRD, 79662306a36Sopenharmony_ci &xfs_attrd_item_ops); 79762306a36Sopenharmony_ci attrdp->attrd_attrip = attrip; 79862306a36Sopenharmony_ci attrdp->attrd_format.alfd_alf_id = attrip->attri_format.alfi_id; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci xfs_trans_add_item(tp, &attrdp->attrd_item); 80162306a36Sopenharmony_ci return attrdp; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci/* Get an ATTRD so we can process all the attrs. */ 80562306a36Sopenharmony_cistatic struct xfs_log_item * 80662306a36Sopenharmony_cixfs_attr_create_done( 80762306a36Sopenharmony_ci struct xfs_trans *tp, 80862306a36Sopenharmony_ci struct xfs_log_item *intent, 80962306a36Sopenharmony_ci unsigned int count) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci if (!intent) 81262306a36Sopenharmony_ci return NULL; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci return &xfs_trans_get_attrd(tp, ATTRI_ITEM(intent))->attrd_item; 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ciconst struct xfs_defer_op_type xfs_attr_defer_type = { 81862306a36Sopenharmony_ci .max_items = 1, 81962306a36Sopenharmony_ci .create_intent = xfs_attr_create_intent, 82062306a36Sopenharmony_ci .abort_intent = xfs_attr_abort_intent, 82162306a36Sopenharmony_ci .create_done = xfs_attr_create_done, 82262306a36Sopenharmony_ci .finish_item = xfs_attr_finish_item, 82362306a36Sopenharmony_ci .cancel_item = xfs_attr_cancel_item, 82462306a36Sopenharmony_ci}; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci/* 82762306a36Sopenharmony_ci * This routine is called when an ATTRD format structure is found in a committed 82862306a36Sopenharmony_ci * transaction in the log. Its purpose is to cancel the corresponding ATTRI if 82962306a36Sopenharmony_ci * it was still in the log. To do this it searches the AIL for the ATTRI with 83062306a36Sopenharmony_ci * an id equal to that in the ATTRD format structure. If we find it we drop 83162306a36Sopenharmony_ci * the ATTRD reference, which removes the ATTRI from the AIL and frees it. 83262306a36Sopenharmony_ci */ 83362306a36Sopenharmony_ciSTATIC int 83462306a36Sopenharmony_cixlog_recover_attrd_commit_pass2( 83562306a36Sopenharmony_ci struct xlog *log, 83662306a36Sopenharmony_ci struct list_head *buffer_list, 83762306a36Sopenharmony_ci struct xlog_recover_item *item, 83862306a36Sopenharmony_ci xfs_lsn_t lsn) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct xfs_attrd_log_format *attrd_formatp; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci attrd_formatp = item->ri_buf[0].i_addr; 84362306a36Sopenharmony_ci if (item->ri_buf[0].i_len != sizeof(struct xfs_attrd_log_format)) { 84462306a36Sopenharmony_ci XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp, 84562306a36Sopenharmony_ci item->ri_buf[0].i_addr, item->ri_buf[0].i_len); 84662306a36Sopenharmony_ci return -EFSCORRUPTED; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci xlog_recover_release_intent(log, XFS_LI_ATTRI, 85062306a36Sopenharmony_ci attrd_formatp->alfd_alf_id); 85162306a36Sopenharmony_ci return 0; 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_cistatic const struct xfs_item_ops xfs_attri_item_ops = { 85562306a36Sopenharmony_ci .flags = XFS_ITEM_INTENT, 85662306a36Sopenharmony_ci .iop_size = xfs_attri_item_size, 85762306a36Sopenharmony_ci .iop_format = xfs_attri_item_format, 85862306a36Sopenharmony_ci .iop_unpin = xfs_attri_item_unpin, 85962306a36Sopenharmony_ci .iop_release = xfs_attri_item_release, 86062306a36Sopenharmony_ci .iop_recover = xfs_attri_item_recover, 86162306a36Sopenharmony_ci .iop_match = xfs_attri_item_match, 86262306a36Sopenharmony_ci .iop_relog = xfs_attri_item_relog, 86362306a36Sopenharmony_ci}; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ciconst struct xlog_recover_item_ops xlog_attri_item_ops = { 86662306a36Sopenharmony_ci .item_type = XFS_LI_ATTRI, 86762306a36Sopenharmony_ci .commit_pass2 = xlog_recover_attri_commit_pass2, 86862306a36Sopenharmony_ci}; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_cistatic const struct xfs_item_ops xfs_attrd_item_ops = { 87162306a36Sopenharmony_ci .flags = XFS_ITEM_RELEASE_WHEN_COMMITTED | 87262306a36Sopenharmony_ci XFS_ITEM_INTENT_DONE, 87362306a36Sopenharmony_ci .iop_size = xfs_attrd_item_size, 87462306a36Sopenharmony_ci .iop_format = xfs_attrd_item_format, 87562306a36Sopenharmony_ci .iop_release = xfs_attrd_item_release, 87662306a36Sopenharmony_ci .iop_intent = xfs_attrd_item_intent, 87762306a36Sopenharmony_ci}; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ciconst struct xlog_recover_item_ops xlog_attrd_item_ops = { 88062306a36Sopenharmony_ci .item_type = XFS_LI_ATTRD, 88162306a36Sopenharmony_ci .commit_pass2 = xlog_recover_attrd_commit_pass2, 88262306a36Sopenharmony_ci}; 883