brintos

brintos / linux-shallow public Read only

0
0
Text · 33.5 KiB · f683b7a Raw
1260 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2022 Oracle.  All Rights Reserved.4 * Author: Allison Henderson <allison.henderson@oracle.com>5 */6 7#include "xfs.h"8#include "xfs_fs.h"9#include "xfs_format.h"10#include "xfs_trans_resv.h"11#include "xfs_shared.h"12#include "xfs_mount.h"13#include "xfs_defer.h"14#include "xfs_log_format.h"15#include "xfs_trans.h"16#include "xfs_bmap_btree.h"17#include "xfs_trans_priv.h"18#include "xfs_log.h"19#include "xfs_inode.h"20#include "xfs_da_format.h"21#include "xfs_da_btree.h"22#include "xfs_attr.h"23#include "xfs_attr_item.h"24#include "xfs_trace.h"25#include "xfs_trans_space.h"26#include "xfs_errortag.h"27#include "xfs_error.h"28#include "xfs_log_priv.h"29#include "xfs_log_recover.h"30#include "xfs_parent.h"31 32struct kmem_cache		*xfs_attri_cache;33struct kmem_cache		*xfs_attrd_cache;34 35static const struct xfs_item_ops xfs_attri_item_ops;36static const struct xfs_item_ops xfs_attrd_item_ops;37 38static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)39{40	return container_of(lip, struct xfs_attri_log_item, attri_item);41}42 43/*44 * Shared xattr name/value buffers for logged extended attribute operations45 *46 * When logging updates to extended attributes, we can create quite a few47 * attribute log intent items for a single xattr update.  To avoid cycling the48 * memory allocator and memcpy overhead, the name (and value, for setxattr)49 * are kept in a refcounted object that is shared across all related log items50 * and the upper-level deferred work state structure.  The shared buffer has51 * a control structure, followed by the name, and then the value.52 */53 54static inline struct xfs_attri_log_nameval *55xfs_attri_log_nameval_get(56	struct xfs_attri_log_nameval	*nv)57{58	if (!refcount_inc_not_zero(&nv->refcount))59		return NULL;60	return nv;61}62 63static inline void64xfs_attri_log_nameval_put(65	struct xfs_attri_log_nameval	*nv)66{67	if (!nv)68		return;69	if (refcount_dec_and_test(&nv->refcount))70		kvfree(nv);71}72 73static inline struct xfs_attri_log_nameval *74xfs_attri_log_nameval_alloc(75	const void			*name,76	unsigned int			name_len,77	const void			*new_name,78	unsigned int			new_name_len,79	const void			*value,80	unsigned int			value_len,81	const void			*new_value,82	unsigned int			new_value_len)83{84	struct xfs_attri_log_nameval	*nv;85 86	/*87	 * This could be over 64kB in length, so we have to use kvmalloc() for88	 * this. But kvmalloc() utterly sucks, so we use our own version.89	 */90	nv = xlog_kvmalloc(sizeof(struct xfs_attri_log_nameval) +91					name_len + new_name_len + value_len +92					new_value_len);93 94	nv->name.i_addr = nv + 1;95	nv->name.i_len = name_len;96	nv->name.i_type = XLOG_REG_TYPE_ATTR_NAME;97	memcpy(nv->name.i_addr, name, name_len);98 99	if (new_name_len) {100		nv->new_name.i_addr = nv->name.i_addr + name_len;101		nv->new_name.i_len = new_name_len;102		memcpy(nv->new_name.i_addr, new_name, new_name_len);103	} else {104		nv->new_name.i_addr = NULL;105		nv->new_name.i_len = 0;106	}107	nv->new_name.i_type = XLOG_REG_TYPE_ATTR_NEWNAME;108 109	if (value_len) {110		nv->value.i_addr = nv->name.i_addr + name_len + new_name_len;111		nv->value.i_len = value_len;112		memcpy(nv->value.i_addr, value, value_len);113	} else {114		nv->value.i_addr = NULL;115		nv->value.i_len = 0;116	}117	nv->value.i_type = XLOG_REG_TYPE_ATTR_VALUE;118 119	if (new_value_len) {120		nv->new_value.i_addr = nv->name.i_addr + name_len +121						new_name_len + value_len;122		nv->new_value.i_len = new_value_len;123		memcpy(nv->new_value.i_addr, new_value, new_value_len);124	} else {125		nv->new_value.i_addr = NULL;126		nv->new_value.i_len = 0;127	}128	nv->new_value.i_type = XLOG_REG_TYPE_ATTR_NEWVALUE;129 130	refcount_set(&nv->refcount, 1);131	return nv;132}133 134STATIC void135xfs_attri_item_free(136	struct xfs_attri_log_item	*attrip)137{138	kvfree(attrip->attri_item.li_lv_shadow);139	xfs_attri_log_nameval_put(attrip->attri_nameval);140	kmem_cache_free(xfs_attri_cache, attrip);141}142 143/*144 * Freeing the attrip requires that we remove it from the AIL if it has already145 * been placed there. However, the ATTRI may not yet have been placed in the146 * AIL when called by xfs_attri_release() from ATTRD processing due to the147 * ordering of committed vs unpin operations in bulk insert operations. Hence148 * the reference count to ensure only the last caller frees the ATTRI.149 */150STATIC void151xfs_attri_release(152	struct xfs_attri_log_item	*attrip)153{154	ASSERT(atomic_read(&attrip->attri_refcount) > 0);155	if (!atomic_dec_and_test(&attrip->attri_refcount))156		return;157 158	xfs_trans_ail_delete(&attrip->attri_item, 0);159	xfs_attri_item_free(attrip);160}161 162STATIC void163xfs_attri_item_size(164	struct xfs_log_item		*lip,165	int				*nvecs,166	int				*nbytes)167{168	struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);169	struct xfs_attri_log_nameval	*nv = attrip->attri_nameval;170 171	*nvecs += 2;172	*nbytes += sizeof(struct xfs_attri_log_format) +173			xlog_calc_iovec_len(nv->name.i_len);174 175	if (nv->new_name.i_len) {176		*nvecs += 1;177		*nbytes += xlog_calc_iovec_len(nv->new_name.i_len);178	}179 180	if (nv->value.i_len) {181		*nvecs += 1;182		*nbytes += xlog_calc_iovec_len(nv->value.i_len);183	}184 185	if (nv->new_value.i_len) {186		*nvecs += 1;187		*nbytes += xlog_calc_iovec_len(nv->new_value.i_len);188	}189}190 191/*192 * This is called to fill in the log iovecs for the given attri log193 * item. We use  1 iovec for the attri_format_item, 1 for the name, and194 * another for the value if it is present195 */196STATIC void197xfs_attri_item_format(198	struct xfs_log_item		*lip,199	struct xfs_log_vec		*lv)200{201	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);202	struct xfs_log_iovec		*vecp = NULL;203	struct xfs_attri_log_nameval	*nv = attrip->attri_nameval;204 205	attrip->attri_format.alfi_type = XFS_LI_ATTRI;206	attrip->attri_format.alfi_size = 1;207 208	/*209	 * This size accounting must be done before copying the attrip into the210	 * iovec.  If we do it after, the wrong size will be recorded to the log211	 * and we trip across assertion checks for bad region sizes later during212	 * the log recovery.213	 */214 215	ASSERT(nv->name.i_len > 0);216	attrip->attri_format.alfi_size++;217 218	if (nv->new_name.i_len > 0)219		attrip->attri_format.alfi_size++;220 221	if (nv->value.i_len > 0)222		attrip->attri_format.alfi_size++;223 224	if (nv->new_value.i_len > 0)225		attrip->attri_format.alfi_size++;226 227	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT,228			&attrip->attri_format,229			sizeof(struct xfs_attri_log_format));230	xlog_copy_from_iovec(lv, &vecp, &nv->name);231 232	if (nv->new_name.i_len > 0)233		xlog_copy_from_iovec(lv, &vecp, &nv->new_name);234 235	if (nv->value.i_len > 0)236		xlog_copy_from_iovec(lv, &vecp, &nv->value);237 238	if (nv->new_value.i_len > 0)239		xlog_copy_from_iovec(lv, &vecp, &nv->new_value);240}241 242/*243 * The unpin operation is the last place an ATTRI is manipulated in the log. It244 * is either inserted in the AIL or aborted in the event of a log I/O error. In245 * either case, the ATTRI transaction has been successfully committed to make246 * it this far. Therefore, we expect whoever committed the ATTRI to either247 * construct and commit the ATTRD or drop the ATTRD's reference in the event of248 * error. Simply drop the log's ATTRI reference now that the log is done with249 * it.250 */251STATIC void252xfs_attri_item_unpin(253	struct xfs_log_item	*lip,254	int			remove)255{256	xfs_attri_release(ATTRI_ITEM(lip));257}258 259 260STATIC void261xfs_attri_item_release(262	struct xfs_log_item	*lip)263{264	xfs_attri_release(ATTRI_ITEM(lip));265}266 267/*268 * Allocate and initialize an attri item.  Caller may allocate an additional269 * trailing buffer for name and value270 */271STATIC struct xfs_attri_log_item *272xfs_attri_init(273	struct xfs_mount		*mp,274	struct xfs_attri_log_nameval	*nv)275{276	struct xfs_attri_log_item	*attrip;277 278	attrip = kmem_cache_zalloc(xfs_attri_cache, GFP_KERNEL | __GFP_NOFAIL);279 280	/*281	 * Grab an extra reference to the name/value buffer for this log item.282	 * The caller retains its own reference!283	 */284	attrip->attri_nameval = xfs_attri_log_nameval_get(nv);285	ASSERT(attrip->attri_nameval);286 287	xfs_log_item_init(mp, &attrip->attri_item, XFS_LI_ATTRI,288			  &xfs_attri_item_ops);289	attrip->attri_format.alfi_id = (uintptr_t)(void *)attrip;290	atomic_set(&attrip->attri_refcount, 2);291 292	return attrip;293}294 295static inline struct xfs_attrd_log_item *ATTRD_ITEM(struct xfs_log_item *lip)296{297	return container_of(lip, struct xfs_attrd_log_item, attrd_item);298}299 300STATIC void301xfs_attrd_item_free(struct xfs_attrd_log_item *attrdp)302{303	kvfree(attrdp->attrd_item.li_lv_shadow);304	kmem_cache_free(xfs_attrd_cache, attrdp);305}306 307STATIC void308xfs_attrd_item_size(309	struct xfs_log_item		*lip,310	int				*nvecs,311	int				*nbytes)312{313	*nvecs += 1;314	*nbytes += sizeof(struct xfs_attrd_log_format);315}316 317/*318 * This is called to fill in the log iovecs for the given attrd log item. We use319 * only 1 iovec for the attrd_format, and we point that at the attr_log_format320 * structure embedded in the attrd item.321 */322STATIC void323xfs_attrd_item_format(324	struct xfs_log_item	*lip,325	struct xfs_log_vec	*lv)326{327	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);328	struct xfs_log_iovec		*vecp = NULL;329 330	attrdp->attrd_format.alfd_type = XFS_LI_ATTRD;331	attrdp->attrd_format.alfd_size = 1;332 333	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT,334			&attrdp->attrd_format,335			sizeof(struct xfs_attrd_log_format));336}337 338/*339 * The ATTRD is either committed or aborted if the transaction is canceled. If340 * the transaction is canceled, drop our reference to the ATTRI and free the341 * ATTRD.342 */343STATIC void344xfs_attrd_item_release(345	struct xfs_log_item		*lip)346{347	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);348 349	xfs_attri_release(attrdp->attrd_attrip);350	xfs_attrd_item_free(attrdp);351}352 353static struct xfs_log_item *354xfs_attrd_item_intent(355	struct xfs_log_item	*lip)356{357	return &ATTRD_ITEM(lip)->attrd_attrip->attri_item;358}359 360static inline unsigned int361xfs_attr_log_item_op(const struct xfs_attri_log_format *attrp)362{363	return attrp->alfi_op_flags & XFS_ATTRI_OP_FLAGS_TYPE_MASK;364}365 366/* Log an attr to the intent item. */367STATIC void368xfs_attr_log_item(369	struct xfs_trans		*tp,370	struct xfs_attri_log_item	*attrip,371	const struct xfs_attr_intent	*attr)372{373	struct xfs_attri_log_format	*attrp;374	struct xfs_attri_log_nameval	*nv = attr->xattri_nameval;375	struct xfs_da_args		*args = attr->xattri_da_args;376 377	/*378	 * At this point the xfs_attr_intent has been constructed, and we've379	 * created the log intent. Fill in the attri log item and log format380	 * structure with fields from this xfs_attr_intent381	 */382	attrp = &attrip->attri_format;383	attrp->alfi_ino = args->dp->i_ino;384	ASSERT(!(attr->xattri_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK));385	attrp->alfi_op_flags = attr->xattri_op_flags;386	attrp->alfi_value_len = nv->value.i_len;387 388	switch (xfs_attr_log_item_op(attrp)) {389	case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:390		ASSERT(nv->value.i_len == nv->new_value.i_len);391 392		attrp->alfi_igen = VFS_I(args->dp)->i_generation;393		attrp->alfi_old_name_len = nv->name.i_len;394		attrp->alfi_new_name_len = nv->new_name.i_len;395		break;396	case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:397	case XFS_ATTRI_OP_FLAGS_PPTR_SET:398		attrp->alfi_igen = VFS_I(args->dp)->i_generation;399		fallthrough;400	default:401		attrp->alfi_name_len = nv->name.i_len;402		break;403	}404 405	ASSERT(!(args->attr_filter & ~XFS_ATTRI_FILTER_MASK));406	attrp->alfi_attr_filter = args->attr_filter;407}408 409/* Get an ATTRI. */410static struct xfs_log_item *411xfs_attr_create_intent(412	struct xfs_trans		*tp,413	struct list_head		*items,414	unsigned int			count,415	bool				sort)416{417	struct xfs_mount		*mp = tp->t_mountp;418	struct xfs_attri_log_item	*attrip;419	struct xfs_attr_intent		*attr;420	struct xfs_da_args		*args;421 422	ASSERT(count == 1);423 424	/*425	 * Each attr item only performs one attribute operation at a time, so426	 * this is a list of one427	 */428	attr = list_first_entry_or_null(items, struct xfs_attr_intent,429			xattri_list);430	args = attr->xattri_da_args;431 432	if (!(args->op_flags & XFS_DA_OP_LOGGED))433		return NULL;434 435	/*436	 * Create a buffer to store the attribute name and value.  This buffer437	 * will be shared between the higher level deferred xattr work state438	 * and the lower level xattr log items.439	 */440	if (!attr->xattri_nameval) {441		/*442		 * Transfer our reference to the name/value buffer to the443		 * deferred work state structure.444		 */445		attr->xattri_nameval = xfs_attri_log_nameval_alloc(446				args->name, args->namelen,447				args->new_name, args->new_namelen,448				args->value, args->valuelen,449				args->new_value, args->new_valuelen);450	}451 452	attrip = xfs_attri_init(mp, attr->xattri_nameval);453	xfs_attr_log_item(tp, attrip, attr);454 455	return &attrip->attri_item;456}457 458static inline void459xfs_attr_free_item(460	struct xfs_attr_intent		*attr)461{462	if (attr->xattri_da_state)463		xfs_da_state_free(attr->xattri_da_state);464	xfs_attri_log_nameval_put(attr->xattri_nameval);465	if (attr->xattri_da_args->op_flags & XFS_DA_OP_RECOVERY)466		kfree(attr);467	else468		kmem_cache_free(xfs_attr_intent_cache, attr);469}470 471static inline struct xfs_attr_intent *attri_entry(const struct list_head *e)472{473	return list_entry(e, struct xfs_attr_intent, xattri_list);474}475 476/* Process an attr. */477STATIC int478xfs_attr_finish_item(479	struct xfs_trans		*tp,480	struct xfs_log_item		*done,481	struct list_head		*item,482	struct xfs_btree_cur		**state)483{484	struct xfs_attr_intent		*attr = attri_entry(item);485	struct xfs_da_args		*args;486	int				error;487 488	args = attr->xattri_da_args;489 490	/* Reset trans after EAGAIN cycle since the transaction is new */491	args->trans = tp;492 493	if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_LARP)) {494		error = -EIO;495		goto out;496	}497 498	/* If an attr removal is trivially complete, we're done. */499	if (attr->xattri_op_flags == XFS_ATTRI_OP_FLAGS_REMOVE &&500	    !xfs_inode_hasattr(args->dp)) {501		error = 0;502		goto out;503	}504 505	error = xfs_attr_set_iter(attr);506	if (!error && attr->xattri_dela_state != XFS_DAS_DONE)507		return -EAGAIN;508 509out:510	xfs_attr_free_item(attr);511	return error;512}513 514/* Abort all pending ATTRs. */515STATIC void516xfs_attr_abort_intent(517	struct xfs_log_item		*intent)518{519	xfs_attri_release(ATTRI_ITEM(intent));520}521 522/* Cancel an attr */523STATIC void524xfs_attr_cancel_item(525	struct list_head		*item)526{527	struct xfs_attr_intent		*attr = attri_entry(item);528 529	xfs_attr_free_item(attr);530}531 532STATIC bool533xfs_attri_item_match(534	struct xfs_log_item	*lip,535	uint64_t		intent_id)536{537	return ATTRI_ITEM(lip)->attri_format.alfi_id == intent_id;538}539 540static inline bool541xfs_attri_validate_namelen(unsigned int namelen)542{543	return namelen > 0 && namelen <= XATTR_NAME_MAX;544}545 546/* Is this recovered ATTRI format ok? */547static inline bool548xfs_attri_validate(549	struct xfs_mount		*mp,550	struct xfs_attri_log_format	*attrp)551{552	unsigned int			op = xfs_attr_log_item_op(attrp);553 554	if (attrp->alfi_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK)555		return false;556 557	if (attrp->alfi_attr_filter & ~XFS_ATTRI_FILTER_MASK)558		return false;559 560	if (!xfs_attr_check_namespace(attrp->alfi_attr_filter &561				      XFS_ATTR_NSP_ONDISK_MASK))562		return false;563 564	switch (op) {565	case XFS_ATTRI_OP_FLAGS_PPTR_SET:566	case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:567		if (!xfs_has_parent(mp))568			return false;569		if (attrp->alfi_value_len != sizeof(struct xfs_parent_rec))570			return false;571		if (!xfs_attri_validate_namelen(attrp->alfi_name_len))572			return false;573		if (!(attrp->alfi_attr_filter & XFS_ATTR_PARENT))574			return false;575		break;576	case XFS_ATTRI_OP_FLAGS_SET:577	case XFS_ATTRI_OP_FLAGS_REPLACE:578		if (!xfs_is_using_logged_xattrs(mp))579			return false;580		if (attrp->alfi_value_len > XATTR_SIZE_MAX)581			return false;582		if (!xfs_attri_validate_namelen(attrp->alfi_name_len))583			return false;584		break;585	case XFS_ATTRI_OP_FLAGS_REMOVE:586		if (!xfs_is_using_logged_xattrs(mp))587			return false;588		if (attrp->alfi_value_len != 0)589			return false;590		if (!xfs_attri_validate_namelen(attrp->alfi_name_len))591			return false;592		break;593	case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:594		if (!xfs_has_parent(mp))595			return false;596		if (!xfs_attri_validate_namelen(attrp->alfi_old_name_len))597			return false;598		if (!xfs_attri_validate_namelen(attrp->alfi_new_name_len))599			return false;600		if (attrp->alfi_value_len != sizeof(struct xfs_parent_rec))601			return false;602		if (!(attrp->alfi_attr_filter & XFS_ATTR_PARENT))603			return false;604		break;605	default:606		return false;607	}608 609	return xfs_verify_ino(mp, attrp->alfi_ino);610}611 612static int613xfs_attri_iread_extents(614	struct xfs_inode		*ip)615{616	struct xfs_trans		*tp;617	int				error;618 619	error = xfs_trans_alloc_empty(ip->i_mount, &tp);620	if (error)621		return error;622 623	xfs_ilock(ip, XFS_ILOCK_EXCL);624	error = xfs_iread_extents(tp, ip, XFS_ATTR_FORK);625	xfs_iunlock(ip, XFS_ILOCK_EXCL);626	xfs_trans_cancel(tp);627 628	return error;629}630 631static inline struct xfs_attr_intent *632xfs_attri_recover_work(633	struct xfs_mount		*mp,634	struct xfs_defer_pending	*dfp,635	struct xfs_attri_log_format	*attrp,636	struct xfs_inode		**ipp,637	struct xfs_attri_log_nameval	*nv)638{639	struct xfs_attr_intent		*attr;640	struct xfs_da_args		*args;641	struct xfs_inode		*ip;642	int				local;643	int				error;644 645	/*646	 * Parent pointer attr items record the generation but regular logged647	 * xattrs do not; select the right iget function.648	 */649	switch (xfs_attr_log_item_op(attrp)) {650	case XFS_ATTRI_OP_FLAGS_PPTR_SET:651	case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:652	case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:653		error = xlog_recover_iget_handle(mp, attrp->alfi_ino,654				attrp->alfi_igen, &ip);655		break;656	default:657		error = xlog_recover_iget(mp, attrp->alfi_ino, &ip);658		break;659	}660	if (error) {661		xfs_irele(ip);662		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, attrp,663				sizeof(*attrp));664		return ERR_PTR(-EFSCORRUPTED);665	}666 667	if (xfs_inode_has_attr_fork(ip)) {668		error = xfs_attri_iread_extents(ip);669		if (error) {670			xfs_irele(ip);671			return ERR_PTR(error);672		}673	}674 675	attr = kzalloc(sizeof(struct xfs_attr_intent) +676			sizeof(struct xfs_da_args), GFP_KERNEL | __GFP_NOFAIL);677	args = (struct xfs_da_args *)(attr + 1);678 679	attr->xattri_da_args = args;680	attr->xattri_op_flags = xfs_attr_log_item_op(attrp);681 682	/*683	 * We're reconstructing the deferred work state structure from the684	 * recovered log item.  Grab a reference to the name/value buffer and685	 * attach it to the new work state.686	 */687	attr->xattri_nameval = xfs_attri_log_nameval_get(nv);688	ASSERT(attr->xattri_nameval);689 690	args->dp = ip;691	args->geo = mp->m_attr_geo;692	args->whichfork = XFS_ATTR_FORK;693	args->name = nv->name.i_addr;694	args->namelen = nv->name.i_len;695	args->new_name = nv->new_name.i_addr;696	args->new_namelen = nv->new_name.i_len;697	args->value = nv->value.i_addr;698	args->valuelen = nv->value.i_len;699	args->new_value = nv->new_value.i_addr;700	args->new_valuelen = nv->new_value.i_len;701	args->attr_filter = attrp->alfi_attr_filter & XFS_ATTRI_FILTER_MASK;702	args->op_flags = XFS_DA_OP_RECOVERY | XFS_DA_OP_OKNOENT |703			 XFS_DA_OP_LOGGED;704	args->owner = args->dp->i_ino;705	xfs_attr_sethash(args);706 707	switch (xfs_attr_intent_op(attr)) {708	case XFS_ATTRI_OP_FLAGS_PPTR_SET:709	case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:710	case XFS_ATTRI_OP_FLAGS_SET:711	case XFS_ATTRI_OP_FLAGS_REPLACE:712		args->total = xfs_attr_calc_size(args, &local);713		if (xfs_inode_hasattr(args->dp))714			attr->xattri_dela_state = xfs_attr_init_replace_state(args);715		else716			attr->xattri_dela_state = xfs_attr_init_add_state(args);717		break;718	case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:719	case XFS_ATTRI_OP_FLAGS_REMOVE:720		attr->xattri_dela_state = xfs_attr_init_remove_state(args);721		break;722	}723 724	xfs_defer_add_item(dfp, &attr->xattri_list);725	*ipp = ip;726	return attr;727}728 729/*730 * Process an attr intent item that was recovered from the log.  We need to731 * delete the attr that it describes.732 */733STATIC int734xfs_attr_recover_work(735	struct xfs_defer_pending	*dfp,736	struct list_head		*capture_list)737{738	struct xfs_log_item		*lip = dfp->dfp_intent;739	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);740	struct xfs_attr_intent		*attr;741	struct xfs_mount		*mp = lip->li_log->l_mp;742	struct xfs_inode		*ip;743	struct xfs_da_args		*args;744	struct xfs_trans		*tp;745	struct xfs_trans_res		resv;746	struct xfs_attri_log_format	*attrp;747	struct xfs_attri_log_nameval	*nv = attrip->attri_nameval;748	int				error;749	unsigned int			total = 0;750 751	/*752	 * First check the validity of the attr described by the ATTRI.  If any753	 * are bad, then assume that all are bad and just toss the ATTRI.754	 */755	attrp = &attrip->attri_format;756	if (!xfs_attri_validate(mp, attrp) ||757	    !xfs_attr_namecheck(attrp->alfi_attr_filter, nv->name.i_addr,758				nv->name.i_len))759		return -EFSCORRUPTED;760 761	attr = xfs_attri_recover_work(mp, dfp, attrp, &ip, nv);762	if (IS_ERR(attr))763		return PTR_ERR(attr);764	args = attr->xattri_da_args;765 766	switch (xfs_attr_intent_op(attr)) {767	case XFS_ATTRI_OP_FLAGS_PPTR_SET:768	case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:769	case XFS_ATTRI_OP_FLAGS_SET:770	case XFS_ATTRI_OP_FLAGS_REPLACE:771		resv = xfs_attr_set_resv(args);772		total = args->total;773		break;774	case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:775	case XFS_ATTRI_OP_FLAGS_REMOVE:776		resv = M_RES(mp)->tr_attrrm;777		total = XFS_ATTRRM_SPACE_RES(mp);778		break;779	}780	resv = xlog_recover_resv(&resv);781	error = xfs_trans_alloc(mp, &resv, total, 0, XFS_TRANS_RESERVE, &tp);782	if (error)783		return error;784	args->trans = tp;785 786	xfs_ilock(ip, XFS_ILOCK_EXCL);787	xfs_trans_ijoin(tp, ip, 0);788 789	error = xlog_recover_finish_intent(tp, dfp);790	if (error == -EFSCORRUPTED)791		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,792				&attrip->attri_format,793				sizeof(attrip->attri_format));794	if (error)795		goto out_cancel;796 797	error = xfs_defer_ops_capture_and_commit(tp, capture_list);798out_unlock:799	xfs_iunlock(ip, XFS_ILOCK_EXCL);800	xfs_irele(ip);801	return error;802out_cancel:803	xfs_trans_cancel(tp);804	goto out_unlock;805}806 807/* Re-log an intent item to push the log tail forward. */808static struct xfs_log_item *809xfs_attr_relog_intent(810	struct xfs_trans		*tp,811	struct xfs_log_item		*intent,812	struct xfs_log_item		*done_item)813{814	struct xfs_attri_log_item	*old_attrip;815	struct xfs_attri_log_item	*new_attrip;816	struct xfs_attri_log_format	*new_attrp;817	struct xfs_attri_log_format	*old_attrp;818 819	old_attrip = ATTRI_ITEM(intent);820	old_attrp = &old_attrip->attri_format;821 822	/*823	 * Create a new log item that shares the same name/value buffer as the824	 * old log item.825	 */826	new_attrip = xfs_attri_init(tp->t_mountp, old_attrip->attri_nameval);827	new_attrp = &new_attrip->attri_format;828 829	new_attrp->alfi_ino = old_attrp->alfi_ino;830	new_attrp->alfi_igen = old_attrp->alfi_igen;831	new_attrp->alfi_op_flags = old_attrp->alfi_op_flags;832	new_attrp->alfi_value_len = old_attrp->alfi_value_len;833 834	switch (xfs_attr_log_item_op(old_attrp)) {835	case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:836		new_attrp->alfi_new_name_len = old_attrp->alfi_new_name_len;837		new_attrp->alfi_old_name_len = old_attrp->alfi_old_name_len;838		break;839	default:840		new_attrp->alfi_name_len = old_attrp->alfi_name_len;841		break;842	}843 844	new_attrp->alfi_attr_filter = old_attrp->alfi_attr_filter;845 846	return &new_attrip->attri_item;847}848 849/* Get an ATTRD so we can process all the attrs. */850static struct xfs_log_item *851xfs_attr_create_done(852	struct xfs_trans		*tp,853	struct xfs_log_item		*intent,854	unsigned int			count)855{856	struct xfs_attri_log_item	*attrip;857	struct xfs_attrd_log_item	*attrdp;858 859	attrip = ATTRI_ITEM(intent);860 861	attrdp = kmem_cache_zalloc(xfs_attrd_cache, GFP_KERNEL | __GFP_NOFAIL);862 863	xfs_log_item_init(tp->t_mountp, &attrdp->attrd_item, XFS_LI_ATTRD,864			  &xfs_attrd_item_ops);865	attrdp->attrd_attrip = attrip;866	attrdp->attrd_format.alfd_alf_id = attrip->attri_format.alfi_id;867 868	return &attrdp->attrd_item;869}870 871void872xfs_attr_defer_add(873	struct xfs_da_args	*args,874	enum xfs_attr_defer_op	op)875{876	struct xfs_attr_intent	*new;877	unsigned int		log_op = 0;878	bool			is_pptr = args->attr_filter & XFS_ATTR_PARENT;879 880	if (is_pptr) {881		ASSERT(xfs_has_parent(args->dp->i_mount));882		ASSERT((args->attr_filter & ~XFS_ATTR_PARENT) == 0);883		ASSERT(args->op_flags & XFS_DA_OP_LOGGED);884		ASSERT(args->valuelen == sizeof(struct xfs_parent_rec));885	}886 887	new = kmem_cache_zalloc(xfs_attr_intent_cache,888			GFP_NOFS | __GFP_NOFAIL);889	new->xattri_da_args = args;890 891	/* Compute log operation from the higher level op and namespace. */892	switch (op) {893	case XFS_ATTR_DEFER_SET:894		if (is_pptr)895			log_op = XFS_ATTRI_OP_FLAGS_PPTR_SET;896		else897			log_op = XFS_ATTRI_OP_FLAGS_SET;898		break;899	case XFS_ATTR_DEFER_REPLACE:900		if (is_pptr)901			log_op = XFS_ATTRI_OP_FLAGS_PPTR_REPLACE;902		else903			log_op = XFS_ATTRI_OP_FLAGS_REPLACE;904		break;905	case XFS_ATTR_DEFER_REMOVE:906		if (is_pptr)907			log_op = XFS_ATTRI_OP_FLAGS_PPTR_REMOVE;908		else909			log_op = XFS_ATTRI_OP_FLAGS_REMOVE;910		break;911	default:912		ASSERT(0);913		break;914	}915	new->xattri_op_flags = log_op;916 917	/* Set up initial attr operation state. */918	switch (log_op) {919	case XFS_ATTRI_OP_FLAGS_PPTR_SET:920	case XFS_ATTRI_OP_FLAGS_SET:921		new->xattri_dela_state = xfs_attr_init_add_state(args);922		break;923	case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:924		ASSERT(args->new_valuelen == args->valuelen);925		new->xattri_dela_state = xfs_attr_init_replace_state(args);926		break;927	case XFS_ATTRI_OP_FLAGS_REPLACE:928		new->xattri_dela_state = xfs_attr_init_replace_state(args);929		break;930	case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:931	case XFS_ATTRI_OP_FLAGS_REMOVE:932		new->xattri_dela_state = xfs_attr_init_remove_state(args);933		break;934	}935 936	xfs_defer_add(args->trans, &new->xattri_list, &xfs_attr_defer_type);937	trace_xfs_attr_defer_add(new->xattri_dela_state, args->dp);938}939 940const struct xfs_defer_op_type xfs_attr_defer_type = {941	.name		= "attr",942	.max_items	= 1,943	.create_intent	= xfs_attr_create_intent,944	.abort_intent	= xfs_attr_abort_intent,945	.create_done	= xfs_attr_create_done,946	.finish_item	= xfs_attr_finish_item,947	.cancel_item	= xfs_attr_cancel_item,948	.recover_work	= xfs_attr_recover_work,949	.relog_intent	= xfs_attr_relog_intent,950};951 952static inline void *953xfs_attri_validate_name_iovec(954	struct xfs_mount		*mp,955	struct xfs_attri_log_format     *attri_formatp,956	const struct xfs_log_iovec	*iovec,957	unsigned int			name_len)958{959	if (iovec->i_len != xlog_calc_iovec_len(name_len)) {960		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,961				attri_formatp, sizeof(*attri_formatp));962		return NULL;963	}964 965	if (!xfs_attr_namecheck(attri_formatp->alfi_attr_filter, iovec->i_addr,966				name_len)) {967		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,968				attri_formatp, sizeof(*attri_formatp));969		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,970				iovec->i_addr, iovec->i_len);971		return NULL;972	}973 974	return iovec->i_addr;975}976 977static inline void *978xfs_attri_validate_value_iovec(979	struct xfs_mount		*mp,980	struct xfs_attri_log_format     *attri_formatp,981	const struct xfs_log_iovec	*iovec,982	unsigned int			value_len)983{984	if (iovec->i_len != xlog_calc_iovec_len(value_len)) {985		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,986				attri_formatp, sizeof(*attri_formatp));987		return NULL;988	}989 990	if ((attri_formatp->alfi_attr_filter & XFS_ATTR_PARENT) &&991	    !xfs_parent_valuecheck(mp, iovec->i_addr, value_len)) {992		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,993				attri_formatp, sizeof(*attri_formatp));994		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,995				iovec->i_addr, iovec->i_len);996		return NULL;997	}998 999	return iovec->i_addr;1000}1001 1002STATIC int1003xlog_recover_attri_commit_pass2(1004	struct xlog                     *log,1005	struct list_head		*buffer_list,1006	struct xlog_recover_item        *item,1007	xfs_lsn_t                       lsn)1008{1009	struct xfs_mount                *mp = log->l_mp;1010	struct xfs_attri_log_item       *attrip;1011	struct xfs_attri_log_format     *attri_formatp;1012	struct xfs_attri_log_nameval	*nv;1013	const void			*attr_name;1014	const void			*attr_value = NULL;1015	const void			*attr_new_name = NULL;1016	const void			*attr_new_value = NULL;1017	size_t				len;1018	unsigned int			name_len = 0;1019	unsigned int			value_len = 0;1020	unsigned int			new_name_len = 0;1021	unsigned int			new_value_len = 0;1022	unsigned int			op, i = 0;1023 1024	/* Validate xfs_attri_log_format before the large memory allocation */1025	len = sizeof(struct xfs_attri_log_format);1026	if (item->ri_buf[i].i_len != len) {1027		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,1028				item->ri_buf[0].i_addr, item->ri_buf[0].i_len);1029		return -EFSCORRUPTED;1030	}1031 1032	attri_formatp = item->ri_buf[i].i_addr;1033	if (!xfs_attri_validate(mp, attri_formatp)) {1034		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,1035				attri_formatp, len);1036		return -EFSCORRUPTED;1037	}1038 1039	/* Check the number of log iovecs makes sense for the op code. */1040	op = xfs_attr_log_item_op(attri_formatp);1041	switch (op) {1042	case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:1043	case XFS_ATTRI_OP_FLAGS_PPTR_SET:1044		/* Log item, attr name, attr value */1045		if (item->ri_total != 3) {1046			XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,1047					     attri_formatp, len);1048			return -EFSCORRUPTED;1049		}1050		name_len = attri_formatp->alfi_name_len;1051		value_len = attri_formatp->alfi_value_len;1052		break;1053	case XFS_ATTRI_OP_FLAGS_SET:1054	case XFS_ATTRI_OP_FLAGS_REPLACE:1055		/* Log item, attr name, attr value */1056		if (item->ri_total != 3) {1057			XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,1058					     attri_formatp, len);1059			return -EFSCORRUPTED;1060		}1061		name_len = attri_formatp->alfi_name_len;1062		value_len = attri_formatp->alfi_value_len;1063		break;1064	case XFS_ATTRI_OP_FLAGS_REMOVE:1065		/* Log item, attr name */1066		if (item->ri_total != 2) {1067			XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,1068					     attri_formatp, len);1069			return -EFSCORRUPTED;1070		}1071		name_len = attri_formatp->alfi_name_len;1072		break;1073	case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:1074		/*1075		 * Log item, attr name, new attr name, attr value, new attr1076		 * value1077		 */1078		if (item->ri_total != 5) {1079			XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,1080					     attri_formatp, len);1081			return -EFSCORRUPTED;1082		}1083		name_len = attri_formatp->alfi_old_name_len;1084		new_name_len = attri_formatp->alfi_new_name_len;1085		new_value_len = value_len = attri_formatp->alfi_value_len;1086		break;1087	default:1088		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,1089				     attri_formatp, len);1090		return -EFSCORRUPTED;1091	}1092	i++;1093 1094	/* Validate the attr name */1095	attr_name = xfs_attri_validate_name_iovec(mp, attri_formatp,1096			&item->ri_buf[i], name_len);1097	if (!attr_name)1098		return -EFSCORRUPTED;1099	i++;1100 1101	/* Validate the new attr name */1102	if (new_name_len > 0) {1103		attr_new_name = xfs_attri_validate_name_iovec(mp,1104					attri_formatp, &item->ri_buf[i],1105					new_name_len);1106		if (!attr_new_name)1107			return -EFSCORRUPTED;1108		i++;1109	}1110 1111	/* Validate the attr value, if present */1112	if (value_len != 0) {1113		attr_value = xfs_attri_validate_value_iovec(mp, attri_formatp,1114				&item->ri_buf[i], value_len);1115		if (!attr_value)1116			return -EFSCORRUPTED;1117		i++;1118	}1119 1120	/* Validate the new attr value, if present */1121	if (new_value_len != 0) {1122		attr_new_value = xfs_attri_validate_value_iovec(mp,1123					attri_formatp, &item->ri_buf[i],1124					new_value_len);1125		if (!attr_new_value)1126			return -EFSCORRUPTED;1127		i++;1128	}1129 1130	/*1131	 * Make sure we got the correct number of buffers for the operation1132	 * that we just loaded.1133	 */1134	if (i != item->ri_total) {1135		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,1136				attri_formatp, len);1137		return -EFSCORRUPTED;1138	}1139 1140	switch (op) {1141	case XFS_ATTRI_OP_FLAGS_REMOVE:1142		/* Regular remove operations operate only on names. */1143		if (attr_value != NULL || value_len != 0) {1144			XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,1145					     attri_formatp, len);1146			return -EFSCORRUPTED;1147		}1148		fallthrough;1149	case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:1150	case XFS_ATTRI_OP_FLAGS_PPTR_SET:1151	case XFS_ATTRI_OP_FLAGS_SET:1152	case XFS_ATTRI_OP_FLAGS_REPLACE:1153		/*1154		 * Regular xattr set/remove/replace operations require a name1155		 * and do not take a newname.  Values are optional for set and1156		 * replace.1157		 *1158		 * Name-value set/remove operations must have a name, do not1159		 * take a newname, and can take a value.1160		 */1161		if (attr_name == NULL || name_len == 0) {1162			XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,1163					     attri_formatp, len);1164			return -EFSCORRUPTED;1165		}1166		break;1167	case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:1168		/*1169		 * Name-value replace operations require the caller to1170		 * specify the old and new names and values explicitly.1171		 * Values are optional.1172		 */1173		if (attr_name == NULL || name_len == 0) {1174			XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,1175					     attri_formatp, len);1176			return -EFSCORRUPTED;1177		}1178		if (attr_new_name == NULL || new_name_len == 0) {1179			XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,1180					     attri_formatp, len);1181			return -EFSCORRUPTED;1182		}1183		break;1184	}1185 1186	/*1187	 * Memory alloc failure will cause replay to abort.  We attach the1188	 * name/value buffer to the recovered incore log item and drop our1189	 * reference.1190	 */1191	nv = xfs_attri_log_nameval_alloc(attr_name, name_len,1192			attr_new_name, new_name_len,1193			attr_value, value_len,1194			attr_new_value, new_value_len);1195 1196	attrip = xfs_attri_init(mp, nv);1197	memcpy(&attrip->attri_format, attri_formatp, len);1198 1199	xlog_recover_intent_item(log, &attrip->attri_item, lsn,1200			&xfs_attr_defer_type);1201	xfs_attri_log_nameval_put(nv);1202	return 0;1203}1204 1205/*1206 * This routine is called when an ATTRD format structure is found in a committed1207 * transaction in the log. Its purpose is to cancel the corresponding ATTRI if1208 * it was still in the log. To do this it searches the AIL for the ATTRI with1209 * an id equal to that in the ATTRD format structure. If we find it we drop1210 * the ATTRD reference, which removes the ATTRI from the AIL and frees it.1211 */1212STATIC int1213xlog_recover_attrd_commit_pass2(1214	struct xlog			*log,1215	struct list_head		*buffer_list,1216	struct xlog_recover_item	*item,1217	xfs_lsn_t			lsn)1218{1219	struct xfs_attrd_log_format	*attrd_formatp;1220 1221	attrd_formatp = item->ri_buf[0].i_addr;1222	if (item->ri_buf[0].i_len != sizeof(struct xfs_attrd_log_format)) {1223		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,1224				item->ri_buf[0].i_addr, item->ri_buf[0].i_len);1225		return -EFSCORRUPTED;1226	}1227 1228	xlog_recover_release_intent(log, XFS_LI_ATTRI,1229				    attrd_formatp->alfd_alf_id);1230	return 0;1231}1232 1233static const struct xfs_item_ops xfs_attri_item_ops = {1234	.flags		= XFS_ITEM_INTENT,1235	.iop_size	= xfs_attri_item_size,1236	.iop_format	= xfs_attri_item_format,1237	.iop_unpin	= xfs_attri_item_unpin,1238	.iop_release    = xfs_attri_item_release,1239	.iop_match	= xfs_attri_item_match,1240};1241 1242const struct xlog_recover_item_ops xlog_attri_item_ops = {1243	.item_type	= XFS_LI_ATTRI,1244	.commit_pass2	= xlog_recover_attri_commit_pass2,1245};1246 1247static const struct xfs_item_ops xfs_attrd_item_ops = {1248	.flags		= XFS_ITEM_RELEASE_WHEN_COMMITTED |1249			  XFS_ITEM_INTENT_DONE,1250	.iop_size	= xfs_attrd_item_size,1251	.iop_format	= xfs_attrd_item_format,1252	.iop_release    = xfs_attrd_item_release,1253	.iop_intent	= xfs_attrd_item_intent,1254};1255 1256const struct xlog_recover_item_ops xlog_attrd_item_ops = {1257	.item_type	= XFS_LI_ATTRD,1258	.commit_pass2	= xlog_recover_attrd_commit_pass2,1259};1260