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