1153323Srodrigc/*
2159451Srodrigc * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3159451Srodrigc * All Rights Reserved.
4153323Srodrigc *
5159451Srodrigc * This program is free software; you can redistribute it and/or
6159451Srodrigc * modify it under the terms of the GNU General Public License as
7153323Srodrigc * published by the Free Software Foundation.
8153323Srodrigc *
9159451Srodrigc * This program is distributed in the hope that it would be useful,
10159451Srodrigc * but WITHOUT ANY WARRANTY; without even the implied warranty of
11159451Srodrigc * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12159451Srodrigc * GNU General Public License for more details.
13153323Srodrigc *
14159451Srodrigc * You should have received a copy of the GNU General Public License
15159451Srodrigc * along with this program; if not, write the Free Software Foundation,
16159451Srodrigc * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17153323Srodrigc */
18153323Srodrigc
19159451Srodrigc//#include <linux/capability.h>
20159451Srodrigc
21153323Srodrigc#include "xfs.h"
22159451Srodrigc#include "xfs_fs.h"
23153323Srodrigc#include "xfs_types.h"
24159451Srodrigc#include "xfs_bit.h"
25159451Srodrigc#include "xfs_log.h"
26153323Srodrigc#include "xfs_inum.h"
27153323Srodrigc#include "xfs_trans.h"
28153323Srodrigc#include "xfs_sb.h"
29153323Srodrigc#include "xfs_ag.h"
30153323Srodrigc#include "xfs_dir.h"
31153323Srodrigc#include "xfs_dir2.h"
32153323Srodrigc#include "xfs_dmapi.h"
33153323Srodrigc#include "xfs_mount.h"
34159451Srodrigc#include "xfs_da_btree.h"
35159451Srodrigc#include "xfs_bmap_btree.h"
36153323Srodrigc#include "xfs_alloc_btree.h"
37153323Srodrigc#include "xfs_ialloc_btree.h"
38153323Srodrigc#include "xfs_dir_sf.h"
39153323Srodrigc#include "xfs_dir2_sf.h"
40159451Srodrigc#include "xfs_attr_sf.h"
41153323Srodrigc#include "xfs_dinode.h"
42159451Srodrigc#include "xfs_inode.h"
43159451Srodrigc#include "xfs_alloc.h"
44159451Srodrigc#include "xfs_btree.h"
45153323Srodrigc#include "xfs_inode_item.h"
46153323Srodrigc#include "xfs_bmap.h"
47153323Srodrigc#include "xfs_attr.h"
48153323Srodrigc#include "xfs_attr_leaf.h"
49153323Srodrigc#include "xfs_error.h"
50153323Srodrigc#include "xfs_quota.h"
51153323Srodrigc#include "xfs_trans_space.h"
52153323Srodrigc#include "xfs_acl.h"
53159451Srodrigc#include "xfs_rw.h"
54153323Srodrigc
55153323Srodrigc/*
56153323Srodrigc * xfs_attr.c
57153323Srodrigc *
58153323Srodrigc * Provide the external interfaces to manage attribute lists.
59153323Srodrigc */
60153323Srodrigc
61159451Srodrigc#define ATTR_SYSCOUNT	2
62159451SrodrigcSTATIC struct attrnames posix_acl_access;
63159451SrodrigcSTATIC struct attrnames posix_acl_default;
64159451SrodrigcSTATIC struct attrnames *attr_system_names[ATTR_SYSCOUNT];
65159451Srodrigc
66153323Srodrigc/*========================================================================
67153323Srodrigc * Function prototypes for the kernel.
68153323Srodrigc *========================================================================*/
69153323Srodrigc
70153323Srodrigc/*
71153323Srodrigc * Internal routines when attribute list fits inside the inode.
72153323Srodrigc */
73153323SrodrigcSTATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
74153323Srodrigc
75153323Srodrigc/*
76153323Srodrigc * Internal routines when attribute list is one block.
77153323Srodrigc */
78159451SrodrigcSTATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
79153323SrodrigcSTATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
80153323SrodrigcSTATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
81153323SrodrigcSTATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context);
82153323Srodrigc
83153323Srodrigc/*
84153323Srodrigc * Internal routines when attribute list is more than one block.
85153323Srodrigc */
86159451SrodrigcSTATIC int xfs_attr_node_get(xfs_da_args_t *args);
87153323SrodrigcSTATIC int xfs_attr_node_addname(xfs_da_args_t *args);
88153323SrodrigcSTATIC int xfs_attr_node_removename(xfs_da_args_t *args);
89153323SrodrigcSTATIC int xfs_attr_node_list(xfs_attr_list_context_t *context);
90153323SrodrigcSTATIC int xfs_attr_fillstate(xfs_da_state_t *state);
91153323SrodrigcSTATIC int xfs_attr_refillstate(xfs_da_state_t *state);
92153323Srodrigc
93153323Srodrigc/*
94153323Srodrigc * Routines to manipulate out-of-line attribute values.
95153323Srodrigc */
96153323SrodrigcSTATIC int xfs_attr_rmtval_get(xfs_da_args_t *args);
97153323SrodrigcSTATIC int xfs_attr_rmtval_set(xfs_da_args_t *args);
98153323SrodrigcSTATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args);
99153323Srodrigc
100153323Srodrigc#define ATTR_RMTVALUE_MAPSIZE	1	/* # of map entries at once */
101153323Srodrigc
102153323Srodrigc#if defined(XFS_ATTR_TRACE)
103153323Srodrigcktrace_t *xfs_attr_trace_buf;
104153323Srodrigc#endif
105153323Srodrigc
106153323Srodrigc
107153323Srodrigc/*========================================================================
108153323Srodrigc * Overall external interface routines.
109153323Srodrigc *========================================================================*/
110153323Srodrigc
111159451Srodrigcint
112159451Srodrigcxfs_attr_fetch(xfs_inode_t *ip, const char *name, int namelen,
113159451Srodrigc	       char *value, int *valuelenp, int flags, struct cred *cred)
114153323Srodrigc{
115153323Srodrigc	xfs_da_args_t   args;
116153323Srodrigc	int             error;
117153323Srodrigc
118153323Srodrigc	if ((XFS_IFORK_Q(ip) == 0) ||
119153323Srodrigc	    (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
120153323Srodrigc	     ip->i_d.di_anextents == 0))
121153323Srodrigc		return(ENOATTR);
122153323Srodrigc
123153323Srodrigc	/*
124153323Srodrigc	 * Fill in the arg structure for this request.
125153323Srodrigc	 */
126153323Srodrigc	memset((char *)&args, 0, sizeof(args));
127153323Srodrigc	args.name = name;
128153323Srodrigc	args.namelen = namelen;
129153323Srodrigc	args.value = value;
130153323Srodrigc	args.valuelen = *valuelenp;
131153323Srodrigc	args.flags = flags;
132153323Srodrigc	args.hashval = xfs_da_hashname(args.name, args.namelen);
133153323Srodrigc	args.dp = ip;
134153323Srodrigc	args.whichfork = XFS_ATTR_FORK;
135153323Srodrigc
136153323Srodrigc	/*
137153323Srodrigc	 * Decide on what work routines to call based on the inode size.
138153323Srodrigc	 */
139153323Srodrigc	if (XFS_IFORK_Q(ip) == 0 ||
140153323Srodrigc	    (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
141153323Srodrigc	     ip->i_d.di_anextents == 0)) {
142153323Srodrigc		error = XFS_ERROR(ENOATTR);
143153323Srodrigc	} else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
144153323Srodrigc		error = xfs_attr_shortform_getvalue(&args);
145153323Srodrigc	} else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) {
146153323Srodrigc		error = xfs_attr_leaf_get(&args);
147153323Srodrigc	} else {
148153323Srodrigc		error = xfs_attr_node_get(&args);
149153323Srodrigc	}
150153323Srodrigc
151153323Srodrigc	/*
152153323Srodrigc	 * Return the number of bytes in the value to the caller.
153153323Srodrigc	 */
154153323Srodrigc	*valuelenp = args.valuelen;
155153323Srodrigc
156153323Srodrigc	if (error == EEXIST)
157153323Srodrigc		error = 0;
158153323Srodrigc	return(error);
159153323Srodrigc}
160153323Srodrigc
161153323Srodrigcint
162153323Srodrigcxfs_attr_get(bhv_desc_t *bdp, const char *name, char *value, int *valuelenp,
163153323Srodrigc	     int flags, struct cred *cred)
164153323Srodrigc{
165153323Srodrigc	xfs_inode_t	*ip = XFS_BHVTOI(bdp);
166159451Srodrigc	int		error, namelen;
167153323Srodrigc
168159451Srodrigc	XFS_STATS_INC(xs_attr_get);
169159451Srodrigc
170153323Srodrigc	if (!name)
171153323Srodrigc		return(EINVAL);
172159451Srodrigc	namelen = strlen(name);
173159451Srodrigc	if (namelen >= MAXNAMELEN)
174159451Srodrigc		return(EFAULT);		/* match IRIX behaviour */
175159451Srodrigc
176159451Srodrigc	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
177159451Srodrigc		return(EIO);
178159451Srodrigc
179159451Srodrigc	xfs_ilock(ip, XFS_ILOCK_SHARED);
180159451Srodrigc	error = xfs_attr_fetch(ip, name, namelen, value, valuelenp, flags, cred);
181159451Srodrigc	xfs_iunlock(ip, XFS_ILOCK_SHARED);
182159451Srodrigc	return(error);
183153323Srodrigc}
184153323Srodrigc
185159451SrodrigcSTATIC int
186159451Srodrigcxfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen,
187159451Srodrigc		 char *value, int valuelen, int flags)
188153323Srodrigc{
189153323Srodrigc	xfs_da_args_t	args;
190153323Srodrigc	xfs_fsblock_t	firstblock;
191153323Srodrigc	xfs_bmap_free_t flist;
192153323Srodrigc	int		error, err2, committed;
193153323Srodrigc	int		local, size;
194153323Srodrigc	uint		nblks;
195159451Srodrigc	xfs_mount_t	*mp = dp->i_mount;
196153323Srodrigc	int             rsvd = (flags & ATTR_ROOT) != 0;
197153323Srodrigc
198153323Srodrigc	/*
199153323Srodrigc	 * Attach the dquots to the inode.
200153323Srodrigc	 */
201153323Srodrigc	if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
202153323Srodrigc		return (error);
203153323Srodrigc
204153323Srodrigc	/*
205159451Srodrigc	 * Determine space new attribute will use, and if it would be
206159451Srodrigc	 * "local" or "remote" (note: local != inline).
207159451Srodrigc	 */
208159451Srodrigc	size = xfs_attr_leaf_newentsize(namelen, valuelen,
209159451Srodrigc					mp->m_sb.sb_blocksize, &local);
210159451Srodrigc
211159451Srodrigc	/*
212153323Srodrigc	 * If the inode doesn't have an attribute fork, add one.
213153323Srodrigc	 * (inode must not be locked when we call this routine)
214153323Srodrigc	 */
215153323Srodrigc	if (XFS_IFORK_Q(dp) == 0) {
216159451Srodrigc		if ((error = xfs_bmap_add_attrfork(dp, size, rsvd)))
217153323Srodrigc			return(error);
218153323Srodrigc	}
219153323Srodrigc
220153323Srodrigc	/*
221153323Srodrigc	 * Fill in the arg structure for this request.
222153323Srodrigc	 */
223153323Srodrigc	memset((char *)&args, 0, sizeof(args));
224153323Srodrigc	args.name = name;
225153323Srodrigc	args.namelen = namelen;
226153323Srodrigc	args.value = value;
227153323Srodrigc	args.valuelen = valuelen;
228153323Srodrigc	args.flags = flags;
229153323Srodrigc	args.hashval = xfs_da_hashname(args.name, args.namelen);
230153323Srodrigc	args.dp = dp;
231153323Srodrigc	args.firstblock = &firstblock;
232153323Srodrigc	args.flist = &flist;
233153323Srodrigc	args.whichfork = XFS_ATTR_FORK;
234159451Srodrigc	args.addname = 1;
235153323Srodrigc	args.oknoent = 1;
236153323Srodrigc
237153323Srodrigc	nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
238153323Srodrigc	if (local) {
239153323Srodrigc		if (size > (mp->m_sb.sb_blocksize >> 1)) {
240153323Srodrigc			/* Double split possible */
241153323Srodrigc			nblks <<= 1;
242153323Srodrigc		}
243153323Srodrigc	} else {
244153323Srodrigc		uint	dblocks = XFS_B_TO_FSB(mp, valuelen);
245153323Srodrigc		/* Out of line attribute, cannot double split, but make
246153323Srodrigc		 * room for the attribute value itself.
247153323Srodrigc		 */
248153323Srodrigc		nblks += dblocks;
249153323Srodrigc		nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
250153323Srodrigc	}
251153323Srodrigc
252153323Srodrigc	/* Size is now blocks for attribute data */
253153323Srodrigc	args.total = nblks;
254153323Srodrigc
255153323Srodrigc	/*
256153323Srodrigc	 * Start our first transaction of the day.
257153323Srodrigc	 *
258153323Srodrigc	 * All future transactions during this code must be "chained" off
259153323Srodrigc	 * this one via the trans_dup() call.  All transactions will contain
260153323Srodrigc	 * the inode, and the inode will always be marked with trans_ihold().
261153323Srodrigc	 * Since the inode will be locked in all transactions, we must log
262153323Srodrigc	 * the inode in every transaction to let it float upward through
263153323Srodrigc	 * the log.
264153323Srodrigc	 */
265153323Srodrigc	args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET);
266153323Srodrigc
267153323Srodrigc	/*
268153323Srodrigc	 * Root fork attributes can use reserved data blocks for this
269153323Srodrigc	 * operation if necessary
270153323Srodrigc	 */
271153323Srodrigc
272153323Srodrigc	if (rsvd)
273153323Srodrigc		args.trans->t_flags |= XFS_TRANS_RESERVE;
274153323Srodrigc
275153323Srodrigc	if ((error = xfs_trans_reserve(args.trans, (uint) nblks,
276153323Srodrigc				      XFS_ATTRSET_LOG_RES(mp, nblks),
277153323Srodrigc				      0, XFS_TRANS_PERM_LOG_RES,
278153323Srodrigc				      XFS_ATTRSET_LOG_COUNT))) {
279153323Srodrigc		xfs_trans_cancel(args.trans, 0);
280153323Srodrigc		return(error);
281153323Srodrigc	}
282153323Srodrigc	xfs_ilock(dp, XFS_ILOCK_EXCL);
283153323Srodrigc
284153323Srodrigc	error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, nblks, 0,
285153323Srodrigc			 rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
286153323Srodrigc				XFS_QMOPT_RES_REGBLKS);
287153323Srodrigc	if (error) {
288153323Srodrigc		xfs_iunlock(dp, XFS_ILOCK_EXCL);
289153323Srodrigc		xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
290153323Srodrigc		return (error);
291153323Srodrigc	}
292153323Srodrigc
293153323Srodrigc	xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
294153323Srodrigc	xfs_trans_ihold(args.trans, dp);
295153323Srodrigc
296153323Srodrigc	/*
297159451Srodrigc	 * If the attribute list is non-existent or a shortform list,
298153323Srodrigc	 * upgrade it to a single-leaf-block attribute list.
299153323Srodrigc	 */
300153323Srodrigc	if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
301153323Srodrigc	    ((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) &&
302153323Srodrigc	     (dp->i_d.di_anextents == 0))) {
303153323Srodrigc
304153323Srodrigc		/*
305153323Srodrigc		 * Build initial attribute list (if required).
306153323Srodrigc		 */
307153323Srodrigc		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
308159451Srodrigc			xfs_attr_shortform_create(&args);
309153323Srodrigc
310153323Srodrigc		/*
311153323Srodrigc		 * Try to add the attr to the attribute list in
312153323Srodrigc		 * the inode.
313153323Srodrigc		 */
314153323Srodrigc		error = xfs_attr_shortform_addname(&args);
315153323Srodrigc		if (error != ENOSPC) {
316153323Srodrigc			/*
317153323Srodrigc			 * Commit the shortform mods, and we're done.
318153323Srodrigc			 * NOTE: this is also the error path (EEXIST, etc).
319153323Srodrigc			 */
320153323Srodrigc			ASSERT(args.trans != NULL);
321153323Srodrigc
322153323Srodrigc			/*
323153323Srodrigc			 * If this is a synchronous mount, make sure that
324153323Srodrigc			 * the transaction goes to disk before returning
325153323Srodrigc			 * to the user.
326153323Srodrigc			 */
327153323Srodrigc			if (mp->m_flags & XFS_MOUNT_WSYNC) {
328153323Srodrigc				xfs_trans_set_sync(args.trans);
329153323Srodrigc			}
330153323Srodrigc			err2 = xfs_trans_commit(args.trans,
331153323Srodrigc						 XFS_TRANS_RELEASE_LOG_RES,
332153323Srodrigc						 NULL);
333153323Srodrigc			xfs_iunlock(dp, XFS_ILOCK_EXCL);
334153323Srodrigc
335153323Srodrigc			/*
336153323Srodrigc			 * Hit the inode change time.
337153323Srodrigc			 */
338153323Srodrigc			if (!error && (flags & ATTR_KERNOTIME) == 0) {
339153323Srodrigc				xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
340153323Srodrigc			}
341153323Srodrigc			return(error == 0 ? err2 : error);
342153323Srodrigc		}
343153323Srodrigc
344153323Srodrigc		/*
345153323Srodrigc		 * It won't fit in the shortform, transform to a leaf block.
346153323Srodrigc		 * GROT: another possible req'mt for a double-split btree op.
347153323Srodrigc		 */
348153323Srodrigc		XFS_BMAP_INIT(args.flist, args.firstblock);
349153323Srodrigc		error = xfs_attr_shortform_to_leaf(&args);
350153323Srodrigc		if (!error) {
351153323Srodrigc			error = xfs_bmap_finish(&args.trans, args.flist,
352153323Srodrigc						*args.firstblock, &committed);
353153323Srodrigc		}
354153323Srodrigc		if (error) {
355153323Srodrigc			ASSERT(committed);
356153323Srodrigc			args.trans = NULL;
357153323Srodrigc			xfs_bmap_cancel(&flist);
358153323Srodrigc			goto out;
359153323Srodrigc		}
360153323Srodrigc
361153323Srodrigc		/*
362153323Srodrigc		 * bmap_finish() may have committed the last trans and started
363153323Srodrigc		 * a new one.  We need the inode to be in all transactions.
364153323Srodrigc		 */
365153323Srodrigc		if (committed) {
366153323Srodrigc			xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
367153323Srodrigc			xfs_trans_ihold(args.trans, dp);
368153323Srodrigc		}
369153323Srodrigc
370153323Srodrigc		/*
371153323Srodrigc		 * Commit the leaf transformation.  We'll need another (linked)
372153323Srodrigc		 * transaction to add the new attribute to the leaf.
373153323Srodrigc		 */
374153323Srodrigc		if ((error = xfs_attr_rolltrans(&args.trans, dp)))
375153323Srodrigc			goto out;
376153323Srodrigc
377153323Srodrigc	}
378153323Srodrigc
379153323Srodrigc	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
380153323Srodrigc		error = xfs_attr_leaf_addname(&args);
381153323Srodrigc	} else {
382153323Srodrigc		error = xfs_attr_node_addname(&args);
383153323Srodrigc	}
384153323Srodrigc	if (error) {
385153323Srodrigc		goto out;
386153323Srodrigc	}
387153323Srodrigc
388153323Srodrigc	/*
389153323Srodrigc	 * If this is a synchronous mount, make sure that the
390153323Srodrigc	 * transaction goes to disk before returning to the user.
391153323Srodrigc	 */
392153323Srodrigc	if (mp->m_flags & XFS_MOUNT_WSYNC) {
393153323Srodrigc		xfs_trans_set_sync(args.trans);
394153323Srodrigc	}
395153323Srodrigc
396153323Srodrigc	/*
397153323Srodrigc	 * Commit the last in the sequence of transactions.
398153323Srodrigc	 */
399153323Srodrigc	xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
400153323Srodrigc	error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,
401153323Srodrigc				 NULL);
402153323Srodrigc	xfs_iunlock(dp, XFS_ILOCK_EXCL);
403153323Srodrigc
404153323Srodrigc	/*
405153323Srodrigc	 * Hit the inode change time.
406153323Srodrigc	 */
407153323Srodrigc	if (!error && (flags & ATTR_KERNOTIME) == 0) {
408153323Srodrigc		xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
409153323Srodrigc	}
410153323Srodrigc
411153323Srodrigc	return(error);
412153323Srodrigc
413153323Srodrigcout:
414153323Srodrigc	if (args.trans)
415153323Srodrigc		xfs_trans_cancel(args.trans,
416153323Srodrigc			XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
417153323Srodrigc	xfs_iunlock(dp, XFS_ILOCK_EXCL);
418153323Srodrigc	return(error);
419153323Srodrigc}
420153323Srodrigc
421159451Srodrigcint
422159451Srodrigcxfs_attr_set(bhv_desc_t *bdp, const char *name, char *value, int valuelen, int flags,
423159451Srodrigc	     struct cred *cred)
424153323Srodrigc{
425159451Srodrigc	xfs_inode_t	*dp;
426159451Srodrigc	int             namelen;
427153323Srodrigc
428153323Srodrigc	namelen = strlen(name);
429159451Srodrigc	if (namelen >= MAXNAMELEN)
430159451Srodrigc		return EFAULT;		/* match IRIX behaviour */
431153323Srodrigc
432159451Srodrigc	XFS_STATS_INC(xs_attr_set);
433153323Srodrigc
434153323Srodrigc	dp = XFS_BHVTOI(bdp);
435159451Srodrigc	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
436153323Srodrigc		return (EIO);
437153323Srodrigc
438159451Srodrigc	return xfs_attr_set_int(dp, name, namelen, value, valuelen, flags);
439159451Srodrigc}
440153323Srodrigc
441159451Srodrigc/*
442159451Srodrigc * Generic handler routine to remove a name from an attribute list.
443159451Srodrigc * Transitions attribute list from Btree to shortform as necessary.
444159451Srodrigc */
445159451SrodrigcSTATIC int
446159451Srodrigcxfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags)
447159451Srodrigc{
448159451Srodrigc	xfs_da_args_t	args;
449159451Srodrigc	xfs_fsblock_t	firstblock;
450159451Srodrigc	xfs_bmap_free_t	flist;
451159451Srodrigc	int		error;
452159451Srodrigc	xfs_mount_t	*mp = dp->i_mount;
453159451Srodrigc
454153323Srodrigc	/*
455153323Srodrigc	 * Fill in the arg structure for this request.
456153323Srodrigc	 */
457153323Srodrigc	memset((char *)&args, 0, sizeof(args));
458153323Srodrigc	args.name = name;
459153323Srodrigc	args.namelen = namelen;
460153323Srodrigc	args.flags = flags;
461153323Srodrigc	args.hashval = xfs_da_hashname(args.name, args.namelen);
462153323Srodrigc	args.dp = dp;
463153323Srodrigc	args.firstblock = &firstblock;
464153323Srodrigc	args.flist = &flist;
465153323Srodrigc	args.total = 0;
466153323Srodrigc	args.whichfork = XFS_ATTR_FORK;
467153323Srodrigc
468153323Srodrigc	/*
469153323Srodrigc	 * Attach the dquots to the inode.
470153323Srodrigc	 */
471153323Srodrigc	if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
472153323Srodrigc		return (error);
473153323Srodrigc
474153323Srodrigc	/*
475153323Srodrigc	 * Start our first transaction of the day.
476153323Srodrigc	 *
477153323Srodrigc	 * All future transactions during this code must be "chained" off
478153323Srodrigc	 * this one via the trans_dup() call.  All transactions will contain
479153323Srodrigc	 * the inode, and the inode will always be marked with trans_ihold().
480153323Srodrigc	 * Since the inode will be locked in all transactions, we must log
481153323Srodrigc	 * the inode in every transaction to let it float upward through
482153323Srodrigc	 * the log.
483153323Srodrigc	 */
484153323Srodrigc	args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM);
485153323Srodrigc
486153323Srodrigc	/*
487153323Srodrigc	 * Root fork attributes can use reserved data blocks for this
488153323Srodrigc	 * operation if necessary
489153323Srodrigc	 */
490153323Srodrigc
491153323Srodrigc	if (flags & ATTR_ROOT)
492153323Srodrigc		args.trans->t_flags |= XFS_TRANS_RESERVE;
493153323Srodrigc
494153323Srodrigc	if ((error = xfs_trans_reserve(args.trans,
495153323Srodrigc				      XFS_ATTRRM_SPACE_RES(mp),
496153323Srodrigc				      XFS_ATTRRM_LOG_RES(mp),
497153323Srodrigc				      0, XFS_TRANS_PERM_LOG_RES,
498153323Srodrigc				      XFS_ATTRRM_LOG_COUNT))) {
499153323Srodrigc		xfs_trans_cancel(args.trans, 0);
500153323Srodrigc		return(error);
501153323Srodrigc	}
502153323Srodrigc
503153323Srodrigc	xfs_ilock(dp, XFS_ILOCK_EXCL);
504153323Srodrigc	/*
505153323Srodrigc	 * No need to make quota reservations here. We expect to release some
506153323Srodrigc	 * blocks not allocate in the common case.
507153323Srodrigc	 */
508153323Srodrigc	xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
509153323Srodrigc	xfs_trans_ihold(args.trans, dp);
510153323Srodrigc
511153323Srodrigc	/*
512153323Srodrigc	 * Decide on what work routines to call based on the inode size.
513153323Srodrigc	 */
514153323Srodrigc	if (XFS_IFORK_Q(dp) == 0 ||
515153323Srodrigc	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
516153323Srodrigc	     dp->i_d.di_anextents == 0)) {
517153323Srodrigc		error = XFS_ERROR(ENOATTR);
518153323Srodrigc		goto out;
519153323Srodrigc	}
520153323Srodrigc	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
521153323Srodrigc		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
522153323Srodrigc		error = xfs_attr_shortform_remove(&args);
523153323Srodrigc		if (error) {
524153323Srodrigc			goto out;
525153323Srodrigc		}
526153323Srodrigc	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
527153323Srodrigc		error = xfs_attr_leaf_removename(&args);
528153323Srodrigc	} else {
529153323Srodrigc		error = xfs_attr_node_removename(&args);
530153323Srodrigc	}
531153323Srodrigc	if (error) {
532153323Srodrigc		goto out;
533153323Srodrigc	}
534153323Srodrigc
535153323Srodrigc	/*
536153323Srodrigc	 * If this is a synchronous mount, make sure that the
537153323Srodrigc	 * transaction goes to disk before returning to the user.
538153323Srodrigc	 */
539153323Srodrigc	if (mp->m_flags & XFS_MOUNT_WSYNC) {
540153323Srodrigc		xfs_trans_set_sync(args.trans);
541153323Srodrigc	}
542153323Srodrigc
543153323Srodrigc	/*
544153323Srodrigc	 * Commit the last in the sequence of transactions.
545153323Srodrigc	 */
546153323Srodrigc	xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
547153323Srodrigc	error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,
548153323Srodrigc				 NULL);
549153323Srodrigc	xfs_iunlock(dp, XFS_ILOCK_EXCL);
550153323Srodrigc
551153323Srodrigc	/*
552153323Srodrigc	 * Hit the inode change time.
553153323Srodrigc	 */
554153323Srodrigc	if (!error && (flags & ATTR_KERNOTIME) == 0) {
555153323Srodrigc		xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
556153323Srodrigc	}
557153323Srodrigc
558153323Srodrigc	return(error);
559153323Srodrigc
560153323Srodrigcout:
561153323Srodrigc	if (args.trans)
562153323Srodrigc		xfs_trans_cancel(args.trans,
563153323Srodrigc			XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
564153323Srodrigc	xfs_iunlock(dp, XFS_ILOCK_EXCL);
565153323Srodrigc	return(error);
566153323Srodrigc}
567153323Srodrigc
568159451Srodrigcint
569159451Srodrigcxfs_attr_remove(bhv_desc_t *bdp, const char *name, int flags, struct cred *cred)
570159451Srodrigc{
571159451Srodrigc	xfs_inode_t         *dp;
572159451Srodrigc	int                 namelen;
573159451Srodrigc
574159451Srodrigc	namelen = strlen(name);
575159451Srodrigc	if (namelen >= MAXNAMELEN)
576159451Srodrigc		return EFAULT;		/* match IRIX behaviour */
577159451Srodrigc
578159451Srodrigc	XFS_STATS_INC(xs_attr_remove);
579159451Srodrigc
580159451Srodrigc	dp = XFS_BHVTOI(bdp);
581159451Srodrigc	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
582159451Srodrigc		return (EIO);
583159451Srodrigc
584159451Srodrigc	xfs_ilock(dp, XFS_ILOCK_SHARED);
585159451Srodrigc	if (XFS_IFORK_Q(dp) == 0 ||
586159451Srodrigc		   (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
587159451Srodrigc		    dp->i_d.di_anextents == 0)) {
588159451Srodrigc		xfs_iunlock(dp, XFS_ILOCK_SHARED);
589159451Srodrigc		return(XFS_ERROR(ENOATTR));
590159451Srodrigc	}
591159451Srodrigc	xfs_iunlock(dp, XFS_ILOCK_SHARED);
592159451Srodrigc
593159451Srodrigc	return xfs_attr_remove_int(dp, name, namelen, flags);
594159451Srodrigc}
595159451Srodrigc
596153323Srodrigc/*
597153323Srodrigc * Generate a list of extended attribute names and optionally
598153323Srodrigc * also value lengths.  Positive return value follows the XFS
599153323Srodrigc * convention of being an error, zero or negative return code
600153323Srodrigc * is the length of the buffer returned (negated), indicating
601153323Srodrigc * success.
602153323Srodrigc */
603153323Srodrigcint
604153323Srodrigcxfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags,
605153323Srodrigc		      attrlist_cursor_kern_t *cursor, struct cred *cred)
606153323Srodrigc{
607153323Srodrigc	xfs_attr_list_context_t context;
608153323Srodrigc	xfs_inode_t *dp;
609153323Srodrigc	int error;
610153323Srodrigc
611153323Srodrigc	XFS_STATS_INC(xs_attr_list);
612153323Srodrigc
613153323Srodrigc	/*
614153323Srodrigc	 * Validate the cursor.
615153323Srodrigc	 */
616153323Srodrigc	if (cursor->pad1 || cursor->pad2)
617153323Srodrigc		return(XFS_ERROR(EINVAL));
618153323Srodrigc	if ((cursor->initted == 0) &&
619153323Srodrigc	    (cursor->hashval || cursor->blkno || cursor->offset))
620153323Srodrigc		return(XFS_ERROR(EINVAL));
621153323Srodrigc
622153323Srodrigc	/*
623153323Srodrigc	 * Check for a properly aligned buffer.
624153323Srodrigc	 */
625153323Srodrigc	if (((long)buffer) & (sizeof(int)-1))
626153323Srodrigc		return(XFS_ERROR(EFAULT));
627153323Srodrigc	if (flags & ATTR_KERNOVAL)
628153323Srodrigc		bufsize = 0;
629153323Srodrigc
630153323Srodrigc	/*
631153323Srodrigc	 * Initialize the output buffer.
632153323Srodrigc	 */
633153323Srodrigc	context.dp = dp = XFS_BHVTOI(bdp);
634153323Srodrigc	context.cursor = cursor;
635153323Srodrigc	context.count = 0;
636153323Srodrigc	context.dupcnt = 0;
637153323Srodrigc	context.resynch = 1;
638153323Srodrigc	context.flags = flags;
639153323Srodrigc	if (!(flags & ATTR_KERNAMELS)) {
640153323Srodrigc		context.bufsize = (bufsize & ~(sizeof(int)-1));  /* align */
641153323Srodrigc		context.firstu = context.bufsize;
642153323Srodrigc		context.alist = (attrlist_t *)buffer;
643153323Srodrigc		context.alist->al_count = 0;
644153323Srodrigc		context.alist->al_more = 0;
645153323Srodrigc		context.alist->al_offset[0] = context.bufsize;
646153323Srodrigc	}
647153323Srodrigc	else {
648153323Srodrigc		context.bufsize = bufsize;
649153323Srodrigc		context.firstu = context.bufsize;
650153323Srodrigc		context.alist = (attrlist_t *)buffer;
651153323Srodrigc	}
652153323Srodrigc
653153323Srodrigc	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
654153323Srodrigc		return (EIO);
655159451Srodrigc
656153323Srodrigc	xfs_ilock(dp, XFS_ILOCK_SHARED);
657153323Srodrigc	/*
658153323Srodrigc	 * Decide on what work routines to call based on the inode size.
659153323Srodrigc	 */
660153323Srodrigc	xfs_attr_trace_l_c("syscall start", &context);
661153323Srodrigc	if (XFS_IFORK_Q(dp) == 0 ||
662153323Srodrigc	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
663153323Srodrigc	     dp->i_d.di_anextents == 0)) {
664153323Srodrigc		error = 0;
665153323Srodrigc	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
666153323Srodrigc		error = xfs_attr_shortform_list(&context);
667153323Srodrigc	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
668153323Srodrigc		error = xfs_attr_leaf_list(&context);
669153323Srodrigc	} else {
670153323Srodrigc		error = xfs_attr_node_list(&context);
671153323Srodrigc	}
672153323Srodrigc	xfs_iunlock(dp, XFS_ILOCK_SHARED);
673153323Srodrigc	xfs_attr_trace_l_c("syscall end", &context);
674153323Srodrigc
675153323Srodrigc	if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) {
676153323Srodrigc		ASSERT(error >= 0);
677153323Srodrigc	}
678153323Srodrigc	else {	/* must return negated buffer size or the error */
679153323Srodrigc		if (context.count < 0)
680153323Srodrigc			error = XFS_ERROR(ERANGE);
681153323Srodrigc		else
682153323Srodrigc			error = -context.count;
683153323Srodrigc	}
684153323Srodrigc
685153323Srodrigc	return(error);
686153323Srodrigc}
687153323Srodrigc
688153323Srodrigcint								/* error */
689153323Srodrigcxfs_attr_inactive(xfs_inode_t *dp)
690153323Srodrigc{
691153323Srodrigc	xfs_trans_t *trans;
692153323Srodrigc	xfs_mount_t *mp;
693153323Srodrigc	int error;
694153323Srodrigc
695153323Srodrigc	mp = dp->i_mount;
696153323Srodrigc	ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
697153323Srodrigc
698159451Srodrigc	xfs_ilock(dp, XFS_ILOCK_SHARED);
699153323Srodrigc	if ((XFS_IFORK_Q(dp) == 0) ||
700153323Srodrigc	    (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
701153323Srodrigc	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
702153323Srodrigc	     dp->i_d.di_anextents == 0)) {
703159451Srodrigc		xfs_iunlock(dp, XFS_ILOCK_SHARED);
704153323Srodrigc		return(0);
705153323Srodrigc	}
706159451Srodrigc	xfs_iunlock(dp, XFS_ILOCK_SHARED);
707153323Srodrigc
708153323Srodrigc	/*
709153323Srodrigc	 * Start our first transaction of the day.
710153323Srodrigc	 *
711153323Srodrigc	 * All future transactions during this code must be "chained" off
712153323Srodrigc	 * this one via the trans_dup() call.  All transactions will contain
713153323Srodrigc	 * the inode, and the inode will always be marked with trans_ihold().
714153323Srodrigc	 * Since the inode will be locked in all transactions, we must log
715153323Srodrigc	 * the inode in every transaction to let it float upward through
716153323Srodrigc	 * the log.
717153323Srodrigc	 */
718153323Srodrigc	trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL);
719153323Srodrigc	if ((error = xfs_trans_reserve(trans, 0, XFS_ATTRINVAL_LOG_RES(mp), 0,
720153323Srodrigc				      XFS_TRANS_PERM_LOG_RES,
721153323Srodrigc				      XFS_ATTRINVAL_LOG_COUNT))) {
722153323Srodrigc		xfs_trans_cancel(trans, 0);
723153323Srodrigc		return(error);
724153323Srodrigc	}
725153323Srodrigc	xfs_ilock(dp, XFS_ILOCK_EXCL);
726153323Srodrigc
727153323Srodrigc	/*
728153323Srodrigc	 * No need to make quota reservations here. We expect to release some
729153323Srodrigc	 * blocks, not allocate, in the common case.
730153323Srodrigc	 */
731153323Srodrigc	xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL);
732153323Srodrigc	xfs_trans_ihold(trans, dp);
733153323Srodrigc
734153323Srodrigc	/*
735153323Srodrigc	 * Decide on what work routines to call based on the inode size.
736153323Srodrigc	 */
737153323Srodrigc	if ((XFS_IFORK_Q(dp) == 0) ||
738153323Srodrigc	    (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
739153323Srodrigc	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
740153323Srodrigc	     dp->i_d.di_anextents == 0)) {
741153323Srodrigc		error = 0;
742153323Srodrigc		goto out;
743153323Srodrigc	}
744153323Srodrigc	error = xfs_attr_root_inactive(&trans, dp);
745153323Srodrigc	if (error)
746153323Srodrigc		goto out;
747153323Srodrigc	/*
748153323Srodrigc	 * signal synchronous inactive transactions unless this
749153323Srodrigc	 * is a synchronous mount filesystem in which case we
750153323Srodrigc	 * know that we're here because we've been called out of
751153323Srodrigc	 * xfs_inactive which means that the last reference is gone
752153323Srodrigc	 * and the unlink transaction has already hit the disk so
753153323Srodrigc	 * async inactive transactions are safe.
754153323Srodrigc	 */
755153323Srodrigc	if ((error = xfs_itruncate_finish(&trans, dp, 0LL, XFS_ATTR_FORK,
756153323Srodrigc				(!(mp->m_flags & XFS_MOUNT_WSYNC)
757153323Srodrigc				 ? 1 : 0))))
758153323Srodrigc		goto out;
759153323Srodrigc
760153323Srodrigc	/*
761153323Srodrigc	 * Commit the last in the sequence of transactions.
762153323Srodrigc	 */
763153323Srodrigc	xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE);
764153323Srodrigc	error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES,
765153323Srodrigc				 NULL);
766153323Srodrigc	xfs_iunlock(dp, XFS_ILOCK_EXCL);
767153323Srodrigc
768153323Srodrigc	return(error);
769153323Srodrigc
770153323Srodrigcout:
771153323Srodrigc	xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
772153323Srodrigc	xfs_iunlock(dp, XFS_ILOCK_EXCL);
773153323Srodrigc	return(error);
774153323Srodrigc}
775153323Srodrigc
776153323Srodrigc
777153323Srodrigc
778153323Srodrigc/*========================================================================
779153323Srodrigc * External routines when attribute list is inside the inode
780153323Srodrigc *========================================================================*/
781153323Srodrigc
782153323Srodrigc/*
783153323Srodrigc * Add a name to the shortform attribute list structure
784153323Srodrigc * This is the external routine.
785153323Srodrigc */
786153323SrodrigcSTATIC int
787153323Srodrigcxfs_attr_shortform_addname(xfs_da_args_t *args)
788153323Srodrigc{
789159451Srodrigc	int newsize, forkoff, retval;
790153323Srodrigc
791153323Srodrigc	retval = xfs_attr_shortform_lookup(args);
792153323Srodrigc	if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
793153323Srodrigc		return(retval);
794153323Srodrigc	} else if (retval == EEXIST) {
795153323Srodrigc		if (args->flags & ATTR_CREATE)
796153323Srodrigc			return(retval);
797153323Srodrigc		retval = xfs_attr_shortform_remove(args);
798153323Srodrigc		ASSERT(retval == 0);
799153323Srodrigc	}
800153323Srodrigc
801159451Srodrigc	if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
802159451Srodrigc	    args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
803159451Srodrigc		return(XFS_ERROR(ENOSPC));
804159451Srodrigc
805153323Srodrigc	newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
806153323Srodrigc	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
807159451Srodrigc
808159451Srodrigc	forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
809159451Srodrigc	if (!forkoff)
810153323Srodrigc		return(XFS_ERROR(ENOSPC));
811159451Srodrigc
812159451Srodrigc	xfs_attr_shortform_add(args, forkoff);
813153323Srodrigc	return(0);
814153323Srodrigc}
815153323Srodrigc
816153323Srodrigc
817153323Srodrigc/*========================================================================
818153323Srodrigc * External routines when attribute list is one block
819153323Srodrigc *========================================================================*/
820153323Srodrigc
821153323Srodrigc/*
822153323Srodrigc * Add a name to the leaf attribute list structure
823153323Srodrigc *
824153323Srodrigc * This leaf block cannot have a "remote" value, we only call this routine
825153323Srodrigc * if bmap_one_block() says there is only one block (ie: no remote blks).
826153323Srodrigc */
827153323Srodrigcint
828153323Srodrigcxfs_attr_leaf_addname(xfs_da_args_t *args)
829153323Srodrigc{
830153323Srodrigc	xfs_inode_t *dp;
831153323Srodrigc	xfs_dabuf_t *bp;
832159451Srodrigc	int retval, error, committed, forkoff;
833153323Srodrigc
834153323Srodrigc	/*
835153323Srodrigc	 * Read the (only) block in the attribute list in.
836153323Srodrigc	 */
837153323Srodrigc	dp = args->dp;
838153323Srodrigc	args->blkno = 0;
839153323Srodrigc	error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
840153323Srodrigc					     XFS_ATTR_FORK);
841153323Srodrigc	if (error)
842153323Srodrigc		return(error);
843153323Srodrigc	ASSERT(bp != NULL);
844153323Srodrigc
845153323Srodrigc	/*
846153323Srodrigc	 * Look up the given attribute in the leaf block.  Figure out if
847153323Srodrigc	 * the given flags produce an error or call for an atomic rename.
848153323Srodrigc	 */
849153323Srodrigc	retval = xfs_attr_leaf_lookup_int(bp, args);
850153323Srodrigc	if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
851153323Srodrigc		xfs_da_brelse(args->trans, bp);
852153323Srodrigc		return(retval);
853153323Srodrigc	} else if (retval == EEXIST) {
854153323Srodrigc		if (args->flags & ATTR_CREATE) {	/* pure create op */
855153323Srodrigc			xfs_da_brelse(args->trans, bp);
856153323Srodrigc			return(retval);
857153323Srodrigc		}
858153323Srodrigc		args->rename = 1;			/* an atomic rename */
859153323Srodrigc		args->blkno2 = args->blkno;		/* set 2nd entry info*/
860153323Srodrigc		args->index2 = args->index;
861153323Srodrigc		args->rmtblkno2 = args->rmtblkno;
862153323Srodrigc		args->rmtblkcnt2 = args->rmtblkcnt;
863153323Srodrigc	}
864153323Srodrigc
865153323Srodrigc	/*
866153323Srodrigc	 * Add the attribute to the leaf block, transitioning to a Btree
867153323Srodrigc	 * if required.
868153323Srodrigc	 */
869153323Srodrigc	retval = xfs_attr_leaf_add(bp, args);
870153323Srodrigc	xfs_da_buf_done(bp);
871153323Srodrigc	if (retval == ENOSPC) {
872153323Srodrigc		/*
873153323Srodrigc		 * Promote the attribute list to the Btree format, then
874153323Srodrigc		 * Commit that transaction so that the node_addname() call
875153323Srodrigc		 * can manage its own transactions.
876153323Srodrigc		 */
877153323Srodrigc		XFS_BMAP_INIT(args->flist, args->firstblock);
878153323Srodrigc		error = xfs_attr_leaf_to_node(args);
879153323Srodrigc		if (!error) {
880153323Srodrigc			error = xfs_bmap_finish(&args->trans, args->flist,
881153323Srodrigc						*args->firstblock, &committed);
882153323Srodrigc		}
883153323Srodrigc		if (error) {
884153323Srodrigc			ASSERT(committed);
885153323Srodrigc			args->trans = NULL;
886153323Srodrigc			xfs_bmap_cancel(args->flist);
887153323Srodrigc			return(error);
888153323Srodrigc		}
889153323Srodrigc
890153323Srodrigc		/*
891153323Srodrigc		 * bmap_finish() may have committed the last trans and started
892153323Srodrigc		 * a new one.  We need the inode to be in all transactions.
893153323Srodrigc		 */
894153323Srodrigc		if (committed) {
895153323Srodrigc			xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
896153323Srodrigc			xfs_trans_ihold(args->trans, dp);
897153323Srodrigc		}
898153323Srodrigc
899153323Srodrigc		/*
900153323Srodrigc		 * Commit the current trans (including the inode) and start
901153323Srodrigc		 * a new one.
902153323Srodrigc		 */
903153323Srodrigc		if ((error = xfs_attr_rolltrans(&args->trans, dp)))
904153323Srodrigc			return (error);
905153323Srodrigc
906153323Srodrigc		/*
907153323Srodrigc		 * Fob the whole rest of the problem off on the Btree code.
908153323Srodrigc		 */
909153323Srodrigc		error = xfs_attr_node_addname(args);
910153323Srodrigc		return(error);
911153323Srodrigc	}
912153323Srodrigc
913153323Srodrigc	/*
914153323Srodrigc	 * Commit the transaction that added the attr name so that
915153323Srodrigc	 * later routines can manage their own transactions.
916153323Srodrigc	 */
917153323Srodrigc	if ((error = xfs_attr_rolltrans(&args->trans, dp)))
918153323Srodrigc		return (error);
919153323Srodrigc
920153323Srodrigc	/*
921153323Srodrigc	 * If there was an out-of-line value, allocate the blocks we
922153323Srodrigc	 * identified for its storage and copy the value.  This is done
923153323Srodrigc	 * after we create the attribute so that we don't overflow the
924153323Srodrigc	 * maximum size of a transaction and/or hit a deadlock.
925153323Srodrigc	 */
926153323Srodrigc	if (args->rmtblkno > 0) {
927153323Srodrigc		error = xfs_attr_rmtval_set(args);
928153323Srodrigc		if (error)
929153323Srodrigc			return(error);
930153323Srodrigc	}
931153323Srodrigc
932153323Srodrigc	/*
933153323Srodrigc	 * If this is an atomic rename operation, we must "flip" the
934153323Srodrigc	 * incomplete flags on the "new" and "old" attribute/value pairs
935153323Srodrigc	 * so that one disappears and one appears atomically.  Then we
936153323Srodrigc	 * must remove the "old" attribute/value pair.
937153323Srodrigc	 */
938153323Srodrigc	if (args->rename) {
939153323Srodrigc		/*
940153323Srodrigc		 * In a separate transaction, set the incomplete flag on the
941153323Srodrigc		 * "old" attr and clear the incomplete flag on the "new" attr.
942153323Srodrigc		 */
943153323Srodrigc		error = xfs_attr_leaf_flipflags(args);
944153323Srodrigc		if (error)
945153323Srodrigc			return(error);
946153323Srodrigc
947153323Srodrigc		/*
948153323Srodrigc		 * Dismantle the "old" attribute/value pair by removing
949153323Srodrigc		 * a "remote" value (if it exists).
950153323Srodrigc		 */
951153323Srodrigc		args->index = args->index2;
952153323Srodrigc		args->blkno = args->blkno2;
953153323Srodrigc		args->rmtblkno = args->rmtblkno2;
954153323Srodrigc		args->rmtblkcnt = args->rmtblkcnt2;
955153323Srodrigc		if (args->rmtblkno) {
956153323Srodrigc			error = xfs_attr_rmtval_remove(args);
957153323Srodrigc			if (error)
958153323Srodrigc				return(error);
959153323Srodrigc		}
960153323Srodrigc
961153323Srodrigc		/*
962153323Srodrigc		 * Read in the block containing the "old" attr, then
963153323Srodrigc		 * remove the "old" attr from that block (neat, huh!)
964153323Srodrigc		 */
965153323Srodrigc		error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1,
966153323Srodrigc						     &bp, XFS_ATTR_FORK);
967153323Srodrigc		if (error)
968153323Srodrigc			return(error);
969153323Srodrigc		ASSERT(bp != NULL);
970153323Srodrigc		(void)xfs_attr_leaf_remove(bp, args);
971153323Srodrigc
972153323Srodrigc		/*
973153323Srodrigc		 * If the result is small enough, shrink it all into the inode.
974153323Srodrigc		 */
975159451Srodrigc		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
976153323Srodrigc			XFS_BMAP_INIT(args->flist, args->firstblock);
977159451Srodrigc			error = xfs_attr_leaf_to_shortform(bp, args, forkoff);
978153323Srodrigc			/* bp is gone due to xfs_da_shrink_inode */
979153323Srodrigc			if (!error) {
980153323Srodrigc				error = xfs_bmap_finish(&args->trans,
981153323Srodrigc							args->flist,
982153323Srodrigc							*args->firstblock,
983153323Srodrigc							&committed);
984153323Srodrigc			}
985153323Srodrigc			if (error) {
986153323Srodrigc				ASSERT(committed);
987153323Srodrigc				args->trans = NULL;
988153323Srodrigc				xfs_bmap_cancel(args->flist);
989153323Srodrigc				return(error);
990153323Srodrigc			}
991153323Srodrigc
992153323Srodrigc			/*
993153323Srodrigc			 * bmap_finish() may have committed the last trans
994153323Srodrigc			 * and started a new one.  We need the inode to be
995153323Srodrigc			 * in all transactions.
996153323Srodrigc			 */
997153323Srodrigc			if (committed) {
998153323Srodrigc				xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
999153323Srodrigc				xfs_trans_ihold(args->trans, dp);
1000153323Srodrigc			}
1001153323Srodrigc		} else
1002153323Srodrigc			xfs_da_buf_done(bp);
1003153323Srodrigc
1004153323Srodrigc		/*
1005153323Srodrigc		 * Commit the remove and start the next trans in series.
1006153323Srodrigc		 */
1007153323Srodrigc		error = xfs_attr_rolltrans(&args->trans, dp);
1008153323Srodrigc
1009153323Srodrigc	} else if (args->rmtblkno > 0) {
1010153323Srodrigc		/*
1011153323Srodrigc		 * Added a "remote" value, just clear the incomplete flag.
1012153323Srodrigc		 */
1013153323Srodrigc		error = xfs_attr_leaf_clearflag(args);
1014153323Srodrigc	}
1015153323Srodrigc	return(error);
1016153323Srodrigc}
1017153323Srodrigc
1018153323Srodrigc/*
1019153323Srodrigc * Remove a name from the leaf attribute list structure
1020153323Srodrigc *
1021153323Srodrigc * This leaf block cannot have a "remote" value, we only call this routine
1022153323Srodrigc * if bmap_one_block() says there is only one block (ie: no remote blks).
1023153323Srodrigc */
1024153323SrodrigcSTATIC int
1025153323Srodrigcxfs_attr_leaf_removename(xfs_da_args_t *args)
1026153323Srodrigc{
1027153323Srodrigc	xfs_inode_t *dp;
1028153323Srodrigc	xfs_dabuf_t *bp;
1029159451Srodrigc	int error, committed, forkoff;
1030153323Srodrigc
1031153323Srodrigc	/*
1032153323Srodrigc	 * Remove the attribute.
1033153323Srodrigc	 */
1034153323Srodrigc	dp = args->dp;
1035153323Srodrigc	args->blkno = 0;
1036153323Srodrigc	error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
1037153323Srodrigc					     XFS_ATTR_FORK);
1038153323Srodrigc	if (error) {
1039153323Srodrigc		return(error);
1040153323Srodrigc	}
1041153323Srodrigc
1042153323Srodrigc	ASSERT(bp != NULL);
1043153323Srodrigc	error = xfs_attr_leaf_lookup_int(bp, args);
1044153323Srodrigc	if (error == ENOATTR) {
1045153323Srodrigc		xfs_da_brelse(args->trans, bp);
1046153323Srodrigc		return(error);
1047153323Srodrigc	}
1048153323Srodrigc
1049153323Srodrigc	(void)xfs_attr_leaf_remove(bp, args);
1050153323Srodrigc
1051153323Srodrigc	/*
1052153323Srodrigc	 * If the result is small enough, shrink it all into the inode.
1053153323Srodrigc	 */
1054159451Srodrigc	if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
1055153323Srodrigc		XFS_BMAP_INIT(args->flist, args->firstblock);
1056159451Srodrigc		error = xfs_attr_leaf_to_shortform(bp, args, forkoff);
1057153323Srodrigc		/* bp is gone due to xfs_da_shrink_inode */
1058153323Srodrigc		if (!error) {
1059153323Srodrigc			error = xfs_bmap_finish(&args->trans, args->flist,
1060153323Srodrigc						*args->firstblock, &committed);
1061153323Srodrigc		}
1062153323Srodrigc		if (error) {
1063153323Srodrigc			ASSERT(committed);
1064153323Srodrigc			args->trans = NULL;
1065153323Srodrigc			xfs_bmap_cancel(args->flist);
1066153323Srodrigc			return(error);
1067153323Srodrigc		}
1068153323Srodrigc
1069153323Srodrigc		/*
1070153323Srodrigc		 * bmap_finish() may have committed the last trans and started
1071153323Srodrigc		 * a new one.  We need the inode to be in all transactions.
1072153323Srodrigc		 */
1073153323Srodrigc		if (committed) {
1074153323Srodrigc			xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1075153323Srodrigc			xfs_trans_ihold(args->trans, dp);
1076153323Srodrigc		}
1077153323Srodrigc	} else
1078153323Srodrigc		xfs_da_buf_done(bp);
1079153323Srodrigc	return(0);
1080153323Srodrigc}
1081153323Srodrigc
1082153323Srodrigc/*
1083153323Srodrigc * Look up a name in a leaf attribute list structure.
1084153323Srodrigc *
1085153323Srodrigc * This leaf block cannot have a "remote" value, we only call this routine
1086153323Srodrigc * if bmap_one_block() says there is only one block (ie: no remote blks).
1087153323Srodrigc */
1088159451SrodrigcSTATIC int
1089153323Srodrigcxfs_attr_leaf_get(xfs_da_args_t *args)
1090153323Srodrigc{
1091153323Srodrigc	xfs_dabuf_t *bp;
1092153323Srodrigc	int error;
1093153323Srodrigc
1094153323Srodrigc	args->blkno = 0;
1095153323Srodrigc	error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
1096153323Srodrigc					     XFS_ATTR_FORK);
1097153323Srodrigc	if (error)
1098153323Srodrigc		return(error);
1099153323Srodrigc	ASSERT(bp != NULL);
1100153323Srodrigc
1101153323Srodrigc	error = xfs_attr_leaf_lookup_int(bp, args);
1102153323Srodrigc	if (error != EEXIST)  {
1103153323Srodrigc		xfs_da_brelse(args->trans, bp);
1104153323Srodrigc		return(error);
1105153323Srodrigc	}
1106153323Srodrigc	error = xfs_attr_leaf_getvalue(bp, args);
1107153323Srodrigc	xfs_da_brelse(args->trans, bp);
1108153323Srodrigc	if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) {
1109153323Srodrigc		error = xfs_attr_rmtval_get(args);
1110153323Srodrigc	}
1111153323Srodrigc	return(error);
1112153323Srodrigc}
1113153323Srodrigc
1114153323Srodrigc/*
1115153323Srodrigc * Copy out attribute entries for attr_list(), for leaf attribute lists.
1116153323Srodrigc */
1117153323SrodrigcSTATIC int
1118153323Srodrigcxfs_attr_leaf_list(xfs_attr_list_context_t *context)
1119153323Srodrigc{
1120153323Srodrigc	xfs_attr_leafblock_t *leaf;
1121153323Srodrigc	int error;
1122153323Srodrigc	xfs_dabuf_t *bp;
1123153323Srodrigc
1124153323Srodrigc	context->cursor->blkno = 0;
1125153323Srodrigc	error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK);
1126153323Srodrigc	if (error)
1127153323Srodrigc		return(error);
1128153323Srodrigc	ASSERT(bp != NULL);
1129153323Srodrigc	leaf = bp->data;
1130159451Srodrigc	if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) {
1131153323Srodrigc		XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW,
1132153323Srodrigc				     context->dp->i_mount, leaf);
1133153323Srodrigc		xfs_da_brelse(NULL, bp);
1134153323Srodrigc		return(XFS_ERROR(EFSCORRUPTED));
1135153323Srodrigc	}
1136153323Srodrigc
1137153323Srodrigc	(void)xfs_attr_leaf_list_int(bp, context);
1138153323Srodrigc	xfs_da_brelse(NULL, bp);
1139153323Srodrigc	return(0);
1140153323Srodrigc}
1141153323Srodrigc
1142153323Srodrigc
1143153323Srodrigc/*========================================================================
1144153323Srodrigc * External routines when attribute list size > XFS_LBSIZE(mp).
1145153323Srodrigc *========================================================================*/
1146153323Srodrigc
1147153323Srodrigc/*
1148153323Srodrigc * Add a name to a Btree-format attribute list.
1149153323Srodrigc *
1150153323Srodrigc * This will involve walking down the Btree, and may involve splitting
1151153323Srodrigc * leaf nodes and even splitting intermediate nodes up to and including
1152153323Srodrigc * the root node (a special case of an intermediate node).
1153153323Srodrigc *
1154153323Srodrigc * "Remote" attribute values confuse the issue and atomic rename operations
1155153323Srodrigc * add a whole extra layer of confusion on top of that.
1156153323Srodrigc */
1157153323SrodrigcSTATIC int
1158153323Srodrigcxfs_attr_node_addname(xfs_da_args_t *args)
1159153323Srodrigc{
1160153323Srodrigc	xfs_da_state_t *state;
1161153323Srodrigc	xfs_da_state_blk_t *blk;
1162153323Srodrigc	xfs_inode_t *dp;
1163153323Srodrigc	xfs_mount_t *mp;
1164153323Srodrigc	int committed, retval, error;
1165153323Srodrigc
1166153323Srodrigc	/*
1167153323Srodrigc	 * Fill in bucket of arguments/results/context to carry around.
1168153323Srodrigc	 */
1169153323Srodrigc	dp = args->dp;
1170153323Srodrigc	mp = dp->i_mount;
1171153323Srodrigcrestart:
1172153323Srodrigc	state = xfs_da_state_alloc();
1173153323Srodrigc	state->args = args;
1174153323Srodrigc	state->mp = mp;
1175153323Srodrigc	state->blocksize = state->mp->m_sb.sb_blocksize;
1176153323Srodrigc	state->node_ents = state->mp->m_attr_node_ents;
1177153323Srodrigc
1178153323Srodrigc	/*
1179153323Srodrigc	 * Search to see if name already exists, and get back a pointer
1180153323Srodrigc	 * to where it should go.
1181153323Srodrigc	 */
1182153323Srodrigc	error = xfs_da_node_lookup_int(state, &retval);
1183153323Srodrigc	if (error)
1184153323Srodrigc		goto out;
1185153323Srodrigc	blk = &state->path.blk[ state->path.active-1 ];
1186153323Srodrigc	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1187153323Srodrigc	if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
1188153323Srodrigc		goto out;
1189153323Srodrigc	} else if (retval == EEXIST) {
1190153323Srodrigc		if (args->flags & ATTR_CREATE)
1191153323Srodrigc			goto out;
1192153323Srodrigc		args->rename = 1;			/* atomic rename op */
1193153323Srodrigc		args->blkno2 = args->blkno;		/* set 2nd entry info*/
1194153323Srodrigc		args->index2 = args->index;
1195153323Srodrigc		args->rmtblkno2 = args->rmtblkno;
1196153323Srodrigc		args->rmtblkcnt2 = args->rmtblkcnt;
1197153323Srodrigc		args->rmtblkno = 0;
1198153323Srodrigc		args->rmtblkcnt = 0;
1199153323Srodrigc	}
1200153323Srodrigc
1201153323Srodrigc	retval = xfs_attr_leaf_add(blk->bp, state->args);
1202153323Srodrigc	if (retval == ENOSPC) {
1203153323Srodrigc		if (state->path.active == 1) {
1204153323Srodrigc			/*
1205153323Srodrigc			 * Its really a single leaf node, but it had
1206153323Srodrigc			 * out-of-line values so it looked like it *might*
1207153323Srodrigc			 * have been a b-tree.
1208153323Srodrigc			 */
1209153323Srodrigc			xfs_da_state_free(state);
1210153323Srodrigc			XFS_BMAP_INIT(args->flist, args->firstblock);
1211153323Srodrigc			error = xfs_attr_leaf_to_node(args);
1212153323Srodrigc			if (!error) {
1213153323Srodrigc				error = xfs_bmap_finish(&args->trans,
1214153323Srodrigc							args->flist,
1215153323Srodrigc							*args->firstblock,
1216153323Srodrigc							&committed);
1217153323Srodrigc			}
1218153323Srodrigc			if (error) {
1219153323Srodrigc				ASSERT(committed);
1220153323Srodrigc				args->trans = NULL;
1221153323Srodrigc				xfs_bmap_cancel(args->flist);
1222153323Srodrigc				goto out;
1223153323Srodrigc			}
1224153323Srodrigc
1225153323Srodrigc			/*
1226153323Srodrigc			 * bmap_finish() may have committed the last trans
1227153323Srodrigc			 * and started a new one.  We need the inode to be
1228153323Srodrigc			 * in all transactions.
1229153323Srodrigc			 */
1230153323Srodrigc			if (committed) {
1231153323Srodrigc				xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1232153323Srodrigc				xfs_trans_ihold(args->trans, dp);
1233153323Srodrigc			}
1234153323Srodrigc
1235153323Srodrigc			/*
1236153323Srodrigc			 * Commit the node conversion and start the next
1237153323Srodrigc			 * trans in the chain.
1238153323Srodrigc			 */
1239153323Srodrigc			if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1240153323Srodrigc				goto out;
1241153323Srodrigc
1242153323Srodrigc			goto restart;
1243153323Srodrigc		}
1244153323Srodrigc
1245153323Srodrigc		/*
1246153323Srodrigc		 * Split as many Btree elements as required.
1247153323Srodrigc		 * This code tracks the new and old attr's location
1248153323Srodrigc		 * in the index/blkno/rmtblkno/rmtblkcnt fields and
1249153323Srodrigc		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
1250153323Srodrigc		 */
1251153323Srodrigc		XFS_BMAP_INIT(args->flist, args->firstblock);
1252153323Srodrigc		error = xfs_da_split(state);
1253153323Srodrigc		if (!error) {
1254153323Srodrigc			error = xfs_bmap_finish(&args->trans, args->flist,
1255153323Srodrigc						*args->firstblock, &committed);
1256153323Srodrigc		}
1257153323Srodrigc		if (error) {
1258153323Srodrigc			ASSERT(committed);
1259153323Srodrigc			args->trans = NULL;
1260153323Srodrigc			xfs_bmap_cancel(args->flist);
1261153323Srodrigc			goto out;
1262153323Srodrigc		}
1263153323Srodrigc
1264153323Srodrigc		/*
1265153323Srodrigc		 * bmap_finish() may have committed the last trans and started
1266153323Srodrigc		 * a new one.  We need the inode to be in all transactions.
1267153323Srodrigc		 */
1268153323Srodrigc		if (committed) {
1269153323Srodrigc			xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1270153323Srodrigc			xfs_trans_ihold(args->trans, dp);
1271153323Srodrigc		}
1272153323Srodrigc	} else {
1273153323Srodrigc		/*
1274153323Srodrigc		 * Addition succeeded, update Btree hashvals.
1275153323Srodrigc		 */
1276153323Srodrigc		xfs_da_fixhashpath(state, &state->path);
1277153323Srodrigc	}
1278153323Srodrigc
1279153323Srodrigc	/*
1280153323Srodrigc	 * Kill the state structure, we're done with it and need to
1281153323Srodrigc	 * allow the buffers to come back later.
1282153323Srodrigc	 */
1283153323Srodrigc	xfs_da_state_free(state);
1284153323Srodrigc	state = NULL;
1285153323Srodrigc
1286153323Srodrigc	/*
1287153323Srodrigc	 * Commit the leaf addition or btree split and start the next
1288153323Srodrigc	 * trans in the chain.
1289153323Srodrigc	 */
1290153323Srodrigc	if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1291153323Srodrigc		goto out;
1292153323Srodrigc
1293153323Srodrigc	/*
1294153323Srodrigc	 * If there was an out-of-line value, allocate the blocks we
1295153323Srodrigc	 * identified for its storage and copy the value.  This is done
1296153323Srodrigc	 * after we create the attribute so that we don't overflow the
1297153323Srodrigc	 * maximum size of a transaction and/or hit a deadlock.
1298153323Srodrigc	 */
1299153323Srodrigc	if (args->rmtblkno > 0) {
1300153323Srodrigc		error = xfs_attr_rmtval_set(args);
1301153323Srodrigc		if (error)
1302153323Srodrigc			return(error);
1303153323Srodrigc	}
1304153323Srodrigc
1305153323Srodrigc	/*
1306153323Srodrigc	 * If this is an atomic rename operation, we must "flip" the
1307153323Srodrigc	 * incomplete flags on the "new" and "old" attribute/value pairs
1308153323Srodrigc	 * so that one disappears and one appears atomically.  Then we
1309153323Srodrigc	 * must remove the "old" attribute/value pair.
1310153323Srodrigc	 */
1311153323Srodrigc	if (args->rename) {
1312153323Srodrigc		/*
1313153323Srodrigc		 * In a separate transaction, set the incomplete flag on the
1314153323Srodrigc		 * "old" attr and clear the incomplete flag on the "new" attr.
1315153323Srodrigc		 */
1316153323Srodrigc		error = xfs_attr_leaf_flipflags(args);
1317153323Srodrigc		if (error)
1318153323Srodrigc			goto out;
1319153323Srodrigc
1320153323Srodrigc		/*
1321153323Srodrigc		 * Dismantle the "old" attribute/value pair by removing
1322153323Srodrigc		 * a "remote" value (if it exists).
1323153323Srodrigc		 */
1324153323Srodrigc		args->index = args->index2;
1325153323Srodrigc		args->blkno = args->blkno2;
1326153323Srodrigc		args->rmtblkno = args->rmtblkno2;
1327153323Srodrigc		args->rmtblkcnt = args->rmtblkcnt2;
1328153323Srodrigc		if (args->rmtblkno) {
1329153323Srodrigc			error = xfs_attr_rmtval_remove(args);
1330153323Srodrigc			if (error)
1331153323Srodrigc				return(error);
1332153323Srodrigc		}
1333153323Srodrigc
1334153323Srodrigc		/*
1335153323Srodrigc		 * Re-find the "old" attribute entry after any split ops.
1336153323Srodrigc		 * The INCOMPLETE flag means that we will find the "old"
1337153323Srodrigc		 * attr, not the "new" one.
1338153323Srodrigc		 */
1339153323Srodrigc		args->flags |= XFS_ATTR_INCOMPLETE;
1340153323Srodrigc		state = xfs_da_state_alloc();
1341153323Srodrigc		state->args = args;
1342153323Srodrigc		state->mp = mp;
1343153323Srodrigc		state->blocksize = state->mp->m_sb.sb_blocksize;
1344153323Srodrigc		state->node_ents = state->mp->m_attr_node_ents;
1345153323Srodrigc		state->inleaf = 0;
1346153323Srodrigc		error = xfs_da_node_lookup_int(state, &retval);
1347153323Srodrigc		if (error)
1348153323Srodrigc			goto out;
1349153323Srodrigc
1350153323Srodrigc		/*
1351153323Srodrigc		 * Remove the name and update the hashvals in the tree.
1352153323Srodrigc		 */
1353153323Srodrigc		blk = &state->path.blk[ state->path.active-1 ];
1354153323Srodrigc		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1355153323Srodrigc		error = xfs_attr_leaf_remove(blk->bp, args);
1356153323Srodrigc		xfs_da_fixhashpath(state, &state->path);
1357153323Srodrigc
1358153323Srodrigc		/*
1359153323Srodrigc		 * Check to see if the tree needs to be collapsed.
1360153323Srodrigc		 */
1361153323Srodrigc		if (retval && (state->path.active > 1)) {
1362153323Srodrigc			XFS_BMAP_INIT(args->flist, args->firstblock);
1363153323Srodrigc			error = xfs_da_join(state);
1364153323Srodrigc			if (!error) {
1365153323Srodrigc				error = xfs_bmap_finish(&args->trans,
1366153323Srodrigc							args->flist,
1367153323Srodrigc							*args->firstblock,
1368153323Srodrigc							&committed);
1369153323Srodrigc			}
1370153323Srodrigc			if (error) {
1371153323Srodrigc				ASSERT(committed);
1372153323Srodrigc				args->trans = NULL;
1373153323Srodrigc				xfs_bmap_cancel(args->flist);
1374153323Srodrigc				goto out;
1375153323Srodrigc			}
1376153323Srodrigc
1377153323Srodrigc			/*
1378153323Srodrigc			 * bmap_finish() may have committed the last trans
1379153323Srodrigc			 * and started a new one.  We need the inode to be
1380153323Srodrigc			 * in all transactions.
1381153323Srodrigc			 */
1382153323Srodrigc			if (committed) {
1383153323Srodrigc				xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1384153323Srodrigc				xfs_trans_ihold(args->trans, dp);
1385153323Srodrigc			}
1386153323Srodrigc		}
1387153323Srodrigc
1388153323Srodrigc		/*
1389153323Srodrigc		 * Commit and start the next trans in the chain.
1390153323Srodrigc		 */
1391153323Srodrigc		if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1392153323Srodrigc			goto out;
1393153323Srodrigc
1394153323Srodrigc	} else if (args->rmtblkno > 0) {
1395153323Srodrigc		/*
1396153323Srodrigc		 * Added a "remote" value, just clear the incomplete flag.
1397153323Srodrigc		 */
1398153323Srodrigc		error = xfs_attr_leaf_clearflag(args);
1399153323Srodrigc		if (error)
1400153323Srodrigc			goto out;
1401153323Srodrigc	}
1402153323Srodrigc	retval = error = 0;
1403153323Srodrigc
1404153323Srodrigcout:
1405153323Srodrigc	if (state)
1406153323Srodrigc		xfs_da_state_free(state);
1407153323Srodrigc	if (error)
1408153323Srodrigc		return(error);
1409153323Srodrigc	return(retval);
1410153323Srodrigc}
1411153323Srodrigc
1412153323Srodrigc/*
1413153323Srodrigc * Remove a name from a B-tree attribute list.
1414153323Srodrigc *
1415153323Srodrigc * This will involve walking down the Btree, and may involve joining
1416153323Srodrigc * leaf nodes and even joining intermediate nodes up to and including
1417153323Srodrigc * the root node (a special case of an intermediate node).
1418153323Srodrigc */
1419153323SrodrigcSTATIC int
1420153323Srodrigcxfs_attr_node_removename(xfs_da_args_t *args)
1421153323Srodrigc{
1422153323Srodrigc	xfs_da_state_t *state;
1423153323Srodrigc	xfs_da_state_blk_t *blk;
1424153323Srodrigc	xfs_inode_t *dp;
1425153323Srodrigc	xfs_dabuf_t *bp;
1426159451Srodrigc	int retval, error, committed, forkoff;
1427153323Srodrigc
1428153323Srodrigc	/*
1429153323Srodrigc	 * Tie a string around our finger to remind us where we are.
1430153323Srodrigc	 */
1431153323Srodrigc	dp = args->dp;
1432153323Srodrigc	state = xfs_da_state_alloc();
1433153323Srodrigc	state->args = args;
1434153323Srodrigc	state->mp = dp->i_mount;
1435153323Srodrigc	state->blocksize = state->mp->m_sb.sb_blocksize;
1436153323Srodrigc	state->node_ents = state->mp->m_attr_node_ents;
1437153323Srodrigc
1438153323Srodrigc	/*
1439153323Srodrigc	 * Search to see if name exists, and get back a pointer to it.
1440153323Srodrigc	 */
1441153323Srodrigc	error = xfs_da_node_lookup_int(state, &retval);
1442153323Srodrigc	if (error || (retval != EEXIST)) {
1443153323Srodrigc		if (error == 0)
1444153323Srodrigc			error = retval;
1445153323Srodrigc		goto out;
1446153323Srodrigc	}
1447153323Srodrigc
1448153323Srodrigc	/*
1449153323Srodrigc	 * If there is an out-of-line value, de-allocate the blocks.
1450153323Srodrigc	 * This is done before we remove the attribute so that we don't
1451153323Srodrigc	 * overflow the maximum size of a transaction and/or hit a deadlock.
1452153323Srodrigc	 */
1453153323Srodrigc	blk = &state->path.blk[ state->path.active-1 ];
1454153323Srodrigc	ASSERT(blk->bp != NULL);
1455153323Srodrigc	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1456153323Srodrigc	if (args->rmtblkno > 0) {
1457153323Srodrigc		/*
1458153323Srodrigc		 * Fill in disk block numbers in the state structure
1459153323Srodrigc		 * so that we can get the buffers back after we commit
1460153323Srodrigc		 * several transactions in the following calls.
1461153323Srodrigc		 */
1462153323Srodrigc		error = xfs_attr_fillstate(state);
1463153323Srodrigc		if (error)
1464153323Srodrigc			goto out;
1465153323Srodrigc
1466153323Srodrigc		/*
1467153323Srodrigc		 * Mark the attribute as INCOMPLETE, then bunmapi() the
1468153323Srodrigc		 * remote value.
1469153323Srodrigc		 */
1470153323Srodrigc		error = xfs_attr_leaf_setflag(args);
1471153323Srodrigc		if (error)
1472153323Srodrigc			goto out;
1473153323Srodrigc		error = xfs_attr_rmtval_remove(args);
1474153323Srodrigc		if (error)
1475153323Srodrigc			goto out;
1476153323Srodrigc
1477153323Srodrigc		/*
1478153323Srodrigc		 * Refill the state structure with buffers, the prior calls
1479153323Srodrigc		 * released our buffers.
1480153323Srodrigc		 */
1481153323Srodrigc		error = xfs_attr_refillstate(state);
1482153323Srodrigc		if (error)
1483153323Srodrigc			goto out;
1484153323Srodrigc	}
1485153323Srodrigc
1486153323Srodrigc	/*
1487153323Srodrigc	 * Remove the name and update the hashvals in the tree.
1488153323Srodrigc	 */
1489153323Srodrigc	blk = &state->path.blk[ state->path.active-1 ];
1490153323Srodrigc	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1491153323Srodrigc	retval = xfs_attr_leaf_remove(blk->bp, args);
1492153323Srodrigc	xfs_da_fixhashpath(state, &state->path);
1493153323Srodrigc
1494153323Srodrigc	/*
1495153323Srodrigc	 * Check to see if the tree needs to be collapsed.
1496153323Srodrigc	 */
1497153323Srodrigc	if (retval && (state->path.active > 1)) {
1498153323Srodrigc		XFS_BMAP_INIT(args->flist, args->firstblock);
1499153323Srodrigc		error = xfs_da_join(state);
1500153323Srodrigc		if (!error) {
1501153323Srodrigc			error = xfs_bmap_finish(&args->trans, args->flist,
1502153323Srodrigc						*args->firstblock, &committed);
1503153323Srodrigc		}
1504153323Srodrigc		if (error) {
1505153323Srodrigc			ASSERT(committed);
1506153323Srodrigc			args->trans = NULL;
1507153323Srodrigc			xfs_bmap_cancel(args->flist);
1508153323Srodrigc			goto out;
1509153323Srodrigc		}
1510153323Srodrigc
1511153323Srodrigc		/*
1512153323Srodrigc		 * bmap_finish() may have committed the last trans and started
1513153323Srodrigc		 * a new one.  We need the inode to be in all transactions.
1514153323Srodrigc		 */
1515153323Srodrigc		if (committed) {
1516153323Srodrigc			xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1517153323Srodrigc			xfs_trans_ihold(args->trans, dp);
1518153323Srodrigc		}
1519153323Srodrigc
1520153323Srodrigc		/*
1521153323Srodrigc		 * Commit the Btree join operation and start a new trans.
1522153323Srodrigc		 */
1523153323Srodrigc		if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1524153323Srodrigc			goto out;
1525153323Srodrigc	}
1526153323Srodrigc
1527153323Srodrigc	/*
1528153323Srodrigc	 * If the result is small enough, push it all into the inode.
1529153323Srodrigc	 */
1530153323Srodrigc	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
1531153323Srodrigc		/*
1532153323Srodrigc		 * Have to get rid of the copy of this dabuf in the state.
1533153323Srodrigc		 */
1534153323Srodrigc		ASSERT(state->path.active == 1);
1535153323Srodrigc		ASSERT(state->path.blk[0].bp);
1536153323Srodrigc		xfs_da_buf_done(state->path.blk[0].bp);
1537153323Srodrigc		state->path.blk[0].bp = NULL;
1538153323Srodrigc
1539153323Srodrigc		error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
1540153323Srodrigc						     XFS_ATTR_FORK);
1541153323Srodrigc		if (error)
1542153323Srodrigc			goto out;
1543159451Srodrigc		ASSERT(be16_to_cpu(((xfs_attr_leafblock_t *)
1544159451Srodrigc				      bp->data)->hdr.info.magic)
1545153323Srodrigc						       == XFS_ATTR_LEAF_MAGIC);
1546153323Srodrigc
1547159451Srodrigc		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
1548153323Srodrigc			XFS_BMAP_INIT(args->flist, args->firstblock);
1549159451Srodrigc			error = xfs_attr_leaf_to_shortform(bp, args, forkoff);
1550153323Srodrigc			/* bp is gone due to xfs_da_shrink_inode */
1551153323Srodrigc			if (!error) {
1552153323Srodrigc				error = xfs_bmap_finish(&args->trans,
1553153323Srodrigc							args->flist,
1554153323Srodrigc							*args->firstblock,
1555153323Srodrigc							&committed);
1556153323Srodrigc			}
1557153323Srodrigc			if (error) {
1558153323Srodrigc				ASSERT(committed);
1559153323Srodrigc				args->trans = NULL;
1560153323Srodrigc				xfs_bmap_cancel(args->flist);
1561153323Srodrigc				goto out;
1562153323Srodrigc			}
1563153323Srodrigc
1564153323Srodrigc			/*
1565153323Srodrigc			 * bmap_finish() may have committed the last trans
1566153323Srodrigc			 * and started a new one.  We need the inode to be
1567153323Srodrigc			 * in all transactions.
1568153323Srodrigc			 */
1569153323Srodrigc			if (committed) {
1570153323Srodrigc				xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1571153323Srodrigc				xfs_trans_ihold(args->trans, dp);
1572153323Srodrigc			}
1573153323Srodrigc		} else
1574153323Srodrigc			xfs_da_brelse(args->trans, bp);
1575153323Srodrigc	}
1576153323Srodrigc	error = 0;
1577153323Srodrigc
1578153323Srodrigcout:
1579153323Srodrigc	xfs_da_state_free(state);
1580153323Srodrigc	return(error);
1581153323Srodrigc}
1582153323Srodrigc
1583153323Srodrigc/*
1584153323Srodrigc * Fill in the disk block numbers in the state structure for the buffers
1585153323Srodrigc * that are attached to the state structure.
1586153323Srodrigc * This is done so that we can quickly reattach ourselves to those buffers
1587159451Srodrigc * after some set of transaction commits have released these buffers.
1588153323Srodrigc */
1589153323SrodrigcSTATIC int
1590153323Srodrigcxfs_attr_fillstate(xfs_da_state_t *state)
1591153323Srodrigc{
1592153323Srodrigc	xfs_da_state_path_t *path;
1593153323Srodrigc	xfs_da_state_blk_t *blk;
1594153323Srodrigc	int level;
1595153323Srodrigc
1596153323Srodrigc	/*
1597153323Srodrigc	 * Roll down the "path" in the state structure, storing the on-disk
1598153323Srodrigc	 * block number for those buffers in the "path".
1599153323Srodrigc	 */
1600153323Srodrigc	path = &state->path;
1601153323Srodrigc	ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1602153323Srodrigc	for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1603153323Srodrigc		if (blk->bp) {
1604153323Srodrigc			blk->disk_blkno = xfs_da_blkno(blk->bp);
1605153323Srodrigc			xfs_da_buf_done(blk->bp);
1606153323Srodrigc			blk->bp = NULL;
1607153323Srodrigc		} else {
1608153323Srodrigc			blk->disk_blkno = 0;
1609153323Srodrigc		}
1610153323Srodrigc	}
1611153323Srodrigc
1612153323Srodrigc	/*
1613153323Srodrigc	 * Roll down the "altpath" in the state structure, storing the on-disk
1614153323Srodrigc	 * block number for those buffers in the "altpath".
1615153323Srodrigc	 */
1616153323Srodrigc	path = &state->altpath;
1617153323Srodrigc	ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1618153323Srodrigc	for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1619153323Srodrigc		if (blk->bp) {
1620153323Srodrigc			blk->disk_blkno = xfs_da_blkno(blk->bp);
1621153323Srodrigc			xfs_da_buf_done(blk->bp);
1622153323Srodrigc			blk->bp = NULL;
1623153323Srodrigc		} else {
1624153323Srodrigc			blk->disk_blkno = 0;
1625153323Srodrigc		}
1626153323Srodrigc	}
1627153323Srodrigc
1628153323Srodrigc	return(0);
1629153323Srodrigc}
1630153323Srodrigc
1631153323Srodrigc/*
1632153323Srodrigc * Reattach the buffers to the state structure based on the disk block
1633153323Srodrigc * numbers stored in the state structure.
1634159451Srodrigc * This is done after some set of transaction commits have released those
1635153323Srodrigc * buffers from our grip.
1636153323Srodrigc */
1637153323SrodrigcSTATIC int
1638153323Srodrigcxfs_attr_refillstate(xfs_da_state_t *state)
1639153323Srodrigc{
1640153323Srodrigc	xfs_da_state_path_t *path;
1641153323Srodrigc	xfs_da_state_blk_t *blk;
1642153323Srodrigc	int level, error;
1643153323Srodrigc
1644153323Srodrigc	/*
1645153323Srodrigc	 * Roll down the "path" in the state structure, storing the on-disk
1646153323Srodrigc	 * block number for those buffers in the "path".
1647153323Srodrigc	 */
1648153323Srodrigc	path = &state->path;
1649153323Srodrigc	ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1650153323Srodrigc	for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1651153323Srodrigc		if (blk->disk_blkno) {
1652153323Srodrigc			error = xfs_da_read_buf(state->args->trans,
1653153323Srodrigc						state->args->dp,
1654153323Srodrigc						blk->blkno, blk->disk_blkno,
1655153323Srodrigc						&blk->bp, XFS_ATTR_FORK);
1656153323Srodrigc			if (error)
1657153323Srodrigc				return(error);
1658153323Srodrigc		} else {
1659153323Srodrigc			blk->bp = NULL;
1660153323Srodrigc		}
1661153323Srodrigc	}
1662153323Srodrigc
1663153323Srodrigc	/*
1664153323Srodrigc	 * Roll down the "altpath" in the state structure, storing the on-disk
1665153323Srodrigc	 * block number for those buffers in the "altpath".
1666153323Srodrigc	 */
1667153323Srodrigc	path = &state->altpath;
1668153323Srodrigc	ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1669153323Srodrigc	for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1670153323Srodrigc		if (blk->disk_blkno) {
1671153323Srodrigc			error = xfs_da_read_buf(state->args->trans,
1672153323Srodrigc						state->args->dp,
1673153323Srodrigc						blk->blkno, blk->disk_blkno,
1674153323Srodrigc						&blk->bp, XFS_ATTR_FORK);
1675153323Srodrigc			if (error)
1676153323Srodrigc				return(error);
1677153323Srodrigc		} else {
1678153323Srodrigc			blk->bp = NULL;
1679153323Srodrigc		}
1680153323Srodrigc	}
1681153323Srodrigc
1682153323Srodrigc	return(0);
1683153323Srodrigc}
1684153323Srodrigc
1685153323Srodrigc/*
1686153323Srodrigc * Look up a filename in a node attribute list.
1687153323Srodrigc *
1688153323Srodrigc * This routine gets called for any attribute fork that has more than one
1689153323Srodrigc * block, ie: both true Btree attr lists and for single-leaf-blocks with
1690153323Srodrigc * "remote" values taking up more blocks.
1691153323Srodrigc */
1692159451SrodrigcSTATIC int
1693153323Srodrigcxfs_attr_node_get(xfs_da_args_t *args)
1694153323Srodrigc{
1695153323Srodrigc	xfs_da_state_t *state;
1696153323Srodrigc	xfs_da_state_blk_t *blk;
1697153323Srodrigc	int error, retval;
1698153323Srodrigc	int i;
1699153323Srodrigc
1700153323Srodrigc	state = xfs_da_state_alloc();
1701153323Srodrigc	state->args = args;
1702153323Srodrigc	state->mp = args->dp->i_mount;
1703153323Srodrigc	state->blocksize = state->mp->m_sb.sb_blocksize;
1704153323Srodrigc	state->node_ents = state->mp->m_attr_node_ents;
1705153323Srodrigc
1706153323Srodrigc	/*
1707153323Srodrigc	 * Search to see if name exists, and get back a pointer to it.
1708153323Srodrigc	 */
1709153323Srodrigc	error = xfs_da_node_lookup_int(state, &retval);
1710153323Srodrigc	if (error) {
1711153323Srodrigc		retval = error;
1712153323Srodrigc	} else if (retval == EEXIST) {
1713153323Srodrigc		blk = &state->path.blk[ state->path.active-1 ];
1714153323Srodrigc		ASSERT(blk->bp != NULL);
1715153323Srodrigc		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1716153323Srodrigc
1717153323Srodrigc		/*
1718153323Srodrigc		 * Get the value, local or "remote"
1719153323Srodrigc		 */
1720153323Srodrigc		retval = xfs_attr_leaf_getvalue(blk->bp, args);
1721153323Srodrigc		if (!retval && (args->rmtblkno > 0)
1722153323Srodrigc		    && !(args->flags & ATTR_KERNOVAL)) {
1723153323Srodrigc			retval = xfs_attr_rmtval_get(args);
1724153323Srodrigc		}
1725153323Srodrigc	}
1726153323Srodrigc
1727153323Srodrigc	/*
1728153323Srodrigc	 * If not in a transaction, we have to release all the buffers.
1729153323Srodrigc	 */
1730153323Srodrigc	for (i = 0; i < state->path.active; i++) {
1731153323Srodrigc		xfs_da_brelse(args->trans, state->path.blk[i].bp);
1732153323Srodrigc		state->path.blk[i].bp = NULL;
1733153323Srodrigc	}
1734153323Srodrigc
1735153323Srodrigc	xfs_da_state_free(state);
1736153323Srodrigc	return(retval);
1737153323Srodrigc}
1738153323Srodrigc
1739153323SrodrigcSTATIC int							/* error */
1740153323Srodrigcxfs_attr_node_list(xfs_attr_list_context_t *context)
1741153323Srodrigc{
1742153323Srodrigc	attrlist_cursor_kern_t *cursor;
1743153323Srodrigc	xfs_attr_leafblock_t *leaf;
1744153323Srodrigc	xfs_da_intnode_t *node;
1745153323Srodrigc	xfs_da_node_entry_t *btree;
1746153323Srodrigc	int error, i;
1747153323Srodrigc	xfs_dabuf_t *bp;
1748153323Srodrigc
1749153323Srodrigc	cursor = context->cursor;
1750153323Srodrigc	cursor->initted = 1;
1751153323Srodrigc
1752153323Srodrigc	/*
1753153323Srodrigc	 * Do all sorts of validation on the passed-in cursor structure.
1754153323Srodrigc	 * If anything is amiss, ignore the cursor and look up the hashval
1755153323Srodrigc	 * starting from the btree root.
1756153323Srodrigc	 */
1757153323Srodrigc	bp = NULL;
1758153323Srodrigc	if (cursor->blkno > 0) {
1759153323Srodrigc		error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
1760153323Srodrigc					      &bp, XFS_ATTR_FORK);
1761153323Srodrigc		if ((error != 0) && (error != EFSCORRUPTED))
1762153323Srodrigc			return(error);
1763153323Srodrigc		if (bp) {
1764153323Srodrigc			node = bp->data;
1765159451Srodrigc			switch (be16_to_cpu(node->hdr.info.magic)) {
1766153323Srodrigc			case XFS_DA_NODE_MAGIC:
1767153323Srodrigc				xfs_attr_trace_l_cn("wrong blk", context, node);
1768153323Srodrigc				xfs_da_brelse(NULL, bp);
1769153323Srodrigc				bp = NULL;
1770153323Srodrigc				break;
1771153323Srodrigc			case XFS_ATTR_LEAF_MAGIC:
1772153323Srodrigc				leaf = bp->data;
1773159451Srodrigc				if (cursor->hashval > be32_to_cpu(leaf->entries[
1774159451Srodrigc				    be16_to_cpu(leaf->hdr.count)-1].hashval)) {
1775153323Srodrigc					xfs_attr_trace_l_cl("wrong blk",
1776153323Srodrigc							   context, leaf);
1777153323Srodrigc					xfs_da_brelse(NULL, bp);
1778153323Srodrigc					bp = NULL;
1779153323Srodrigc				} else if (cursor->hashval <=
1780159451Srodrigc					     be32_to_cpu(leaf->entries[0].hashval)) {
1781153323Srodrigc					xfs_attr_trace_l_cl("maybe wrong blk",
1782153323Srodrigc							   context, leaf);
1783153323Srodrigc					xfs_da_brelse(NULL, bp);
1784153323Srodrigc					bp = NULL;
1785153323Srodrigc				}
1786153323Srodrigc				break;
1787153323Srodrigc			default:
1788153323Srodrigc				xfs_attr_trace_l_c("wrong blk - ??", context);
1789153323Srodrigc				xfs_da_brelse(NULL, bp);
1790153323Srodrigc				bp = NULL;
1791153323Srodrigc			}
1792153323Srodrigc		}
1793153323Srodrigc	}
1794153323Srodrigc
1795153323Srodrigc	/*
1796153323Srodrigc	 * We did not find what we expected given the cursor's contents,
1797153323Srodrigc	 * so we start from the top and work down based on the hash value.
1798153323Srodrigc	 * Note that start of node block is same as start of leaf block.
1799153323Srodrigc	 */
1800153323Srodrigc	if (bp == NULL) {
1801153323Srodrigc		cursor->blkno = 0;
1802153323Srodrigc		for (;;) {
1803153323Srodrigc			error = xfs_da_read_buf(NULL, context->dp,
1804153323Srodrigc						      cursor->blkno, -1, &bp,
1805153323Srodrigc						      XFS_ATTR_FORK);
1806153323Srodrigc			if (error)
1807153323Srodrigc				return(error);
1808153323Srodrigc			if (unlikely(bp == NULL)) {
1809153323Srodrigc				XFS_ERROR_REPORT("xfs_attr_node_list(2)",
1810153323Srodrigc						 XFS_ERRLEVEL_LOW,
1811153323Srodrigc						 context->dp->i_mount);
1812153323Srodrigc				return(XFS_ERROR(EFSCORRUPTED));
1813153323Srodrigc			}
1814153323Srodrigc			node = bp->data;
1815159451Srodrigc			if (be16_to_cpu(node->hdr.info.magic)
1816153323Srodrigc							== XFS_ATTR_LEAF_MAGIC)
1817153323Srodrigc				break;
1818159451Srodrigc			if (unlikely(be16_to_cpu(node->hdr.info.magic)
1819153323Srodrigc							!= XFS_DA_NODE_MAGIC)) {
1820153323Srodrigc				XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)",
1821153323Srodrigc						     XFS_ERRLEVEL_LOW,
1822153323Srodrigc						     context->dp->i_mount,
1823153323Srodrigc						     node);
1824153323Srodrigc				xfs_da_brelse(NULL, bp);
1825153323Srodrigc				return(XFS_ERROR(EFSCORRUPTED));
1826153323Srodrigc			}
1827153323Srodrigc			btree = node->btree;
1828159451Srodrigc			for (i = 0; i < be16_to_cpu(node->hdr.count);
1829153323Srodrigc								btree++, i++) {
1830153323Srodrigc				if (cursor->hashval
1831159451Srodrigc						<= be32_to_cpu(btree->hashval)) {
1832159451Srodrigc					cursor->blkno = be32_to_cpu(btree->before);
1833153323Srodrigc					xfs_attr_trace_l_cb("descending",
1834153323Srodrigc							    context, btree);
1835153323Srodrigc					break;
1836153323Srodrigc				}
1837153323Srodrigc			}
1838159451Srodrigc			if (i == be16_to_cpu(node->hdr.count)) {
1839153323Srodrigc				xfs_da_brelse(NULL, bp);
1840153323Srodrigc				return(0);
1841153323Srodrigc			}
1842153323Srodrigc			xfs_da_brelse(NULL, bp);
1843153323Srodrigc		}
1844153323Srodrigc	}
1845153323Srodrigc	ASSERT(bp != NULL);
1846153323Srodrigc
1847153323Srodrigc	/*
1848153323Srodrigc	 * Roll upward through the blocks, processing each leaf block in
1849153323Srodrigc	 * order.  As long as there is space in the result buffer, keep
1850153323Srodrigc	 * adding the information.
1851153323Srodrigc	 */
1852153323Srodrigc	for (;;) {
1853153323Srodrigc		leaf = bp->data;
1854159451Srodrigc		if (unlikely(be16_to_cpu(leaf->hdr.info.magic)
1855153323Srodrigc						!= XFS_ATTR_LEAF_MAGIC)) {
1856153323Srodrigc			XFS_CORRUPTION_ERROR("xfs_attr_node_list(4)",
1857153323Srodrigc					     XFS_ERRLEVEL_LOW,
1858153323Srodrigc					     context->dp->i_mount, leaf);
1859153323Srodrigc			xfs_da_brelse(NULL, bp);
1860153323Srodrigc			return(XFS_ERROR(EFSCORRUPTED));
1861153323Srodrigc		}
1862153323Srodrigc		error = xfs_attr_leaf_list_int(bp, context);
1863159451Srodrigc		if (error || !leaf->hdr.info.forw)
1864153323Srodrigc			break;	/* not really an error, buffer full or EOF */
1865159451Srodrigc		cursor->blkno = be32_to_cpu(leaf->hdr.info.forw);
1866153323Srodrigc		xfs_da_brelse(NULL, bp);
1867153323Srodrigc		error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
1868153323Srodrigc					      &bp, XFS_ATTR_FORK);
1869153323Srodrigc		if (error)
1870153323Srodrigc			return(error);
1871153323Srodrigc		if (unlikely((bp == NULL))) {
1872153323Srodrigc			XFS_ERROR_REPORT("xfs_attr_node_list(5)",
1873153323Srodrigc					 XFS_ERRLEVEL_LOW,
1874153323Srodrigc					 context->dp->i_mount);
1875153323Srodrigc			return(XFS_ERROR(EFSCORRUPTED));
1876153323Srodrigc		}
1877153323Srodrigc	}
1878153323Srodrigc	xfs_da_brelse(NULL, bp);
1879153323Srodrigc	return(0);
1880153323Srodrigc}
1881153323Srodrigc
1882153323Srodrigc
1883153323Srodrigc/*========================================================================
1884153323Srodrigc * External routines for manipulating out-of-line attribute values.
1885153323Srodrigc *========================================================================*/
1886153323Srodrigc
1887153323Srodrigc/*
1888153323Srodrigc * Read the value associated with an attribute from the out-of-line buffer
1889153323Srodrigc * that we stored it in.
1890153323Srodrigc */
1891153323SrodrigcSTATIC int
1892153323Srodrigcxfs_attr_rmtval_get(xfs_da_args_t *args)
1893153323Srodrigc{
1894153323Srodrigc	xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE];
1895153323Srodrigc	xfs_mount_t *mp;
1896153323Srodrigc	xfs_daddr_t dblkno;
1897153323Srodrigc	xfs_caddr_t dst;
1898153323Srodrigc	xfs_buf_t *bp;
1899153323Srodrigc	int nmap, error, tmp, valuelen, blkcnt, i;
1900153323Srodrigc	xfs_dablk_t lblkno;
1901153323Srodrigc
1902153323Srodrigc	ASSERT(!(args->flags & ATTR_KERNOVAL));
1903153323Srodrigc
1904153323Srodrigc	mp = args->dp->i_mount;
1905153323Srodrigc	dst = args->value;
1906153323Srodrigc	valuelen = args->valuelen;
1907153323Srodrigc	lblkno = args->rmtblkno;
1908153323Srodrigc	while (valuelen > 0) {
1909153323Srodrigc		nmap = ATTR_RMTVALUE_MAPSIZE;
1910153323Srodrigc		error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno,
1911153323Srodrigc				  args->rmtblkcnt,
1912153323Srodrigc				  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
1913159451Srodrigc				  NULL, 0, map, &nmap, NULL, NULL);
1914153323Srodrigc		if (error)
1915153323Srodrigc			return(error);
1916153323Srodrigc		ASSERT(nmap >= 1);
1917153323Srodrigc
1918153323Srodrigc		for (i = 0; (i < nmap) && (valuelen > 0); i++) {
1919153323Srodrigc			ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
1920153323Srodrigc			       (map[i].br_startblock != HOLESTARTBLOCK));
1921153323Srodrigc			dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
1922153323Srodrigc			blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
1923153323Srodrigc			error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno,
1924153323Srodrigc					     blkcnt, XFS_BUF_LOCK, &bp);
1925153323Srodrigc			if (error)
1926153323Srodrigc				return(error);
1927153323Srodrigc
1928153323Srodrigc			tmp = (valuelen < XFS_BUF_SIZE(bp))
1929153323Srodrigc				? valuelen : XFS_BUF_SIZE(bp);
1930153323Srodrigc			xfs_biomove(bp, 0, tmp, dst, XFS_B_READ);
1931153323Srodrigc			xfs_buf_relse(bp);
1932153323Srodrigc			dst += tmp;
1933153323Srodrigc			valuelen -= tmp;
1934153323Srodrigc
1935153323Srodrigc			lblkno += map[i].br_blockcount;
1936153323Srodrigc		}
1937153323Srodrigc	}
1938153323Srodrigc	ASSERT(valuelen == 0);
1939153323Srodrigc	return(0);
1940153323Srodrigc}
1941153323Srodrigc
1942153323Srodrigc/*
1943153323Srodrigc * Write the value associated with an attribute into the out-of-line buffer
1944153323Srodrigc * that we have defined for it.
1945153323Srodrigc */
1946153323SrodrigcSTATIC int
1947153323Srodrigcxfs_attr_rmtval_set(xfs_da_args_t *args)
1948153323Srodrigc{
1949153323Srodrigc	xfs_mount_t *mp;
1950153323Srodrigc	xfs_fileoff_t lfileoff;
1951153323Srodrigc	xfs_inode_t *dp;
1952153323Srodrigc	xfs_bmbt_irec_t map;
1953153323Srodrigc	xfs_daddr_t dblkno;
1954153323Srodrigc	xfs_caddr_t src;
1955153323Srodrigc	xfs_buf_t *bp;
1956153323Srodrigc	xfs_dablk_t lblkno;
1957153323Srodrigc	int blkcnt, valuelen, nmap, error, tmp, committed;
1958153323Srodrigc
1959153323Srodrigc	dp = args->dp;
1960153323Srodrigc	mp = dp->i_mount;
1961153323Srodrigc	src = args->value;
1962153323Srodrigc
1963153323Srodrigc	/*
1964153323Srodrigc	 * Find a "hole" in the attribute address space large enough for
1965153323Srodrigc	 * us to drop the new attribute's value into.
1966153323Srodrigc	 */
1967153323Srodrigc	blkcnt = XFS_B_TO_FSB(mp, args->valuelen);
1968153323Srodrigc	lfileoff = 0;
1969153323Srodrigc	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
1970153323Srodrigc						   XFS_ATTR_FORK);
1971153323Srodrigc	if (error) {
1972153323Srodrigc		return(error);
1973153323Srodrigc	}
1974153323Srodrigc	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
1975153323Srodrigc	args->rmtblkcnt = blkcnt;
1976153323Srodrigc
1977153323Srodrigc	/*
1978153323Srodrigc	 * Roll through the "value", allocating blocks on disk as required.
1979153323Srodrigc	 */
1980153323Srodrigc	while (blkcnt > 0) {
1981153323Srodrigc		/*
1982153323Srodrigc		 * Allocate a single extent, up to the size of the value.
1983153323Srodrigc		 */
1984153323Srodrigc		XFS_BMAP_INIT(args->flist, args->firstblock);
1985153323Srodrigc		nmap = 1;
1986153323Srodrigc		error = xfs_bmapi(args->trans, dp, (xfs_fileoff_t)lblkno,
1987153323Srodrigc				  blkcnt,
1988153323Srodrigc				  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA |
1989153323Srodrigc							XFS_BMAPI_WRITE,
1990153323Srodrigc				  args->firstblock, args->total, &map, &nmap,
1991159451Srodrigc				  args->flist, NULL);
1992153323Srodrigc		if (!error) {
1993153323Srodrigc			error = xfs_bmap_finish(&args->trans, args->flist,
1994153323Srodrigc						*args->firstblock, &committed);
1995153323Srodrigc		}
1996153323Srodrigc		if (error) {
1997153323Srodrigc			ASSERT(committed);
1998153323Srodrigc			args->trans = NULL;
1999153323Srodrigc			xfs_bmap_cancel(args->flist);
2000153323Srodrigc			return(error);
2001153323Srodrigc		}
2002153323Srodrigc
2003153323Srodrigc		/*
2004153323Srodrigc		 * bmap_finish() may have committed the last trans and started
2005153323Srodrigc		 * a new one.  We need the inode to be in all transactions.
2006153323Srodrigc		 */
2007153323Srodrigc		if (committed) {
2008153323Srodrigc			xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
2009153323Srodrigc			xfs_trans_ihold(args->trans, dp);
2010153323Srodrigc		}
2011153323Srodrigc
2012153323Srodrigc		ASSERT(nmap == 1);
2013153323Srodrigc		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
2014153323Srodrigc		       (map.br_startblock != HOLESTARTBLOCK));
2015153323Srodrigc		lblkno += map.br_blockcount;
2016153323Srodrigc		blkcnt -= map.br_blockcount;
2017153323Srodrigc
2018153323Srodrigc		/*
2019153323Srodrigc		 * Start the next trans in the chain.
2020153323Srodrigc		 */
2021153323Srodrigc		if ((error = xfs_attr_rolltrans(&args->trans, dp)))
2022153323Srodrigc			return (error);
2023153323Srodrigc	}
2024153323Srodrigc
2025153323Srodrigc	/*
2026153323Srodrigc	 * Roll through the "value", copying the attribute value to the
2027153323Srodrigc	 * already-allocated blocks.  Blocks are written synchronously
2028153323Srodrigc	 * so that we can know they are all on disk before we turn off
2029153323Srodrigc	 * the INCOMPLETE flag.
2030153323Srodrigc	 */
2031153323Srodrigc	lblkno = args->rmtblkno;
2032153323Srodrigc	valuelen = args->valuelen;
2033153323Srodrigc	while (valuelen > 0) {
2034153323Srodrigc		/*
2035153323Srodrigc		 * Try to remember where we decided to put the value.
2036153323Srodrigc		 */
2037153323Srodrigc		XFS_BMAP_INIT(args->flist, args->firstblock);
2038153323Srodrigc		nmap = 1;
2039153323Srodrigc		error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno,
2040153323Srodrigc				  args->rmtblkcnt,
2041153323Srodrigc				  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
2042159451Srodrigc				  args->firstblock, 0, &map, &nmap,
2043159451Srodrigc				  NULL, NULL);
2044153323Srodrigc		if (error) {
2045153323Srodrigc			return(error);
2046153323Srodrigc		}
2047153323Srodrigc		ASSERT(nmap == 1);
2048153323Srodrigc		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
2049153323Srodrigc		       (map.br_startblock != HOLESTARTBLOCK));
2050153323Srodrigc
2051153323Srodrigc		dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
2052153323Srodrigc		blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
2053153323Srodrigc
2054153323Srodrigc		bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno,
2055153323Srodrigc							blkcnt, XFS_BUF_LOCK);
2056153323Srodrigc		ASSERT(bp);
2057153323Srodrigc		ASSERT(!XFS_BUF_GETERROR(bp));
2058153323Srodrigc
2059153323Srodrigc		tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen :
2060153323Srodrigc							XFS_BUF_SIZE(bp);
2061153323Srodrigc		xfs_biomove(bp, 0, tmp, src, XFS_B_WRITE);
2062153323Srodrigc		if (tmp < XFS_BUF_SIZE(bp))
2063153323Srodrigc			xfs_biozero(bp, tmp, XFS_BUF_SIZE(bp) - tmp);
2064153323Srodrigc		if ((error = xfs_bwrite(mp, bp))) {/* GROT: NOTE: synchronous write */
2065153323Srodrigc			return (error);
2066153323Srodrigc		}
2067153323Srodrigc		src += tmp;
2068153323Srodrigc		valuelen -= tmp;
2069153323Srodrigc
2070153323Srodrigc		lblkno += map.br_blockcount;
2071153323Srodrigc	}
2072153323Srodrigc	ASSERT(valuelen == 0);
2073153323Srodrigc	return(0);
2074153323Srodrigc}
2075153323Srodrigc
2076153323Srodrigc/*
2077153323Srodrigc * Remove the value associated with an attribute by deleting the
2078153323Srodrigc * out-of-line buffer that it is stored on.
2079153323Srodrigc */
2080153323SrodrigcSTATIC int
2081153323Srodrigcxfs_attr_rmtval_remove(xfs_da_args_t *args)
2082153323Srodrigc{
2083153323Srodrigc	xfs_mount_t *mp;
2084153323Srodrigc	xfs_bmbt_irec_t map;
2085153323Srodrigc	xfs_buf_t *bp;
2086153323Srodrigc	xfs_daddr_t dblkno;
2087153323Srodrigc	xfs_dablk_t lblkno;
2088153323Srodrigc	int valuelen, blkcnt, nmap, error, done, committed;
2089153323Srodrigc
2090153323Srodrigc	mp = args->dp->i_mount;
2091153323Srodrigc
2092153323Srodrigc	/*
2093153323Srodrigc	 * Roll through the "value", invalidating the attribute value's
2094153323Srodrigc	 * blocks.
2095153323Srodrigc	 */
2096153323Srodrigc	lblkno = args->rmtblkno;
2097153323Srodrigc	valuelen = args->rmtblkcnt;
2098153323Srodrigc	while (valuelen > 0) {
2099153323Srodrigc		/*
2100153323Srodrigc		 * Try to remember where we decided to put the value.
2101153323Srodrigc		 */
2102153323Srodrigc		XFS_BMAP_INIT(args->flist, args->firstblock);
2103153323Srodrigc		nmap = 1;
2104153323Srodrigc		error = xfs_bmapi(NULL, args->dp, (xfs_fileoff_t)lblkno,
2105153323Srodrigc					args->rmtblkcnt,
2106153323Srodrigc					XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
2107153323Srodrigc					args->firstblock, 0, &map, &nmap,
2108159451Srodrigc					args->flist, NULL);
2109153323Srodrigc		if (error) {
2110153323Srodrigc			return(error);
2111153323Srodrigc		}
2112153323Srodrigc		ASSERT(nmap == 1);
2113153323Srodrigc		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
2114153323Srodrigc		       (map.br_startblock != HOLESTARTBLOCK));
2115153323Srodrigc
2116153323Srodrigc		dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
2117153323Srodrigc		blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
2118153323Srodrigc
2119153323Srodrigc		/*
2120153323Srodrigc		 * If the "remote" value is in the cache, remove it.
2121153323Srodrigc		 */
2122159451Srodrigc		bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt,
2123159451Srodrigc				XFS_INCORE_TRYLOCK);
2124153323Srodrigc		if (bp) {
2125153323Srodrigc			XFS_BUF_STALE(bp);
2126153323Srodrigc			XFS_BUF_UNDELAYWRITE(bp);
2127153323Srodrigc			xfs_buf_relse(bp);
2128153323Srodrigc			bp = NULL;
2129153323Srodrigc		}
2130153323Srodrigc
2131153323Srodrigc		valuelen -= map.br_blockcount;
2132153323Srodrigc
2133153323Srodrigc		lblkno += map.br_blockcount;
2134153323Srodrigc	}
2135153323Srodrigc
2136153323Srodrigc	/*
2137153323Srodrigc	 * Keep de-allocating extents until the remote-value region is gone.
2138153323Srodrigc	 */
2139153323Srodrigc	lblkno = args->rmtblkno;
2140153323Srodrigc	blkcnt = args->rmtblkcnt;
2141153323Srodrigc	done = 0;
2142153323Srodrigc	while (!done) {
2143153323Srodrigc		XFS_BMAP_INIT(args->flist, args->firstblock);
2144153323Srodrigc		error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
2145153323Srodrigc				    XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
2146159451Srodrigc				    1, args->firstblock, args->flist,
2147159451Srodrigc				    NULL, &done);
2148153323Srodrigc		if (!error) {
2149153323Srodrigc			error = xfs_bmap_finish(&args->trans, args->flist,
2150153323Srodrigc						*args->firstblock, &committed);
2151153323Srodrigc		}
2152153323Srodrigc		if (error) {
2153153323Srodrigc			ASSERT(committed);
2154153323Srodrigc			args->trans = NULL;
2155153323Srodrigc			xfs_bmap_cancel(args->flist);
2156153323Srodrigc			return(error);
2157153323Srodrigc		}
2158153323Srodrigc
2159153323Srodrigc		/*
2160153323Srodrigc		 * bmap_finish() may have committed the last trans and started
2161153323Srodrigc		 * a new one.  We need the inode to be in all transactions.
2162153323Srodrigc		 */
2163153323Srodrigc		if (committed) {
2164153323Srodrigc			xfs_trans_ijoin(args->trans, args->dp, XFS_ILOCK_EXCL);
2165153323Srodrigc			xfs_trans_ihold(args->trans, args->dp);
2166153323Srodrigc		}
2167153323Srodrigc
2168153323Srodrigc		/*
2169153323Srodrigc		 * Close out trans and start the next one in the chain.
2170153323Srodrigc		 */
2171153323Srodrigc		if ((error = xfs_attr_rolltrans(&args->trans, args->dp)))
2172153323Srodrigc			return (error);
2173153323Srodrigc	}
2174153323Srodrigc	return(0);
2175153323Srodrigc}
2176153323Srodrigc
2177153323Srodrigc#if defined(XFS_ATTR_TRACE)
2178153323Srodrigc/*
2179153323Srodrigc * Add a trace buffer entry for an attr_list context structure.
2180153323Srodrigc */
2181153323Srodrigcvoid
2182153323Srodrigcxfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context)
2183153323Srodrigc{
2184153323Srodrigc	xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where,
2185153323Srodrigc		(__psunsigned_t)context->dp,
2186153323Srodrigc		(__psunsigned_t)context->cursor->hashval,
2187153323Srodrigc		(__psunsigned_t)context->cursor->blkno,
2188153323Srodrigc		(__psunsigned_t)context->cursor->offset,
2189153323Srodrigc		(__psunsigned_t)context->alist,
2190153323Srodrigc		(__psunsigned_t)context->bufsize,
2191153323Srodrigc		(__psunsigned_t)context->count,
2192153323Srodrigc		(__psunsigned_t)context->firstu,
2193153323Srodrigc		(__psunsigned_t)
2194153323Srodrigc			((context->count > 0) &&
2195153323Srodrigc			!(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
2196153323Srodrigc				? (ATTR_ENTRY(context->alist,
2197153323Srodrigc					      context->count-1)->a_valuelen)
2198153323Srodrigc				: 0,
2199153323Srodrigc		(__psunsigned_t)context->dupcnt,
2200153323Srodrigc		(__psunsigned_t)context->flags,
2201153323Srodrigc		(__psunsigned_t)NULL,
2202153323Srodrigc		(__psunsigned_t)NULL,
2203153323Srodrigc		(__psunsigned_t)NULL);
2204153323Srodrigc}
2205153323Srodrigc
2206153323Srodrigc/*
2207153323Srodrigc * Add a trace buffer entry for a context structure and a Btree node.
2208153323Srodrigc */
2209153323Srodrigcvoid
2210153323Srodrigcxfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context,
2211153323Srodrigc			 struct xfs_da_intnode *node)
2212153323Srodrigc{
2213153323Srodrigc	xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where,
2214153323Srodrigc		(__psunsigned_t)context->dp,
2215153323Srodrigc		(__psunsigned_t)context->cursor->hashval,
2216153323Srodrigc		(__psunsigned_t)context->cursor->blkno,
2217153323Srodrigc		(__psunsigned_t)context->cursor->offset,
2218153323Srodrigc		(__psunsigned_t)context->alist,
2219153323Srodrigc		(__psunsigned_t)context->bufsize,
2220153323Srodrigc		(__psunsigned_t)context->count,
2221153323Srodrigc		(__psunsigned_t)context->firstu,
2222153323Srodrigc		(__psunsigned_t)
2223153323Srodrigc			((context->count > 0) &&
2224153323Srodrigc			!(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
2225153323Srodrigc				? (ATTR_ENTRY(context->alist,
2226153323Srodrigc					      context->count-1)->a_valuelen)
2227153323Srodrigc				: 0,
2228153323Srodrigc		(__psunsigned_t)context->dupcnt,
2229153323Srodrigc		(__psunsigned_t)context->flags,
2230159451Srodrigc		(__psunsigned_t)be16_to_cpu(node->hdr.count),
2231159451Srodrigc		(__psunsigned_t)be32_to_cpu(node->btree[0].hashval),
2232159451Srodrigc		(__psunsigned_t)be32_to_cpu(node->btree[
2233159451Srodrigc				    be16_to_cpu(node->hdr.count)-1].hashval));
2234153323Srodrigc}
2235153323Srodrigc
2236153323Srodrigc/*
2237153323Srodrigc * Add a trace buffer entry for a context structure and a Btree element.
2238153323Srodrigc */
2239153323Srodrigcvoid
2240153323Srodrigcxfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context,
2241153323Srodrigc			  struct xfs_da_node_entry *btree)
2242153323Srodrigc{
2243153323Srodrigc	xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where,
2244153323Srodrigc		(__psunsigned_t)context->dp,
2245153323Srodrigc		(__psunsigned_t)context->cursor->hashval,
2246153323Srodrigc		(__psunsigned_t)context->cursor->blkno,
2247153323Srodrigc		(__psunsigned_t)context->cursor->offset,
2248153323Srodrigc		(__psunsigned_t)context->alist,
2249153323Srodrigc		(__psunsigned_t)context->bufsize,
2250153323Srodrigc		(__psunsigned_t)context->count,
2251153323Srodrigc		(__psunsigned_t)context->firstu,
2252153323Srodrigc		(__psunsigned_t)
2253153323Srodrigc			((context->count > 0) &&
2254153323Srodrigc			!(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
2255153323Srodrigc				? (ATTR_ENTRY(context->alist,
2256153323Srodrigc					      context->count-1)->a_valuelen)
2257153323Srodrigc				: 0,
2258153323Srodrigc		(__psunsigned_t)context->dupcnt,
2259153323Srodrigc		(__psunsigned_t)context->flags,
2260159451Srodrigc		(__psunsigned_t)be32_to_cpu(btree->hashval),
2261159451Srodrigc		(__psunsigned_t)be32_to_cpu(btree->before),
2262153323Srodrigc		(__psunsigned_t)NULL);
2263153323Srodrigc}
2264153323Srodrigc
2265153323Srodrigc/*
2266153323Srodrigc * Add a trace buffer entry for a context structure and a leaf block.
2267153323Srodrigc */
2268153323Srodrigcvoid
2269153323Srodrigcxfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context,
2270153323Srodrigc			      struct xfs_attr_leafblock *leaf)
2271153323Srodrigc{
2272153323Srodrigc	xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where,
2273153323Srodrigc		(__psunsigned_t)context->dp,
2274153323Srodrigc		(__psunsigned_t)context->cursor->hashval,
2275153323Srodrigc		(__psunsigned_t)context->cursor->blkno,
2276153323Srodrigc		(__psunsigned_t)context->cursor->offset,
2277153323Srodrigc		(__psunsigned_t)context->alist,
2278153323Srodrigc		(__psunsigned_t)context->bufsize,
2279153323Srodrigc		(__psunsigned_t)context->count,
2280153323Srodrigc		(__psunsigned_t)context->firstu,
2281153323Srodrigc		(__psunsigned_t)
2282153323Srodrigc			((context->count > 0) &&
2283153323Srodrigc			!(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
2284153323Srodrigc				? (ATTR_ENTRY(context->alist,
2285153323Srodrigc					      context->count-1)->a_valuelen)
2286153323Srodrigc				: 0,
2287153323Srodrigc		(__psunsigned_t)context->dupcnt,
2288153323Srodrigc		(__psunsigned_t)context->flags,
2289159451Srodrigc		(__psunsigned_t)be16_to_cpu(leaf->hdr.count),
2290159451Srodrigc		(__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval),
2291159451Srodrigc		(__psunsigned_t)be32_to_cpu(leaf->entries[
2292159451Srodrigc				be16_to_cpu(leaf->hdr.count)-1].hashval));
2293153323Srodrigc}
2294153323Srodrigc
2295153323Srodrigc/*
2296153323Srodrigc * Add a trace buffer entry for the arguments given to the routine,
2297153323Srodrigc * generic form.
2298153323Srodrigc */
2299153323Srodrigcvoid
2300153323Srodrigcxfs_attr_trace_enter(int type, char *where,
2301153323Srodrigc			 __psunsigned_t a2, __psunsigned_t a3,
2302153323Srodrigc			 __psunsigned_t a4, __psunsigned_t a5,
2303153323Srodrigc			 __psunsigned_t a6, __psunsigned_t a7,
2304153323Srodrigc			 __psunsigned_t a8, __psunsigned_t a9,
2305153323Srodrigc			 __psunsigned_t a10, __psunsigned_t a11,
2306153323Srodrigc			 __psunsigned_t a12, __psunsigned_t a13,
2307153323Srodrigc			 __psunsigned_t a14, __psunsigned_t a15)
2308153323Srodrigc{
2309153323Srodrigc	ASSERT(xfs_attr_trace_buf);
2310153323Srodrigc	ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type),
2311153323Srodrigc					 (void *)where,
2312153323Srodrigc					 (void *)a2,  (void *)a3,  (void *)a4,
2313153323Srodrigc					 (void *)a5,  (void *)a6,  (void *)a7,
2314153323Srodrigc					 (void *)a8,  (void *)a9,  (void *)a10,
2315153323Srodrigc					 (void *)a11, (void *)a12, (void *)a13,
2316153323Srodrigc					 (void *)a14, (void *)a15);
2317153323Srodrigc}
2318153323Srodrigc#endif	/* XFS_ATTR_TRACE */
2319153323Srodrigc
2320153323Srodrigc
2321153323Srodrigc/*========================================================================
2322153323Srodrigc * System (pseudo) namespace attribute interface routines.
2323153323Srodrigc *========================================================================*/
2324153323Srodrigc
2325153323SrodrigcSTATIC int
2326153323Srodrigcposix_acl_access_set(
2327153323Srodrigc	xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags)
2328153323Srodrigc{
2329153323Srodrigc	return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS);
2330153323Srodrigc}
2331153323Srodrigc
2332153323SrodrigcSTATIC int
2333153323Srodrigcposix_acl_access_remove(
2334153323Srodrigc	struct xfs_vnode *vp, char *name, int xflags)
2335153323Srodrigc{
2336153323Srodrigc	return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
2337153323Srodrigc}
2338153323Srodrigc
2339153323SrodrigcSTATIC int
2340153323Srodrigcposix_acl_access_get(
2341153323Srodrigc	xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags)
2342153323Srodrigc{
2343153323Srodrigc	return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
2344153323Srodrigc}
2345153323Srodrigc
2346153323SrodrigcSTATIC int
2347153323Srodrigcposix_acl_access_exists(
2348153323Srodrigc	xfs_vnode_t *vp)
2349153323Srodrigc{
2350153323Srodrigc	return xfs_acl_vhasacl_access(vp);
2351153323Srodrigc}
2352153323Srodrigc
2353153323SrodrigcSTATIC int
2354153323Srodrigcposix_acl_default_set(
2355153323Srodrigc	xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags)
2356153323Srodrigc{
2357153323Srodrigc	return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT);
2358153323Srodrigc}
2359153323Srodrigc
2360153323SrodrigcSTATIC int
2361153323Srodrigcposix_acl_default_get(
2362153323Srodrigc	xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags)
2363153323Srodrigc{
2364153323Srodrigc	return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
2365153323Srodrigc}
2366153323Srodrigc
2367153323SrodrigcSTATIC int
2368153323Srodrigcposix_acl_default_remove(
2369153323Srodrigc	struct xfs_vnode *vp, char *name, int xflags)
2370153323Srodrigc{
2371153323Srodrigc	return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT);
2372153323Srodrigc}
2373153323Srodrigc
2374153323SrodrigcSTATIC int
2375153323Srodrigcposix_acl_default_exists(
2376153323Srodrigc	xfs_vnode_t *vp)
2377153323Srodrigc{
2378153323Srodrigc	return xfs_acl_vhasacl_default(vp);
2379153323Srodrigc}
2380153323Srodrigc
2381159451SrodrigcSTATIC struct attrnames posix_acl_access = {
2382153323Srodrigc	.attr_name	= "posix_acl_access",
2383153323Srodrigc	.attr_namelen	= sizeof("posix_acl_access") - 1,
2384153323Srodrigc	.attr_get	= posix_acl_access_get,
2385153323Srodrigc	.attr_set	= posix_acl_access_set,
2386153323Srodrigc	.attr_remove	= posix_acl_access_remove,
2387153323Srodrigc	.attr_exists	= posix_acl_access_exists,
2388153323Srodrigc};
2389153323Srodrigc
2390159451SrodrigcSTATIC struct attrnames posix_acl_default = {
2391153323Srodrigc	.attr_name	= "posix_acl_default",
2392153323Srodrigc	.attr_namelen	= sizeof("posix_acl_default") - 1,
2393153323Srodrigc	.attr_get	= posix_acl_default_get,
2394153323Srodrigc	.attr_set	= posix_acl_default_set,
2395153323Srodrigc	.attr_remove	= posix_acl_default_remove,
2396153323Srodrigc	.attr_exists	= posix_acl_default_exists,
2397153323Srodrigc};
2398153323Srodrigc
2399159451SrodrigcSTATIC struct attrnames *attr_system_names[] =
2400153323Srodrigc	{ &posix_acl_access, &posix_acl_default };
2401153323Srodrigc
2402153323Srodrigc
2403153323Srodrigc/*========================================================================
2404153323Srodrigc * Namespace-prefix-style attribute name interface routines.
2405153323Srodrigc *========================================================================*/
2406153323Srodrigc
2407153323SrodrigcSTATIC int
2408153323Srodrigcattr_generic_set(
2409153323Srodrigc	struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags)
2410153323Srodrigc{
2411153323Srodrigc	int 	error;
2412153323Srodrigc
2413153323Srodrigc	XVOP_ATTR_SET(vp, name, data, size, xflags, NULL, error);
2414153323Srodrigc	return -error;
2415153323Srodrigc}
2416153323Srodrigc
2417153323SrodrigcSTATIC int
2418153323Srodrigcattr_generic_get(
2419153323Srodrigc	struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags)
2420153323Srodrigc{
2421153323Srodrigc	int	error, asize = size;
2422153323Srodrigc
2423153323Srodrigc	XVOP_ATTR_GET(vp, name, data, &asize, xflags, NULL, error);
2424153323Srodrigc	if (!error)
2425153323Srodrigc		return asize;
2426153323Srodrigc	return -error;
2427153323Srodrigc}
2428153323Srodrigc
2429153323SrodrigcSTATIC int
2430153323Srodrigcattr_generic_remove(
2431153323Srodrigc	struct xfs_vnode *vp, char *name, int xflags)
2432153323Srodrigc{
2433153323Srodrigc	int	error;
2434153323Srodrigc
2435153323Srodrigc	XVOP_ATTR_REMOVE(vp, name, xflags, NULL, error);
2436153323Srodrigc	return -error;
2437153323Srodrigc}
2438153323Srodrigc
2439153323SrodrigcSTATIC int
2440153323Srodrigcattr_generic_listadd(
2441153323Srodrigc	attrnames_t		*prefix,
2442153323Srodrigc	attrnames_t		*namesp,
2443153323Srodrigc	void			*data,
2444153323Srodrigc	size_t			size,
2445153323Srodrigc	ssize_t			*result)
2446153323Srodrigc{
2447153323Srodrigc	char			*p = (char *)data + *result;
2448153323Srodrigc
2449153323Srodrigc	*result += prefix->attr_namelen;
2450153323Srodrigc	*result += namesp->attr_namelen + 1;
2451153323Srodrigc	if (!size)
2452153323Srodrigc		return 0;
2453153323Srodrigc	if (*result > size)
2454153323Srodrigc		return -ERANGE;
2455153323Srodrigc	strcpy(p, prefix->attr_name);
2456153323Srodrigc	p += prefix->attr_namelen;
2457153323Srodrigc	strcpy(p, namesp->attr_name);
2458153323Srodrigc	p += namesp->attr_namelen + 1;
2459153323Srodrigc	return 0;
2460153323Srodrigc}
2461153323Srodrigc
2462153323SrodrigcSTATIC int
2463153323Srodrigcattr_system_list(
2464153323Srodrigc	struct xfs_vnode		*vp,
2465153323Srodrigc	void			*data,
2466153323Srodrigc	size_t			size,
2467153323Srodrigc	ssize_t			*result)
2468153323Srodrigc{
2469153323Srodrigc	attrnames_t		*namesp;
2470153323Srodrigc	int			i, error = 0;
2471153323Srodrigc
2472153323Srodrigc	for (i = 0; i < ATTR_SYSCOUNT; i++) {
2473153323Srodrigc		namesp = attr_system_names[i];
2474153323Srodrigc		if (!namesp->attr_exists || !namesp->attr_exists(vp))
2475153323Srodrigc			continue;
2476153323Srodrigc		error = attr_generic_listadd(&attr_system, namesp,
2477153323Srodrigc						data, size, result);
2478153323Srodrigc		if (error)
2479153323Srodrigc			break;
2480153323Srodrigc	}
2481153323Srodrigc	return error;
2482153323Srodrigc}
2483153323Srodrigc
2484153323Srodrigcint
2485153323Srodrigcattr_generic_list(
2486153323Srodrigc	struct xfs_vnode *vp, void *data, size_t size, int xflags, ssize_t *result)
2487153323Srodrigc{
2488153323Srodrigc	attrlist_cursor_kern_t	cursor = { 0 };
2489153323Srodrigc	int			error;
2490153323Srodrigc
2491153323Srodrigc	XVOP_ATTR_LIST(vp, data, size, xflags, &cursor, NULL, error);
2492153323Srodrigc	if (error > 0)
2493153323Srodrigc		return -error;
2494153323Srodrigc	*result = -error;
2495153323Srodrigc	return attr_system_list(vp, data, size, result);
2496153323Srodrigc}
2497153323Srodrigc
2498153323Srodrigcattrnames_t *
2499153323Srodrigcattr_lookup_namespace(
2500153323Srodrigc	char			*name,
2501153323Srodrigc	struct attrnames	**names,
2502153323Srodrigc	int			nnames)
2503153323Srodrigc{
2504153323Srodrigc	int			i;
2505153323Srodrigc
2506153323Srodrigc	for (i = 0; i < nnames; i++)
2507153323Srodrigc		if (!strncmp(name, names[i]->attr_name, names[i]->attr_namelen))
2508153323Srodrigc			return names[i];
2509153323Srodrigc	return NULL;
2510153323Srodrigc}
2511153323Srodrigc
2512153323Srodrigc/*
2513153323Srodrigc * Some checks to prevent people abusing EAs to get over quota:
2514153323Srodrigc * - Don't allow modifying user EAs on devices/symlinks;
2515153323Srodrigc * - Don't allow modifying user EAs if sticky bit set;
2516153323Srodrigc */
2517153323SrodrigcSTATIC int
2518153323Srodrigcattr_user_capable(
2519153323Srodrigc	struct xfs_vnode	*vp,
2520153323Srodrigc	cred_t		*cred)
2521153323Srodrigc{
2522159147Simp#ifdef XXXKAN
2523159451Srodrigc	struct inode	*inode = vn_to_inode(vp);
2524153323Srodrigc
2525153323Srodrigc	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
2526153323Srodrigc		return -EPERM;
2527153323Srodrigc	if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) &&
2528153323Srodrigc	    !capable(CAP_SYS_ADMIN))
2529153323Srodrigc		return -EPERM;
2530153323Srodrigc	if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
2531153323Srodrigc	    (current_fsuid(cred) != inode->i_uid) && !capable(CAP_FOWNER))
2532153323Srodrigc		return -EPERM;
2533153323Srodrigc#endif
2534153323Srodrigc	return 0;
2535153323Srodrigc}
2536153323Srodrigc
2537153323SrodrigcSTATIC int
2538153323Srodrigcattr_trusted_capable(
2539153323Srodrigc	struct xfs_vnode	*vp,
2540153323Srodrigc	cred_t		*cred)
2541153323Srodrigc{
2542159147Simp#ifdef XXXKAN
2543159451Srodrigc	struct inode	*inode = vn_to_inode(vp);
2544153323Srodrigc
2545153323Srodrigc	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
2546153323Srodrigc		return -EPERM;
2547153323Srodrigc	if (!capable(CAP_SYS_ADMIN))
2548153323Srodrigc		return -EPERM;
2549153323Srodrigc#endif
2550153323Srodrigc	return 0;
2551153323Srodrigc}
2552153323Srodrigc
2553153323SrodrigcSTATIC int
2554153323Srodrigcattr_secure_capable(
2555153323Srodrigc	struct xfs_vnode *vp,
2556153323Srodrigc	cred_t		 *cred)
2557153323Srodrigc{
2558153323Srodrigc	return -ENOSECURITY;
2559153323Srodrigc}
2560153323Srodrigc
2561153323SrodrigcSTATIC int
2562153323Srodrigcattr_system_set(
2563153323Srodrigc	struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags)
2564153323Srodrigc{
2565153323Srodrigc	attrnames_t	*namesp;
2566153323Srodrigc	int		error;
2567153323Srodrigc
2568153323Srodrigc	if (xflags & ATTR_CREATE)
2569153323Srodrigc		return -EINVAL;
2570153323Srodrigc
2571153323Srodrigc	namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
2572153323Srodrigc	if (!namesp)
2573153323Srodrigc		return -EOPNOTSUPP;
2574153323Srodrigc	error = namesp->attr_set(vp, name, data, size, xflags);
2575159147Simp#ifdef XXXKAN
2576153323Srodrigc	if (!error)
2577153323Srodrigc		error = vn_revalidate(vp);
2578153323Srodrigc#endif
2579153323Srodrigc	return error;
2580153323Srodrigc}
2581153323Srodrigc
2582153323SrodrigcSTATIC int
2583153323Srodrigcattr_system_get(
2584153323Srodrigc	struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags)
2585153323Srodrigc{
2586153323Srodrigc	attrnames_t	*namesp;
2587153323Srodrigc
2588153323Srodrigc	namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
2589153323Srodrigc	if (!namesp)
2590153323Srodrigc		return -EOPNOTSUPP;
2591153323Srodrigc	return namesp->attr_get(vp, name, data, size, xflags);
2592153323Srodrigc}
2593153323Srodrigc
2594153323SrodrigcSTATIC int
2595153323Srodrigcattr_system_remove(
2596153323Srodrigc	struct xfs_vnode *vp, char *name, int xflags)
2597153323Srodrigc{
2598153323Srodrigc	attrnames_t	*namesp;
2599153323Srodrigc
2600153323Srodrigc	namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
2601153323Srodrigc	if (!namesp)
2602153323Srodrigc		return -EOPNOTSUPP;
2603153323Srodrigc	return namesp->attr_remove(vp, name, xflags);
2604153323Srodrigc}
2605153323Srodrigc
2606153323Srodrigcstruct attrnames attr_system = {
2607153323Srodrigc	.attr_name	= "system.",
2608153323Srodrigc	.attr_namelen	= sizeof("system.") - 1,
2609153323Srodrigc	.attr_flag	= ATTR_SYSTEM,
2610153323Srodrigc	.attr_get	= attr_system_get,
2611153323Srodrigc	.attr_set	= attr_system_set,
2612153323Srodrigc	.attr_remove	= attr_system_remove,
2613153323Srodrigc	.attr_capable	= (attrcapable_t)fs_noerr,
2614153323Srodrigc};
2615153323Srodrigc
2616153323Srodrigcstruct attrnames attr_trusted = {
2617153323Srodrigc	.attr_name	= "trusted.",
2618153323Srodrigc	.attr_namelen	= sizeof("trusted.") - 1,
2619153323Srodrigc	.attr_flag	= ATTR_ROOT,
2620153323Srodrigc	.attr_get	= attr_generic_get,
2621153323Srodrigc	.attr_set	= attr_generic_set,
2622153323Srodrigc	.attr_remove	= attr_generic_remove,
2623153323Srodrigc	.attr_capable	= attr_trusted_capable,
2624153323Srodrigc};
2625153323Srodrigc
2626153323Srodrigcstruct attrnames attr_secure = {
2627153323Srodrigc	.attr_name	= "security.",
2628153323Srodrigc	.attr_namelen	= sizeof("security.") - 1,
2629153323Srodrigc	.attr_flag	= ATTR_SECURE,
2630153323Srodrigc	.attr_get	= attr_generic_get,
2631153323Srodrigc	.attr_set	= attr_generic_set,
2632153323Srodrigc	.attr_remove	= attr_generic_remove,
2633153323Srodrigc	.attr_capable	= attr_secure_capable,
2634153323Srodrigc};
2635153323Srodrigc
2636153323Srodrigcstruct attrnames attr_user = {
2637153323Srodrigc	.attr_name	= "user.",
2638153323Srodrigc	.attr_namelen	= sizeof("user.") - 1,
2639153323Srodrigc	.attr_get	= attr_generic_get,
2640153323Srodrigc	.attr_set	= attr_generic_set,
2641153323Srodrigc	.attr_remove	= attr_generic_remove,
2642153323Srodrigc	.attr_capable	= attr_user_capable,
2643153323Srodrigc};
2644153323Srodrigc
2645153323Srodrigcstruct attrnames *attr_namespaces[] =
2646153323Srodrigc	{ &attr_system, &attr_trusted, &attr_secure, &attr_user };
2647