xfs_attr.c revision 153323
1/*
2 * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like.  Any license provided herein, whether implied or
15 * otherwise, applies only to this software file.  Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA  94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33#include "xfs.h"
34
35#include "xfs_macros.h"
36#include "xfs_types.h"
37#include "xfs_inum.h"
38#include "xfs_log.h"
39#include "xfs_trans.h"
40#include "xfs_sb.h"
41#include "xfs_ag.h"
42#include "xfs_dir.h"
43#include "xfs_dir2.h"
44#include "xfs_dmapi.h"
45#include "xfs_mount.h"
46#include "xfs_alloc_btree.h"
47#include "xfs_bmap_btree.h"
48#include "xfs_ialloc_btree.h"
49#include "xfs_alloc.h"
50#include "xfs_btree.h"
51#include "xfs_attr_sf.h"
52#include "xfs_dir_sf.h"
53#include "xfs_dir2_sf.h"
54#include "xfs_dinode.h"
55#include "xfs_inode_item.h"
56#include "xfs_inode.h"
57#include "xfs_bmap.h"
58#include "xfs_da_btree.h"
59#include "xfs_attr.h"
60#include "xfs_attr_leaf.h"
61#include "xfs_error.h"
62#include "xfs_bit.h"
63#include "xfs_quota.h"
64#include "xfs_rw.h"
65#include "xfs_trans_space.h"
66#include "xfs_acl.h"
67
68/*
69 * xfs_attr.c
70 *
71 * Provide the external interfaces to manage attribute lists.
72 */
73
74/*========================================================================
75 * Function prototypes for the kernel.
76 *========================================================================*/
77
78/*
79 * Internal routines when attribute list fits inside the inode.
80 */
81STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
82
83/*
84 * Internal routines when attribute list is one block.
85 */
86STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
87STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
88STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context);
89
90/*
91 * Internal routines when attribute list is more than one block.
92 */
93STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
94STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
95STATIC int xfs_attr_node_list(xfs_attr_list_context_t *context);
96STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
97STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
98
99/*
100 * Routines to manipulate out-of-line attribute values.
101 */
102STATIC int xfs_attr_rmtval_get(xfs_da_args_t *args);
103STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args);
104STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args);
105
106#define ATTR_RMTVALUE_MAPSIZE	1	/* # of map entries at once */
107#define ATTR_RMTVALUE_TRANSBLKS	8	/* max # of blks in a transaction */
108
109#if defined(XFS_ATTR_TRACE)
110ktrace_t *xfs_attr_trace_buf;
111#endif
112
113
114/*========================================================================
115 * Overall external interface routines.
116 *========================================================================*/
117
118/*ARGSUSED*/
119STATIC int
120xfs_attr_get_int(xfs_inode_t *ip, const char *name, char *value, int *valuelenp,
121	     int flags, int lock, struct cred *cred)
122{
123	xfs_da_args_t   args;
124	int             error;
125	int             namelen;
126
127	ASSERT(MAXNAMELEN-1 <= 0xff);	/* length is stored in uint8 */
128	namelen = strlen(name);
129	if (namelen >= MAXNAMELEN)
130		return(EFAULT);		/* match IRIX behaviour */
131	XFS_STATS_INC(xs_attr_get);
132
133	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
134		return(EIO);
135
136	if ((XFS_IFORK_Q(ip) == 0) ||
137	    (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
138	     ip->i_d.di_anextents == 0))
139		return(ENOATTR);
140
141	if (lock) {
142		xfs_ilock(ip, XFS_ILOCK_SHARED);
143		/*
144		 * Do we answer them, or ignore them?
145		 */
146		if ((error = xfs_iaccess(ip, S_IRUSR, cred))) {
147			xfs_iunlock(ip, XFS_ILOCK_SHARED);
148			return(XFS_ERROR(error));
149		}
150	}
151
152	/*
153	 * Fill in the arg structure for this request.
154	 */
155	memset((char *)&args, 0, sizeof(args));
156	args.name = name;
157	args.namelen = namelen;
158	args.value = value;
159	args.valuelen = *valuelenp;
160	args.flags = flags;
161	args.hashval = xfs_da_hashname(args.name, args.namelen);
162	args.dp = ip;
163	args.whichfork = XFS_ATTR_FORK;
164	args.trans = NULL;
165
166	/*
167	 * Decide on what work routines to call based on the inode size.
168	 */
169	if (XFS_IFORK_Q(ip) == 0 ||
170	    (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
171	     ip->i_d.di_anextents == 0)) {
172		error = XFS_ERROR(ENOATTR);
173	} else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
174		error = xfs_attr_shortform_getvalue(&args);
175	} else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) {
176		error = xfs_attr_leaf_get(&args);
177	} else {
178		error = xfs_attr_node_get(&args);
179	}
180
181	if (lock)
182		xfs_iunlock(ip, XFS_ILOCK_SHARED);
183
184	/*
185	 * Return the number of bytes in the value to the caller.
186	 */
187	*valuelenp = args.valuelen;
188
189	if (error == EEXIST)
190		error = 0;
191	return(error);
192}
193
194int
195xfs_attr_fetch(xfs_inode_t *ip, const char *name, char *value, int valuelen)
196{
197	return xfs_attr_get_int(ip, name, value, &valuelen, ATTR_ROOT, 0, NULL);
198}
199
200int
201xfs_attr_get(bhv_desc_t *bdp, const char *name, char *value, int *valuelenp,
202	     int flags, struct cred *cred)
203{
204	xfs_inode_t	*ip = XFS_BHVTOI(bdp);
205
206	if (!name)
207		return(EINVAL);
208	return xfs_attr_get_int(ip, name, value, valuelenp, flags, 1, cred);
209}
210
211/*ARGSUSED*/
212int								/* error */
213xfs_attr_set(bhv_desc_t *bdp, const char *name, char *value, int valuelen, int flags,
214		     struct cred *cred)
215{
216	xfs_da_args_t	args;
217	xfs_inode_t	*dp;
218	xfs_fsblock_t	firstblock;
219	xfs_bmap_free_t flist;
220	int		error, err2, committed;
221	int		local, size;
222	uint		nblks;
223	xfs_mount_t	*mp;
224	int             rsvd = (flags & ATTR_ROOT) != 0;
225	int             namelen;
226
227	ASSERT(MAXNAMELEN-1 <= 0xff); /* length is stored in uint8 */
228	namelen = strlen(name);
229	if (namelen >= MAXNAMELEN)
230		return EFAULT; /* match irix behaviour */
231
232	XFS_STATS_INC(xs_attr_set);
233	/*
234	 * Do we answer them, or ignore them?
235	 */
236	dp = XFS_BHVTOI(bdp);
237	mp = dp->i_mount;
238	if (XFS_FORCED_SHUTDOWN(mp))
239		return (EIO);
240
241	xfs_ilock(dp, XFS_ILOCK_SHARED);
242	if ((error = xfs_iaccess(dp, S_IWUSR, cred))) {
243		xfs_iunlock(dp, XFS_ILOCK_SHARED);
244		return(XFS_ERROR(error));
245	}
246	xfs_iunlock(dp, XFS_ILOCK_SHARED);
247
248	/*
249	 * Attach the dquots to the inode.
250	 */
251	if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
252		return (error);
253
254	/*
255	 * If the inode doesn't have an attribute fork, add one.
256	 * (inode must not be locked when we call this routine)
257	 */
258	if (XFS_IFORK_Q(dp) == 0) {
259		error = xfs_bmap_add_attrfork(dp, rsvd);
260		if (error)
261			return(error);
262	}
263
264	/*
265	 * Fill in the arg structure for this request.
266	 */
267	memset((char *)&args, 0, sizeof(args));
268	args.name = name;
269	args.namelen = namelen;
270	args.value = value;
271	args.valuelen = valuelen;
272	args.flags = flags;
273	args.hashval = xfs_da_hashname(args.name, args.namelen);
274	args.dp = dp;
275	args.firstblock = &firstblock;
276	args.flist = &flist;
277	args.whichfork = XFS_ATTR_FORK;
278	args.oknoent = 1;
279
280	/* Determine space new attribute will use, and if it will be inline
281	 * or out of line.
282	 */
283	size = xfs_attr_leaf_newentsize(&args, mp->m_sb.sb_blocksize, &local);
284
285	nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
286	if (local) {
287		if (size > (mp->m_sb.sb_blocksize >> 1)) {
288			/* Double split possible */
289			nblks <<= 1;
290		}
291	} else {
292		uint	dblocks = XFS_B_TO_FSB(mp, valuelen);
293		/* Out of line attribute, cannot double split, but make
294		 * room for the attribute value itself.
295		 */
296		nblks += dblocks;
297		nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
298	}
299
300	/* Size is now blocks for attribute data */
301	args.total = nblks;
302
303	/*
304	 * Start our first transaction of the day.
305	 *
306	 * All future transactions during this code must be "chained" off
307	 * this one via the trans_dup() call.  All transactions will contain
308	 * the inode, and the inode will always be marked with trans_ihold().
309	 * Since the inode will be locked in all transactions, we must log
310	 * the inode in every transaction to let it float upward through
311	 * the log.
312	 */
313	args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET);
314
315	/*
316	 * Root fork attributes can use reserved data blocks for this
317	 * operation if necessary
318	 */
319
320	if (rsvd)
321		args.trans->t_flags |= XFS_TRANS_RESERVE;
322
323	if ((error = xfs_trans_reserve(args.trans, (uint) nblks,
324				      XFS_ATTRSET_LOG_RES(mp, nblks),
325				      0, XFS_TRANS_PERM_LOG_RES,
326				      XFS_ATTRSET_LOG_COUNT))) {
327		xfs_trans_cancel(args.trans, 0);
328		return(error);
329	}
330	xfs_ilock(dp, XFS_ILOCK_EXCL);
331
332	error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, nblks, 0,
333			 rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
334				XFS_QMOPT_RES_REGBLKS);
335	if (error) {
336		xfs_iunlock(dp, XFS_ILOCK_EXCL);
337		xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
338		return (error);
339	}
340
341	xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
342	xfs_trans_ihold(args.trans, dp);
343
344	/*
345	 * If the attribute list is non-existant or a shortform list,
346	 * upgrade it to a single-leaf-block attribute list.
347	 */
348	if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
349	    ((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) &&
350	     (dp->i_d.di_anextents == 0))) {
351
352		/*
353		 * Build initial attribute list (if required).
354		 */
355		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
356			(void)xfs_attr_shortform_create(&args);
357
358		/*
359		 * Try to add the attr to the attribute list in
360		 * the inode.
361		 */
362		error = xfs_attr_shortform_addname(&args);
363		if (error != ENOSPC) {
364			/*
365			 * Commit the shortform mods, and we're done.
366			 * NOTE: this is also the error path (EEXIST, etc).
367			 */
368			ASSERT(args.trans != NULL);
369
370			/*
371			 * If this is a synchronous mount, make sure that
372			 * the transaction goes to disk before returning
373			 * to the user.
374			 */
375			if (mp->m_flags & XFS_MOUNT_WSYNC) {
376				xfs_trans_set_sync(args.trans);
377			}
378			err2 = xfs_trans_commit(args.trans,
379						 XFS_TRANS_RELEASE_LOG_RES,
380						 NULL);
381			xfs_iunlock(dp, XFS_ILOCK_EXCL);
382
383			/*
384			 * Hit the inode change time.
385			 */
386			if (!error && (flags & ATTR_KERNOTIME) == 0) {
387				xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
388			}
389			return(error == 0 ? err2 : error);
390		}
391
392		/*
393		 * It won't fit in the shortform, transform to a leaf block.
394		 * GROT: another possible req'mt for a double-split btree op.
395		 */
396		XFS_BMAP_INIT(args.flist, args.firstblock);
397		error = xfs_attr_shortform_to_leaf(&args);
398		if (!error) {
399			error = xfs_bmap_finish(&args.trans, args.flist,
400						*args.firstblock, &committed);
401		}
402		if (error) {
403			ASSERT(committed);
404			args.trans = NULL;
405			xfs_bmap_cancel(&flist);
406			goto out;
407		}
408
409		/*
410		 * bmap_finish() may have committed the last trans and started
411		 * a new one.  We need the inode to be in all transactions.
412		 */
413		if (committed) {
414			xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
415			xfs_trans_ihold(args.trans, dp);
416		}
417
418		/*
419		 * Commit the leaf transformation.  We'll need another (linked)
420		 * transaction to add the new attribute to the leaf.
421		 */
422		if ((error = xfs_attr_rolltrans(&args.trans, dp)))
423			goto out;
424
425	}
426
427	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
428		error = xfs_attr_leaf_addname(&args);
429	} else {
430		error = xfs_attr_node_addname(&args);
431	}
432	if (error) {
433		goto out;
434	}
435
436	/*
437	 * If this is a synchronous mount, make sure that the
438	 * transaction goes to disk before returning to the user.
439	 */
440	if (mp->m_flags & XFS_MOUNT_WSYNC) {
441		xfs_trans_set_sync(args.trans);
442	}
443
444	/*
445	 * Commit the last in the sequence of transactions.
446	 */
447	xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
448	error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,
449				 NULL);
450	xfs_iunlock(dp, XFS_ILOCK_EXCL);
451
452	/*
453	 * Hit the inode change time.
454	 */
455	if (!error && (flags & ATTR_KERNOTIME) == 0) {
456		xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
457	}
458
459	return(error);
460
461out:
462	if (args.trans)
463		xfs_trans_cancel(args.trans,
464			XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
465	xfs_iunlock(dp, XFS_ILOCK_EXCL);
466	return(error);
467}
468
469/*
470 * Generic handler routine to remove a name from an attribute list.
471 * Transitions attribute list from Btree to shortform as necessary.
472 */
473/*ARGSUSED*/
474int								/* error */
475xfs_attr_remove(bhv_desc_t *bdp, const char *name, int flags, struct cred *cred)
476{
477	xfs_da_args_t       args;
478	xfs_inode_t         *dp;
479	xfs_fsblock_t       firstblock;
480	xfs_bmap_free_t     flist;
481	int                 error;
482	xfs_mount_t         *mp;
483	int                 namelen;
484
485	ASSERT(MAXNAMELEN-1<=0xff); /* length is stored in uint8 */
486	namelen = strlen(name);
487	if (namelen>=MAXNAMELEN)
488		return EFAULT; /* match irix behaviour */
489
490	XFS_STATS_INC(xs_attr_remove);
491
492	/*
493	 * Do we answer them, or ignore them?
494	 */
495	dp = XFS_BHVTOI(bdp);
496	mp = dp->i_mount;
497	if (XFS_FORCED_SHUTDOWN(mp))
498		return (EIO);
499
500	xfs_ilock(dp, XFS_ILOCK_SHARED);
501	if ((error = xfs_iaccess(dp, S_IWUSR, cred))) {
502		xfs_iunlock(dp, XFS_ILOCK_SHARED);
503		return(XFS_ERROR(error));
504	} else if (XFS_IFORK_Q(dp) == 0 ||
505		   (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
506		    dp->i_d.di_anextents == 0)) {
507		xfs_iunlock(dp, XFS_ILOCK_SHARED);
508		return(XFS_ERROR(ENOATTR));
509	}
510	xfs_iunlock(dp, XFS_ILOCK_SHARED);
511
512	/*
513	 * Fill in the arg structure for this request.
514	 */
515	memset((char *)&args, 0, sizeof(args));
516	args.name = name;
517	args.namelen = namelen;
518	args.flags = flags;
519	args.hashval = xfs_da_hashname(args.name, args.namelen);
520	args.dp = dp;
521	args.firstblock = &firstblock;
522	args.flist = &flist;
523	args.total = 0;
524	args.whichfork = XFS_ATTR_FORK;
525
526	/*
527	 * Attach the dquots to the inode.
528	 */
529	if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
530		return (error);
531
532	/*
533	 * Start our first transaction of the day.
534	 *
535	 * All future transactions during this code must be "chained" off
536	 * this one via the trans_dup() call.  All transactions will contain
537	 * the inode, and the inode will always be marked with trans_ihold().
538	 * Since the inode will be locked in all transactions, we must log
539	 * the inode in every transaction to let it float upward through
540	 * the log.
541	 */
542	args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM);
543
544	/*
545	 * Root fork attributes can use reserved data blocks for this
546	 * operation if necessary
547	 */
548
549	if (flags & ATTR_ROOT)
550		args.trans->t_flags |= XFS_TRANS_RESERVE;
551
552	if ((error = xfs_trans_reserve(args.trans,
553				      XFS_ATTRRM_SPACE_RES(mp),
554				      XFS_ATTRRM_LOG_RES(mp),
555				      0, XFS_TRANS_PERM_LOG_RES,
556				      XFS_ATTRRM_LOG_COUNT))) {
557		xfs_trans_cancel(args.trans, 0);
558		return(error);
559
560	}
561
562	xfs_ilock(dp, XFS_ILOCK_EXCL);
563	/*
564	 * No need to make quota reservations here. We expect to release some
565	 * blocks not allocate in the common case.
566	 */
567	xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
568	xfs_trans_ihold(args.trans, dp);
569
570	/*
571	 * Decide on what work routines to call based on the inode size.
572	 */
573	if (XFS_IFORK_Q(dp) == 0 ||
574	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
575	     dp->i_d.di_anextents == 0)) {
576		error = XFS_ERROR(ENOATTR);
577		goto out;
578	}
579	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
580		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
581		error = xfs_attr_shortform_remove(&args);
582		if (error) {
583			goto out;
584		}
585	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
586		error = xfs_attr_leaf_removename(&args);
587	} else {
588		error = xfs_attr_node_removename(&args);
589	}
590	if (error) {
591		goto out;
592	}
593
594	/*
595	 * If this is a synchronous mount, make sure that the
596	 * transaction goes to disk before returning to the user.
597	 */
598	if (mp->m_flags & XFS_MOUNT_WSYNC) {
599		xfs_trans_set_sync(args.trans);
600	}
601
602	/*
603	 * Commit the last in the sequence of transactions.
604	 */
605	xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
606	error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,
607				 NULL);
608	xfs_iunlock(dp, XFS_ILOCK_EXCL);
609
610	/*
611	 * Hit the inode change time.
612	 */
613	if (!error && (flags & ATTR_KERNOTIME) == 0) {
614		xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
615	}
616
617	return(error);
618
619out:
620	if (args.trans)
621		xfs_trans_cancel(args.trans,
622			XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
623	xfs_iunlock(dp, XFS_ILOCK_EXCL);
624	return(error);
625}
626
627/*
628 * Generate a list of extended attribute names and optionally
629 * also value lengths.  Positive return value follows the XFS
630 * convention of being an error, zero or negative return code
631 * is the length of the buffer returned (negated), indicating
632 * success.
633 */
634int
635xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags,
636		      attrlist_cursor_kern_t *cursor, struct cred *cred)
637{
638	xfs_attr_list_context_t context;
639	xfs_inode_t *dp;
640	int error;
641
642	XFS_STATS_INC(xs_attr_list);
643
644	/*
645	 * Validate the cursor.
646	 */
647	if (cursor->pad1 || cursor->pad2)
648		return(XFS_ERROR(EINVAL));
649	if ((cursor->initted == 0) &&
650	    (cursor->hashval || cursor->blkno || cursor->offset))
651		return(XFS_ERROR(EINVAL));
652
653	/*
654	 * Check for a properly aligned buffer.
655	 */
656	if (((long)buffer) & (sizeof(int)-1))
657		return(XFS_ERROR(EFAULT));
658	if (flags & ATTR_KERNOVAL)
659		bufsize = 0;
660
661	/*
662	 * Initialize the output buffer.
663	 */
664	context.dp = dp = XFS_BHVTOI(bdp);
665	context.cursor = cursor;
666	context.count = 0;
667	context.dupcnt = 0;
668	context.resynch = 1;
669	context.flags = flags;
670	if (!(flags & ATTR_KERNAMELS)) {
671		context.bufsize = (bufsize & ~(sizeof(int)-1));  /* align */
672		context.firstu = context.bufsize;
673		context.alist = (attrlist_t *)buffer;
674		context.alist->al_count = 0;
675		context.alist->al_more = 0;
676		context.alist->al_offset[0] = context.bufsize;
677	}
678	else {
679		context.bufsize = bufsize;
680		context.firstu = context.bufsize;
681		context.alist = (attrlist_t *)buffer;
682	}
683
684	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
685		return (EIO);
686	/*
687	 * Do they have permission?
688	 */
689	xfs_ilock(dp, XFS_ILOCK_SHARED);
690	if ((error = xfs_iaccess(dp, S_IRUSR, cred))) {
691		xfs_iunlock(dp, XFS_ILOCK_SHARED);
692		return(XFS_ERROR(error));
693	}
694
695	/*
696	 * Decide on what work routines to call based on the inode size.
697	 */
698	xfs_attr_trace_l_c("syscall start", &context);
699	if (XFS_IFORK_Q(dp) == 0 ||
700	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
701	     dp->i_d.di_anextents == 0)) {
702		error = 0;
703	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
704		error = xfs_attr_shortform_list(&context);
705	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
706		error = xfs_attr_leaf_list(&context);
707	} else {
708		error = xfs_attr_node_list(&context);
709	}
710	xfs_iunlock(dp, XFS_ILOCK_SHARED);
711	xfs_attr_trace_l_c("syscall end", &context);
712
713	if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) {
714		ASSERT(error >= 0);
715	}
716	else {	/* must return negated buffer size or the error */
717		if (context.count < 0)
718			error = XFS_ERROR(ERANGE);
719		else
720			error = -context.count;
721	}
722
723	return(error);
724}
725
726int								/* error */
727xfs_attr_inactive(xfs_inode_t *dp)
728{
729	xfs_trans_t *trans;
730	xfs_mount_t *mp;
731	int error;
732
733	mp = dp->i_mount;
734	ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
735
736	/* XXXsup - why on earth are we taking ILOCK_EXCL here??? */
737	xfs_ilock(dp, XFS_ILOCK_EXCL);
738	if ((XFS_IFORK_Q(dp) == 0) ||
739	    (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
740	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
741	     dp->i_d.di_anextents == 0)) {
742		xfs_iunlock(dp, XFS_ILOCK_EXCL);
743		return(0);
744	}
745	xfs_iunlock(dp, XFS_ILOCK_EXCL);
746
747	/*
748	 * Start our first transaction of the day.
749	 *
750	 * All future transactions during this code must be "chained" off
751	 * this one via the trans_dup() call.  All transactions will contain
752	 * the inode, and the inode will always be marked with trans_ihold().
753	 * Since the inode will be locked in all transactions, we must log
754	 * the inode in every transaction to let it float upward through
755	 * the log.
756	 */
757	trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL);
758	if ((error = xfs_trans_reserve(trans, 0, XFS_ATTRINVAL_LOG_RES(mp), 0,
759				      XFS_TRANS_PERM_LOG_RES,
760				      XFS_ATTRINVAL_LOG_COUNT))) {
761		xfs_trans_cancel(trans, 0);
762		return(error);
763	}
764	xfs_ilock(dp, XFS_ILOCK_EXCL);
765
766	/*
767	 * No need to make quota reservations here. We expect to release some
768	 * blocks, not allocate, in the common case.
769	 */
770	xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL);
771	xfs_trans_ihold(trans, dp);
772
773	/*
774	 * Decide on what work routines to call based on the inode size.
775	 */
776	if ((XFS_IFORK_Q(dp) == 0) ||
777	    (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
778	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
779	     dp->i_d.di_anextents == 0)) {
780		error = 0;
781		goto out;
782	}
783	error = xfs_attr_root_inactive(&trans, dp);
784	if (error)
785		goto out;
786	/*
787	 * signal synchronous inactive transactions unless this
788	 * is a synchronous mount filesystem in which case we
789	 * know that we're here because we've been called out of
790	 * xfs_inactive which means that the last reference is gone
791	 * and the unlink transaction has already hit the disk so
792	 * async inactive transactions are safe.
793	 */
794	if ((error = xfs_itruncate_finish(&trans, dp, 0LL, XFS_ATTR_FORK,
795				(!(mp->m_flags & XFS_MOUNT_WSYNC)
796				 ? 1 : 0))))
797		goto out;
798
799	/*
800	 * Commit the last in the sequence of transactions.
801	 */
802	xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE);
803	error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES,
804				 NULL);
805	xfs_iunlock(dp, XFS_ILOCK_EXCL);
806
807	return(error);
808
809out:
810	xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
811	xfs_iunlock(dp, XFS_ILOCK_EXCL);
812	return(error);
813}
814
815
816
817/*========================================================================
818 * External routines when attribute list is inside the inode
819 *========================================================================*/
820
821/*
822 * Add a name to the shortform attribute list structure
823 * This is the external routine.
824 */
825STATIC int
826xfs_attr_shortform_addname(xfs_da_args_t *args)
827{
828	int newsize, retval;
829
830	retval = xfs_attr_shortform_lookup(args);
831	if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
832		return(retval);
833	} else if (retval == EEXIST) {
834		if (args->flags & ATTR_CREATE)
835			return(retval);
836		retval = xfs_attr_shortform_remove(args);
837		ASSERT(retval == 0);
838	}
839
840	newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
841	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
842	if ((newsize <= XFS_IFORK_ASIZE(args->dp)) &&
843	    (args->namelen < XFS_ATTR_SF_ENTSIZE_MAX) &&
844	    (args->valuelen < XFS_ATTR_SF_ENTSIZE_MAX)) {
845		retval = xfs_attr_shortform_add(args);
846		ASSERT(retval == 0);
847	} else {
848		return(XFS_ERROR(ENOSPC));
849	}
850	return(0);
851}
852
853
854/*========================================================================
855 * External routines when attribute list is one block
856 *========================================================================*/
857
858/*
859 * Add a name to the leaf attribute list structure
860 *
861 * This leaf block cannot have a "remote" value, we only call this routine
862 * if bmap_one_block() says there is only one block (ie: no remote blks).
863 */
864int
865xfs_attr_leaf_addname(xfs_da_args_t *args)
866{
867	xfs_inode_t *dp;
868	xfs_dabuf_t *bp;
869	int retval, error, committed;
870
871	/*
872	 * Read the (only) block in the attribute list in.
873	 */
874	dp = args->dp;
875	args->blkno = 0;
876	error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
877					     XFS_ATTR_FORK);
878	if (error)
879		return(error);
880	ASSERT(bp != NULL);
881
882	/*
883	 * Look up the given attribute in the leaf block.  Figure out if
884	 * the given flags produce an error or call for an atomic rename.
885	 */
886	retval = xfs_attr_leaf_lookup_int(bp, args);
887	if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
888		xfs_da_brelse(args->trans, bp);
889		return(retval);
890	} else if (retval == EEXIST) {
891		if (args->flags & ATTR_CREATE) {	/* pure create op */
892			xfs_da_brelse(args->trans, bp);
893			return(retval);
894		}
895		args->rename = 1;			/* an atomic rename */
896		args->blkno2 = args->blkno;		/* set 2nd entry info*/
897		args->index2 = args->index;
898		args->rmtblkno2 = args->rmtblkno;
899		args->rmtblkcnt2 = args->rmtblkcnt;
900	}
901
902	/*
903	 * Add the attribute to the leaf block, transitioning to a Btree
904	 * if required.
905	 */
906	retval = xfs_attr_leaf_add(bp, args);
907	xfs_da_buf_done(bp);
908	if (retval == ENOSPC) {
909		/*
910		 * Promote the attribute list to the Btree format, then
911		 * Commit that transaction so that the node_addname() call
912		 * can manage its own transactions.
913		 */
914		XFS_BMAP_INIT(args->flist, args->firstblock);
915		error = xfs_attr_leaf_to_node(args);
916		if (!error) {
917			error = xfs_bmap_finish(&args->trans, args->flist,
918						*args->firstblock, &committed);
919		}
920		if (error) {
921			ASSERT(committed);
922			args->trans = NULL;
923			xfs_bmap_cancel(args->flist);
924			return(error);
925		}
926
927		/*
928		 * bmap_finish() may have committed the last trans and started
929		 * a new one.  We need the inode to be in all transactions.
930		 */
931		if (committed) {
932			xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
933			xfs_trans_ihold(args->trans, dp);
934		}
935
936		/*
937		 * Commit the current trans (including the inode) and start
938		 * a new one.
939		 */
940		if ((error = xfs_attr_rolltrans(&args->trans, dp)))
941			return (error);
942
943		/*
944		 * Fob the whole rest of the problem off on the Btree code.
945		 */
946		error = xfs_attr_node_addname(args);
947		return(error);
948	}
949
950	/*
951	 * Commit the transaction that added the attr name so that
952	 * later routines can manage their own transactions.
953	 */
954	if ((error = xfs_attr_rolltrans(&args->trans, dp)))
955		return (error);
956
957	/*
958	 * If there was an out-of-line value, allocate the blocks we
959	 * identified for its storage and copy the value.  This is done
960	 * after we create the attribute so that we don't overflow the
961	 * maximum size of a transaction and/or hit a deadlock.
962	 */
963	if (args->rmtblkno > 0) {
964		error = xfs_attr_rmtval_set(args);
965		if (error)
966			return(error);
967	}
968
969	/*
970	 * If this is an atomic rename operation, we must "flip" the
971	 * incomplete flags on the "new" and "old" attribute/value pairs
972	 * so that one disappears and one appears atomically.  Then we
973	 * must remove the "old" attribute/value pair.
974	 */
975	if (args->rename) {
976		/*
977		 * In a separate transaction, set the incomplete flag on the
978		 * "old" attr and clear the incomplete flag on the "new" attr.
979		 */
980		error = xfs_attr_leaf_flipflags(args);
981		if (error)
982			return(error);
983
984		/*
985		 * Dismantle the "old" attribute/value pair by removing
986		 * a "remote" value (if it exists).
987		 */
988		args->index = args->index2;
989		args->blkno = args->blkno2;
990		args->rmtblkno = args->rmtblkno2;
991		args->rmtblkcnt = args->rmtblkcnt2;
992		if (args->rmtblkno) {
993			error = xfs_attr_rmtval_remove(args);
994			if (error)
995				return(error);
996		}
997
998		/*
999		 * Read in the block containing the "old" attr, then
1000		 * remove the "old" attr from that block (neat, huh!)
1001		 */
1002		error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1,
1003						     &bp, XFS_ATTR_FORK);
1004		if (error)
1005			return(error);
1006		ASSERT(bp != NULL);
1007		(void)xfs_attr_leaf_remove(bp, args);
1008
1009		/*
1010		 * If the result is small enough, shrink it all into the inode.
1011		 */
1012		if (xfs_attr_shortform_allfit(bp, dp)) {
1013			XFS_BMAP_INIT(args->flist, args->firstblock);
1014			error = xfs_attr_leaf_to_shortform(bp, args);
1015			/* bp is gone due to xfs_da_shrink_inode */
1016			if (!error) {
1017				error = xfs_bmap_finish(&args->trans,
1018							args->flist,
1019							*args->firstblock,
1020							&committed);
1021			}
1022			if (error) {
1023				ASSERT(committed);
1024				args->trans = NULL;
1025				xfs_bmap_cancel(args->flist);
1026				return(error);
1027			}
1028
1029			/*
1030			 * bmap_finish() may have committed the last trans
1031			 * and started a new one.  We need the inode to be
1032			 * in all transactions.
1033			 */
1034			if (committed) {
1035				xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1036				xfs_trans_ihold(args->trans, dp);
1037			}
1038		} else
1039			xfs_da_buf_done(bp);
1040
1041		/*
1042		 * Commit the remove and start the next trans in series.
1043		 */
1044		error = xfs_attr_rolltrans(&args->trans, dp);
1045
1046	} else if (args->rmtblkno > 0) {
1047		/*
1048		 * Added a "remote" value, just clear the incomplete flag.
1049		 */
1050		error = xfs_attr_leaf_clearflag(args);
1051	}
1052	return(error);
1053}
1054
1055/*
1056 * Remove a name from the leaf attribute list structure
1057 *
1058 * This leaf block cannot have a "remote" value, we only call this routine
1059 * if bmap_one_block() says there is only one block (ie: no remote blks).
1060 */
1061STATIC int
1062xfs_attr_leaf_removename(xfs_da_args_t *args)
1063{
1064	xfs_inode_t *dp;
1065	xfs_dabuf_t *bp;
1066	int committed;
1067	int error;
1068
1069	/*
1070	 * Remove the attribute.
1071	 */
1072	dp = args->dp;
1073	args->blkno = 0;
1074	error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
1075					     XFS_ATTR_FORK);
1076	if (error) {
1077		return(error);
1078	}
1079
1080	ASSERT(bp != NULL);
1081	error = xfs_attr_leaf_lookup_int(bp, args);
1082	if (error == ENOATTR) {
1083		xfs_da_brelse(args->trans, bp);
1084		return(error);
1085	}
1086
1087	(void)xfs_attr_leaf_remove(bp, args);
1088
1089	/*
1090	 * If the result is small enough, shrink it all into the inode.
1091	 */
1092	if (xfs_attr_shortform_allfit(bp, dp)) {
1093		XFS_BMAP_INIT(args->flist, args->firstblock);
1094		error = xfs_attr_leaf_to_shortform(bp, args);
1095		/* bp is gone due to xfs_da_shrink_inode */
1096		if (!error) {
1097			error = xfs_bmap_finish(&args->trans, args->flist,
1098						*args->firstblock, &committed);
1099		}
1100		if (error) {
1101			ASSERT(committed);
1102			args->trans = NULL;
1103			xfs_bmap_cancel(args->flist);
1104			return(error);
1105		}
1106
1107		/*
1108		 * bmap_finish() may have committed the last trans and started
1109		 * a new one.  We need the inode to be in all transactions.
1110		 */
1111		if (committed) {
1112			xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1113			xfs_trans_ihold(args->trans, dp);
1114		}
1115	} else
1116		xfs_da_buf_done(bp);
1117	return(0);
1118}
1119
1120/*
1121 * Look up a name in a leaf attribute list structure.
1122 *
1123 * This leaf block cannot have a "remote" value, we only call this routine
1124 * if bmap_one_block() says there is only one block (ie: no remote blks).
1125 */
1126int
1127xfs_attr_leaf_get(xfs_da_args_t *args)
1128{
1129	xfs_dabuf_t *bp;
1130	int error;
1131
1132	args->blkno = 0;
1133	error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
1134					     XFS_ATTR_FORK);
1135	if (error)
1136		return(error);
1137	ASSERT(bp != NULL);
1138
1139	error = xfs_attr_leaf_lookup_int(bp, args);
1140	if (error != EEXIST)  {
1141		xfs_da_brelse(args->trans, bp);
1142		return(error);
1143	}
1144	error = xfs_attr_leaf_getvalue(bp, args);
1145	xfs_da_brelse(args->trans, bp);
1146	if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) {
1147		error = xfs_attr_rmtval_get(args);
1148	}
1149	return(error);
1150}
1151
1152/*
1153 * Copy out attribute entries for attr_list(), for leaf attribute lists.
1154 */
1155STATIC int
1156xfs_attr_leaf_list(xfs_attr_list_context_t *context)
1157{
1158	xfs_attr_leafblock_t *leaf;
1159	int error;
1160	xfs_dabuf_t *bp;
1161
1162	context->cursor->blkno = 0;
1163	error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK);
1164	if (error)
1165		return(error);
1166	ASSERT(bp != NULL);
1167	leaf = bp->data;
1168	if (unlikely(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
1169						!= XFS_ATTR_LEAF_MAGIC)) {
1170		XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW,
1171				     context->dp->i_mount, leaf);
1172		xfs_da_brelse(NULL, bp);
1173		return(XFS_ERROR(EFSCORRUPTED));
1174	}
1175
1176	(void)xfs_attr_leaf_list_int(bp, context);
1177	xfs_da_brelse(NULL, bp);
1178	return(0);
1179}
1180
1181
1182/*========================================================================
1183 * External routines when attribute list size > XFS_LBSIZE(mp).
1184 *========================================================================*/
1185
1186/*
1187 * Add a name to a Btree-format attribute list.
1188 *
1189 * This will involve walking down the Btree, and may involve splitting
1190 * leaf nodes and even splitting intermediate nodes up to and including
1191 * the root node (a special case of an intermediate node).
1192 *
1193 * "Remote" attribute values confuse the issue and atomic rename operations
1194 * add a whole extra layer of confusion on top of that.
1195 */
1196STATIC int
1197xfs_attr_node_addname(xfs_da_args_t *args)
1198{
1199	xfs_da_state_t *state;
1200	xfs_da_state_blk_t *blk;
1201	xfs_inode_t *dp;
1202	xfs_mount_t *mp;
1203	int committed, retval, error;
1204
1205	/*
1206	 * Fill in bucket of arguments/results/context to carry around.
1207	 */
1208	dp = args->dp;
1209	mp = dp->i_mount;
1210restart:
1211	state = xfs_da_state_alloc();
1212	state->args = args;
1213	state->mp = mp;
1214	state->blocksize = state->mp->m_sb.sb_blocksize;
1215	state->node_ents = state->mp->m_attr_node_ents;
1216
1217	/*
1218	 * Search to see if name already exists, and get back a pointer
1219	 * to where it should go.
1220	 */
1221	error = xfs_da_node_lookup_int(state, &retval);
1222	if (error)
1223		goto out;
1224	blk = &state->path.blk[ state->path.active-1 ];
1225	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1226	if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
1227		goto out;
1228	} else if (retval == EEXIST) {
1229		if (args->flags & ATTR_CREATE)
1230			goto out;
1231		args->rename = 1;			/* atomic rename op */
1232		args->blkno2 = args->blkno;		/* set 2nd entry info*/
1233		args->index2 = args->index;
1234		args->rmtblkno2 = args->rmtblkno;
1235		args->rmtblkcnt2 = args->rmtblkcnt;
1236		args->rmtblkno = 0;
1237		args->rmtblkcnt = 0;
1238	}
1239
1240	retval = xfs_attr_leaf_add(blk->bp, state->args);
1241	if (retval == ENOSPC) {
1242		if (state->path.active == 1) {
1243			/*
1244			 * Its really a single leaf node, but it had
1245			 * out-of-line values so it looked like it *might*
1246			 * have been a b-tree.
1247			 */
1248			xfs_da_state_free(state);
1249			XFS_BMAP_INIT(args->flist, args->firstblock);
1250			error = xfs_attr_leaf_to_node(args);
1251			if (!error) {
1252				error = xfs_bmap_finish(&args->trans,
1253							args->flist,
1254							*args->firstblock,
1255							&committed);
1256			}
1257			if (error) {
1258				ASSERT(committed);
1259				args->trans = NULL;
1260				xfs_bmap_cancel(args->flist);
1261				goto out;
1262			}
1263
1264			/*
1265			 * bmap_finish() may have committed the last trans
1266			 * and started a new one.  We need the inode to be
1267			 * in all transactions.
1268			 */
1269			if (committed) {
1270				xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1271				xfs_trans_ihold(args->trans, dp);
1272			}
1273
1274			/*
1275			 * Commit the node conversion and start the next
1276			 * trans in the chain.
1277			 */
1278			if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1279				goto out;
1280
1281			goto restart;
1282		}
1283
1284		/*
1285		 * Split as many Btree elements as required.
1286		 * This code tracks the new and old attr's location
1287		 * in the index/blkno/rmtblkno/rmtblkcnt fields and
1288		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
1289		 */
1290		XFS_BMAP_INIT(args->flist, args->firstblock);
1291		error = xfs_da_split(state);
1292		if (!error) {
1293			error = xfs_bmap_finish(&args->trans, args->flist,
1294						*args->firstblock, &committed);
1295		}
1296		if (error) {
1297			ASSERT(committed);
1298			args->trans = NULL;
1299			xfs_bmap_cancel(args->flist);
1300			goto out;
1301		}
1302
1303		/*
1304		 * bmap_finish() may have committed the last trans and started
1305		 * a new one.  We need the inode to be in all transactions.
1306		 */
1307		if (committed) {
1308			xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1309			xfs_trans_ihold(args->trans, dp);
1310		}
1311	} else {
1312		/*
1313		 * Addition succeeded, update Btree hashvals.
1314		 */
1315		xfs_da_fixhashpath(state, &state->path);
1316	}
1317
1318	/*
1319	 * Kill the state structure, we're done with it and need to
1320	 * allow the buffers to come back later.
1321	 */
1322	xfs_da_state_free(state);
1323	state = NULL;
1324
1325	/*
1326	 * Commit the leaf addition or btree split and start the next
1327	 * trans in the chain.
1328	 */
1329	if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1330		goto out;
1331
1332	/*
1333	 * If there was an out-of-line value, allocate the blocks we
1334	 * identified for its storage and copy the value.  This is done
1335	 * after we create the attribute so that we don't overflow the
1336	 * maximum size of a transaction and/or hit a deadlock.
1337	 */
1338	if (args->rmtblkno > 0) {
1339		error = xfs_attr_rmtval_set(args);
1340		if (error)
1341			return(error);
1342	}
1343
1344	/*
1345	 * If this is an atomic rename operation, we must "flip" the
1346	 * incomplete flags on the "new" and "old" attribute/value pairs
1347	 * so that one disappears and one appears atomically.  Then we
1348	 * must remove the "old" attribute/value pair.
1349	 */
1350	if (args->rename) {
1351		/*
1352		 * In a separate transaction, set the incomplete flag on the
1353		 * "old" attr and clear the incomplete flag on the "new" attr.
1354		 */
1355		error = xfs_attr_leaf_flipflags(args);
1356		if (error)
1357			goto out;
1358
1359		/*
1360		 * Dismantle the "old" attribute/value pair by removing
1361		 * a "remote" value (if it exists).
1362		 */
1363		args->index = args->index2;
1364		args->blkno = args->blkno2;
1365		args->rmtblkno = args->rmtblkno2;
1366		args->rmtblkcnt = args->rmtblkcnt2;
1367		if (args->rmtblkno) {
1368			error = xfs_attr_rmtval_remove(args);
1369			if (error)
1370				return(error);
1371		}
1372
1373		/*
1374		 * Re-find the "old" attribute entry after any split ops.
1375		 * The INCOMPLETE flag means that we will find the "old"
1376		 * attr, not the "new" one.
1377		 */
1378		args->flags |= XFS_ATTR_INCOMPLETE;
1379		state = xfs_da_state_alloc();
1380		state->args = args;
1381		state->mp = mp;
1382		state->blocksize = state->mp->m_sb.sb_blocksize;
1383		state->node_ents = state->mp->m_attr_node_ents;
1384		state->inleaf = 0;
1385		error = xfs_da_node_lookup_int(state, &retval);
1386		if (error)
1387			goto out;
1388
1389		/*
1390		 * Remove the name and update the hashvals in the tree.
1391		 */
1392		blk = &state->path.blk[ state->path.active-1 ];
1393		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1394		error = xfs_attr_leaf_remove(blk->bp, args);
1395		xfs_da_fixhashpath(state, &state->path);
1396
1397		/*
1398		 * Check to see if the tree needs to be collapsed.
1399		 */
1400		if (retval && (state->path.active > 1)) {
1401			XFS_BMAP_INIT(args->flist, args->firstblock);
1402			error = xfs_da_join(state);
1403			if (!error) {
1404				error = xfs_bmap_finish(&args->trans,
1405							args->flist,
1406							*args->firstblock,
1407							&committed);
1408			}
1409			if (error) {
1410				ASSERT(committed);
1411				args->trans = NULL;
1412				xfs_bmap_cancel(args->flist);
1413				goto out;
1414			}
1415
1416			/*
1417			 * bmap_finish() may have committed the last trans
1418			 * and started a new one.  We need the inode to be
1419			 * in all transactions.
1420			 */
1421			if (committed) {
1422				xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1423				xfs_trans_ihold(args->trans, dp);
1424			}
1425		}
1426
1427		/*
1428		 * Commit and start the next trans in the chain.
1429		 */
1430		if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1431			goto out;
1432
1433	} else if (args->rmtblkno > 0) {
1434		/*
1435		 * Added a "remote" value, just clear the incomplete flag.
1436		 */
1437		error = xfs_attr_leaf_clearflag(args);
1438		if (error)
1439			goto out;
1440	}
1441	retval = error = 0;
1442
1443out:
1444	if (state)
1445		xfs_da_state_free(state);
1446	if (error)
1447		return(error);
1448	return(retval);
1449}
1450
1451/*
1452 * Remove a name from a B-tree attribute list.
1453 *
1454 * This will involve walking down the Btree, and may involve joining
1455 * leaf nodes and even joining intermediate nodes up to and including
1456 * the root node (a special case of an intermediate node).
1457 */
1458STATIC int
1459xfs_attr_node_removename(xfs_da_args_t *args)
1460{
1461	xfs_da_state_t *state;
1462	xfs_da_state_blk_t *blk;
1463	xfs_inode_t *dp;
1464	xfs_dabuf_t *bp;
1465	int retval, error, committed;
1466
1467	/*
1468	 * Tie a string around our finger to remind us where we are.
1469	 */
1470	dp = args->dp;
1471	state = xfs_da_state_alloc();
1472	state->args = args;
1473	state->mp = dp->i_mount;
1474	state->blocksize = state->mp->m_sb.sb_blocksize;
1475	state->node_ents = state->mp->m_attr_node_ents;
1476
1477	/*
1478	 * Search to see if name exists, and get back a pointer to it.
1479	 */
1480	error = xfs_da_node_lookup_int(state, &retval);
1481	if (error || (retval != EEXIST)) {
1482		if (error == 0)
1483			error = retval;
1484		goto out;
1485	}
1486
1487	/*
1488	 * If there is an out-of-line value, de-allocate the blocks.
1489	 * This is done before we remove the attribute so that we don't
1490	 * overflow the maximum size of a transaction and/or hit a deadlock.
1491	 */
1492	blk = &state->path.blk[ state->path.active-1 ];
1493	ASSERT(blk->bp != NULL);
1494	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1495	if (args->rmtblkno > 0) {
1496		/*
1497		 * Fill in disk block numbers in the state structure
1498		 * so that we can get the buffers back after we commit
1499		 * several transactions in the following calls.
1500		 */
1501		error = xfs_attr_fillstate(state);
1502		if (error)
1503			goto out;
1504
1505		/*
1506		 * Mark the attribute as INCOMPLETE, then bunmapi() the
1507		 * remote value.
1508		 */
1509		error = xfs_attr_leaf_setflag(args);
1510		if (error)
1511			goto out;
1512		error = xfs_attr_rmtval_remove(args);
1513		if (error)
1514			goto out;
1515
1516		/*
1517		 * Refill the state structure with buffers, the prior calls
1518		 * released our buffers.
1519		 */
1520		error = xfs_attr_refillstate(state);
1521		if (error)
1522			goto out;
1523	}
1524
1525	/*
1526	 * Remove the name and update the hashvals in the tree.
1527	 */
1528	blk = &state->path.blk[ state->path.active-1 ];
1529	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1530	retval = xfs_attr_leaf_remove(blk->bp, args);
1531	xfs_da_fixhashpath(state, &state->path);
1532
1533	/*
1534	 * Check to see if the tree needs to be collapsed.
1535	 */
1536	if (retval && (state->path.active > 1)) {
1537		XFS_BMAP_INIT(args->flist, args->firstblock);
1538		error = xfs_da_join(state);
1539		if (!error) {
1540			error = xfs_bmap_finish(&args->trans, args->flist,
1541						*args->firstblock, &committed);
1542		}
1543		if (error) {
1544			ASSERT(committed);
1545			args->trans = NULL;
1546			xfs_bmap_cancel(args->flist);
1547			goto out;
1548		}
1549
1550		/*
1551		 * bmap_finish() may have committed the last trans and started
1552		 * a new one.  We need the inode to be in all transactions.
1553		 */
1554		if (committed) {
1555			xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1556			xfs_trans_ihold(args->trans, dp);
1557		}
1558
1559		/*
1560		 * Commit the Btree join operation and start a new trans.
1561		 */
1562		if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1563			goto out;
1564	}
1565
1566	/*
1567	 * If the result is small enough, push it all into the inode.
1568	 */
1569	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
1570		/*
1571		 * Have to get rid of the copy of this dabuf in the state.
1572		 */
1573		ASSERT(state->path.active == 1);
1574		ASSERT(state->path.blk[0].bp);
1575		xfs_da_buf_done(state->path.blk[0].bp);
1576		state->path.blk[0].bp = NULL;
1577
1578		error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
1579						     XFS_ATTR_FORK);
1580		if (error)
1581			goto out;
1582		ASSERT(INT_GET(((xfs_attr_leafblock_t *)
1583				      bp->data)->hdr.info.magic, ARCH_CONVERT)
1584						       == XFS_ATTR_LEAF_MAGIC);
1585
1586		if (xfs_attr_shortform_allfit(bp, dp)) {
1587			XFS_BMAP_INIT(args->flist, args->firstblock);
1588			error = xfs_attr_leaf_to_shortform(bp, args);
1589			/* bp is gone due to xfs_da_shrink_inode */
1590			if (!error) {
1591				error = xfs_bmap_finish(&args->trans,
1592							args->flist,
1593							*args->firstblock,
1594							&committed);
1595			}
1596			if (error) {
1597				ASSERT(committed);
1598				args->trans = NULL;
1599				xfs_bmap_cancel(args->flist);
1600				goto out;
1601			}
1602
1603			/*
1604			 * bmap_finish() may have committed the last trans
1605			 * and started a new one.  We need the inode to be
1606			 * in all transactions.
1607			 */
1608			if (committed) {
1609				xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1610				xfs_trans_ihold(args->trans, dp);
1611			}
1612		} else
1613			xfs_da_brelse(args->trans, bp);
1614	}
1615	error = 0;
1616
1617out:
1618	xfs_da_state_free(state);
1619	return(error);
1620}
1621
1622/*
1623 * Fill in the disk block numbers in the state structure for the buffers
1624 * that are attached to the state structure.
1625 * This is done so that we can quickly reattach ourselves to those buffers
1626 * after some set of transaction commit's has released these buffers.
1627 */
1628STATIC int
1629xfs_attr_fillstate(xfs_da_state_t *state)
1630{
1631	xfs_da_state_path_t *path;
1632	xfs_da_state_blk_t *blk;
1633	int level;
1634
1635	/*
1636	 * Roll down the "path" in the state structure, storing the on-disk
1637	 * block number for those buffers in the "path".
1638	 */
1639	path = &state->path;
1640	ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1641	for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1642		if (blk->bp) {
1643			blk->disk_blkno = xfs_da_blkno(blk->bp);
1644			xfs_da_buf_done(blk->bp);
1645			blk->bp = NULL;
1646		} else {
1647			blk->disk_blkno = 0;
1648		}
1649	}
1650
1651	/*
1652	 * Roll down the "altpath" in the state structure, storing the on-disk
1653	 * block number for those buffers in the "altpath".
1654	 */
1655	path = &state->altpath;
1656	ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1657	for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1658		if (blk->bp) {
1659			blk->disk_blkno = xfs_da_blkno(blk->bp);
1660			xfs_da_buf_done(blk->bp);
1661			blk->bp = NULL;
1662		} else {
1663			blk->disk_blkno = 0;
1664		}
1665	}
1666
1667	return(0);
1668}
1669
1670/*
1671 * Reattach the buffers to the state structure based on the disk block
1672 * numbers stored in the state structure.
1673 * This is done after some set of transaction commit's has released those
1674 * buffers from our grip.
1675 */
1676STATIC int
1677xfs_attr_refillstate(xfs_da_state_t *state)
1678{
1679	xfs_da_state_path_t *path;
1680	xfs_da_state_blk_t *blk;
1681	int level, error;
1682
1683	/*
1684	 * Roll down the "path" in the state structure, storing the on-disk
1685	 * block number for those buffers in the "path".
1686	 */
1687	path = &state->path;
1688	ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1689	for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1690		if (blk->disk_blkno) {
1691			error = xfs_da_read_buf(state->args->trans,
1692						state->args->dp,
1693						blk->blkno, blk->disk_blkno,
1694						&blk->bp, XFS_ATTR_FORK);
1695			if (error)
1696				return(error);
1697		} else {
1698			blk->bp = NULL;
1699		}
1700	}
1701
1702	/*
1703	 * Roll down the "altpath" in the state structure, storing the on-disk
1704	 * block number for those buffers in the "altpath".
1705	 */
1706	path = &state->altpath;
1707	ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1708	for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1709		if (blk->disk_blkno) {
1710			error = xfs_da_read_buf(state->args->trans,
1711						state->args->dp,
1712						blk->blkno, blk->disk_blkno,
1713						&blk->bp, XFS_ATTR_FORK);
1714			if (error)
1715				return(error);
1716		} else {
1717			blk->bp = NULL;
1718		}
1719	}
1720
1721	return(0);
1722}
1723
1724/*
1725 * Look up a filename in a node attribute list.
1726 *
1727 * This routine gets called for any attribute fork that has more than one
1728 * block, ie: both true Btree attr lists and for single-leaf-blocks with
1729 * "remote" values taking up more blocks.
1730 */
1731int
1732xfs_attr_node_get(xfs_da_args_t *args)
1733{
1734	xfs_da_state_t *state;
1735	xfs_da_state_blk_t *blk;
1736	int error, retval;
1737	int i;
1738
1739	state = xfs_da_state_alloc();
1740	state->args = args;
1741	state->mp = args->dp->i_mount;
1742	state->blocksize = state->mp->m_sb.sb_blocksize;
1743	state->node_ents = state->mp->m_attr_node_ents;
1744
1745	/*
1746	 * Search to see if name exists, and get back a pointer to it.
1747	 */
1748	error = xfs_da_node_lookup_int(state, &retval);
1749	if (error) {
1750		retval = error;
1751	} else if (retval == EEXIST) {
1752		blk = &state->path.blk[ state->path.active-1 ];
1753		ASSERT(blk->bp != NULL);
1754		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1755
1756		/*
1757		 * Get the value, local or "remote"
1758		 */
1759		retval = xfs_attr_leaf_getvalue(blk->bp, args);
1760		if (!retval && (args->rmtblkno > 0)
1761		    && !(args->flags & ATTR_KERNOVAL)) {
1762			retval = xfs_attr_rmtval_get(args);
1763		}
1764	}
1765
1766	/*
1767	 * If not in a transaction, we have to release all the buffers.
1768	 */
1769	for (i = 0; i < state->path.active; i++) {
1770		xfs_da_brelse(args->trans, state->path.blk[i].bp);
1771		state->path.blk[i].bp = NULL;
1772	}
1773
1774	xfs_da_state_free(state);
1775	return(retval);
1776}
1777
1778STATIC int							/* error */
1779xfs_attr_node_list(xfs_attr_list_context_t *context)
1780{
1781	attrlist_cursor_kern_t *cursor;
1782	xfs_attr_leafblock_t *leaf;
1783	xfs_da_intnode_t *node;
1784	xfs_da_node_entry_t *btree;
1785	int error, i;
1786	xfs_dabuf_t *bp;
1787
1788	cursor = context->cursor;
1789	cursor->initted = 1;
1790
1791	/*
1792	 * Do all sorts of validation on the passed-in cursor structure.
1793	 * If anything is amiss, ignore the cursor and look up the hashval
1794	 * starting from the btree root.
1795	 */
1796	bp = NULL;
1797	if (cursor->blkno > 0) {
1798		error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
1799					      &bp, XFS_ATTR_FORK);
1800		if ((error != 0) && (error != EFSCORRUPTED))
1801			return(error);
1802		if (bp) {
1803			node = bp->data;
1804			switch (INT_GET(node->hdr.info.magic, ARCH_CONVERT)) {
1805			case XFS_DA_NODE_MAGIC:
1806				xfs_attr_trace_l_cn("wrong blk", context, node);
1807				xfs_da_brelse(NULL, bp);
1808				bp = NULL;
1809				break;
1810			case XFS_ATTR_LEAF_MAGIC:
1811				leaf = bp->data;
1812				if (cursor->hashval >
1813				    INT_GET(leaf->entries[
1814					 INT_GET(leaf->hdr.count,
1815						ARCH_CONVERT)-1].hashval,
1816							ARCH_CONVERT)) {
1817					xfs_attr_trace_l_cl("wrong blk",
1818							   context, leaf);
1819					xfs_da_brelse(NULL, bp);
1820					bp = NULL;
1821				} else if (cursor->hashval <=
1822					     INT_GET(leaf->entries[0].hashval,
1823							ARCH_CONVERT)) {
1824					xfs_attr_trace_l_cl("maybe wrong blk",
1825							   context, leaf);
1826					xfs_da_brelse(NULL, bp);
1827					bp = NULL;
1828				}
1829				break;
1830			default:
1831				xfs_attr_trace_l_c("wrong blk - ??", context);
1832				xfs_da_brelse(NULL, bp);
1833				bp = NULL;
1834			}
1835		}
1836	}
1837
1838	/*
1839	 * We did not find what we expected given the cursor's contents,
1840	 * so we start from the top and work down based on the hash value.
1841	 * Note that start of node block is same as start of leaf block.
1842	 */
1843	if (bp == NULL) {
1844		cursor->blkno = 0;
1845		for (;;) {
1846			error = xfs_da_read_buf(NULL, context->dp,
1847						      cursor->blkno, -1, &bp,
1848						      XFS_ATTR_FORK);
1849			if (error)
1850				return(error);
1851			if (unlikely(bp == NULL)) {
1852				XFS_ERROR_REPORT("xfs_attr_node_list(2)",
1853						 XFS_ERRLEVEL_LOW,
1854						 context->dp->i_mount);
1855				return(XFS_ERROR(EFSCORRUPTED));
1856			}
1857			node = bp->data;
1858			if (INT_GET(node->hdr.info.magic, ARCH_CONVERT)
1859							== XFS_ATTR_LEAF_MAGIC)
1860				break;
1861			if (unlikely(INT_GET(node->hdr.info.magic, ARCH_CONVERT)
1862							!= XFS_DA_NODE_MAGIC)) {
1863				XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)",
1864						     XFS_ERRLEVEL_LOW,
1865						     context->dp->i_mount,
1866						     node);
1867				xfs_da_brelse(NULL, bp);
1868				return(XFS_ERROR(EFSCORRUPTED));
1869			}
1870			btree = node->btree;
1871			for (i = 0;
1872				i < INT_GET(node->hdr.count, ARCH_CONVERT);
1873								btree++, i++) {
1874				if (cursor->hashval
1875						<= INT_GET(btree->hashval,
1876							    ARCH_CONVERT)) {
1877					cursor->blkno = INT_GET(btree->before, ARCH_CONVERT);
1878					xfs_attr_trace_l_cb("descending",
1879							    context, btree);
1880					break;
1881				}
1882			}
1883			if (i == INT_GET(node->hdr.count, ARCH_CONVERT)) {
1884				xfs_da_brelse(NULL, bp);
1885				return(0);
1886			}
1887			xfs_da_brelse(NULL, bp);
1888		}
1889	}
1890	ASSERT(bp != NULL);
1891
1892	/*
1893	 * Roll upward through the blocks, processing each leaf block in
1894	 * order.  As long as there is space in the result buffer, keep
1895	 * adding the information.
1896	 */
1897	for (;;) {
1898		leaf = bp->data;
1899		if (unlikely(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
1900						!= XFS_ATTR_LEAF_MAGIC)) {
1901			XFS_CORRUPTION_ERROR("xfs_attr_node_list(4)",
1902					     XFS_ERRLEVEL_LOW,
1903					     context->dp->i_mount, leaf);
1904			xfs_da_brelse(NULL, bp);
1905			return(XFS_ERROR(EFSCORRUPTED));
1906		}
1907		error = xfs_attr_leaf_list_int(bp, context);
1908		if (error || (INT_ISZERO(leaf->hdr.info.forw, ARCH_CONVERT)))
1909			break;	/* not really an error, buffer full or EOF */
1910		cursor->blkno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
1911		xfs_da_brelse(NULL, bp);
1912		error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
1913					      &bp, XFS_ATTR_FORK);
1914		if (error)
1915			return(error);
1916		if (unlikely((bp == NULL))) {
1917			XFS_ERROR_REPORT("xfs_attr_node_list(5)",
1918					 XFS_ERRLEVEL_LOW,
1919					 context->dp->i_mount);
1920			return(XFS_ERROR(EFSCORRUPTED));
1921		}
1922	}
1923	xfs_da_brelse(NULL, bp);
1924	return(0);
1925}
1926
1927
1928/*========================================================================
1929 * External routines for manipulating out-of-line attribute values.
1930 *========================================================================*/
1931
1932/*
1933 * Read the value associated with an attribute from the out-of-line buffer
1934 * that we stored it in.
1935 */
1936STATIC int
1937xfs_attr_rmtval_get(xfs_da_args_t *args)
1938{
1939	xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE];
1940	xfs_mount_t *mp;
1941	xfs_daddr_t dblkno;
1942	xfs_caddr_t dst;
1943	xfs_buf_t *bp;
1944	int nmap, error, tmp, valuelen, blkcnt, i;
1945	xfs_dablk_t lblkno;
1946
1947	ASSERT(!(args->flags & ATTR_KERNOVAL));
1948
1949	mp = args->dp->i_mount;
1950	dst = args->value;
1951	valuelen = args->valuelen;
1952	lblkno = args->rmtblkno;
1953	while (valuelen > 0) {
1954		nmap = ATTR_RMTVALUE_MAPSIZE;
1955		error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno,
1956				  args->rmtblkcnt,
1957				  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
1958				  NULL, 0, map, &nmap, NULL);
1959		if (error)
1960			return(error);
1961		ASSERT(nmap >= 1);
1962
1963		for (i = 0; (i < nmap) && (valuelen > 0); i++) {
1964			ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
1965			       (map[i].br_startblock != HOLESTARTBLOCK));
1966			dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
1967			blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
1968			error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno,
1969					     blkcnt, XFS_BUF_LOCK, &bp);
1970			if (error)
1971				return(error);
1972
1973			tmp = (valuelen < XFS_BUF_SIZE(bp))
1974				? valuelen : XFS_BUF_SIZE(bp);
1975			xfs_biomove(bp, 0, tmp, dst, XFS_B_READ);
1976			xfs_buf_relse(bp);
1977			dst += tmp;
1978			valuelen -= tmp;
1979
1980			lblkno += map[i].br_blockcount;
1981		}
1982	}
1983	ASSERT(valuelen == 0);
1984	return(0);
1985}
1986
1987/*
1988 * Write the value associated with an attribute into the out-of-line buffer
1989 * that we have defined for it.
1990 */
1991STATIC int
1992xfs_attr_rmtval_set(xfs_da_args_t *args)
1993{
1994	xfs_mount_t *mp;
1995	xfs_fileoff_t lfileoff;
1996	xfs_inode_t *dp;
1997	xfs_bmbt_irec_t map;
1998	xfs_daddr_t dblkno;
1999	xfs_caddr_t src;
2000	xfs_buf_t *bp;
2001	xfs_dablk_t lblkno;
2002	int blkcnt, valuelen, nmap, error, tmp, committed;
2003
2004	dp = args->dp;
2005	mp = dp->i_mount;
2006	src = args->value;
2007
2008	/*
2009	 * Find a "hole" in the attribute address space large enough for
2010	 * us to drop the new attribute's value into.
2011	 */
2012	blkcnt = XFS_B_TO_FSB(mp, args->valuelen);
2013	lfileoff = 0;
2014	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
2015						   XFS_ATTR_FORK);
2016	if (error) {
2017		return(error);
2018	}
2019	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
2020	args->rmtblkcnt = blkcnt;
2021
2022	/*
2023	 * Roll through the "value", allocating blocks on disk as required.
2024	 */
2025	while (blkcnt > 0) {
2026		/*
2027		 * Allocate a single extent, up to the size of the value.
2028		 */
2029		XFS_BMAP_INIT(args->flist, args->firstblock);
2030		nmap = 1;
2031		error = xfs_bmapi(args->trans, dp, (xfs_fileoff_t)lblkno,
2032				  blkcnt,
2033				  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA |
2034							XFS_BMAPI_WRITE,
2035				  args->firstblock, args->total, &map, &nmap,
2036				  args->flist);
2037		if (!error) {
2038			error = xfs_bmap_finish(&args->trans, args->flist,
2039						*args->firstblock, &committed);
2040		}
2041		if (error) {
2042			ASSERT(committed);
2043			args->trans = NULL;
2044			xfs_bmap_cancel(args->flist);
2045			return(error);
2046		}
2047
2048		/*
2049		 * bmap_finish() may have committed the last trans and started
2050		 * a new one.  We need the inode to be in all transactions.
2051		 */
2052		if (committed) {
2053			xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
2054			xfs_trans_ihold(args->trans, dp);
2055		}
2056
2057		ASSERT(nmap == 1);
2058		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
2059		       (map.br_startblock != HOLESTARTBLOCK));
2060		lblkno += map.br_blockcount;
2061		blkcnt -= map.br_blockcount;
2062
2063		/*
2064		 * Start the next trans in the chain.
2065		 */
2066		if ((error = xfs_attr_rolltrans(&args->trans, dp)))
2067			return (error);
2068	}
2069
2070	/*
2071	 * Roll through the "value", copying the attribute value to the
2072	 * already-allocated blocks.  Blocks are written synchronously
2073	 * so that we can know they are all on disk before we turn off
2074	 * the INCOMPLETE flag.
2075	 */
2076	lblkno = args->rmtblkno;
2077	valuelen = args->valuelen;
2078	while (valuelen > 0) {
2079		/*
2080		 * Try to remember where we decided to put the value.
2081		 */
2082		XFS_BMAP_INIT(args->flist, args->firstblock);
2083		nmap = 1;
2084		error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno,
2085				  args->rmtblkcnt,
2086				  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
2087				  args->firstblock, 0, &map, &nmap, NULL);
2088		if (error) {
2089			return(error);
2090		}
2091		ASSERT(nmap == 1);
2092		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
2093		       (map.br_startblock != HOLESTARTBLOCK));
2094
2095		dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
2096		blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
2097
2098		bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno,
2099							blkcnt, XFS_BUF_LOCK);
2100		ASSERT(bp);
2101		ASSERT(!XFS_BUF_GETERROR(bp));
2102
2103		tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen :
2104							XFS_BUF_SIZE(bp);
2105		xfs_biomove(bp, 0, tmp, src, XFS_B_WRITE);
2106		if (tmp < XFS_BUF_SIZE(bp))
2107			xfs_biozero(bp, tmp, XFS_BUF_SIZE(bp) - tmp);
2108		if ((error = xfs_bwrite(mp, bp))) {/* GROT: NOTE: synchronous write */
2109			return (error);
2110		}
2111		src += tmp;
2112		valuelen -= tmp;
2113
2114		lblkno += map.br_blockcount;
2115	}
2116	ASSERT(valuelen == 0);
2117	return(0);
2118}
2119
2120/*
2121 * Remove the value associated with an attribute by deleting the
2122 * out-of-line buffer that it is stored on.
2123 */
2124STATIC int
2125xfs_attr_rmtval_remove(xfs_da_args_t *args)
2126{
2127	xfs_mount_t *mp;
2128	xfs_bmbt_irec_t map;
2129	xfs_buf_t *bp;
2130	xfs_daddr_t dblkno;
2131	xfs_dablk_t lblkno;
2132	int valuelen, blkcnt, nmap, error, done, committed;
2133
2134	mp = args->dp->i_mount;
2135
2136	/*
2137	 * Roll through the "value", invalidating the attribute value's
2138	 * blocks.
2139	 */
2140	lblkno = args->rmtblkno;
2141	valuelen = args->rmtblkcnt;
2142	while (valuelen > 0) {
2143		/*
2144		 * Try to remember where we decided to put the value.
2145		 */
2146		XFS_BMAP_INIT(args->flist, args->firstblock);
2147		nmap = 1;
2148		error = xfs_bmapi(NULL, args->dp, (xfs_fileoff_t)lblkno,
2149					args->rmtblkcnt,
2150					XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
2151					args->firstblock, 0, &map, &nmap,
2152					args->flist);
2153		if (error) {
2154			return(error);
2155		}
2156		ASSERT(nmap == 1);
2157		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
2158		       (map.br_startblock != HOLESTARTBLOCK));
2159
2160		dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
2161		blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
2162
2163		/*
2164		 * If the "remote" value is in the cache, remove it.
2165		 */
2166		/* bp = incore(mp->m_dev, dblkno, blkcnt, 1); */
2167		bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, 1);
2168		if (bp) {
2169			XFS_BUF_STALE(bp);
2170			XFS_BUF_UNDELAYWRITE(bp);
2171			xfs_buf_relse(bp);
2172			bp = NULL;
2173		}
2174
2175		valuelen -= map.br_blockcount;
2176
2177		lblkno += map.br_blockcount;
2178	}
2179
2180	/*
2181	 * Keep de-allocating extents until the remote-value region is gone.
2182	 */
2183	lblkno = args->rmtblkno;
2184	blkcnt = args->rmtblkcnt;
2185	done = 0;
2186	while (!done) {
2187		XFS_BMAP_INIT(args->flist, args->firstblock);
2188		error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
2189				    XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
2190				    1, args->firstblock, args->flist, &done);
2191		if (!error) {
2192			error = xfs_bmap_finish(&args->trans, args->flist,
2193						*args->firstblock, &committed);
2194		}
2195		if (error) {
2196			ASSERT(committed);
2197			args->trans = NULL;
2198			xfs_bmap_cancel(args->flist);
2199			return(error);
2200		}
2201
2202		/*
2203		 * bmap_finish() may have committed the last trans and started
2204		 * a new one.  We need the inode to be in all transactions.
2205		 */
2206		if (committed) {
2207			xfs_trans_ijoin(args->trans, args->dp, XFS_ILOCK_EXCL);
2208			xfs_trans_ihold(args->trans, args->dp);
2209		}
2210
2211		/*
2212		 * Close out trans and start the next one in the chain.
2213		 */
2214		if ((error = xfs_attr_rolltrans(&args->trans, args->dp)))
2215			return (error);
2216	}
2217	return(0);
2218}
2219
2220#if defined(XFS_ATTR_TRACE)
2221/*
2222 * Add a trace buffer entry for an attr_list context structure.
2223 */
2224void
2225xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context)
2226{
2227	xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where,
2228		(__psunsigned_t)context->dp,
2229		(__psunsigned_t)context->cursor->hashval,
2230		(__psunsigned_t)context->cursor->blkno,
2231		(__psunsigned_t)context->cursor->offset,
2232		(__psunsigned_t)context->alist,
2233		(__psunsigned_t)context->bufsize,
2234		(__psunsigned_t)context->count,
2235		(__psunsigned_t)context->firstu,
2236		(__psunsigned_t)
2237			((context->count > 0) &&
2238			!(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
2239				? (ATTR_ENTRY(context->alist,
2240					      context->count-1)->a_valuelen)
2241				: 0,
2242		(__psunsigned_t)context->dupcnt,
2243		(__psunsigned_t)context->flags,
2244		(__psunsigned_t)NULL,
2245		(__psunsigned_t)NULL,
2246		(__psunsigned_t)NULL);
2247}
2248
2249/*
2250 * Add a trace buffer entry for a context structure and a Btree node.
2251 */
2252void
2253xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context,
2254			 struct xfs_da_intnode *node)
2255{
2256	xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where,
2257		(__psunsigned_t)context->dp,
2258		(__psunsigned_t)context->cursor->hashval,
2259		(__psunsigned_t)context->cursor->blkno,
2260		(__psunsigned_t)context->cursor->offset,
2261		(__psunsigned_t)context->alist,
2262		(__psunsigned_t)context->bufsize,
2263		(__psunsigned_t)context->count,
2264		(__psunsigned_t)context->firstu,
2265		(__psunsigned_t)
2266			((context->count > 0) &&
2267			!(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
2268				? (ATTR_ENTRY(context->alist,
2269					      context->count-1)->a_valuelen)
2270				: 0,
2271		(__psunsigned_t)context->dupcnt,
2272		(__psunsigned_t)context->flags,
2273		(__psunsigned_t)INT_GET(node->hdr.count, ARCH_CONVERT),
2274		(__psunsigned_t)INT_GET(node->btree[0].hashval, ARCH_CONVERT),
2275		(__psunsigned_t)INT_GET(node->btree[INT_GET(node->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT));
2276}
2277
2278/*
2279 * Add a trace buffer entry for a context structure and a Btree element.
2280 */
2281void
2282xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context,
2283			  struct xfs_da_node_entry *btree)
2284{
2285	xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where,
2286		(__psunsigned_t)context->dp,
2287		(__psunsigned_t)context->cursor->hashval,
2288		(__psunsigned_t)context->cursor->blkno,
2289		(__psunsigned_t)context->cursor->offset,
2290		(__psunsigned_t)context->alist,
2291		(__psunsigned_t)context->bufsize,
2292		(__psunsigned_t)context->count,
2293		(__psunsigned_t)context->firstu,
2294		(__psunsigned_t)
2295			((context->count > 0) &&
2296			!(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
2297				? (ATTR_ENTRY(context->alist,
2298					      context->count-1)->a_valuelen)
2299				: 0,
2300		(__psunsigned_t)context->dupcnt,
2301		(__psunsigned_t)context->flags,
2302		(__psunsigned_t)INT_GET(btree->hashval, ARCH_CONVERT),
2303		(__psunsigned_t)INT_GET(btree->before, ARCH_CONVERT),
2304		(__psunsigned_t)NULL);
2305}
2306
2307/*
2308 * Add a trace buffer entry for a context structure and a leaf block.
2309 */
2310void
2311xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context,
2312			      struct xfs_attr_leafblock *leaf)
2313{
2314	xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where,
2315		(__psunsigned_t)context->dp,
2316		(__psunsigned_t)context->cursor->hashval,
2317		(__psunsigned_t)context->cursor->blkno,
2318		(__psunsigned_t)context->cursor->offset,
2319		(__psunsigned_t)context->alist,
2320		(__psunsigned_t)context->bufsize,
2321		(__psunsigned_t)context->count,
2322		(__psunsigned_t)context->firstu,
2323		(__psunsigned_t)
2324			((context->count > 0) &&
2325			!(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
2326				? (ATTR_ENTRY(context->alist,
2327					      context->count-1)->a_valuelen)
2328				: 0,
2329		(__psunsigned_t)context->dupcnt,
2330		(__psunsigned_t)context->flags,
2331		(__psunsigned_t)INT_GET(leaf->hdr.count, ARCH_CONVERT),
2332		(__psunsigned_t)INT_GET(leaf->entries[0].hashval, ARCH_CONVERT),
2333		(__psunsigned_t)INT_GET(leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT));
2334}
2335
2336/*
2337 * Add a trace buffer entry for the arguments given to the routine,
2338 * generic form.
2339 */
2340void
2341xfs_attr_trace_enter(int type, char *where,
2342			 __psunsigned_t a2, __psunsigned_t a3,
2343			 __psunsigned_t a4, __psunsigned_t a5,
2344			 __psunsigned_t a6, __psunsigned_t a7,
2345			 __psunsigned_t a8, __psunsigned_t a9,
2346			 __psunsigned_t a10, __psunsigned_t a11,
2347			 __psunsigned_t a12, __psunsigned_t a13,
2348			 __psunsigned_t a14, __psunsigned_t a15)
2349{
2350	ASSERT(xfs_attr_trace_buf);
2351	ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type),
2352					 (void *)where,
2353					 (void *)a2,  (void *)a3,  (void *)a4,
2354					 (void *)a5,  (void *)a6,  (void *)a7,
2355					 (void *)a8,  (void *)a9,  (void *)a10,
2356					 (void *)a11, (void *)a12, (void *)a13,
2357					 (void *)a14, (void *)a15);
2358}
2359#endif	/* XFS_ATTR_TRACE */
2360
2361
2362/*========================================================================
2363 * System (pseudo) namespace attribute interface routines.
2364 *========================================================================*/
2365
2366STATIC int
2367posix_acl_access_set(
2368	xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags)
2369{
2370	return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS);
2371}
2372
2373STATIC int
2374posix_acl_access_remove(
2375	struct xfs_vnode *vp, char *name, int xflags)
2376{
2377	return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
2378}
2379
2380STATIC int
2381posix_acl_access_get(
2382	xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags)
2383{
2384	return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
2385}
2386
2387STATIC int
2388posix_acl_access_exists(
2389	xfs_vnode_t *vp)
2390{
2391	return xfs_acl_vhasacl_access(vp);
2392}
2393
2394STATIC int
2395posix_acl_default_set(
2396	xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags)
2397{
2398	return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT);
2399}
2400
2401STATIC int
2402posix_acl_default_get(
2403	xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags)
2404{
2405	return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
2406}
2407
2408STATIC int
2409posix_acl_default_remove(
2410	struct xfs_vnode *vp, char *name, int xflags)
2411{
2412	return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT);
2413}
2414
2415STATIC int
2416posix_acl_default_exists(
2417	xfs_vnode_t *vp)
2418{
2419	return xfs_acl_vhasacl_default(vp);
2420}
2421
2422struct attrnames posix_acl_access = {
2423	.attr_name	= "posix_acl_access",
2424	.attr_namelen	= sizeof("posix_acl_access") - 1,
2425	.attr_get	= posix_acl_access_get,
2426	.attr_set	= posix_acl_access_set,
2427	.attr_remove	= posix_acl_access_remove,
2428	.attr_exists	= posix_acl_access_exists,
2429};
2430
2431struct attrnames posix_acl_default = {
2432	.attr_name	= "posix_acl_default",
2433	.attr_namelen	= sizeof("posix_acl_default") - 1,
2434	.attr_get	= posix_acl_default_get,
2435	.attr_set	= posix_acl_default_set,
2436	.attr_remove	= posix_acl_default_remove,
2437	.attr_exists	= posix_acl_default_exists,
2438};
2439
2440struct attrnames *attr_system_names[] =
2441	{ &posix_acl_access, &posix_acl_default };
2442
2443
2444/*========================================================================
2445 * Namespace-prefix-style attribute name interface routines.
2446 *========================================================================*/
2447
2448STATIC int
2449attr_generic_set(
2450	struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags)
2451{
2452	int 	error;
2453
2454	XVOP_ATTR_SET(vp, name, data, size, xflags, NULL, error);
2455	return -error;
2456}
2457
2458STATIC int
2459attr_generic_get(
2460	struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags)
2461{
2462	int	error, asize = size;
2463
2464	XVOP_ATTR_GET(vp, name, data, &asize, xflags, NULL, error);
2465	if (!error)
2466		return asize;
2467	return -error;
2468}
2469
2470STATIC int
2471attr_generic_remove(
2472	struct xfs_vnode *vp, char *name, int xflags)
2473{
2474	int	error;
2475
2476	XVOP_ATTR_REMOVE(vp, name, xflags, NULL, error);
2477	return -error;
2478}
2479
2480STATIC int
2481attr_generic_listadd(
2482	attrnames_t		*prefix,
2483	attrnames_t		*namesp,
2484	void			*data,
2485	size_t			size,
2486	ssize_t			*result)
2487{
2488	char			*p = (char *)data + *result;
2489
2490	*result += prefix->attr_namelen;
2491	*result += namesp->attr_namelen + 1;
2492	if (!size)
2493		return 0;
2494	if (*result > size)
2495		return -ERANGE;
2496	strcpy(p, prefix->attr_name);
2497	p += prefix->attr_namelen;
2498	strcpy(p, namesp->attr_name);
2499	p += namesp->attr_namelen + 1;
2500	return 0;
2501}
2502
2503STATIC int
2504attr_system_list(
2505	struct xfs_vnode		*vp,
2506	void			*data,
2507	size_t			size,
2508	ssize_t			*result)
2509{
2510	attrnames_t		*namesp;
2511	int			i, error = 0;
2512
2513	for (i = 0; i < ATTR_SYSCOUNT; i++) {
2514		namesp = attr_system_names[i];
2515		if (!namesp->attr_exists || !namesp->attr_exists(vp))
2516			continue;
2517		error = attr_generic_listadd(&attr_system, namesp,
2518						data, size, result);
2519		if (error)
2520			break;
2521	}
2522	return error;
2523}
2524
2525int
2526attr_generic_list(
2527	struct xfs_vnode *vp, void *data, size_t size, int xflags, ssize_t *result)
2528{
2529	attrlist_cursor_kern_t	cursor = { 0 };
2530	int			error;
2531
2532	XVOP_ATTR_LIST(vp, data, size, xflags, &cursor, NULL, error);
2533	if (error > 0)
2534		return -error;
2535	*result = -error;
2536	return attr_system_list(vp, data, size, result);
2537}
2538
2539attrnames_t *
2540attr_lookup_namespace(
2541	char			*name,
2542	struct attrnames	**names,
2543	int			nnames)
2544{
2545	int			i;
2546
2547	for (i = 0; i < nnames; i++)
2548		if (!strncmp(name, names[i]->attr_name, names[i]->attr_namelen))
2549			return names[i];
2550	return NULL;
2551}
2552
2553/*
2554 * Some checks to prevent people abusing EAs to get over quota:
2555 * - Don't allow modifying user EAs on devices/symlinks;
2556 * - Don't allow modifying user EAs if sticky bit set;
2557 */
2558STATIC int
2559attr_user_capable(
2560	struct xfs_vnode	*vp,
2561	cred_t		*cred)
2562{
2563#if XXXKAN
2564	struct inode	*inode = LINVFS_GET_IP(vp);
2565
2566	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
2567		return -EPERM;
2568	if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) &&
2569	    !capable(CAP_SYS_ADMIN))
2570		return -EPERM;
2571	if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
2572	    (current_fsuid(cred) != inode->i_uid) && !capable(CAP_FOWNER))
2573		return -EPERM;
2574#endif
2575	return 0;
2576}
2577
2578STATIC int
2579attr_trusted_capable(
2580	struct xfs_vnode	*vp,
2581	cred_t		*cred)
2582{
2583#if XXXKAN
2584	struct inode	*inode = LINVFS_GET_IP(vp);
2585
2586	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
2587		return -EPERM;
2588	if (!capable(CAP_SYS_ADMIN))
2589		return -EPERM;
2590#endif
2591	return 0;
2592}
2593
2594STATIC int
2595attr_secure_capable(
2596	struct xfs_vnode *vp,
2597	cred_t		 *cred)
2598{
2599	return -ENOSECURITY;
2600}
2601
2602STATIC int
2603attr_system_set(
2604	struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags)
2605{
2606	attrnames_t	*namesp;
2607	int		error;
2608
2609	if (xflags & ATTR_CREATE)
2610		return -EINVAL;
2611
2612	namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
2613	if (!namesp)
2614		return -EOPNOTSUPP;
2615	error = namesp->attr_set(vp, name, data, size, xflags);
2616#if XXXKAN
2617	if (!error)
2618		error = vn_revalidate(vp);
2619#endif
2620	return error;
2621}
2622
2623STATIC int
2624attr_system_get(
2625	struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags)
2626{
2627	attrnames_t	*namesp;
2628
2629	namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
2630	if (!namesp)
2631		return -EOPNOTSUPP;
2632	return namesp->attr_get(vp, name, data, size, xflags);
2633}
2634
2635STATIC int
2636attr_system_remove(
2637	struct xfs_vnode *vp, char *name, int xflags)
2638{
2639	attrnames_t	*namesp;
2640
2641	namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
2642	if (!namesp)
2643		return -EOPNOTSUPP;
2644	return namesp->attr_remove(vp, name, xflags);
2645}
2646
2647struct attrnames attr_system = {
2648	.attr_name	= "system.",
2649	.attr_namelen	= sizeof("system.") - 1,
2650	.attr_flag	= ATTR_SYSTEM,
2651	.attr_get	= attr_system_get,
2652	.attr_set	= attr_system_set,
2653	.attr_remove	= attr_system_remove,
2654	.attr_capable	= (attrcapable_t)fs_noerr,
2655};
2656
2657struct attrnames attr_trusted = {
2658	.attr_name	= "trusted.",
2659	.attr_namelen	= sizeof("trusted.") - 1,
2660	.attr_flag	= ATTR_ROOT,
2661	.attr_get	= attr_generic_get,
2662	.attr_set	= attr_generic_set,
2663	.attr_remove	= attr_generic_remove,
2664	.attr_capable	= attr_trusted_capable,
2665};
2666
2667struct attrnames attr_secure = {
2668	.attr_name	= "security.",
2669	.attr_namelen	= sizeof("security.") - 1,
2670	.attr_flag	= ATTR_SECURE,
2671	.attr_get	= attr_generic_get,
2672	.attr_set	= attr_generic_set,
2673	.attr_remove	= attr_generic_remove,
2674	.attr_capable	= attr_secure_capable,
2675};
2676
2677struct attrnames attr_user = {
2678	.attr_name	= "user.",
2679	.attr_namelen	= sizeof("user.") - 1,
2680	.attr_get	= attr_generic_get,
2681	.attr_set	= attr_generic_set,
2682	.attr_remove	= attr_generic_remove,
2683	.attr_capable	= attr_user_capable,
2684};
2685
2686struct attrnames *attr_namespaces[] =
2687	{ &attr_system, &attr_trusted, &attr_secure, &attr_user };
2688