2 * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
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.
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.
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.
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.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
35 #include "xfs_macros.h"
36 #include "xfs_types.h"
39 #include "xfs_trans.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"
58 #include "xfs_da_btree.h"
60 #include "xfs_attr_leaf.h"
61 #include "xfs_error.h"
63 #include "xfs_quota.h"
65 #include "xfs_trans_space.h"
71 * Provide the external interfaces to manage attribute lists.
74 /*========================================================================
75 * Function prototypes for the kernel.
76 *========================================================================*/
79 * Internal routines when attribute list fits inside the inode.
81 STATIC
int xfs_attr_shortform_addname(xfs_da_args_t
*args
);
84 * Internal routines when attribute list is one block.
86 STATIC
int xfs_attr_leaf_addname(xfs_da_args_t
*args
);
87 STATIC
int xfs_attr_leaf_removename(xfs_da_args_t
*args
);
88 STATIC
int xfs_attr_leaf_list(xfs_attr_list_context_t
*context
);
91 * Internal routines when attribute list is more than one block.
93 STATIC
int xfs_attr_node_addname(xfs_da_args_t
*args
);
94 STATIC
int xfs_attr_node_removename(xfs_da_args_t
*args
);
95 STATIC
int xfs_attr_node_list(xfs_attr_list_context_t
*context
);
96 STATIC
int xfs_attr_fillstate(xfs_da_state_t
*state
);
97 STATIC
int xfs_attr_refillstate(xfs_da_state_t
*state
);
100 * Routines to manipulate out-of-line attribute values.
102 STATIC
int xfs_attr_rmtval_get(xfs_da_args_t
*args
);
103 STATIC
int xfs_attr_rmtval_set(xfs_da_args_t
*args
);
104 STATIC
int xfs_attr_rmtval_remove(xfs_da_args_t
*args
);
106 #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */
108 #if defined(XFS_ATTR_TRACE)
109 ktrace_t
*xfs_attr_trace_buf
;
113 /*========================================================================
114 * Overall external interface routines.
115 *========================================================================*/
118 xfs_attr_fetch(xfs_inode_t
*ip
, char *name
, int namelen
,
119 char *value
, int *valuelenp
, int flags
, struct cred
*cred
)
124 if ((XFS_IFORK_Q(ip
) == 0) ||
125 (ip
->i_d
.di_aformat
== XFS_DINODE_FMT_EXTENTS
&&
126 ip
->i_d
.di_anextents
== 0))
129 if (!(flags
& (ATTR_KERNACCESS
|ATTR_SECURE
))) {
130 if ((error
= xfs_iaccess(ip
, S_IRUSR
, cred
)))
131 return(XFS_ERROR(error
));
135 * Fill in the arg structure for this request.
137 memset((char *)&args
, 0, sizeof(args
));
139 args
.namelen
= namelen
;
141 args
.valuelen
= *valuelenp
;
143 args
.hashval
= xfs_da_hashname(args
.name
, args
.namelen
);
145 args
.whichfork
= XFS_ATTR_FORK
;
148 * Decide on what work routines to call based on the inode size.
150 if (XFS_IFORK_Q(ip
) == 0 ||
151 (ip
->i_d
.di_aformat
== XFS_DINODE_FMT_EXTENTS
&&
152 ip
->i_d
.di_anextents
== 0)) {
153 error
= XFS_ERROR(ENOATTR
);
154 } else if (ip
->i_d
.di_aformat
== XFS_DINODE_FMT_LOCAL
) {
155 error
= xfs_attr_shortform_getvalue(&args
);
156 } else if (xfs_bmap_one_block(ip
, XFS_ATTR_FORK
)) {
157 error
= xfs_attr_leaf_get(&args
);
159 error
= xfs_attr_node_get(&args
);
163 * Return the number of bytes in the value to the caller.
165 *valuelenp
= args
.valuelen
;
173 xfs_attr_get(bhv_desc_t
*bdp
, char *name
, char *value
, int *valuelenp
,
174 int flags
, struct cred
*cred
)
176 xfs_inode_t
*ip
= XFS_BHVTOI(bdp
);
179 XFS_STATS_INC(xs_attr_get
);
183 namelen
= strlen(name
);
184 if (namelen
>= MAXNAMELEN
)
185 return(EFAULT
); /* match IRIX behaviour */
187 if (XFS_FORCED_SHUTDOWN(ip
->i_mount
))
190 xfs_ilock(ip
, XFS_ILOCK_SHARED
);
191 error
= xfs_attr_fetch(ip
, name
, namelen
, value
, valuelenp
, flags
, cred
);
192 xfs_iunlock(ip
, XFS_ILOCK_SHARED
);
198 xfs_attr_set(bhv_desc_t
*bdp
, char *name
, char *value
, int valuelen
, int flags
,
203 xfs_fsblock_t firstblock
;
204 xfs_bmap_free_t flist
;
205 int error
, err2
, committed
;
209 int rsvd
= (flags
& ATTR_ROOT
) != 0;
212 namelen
= strlen(name
);
213 if (namelen
>= MAXNAMELEN
)
214 return EFAULT
; /* match IRIX behaviour */
216 XFS_STATS_INC(xs_attr_set
);
218 dp
= XFS_BHVTOI(bdp
);
220 if (XFS_FORCED_SHUTDOWN(mp
))
223 xfs_ilock(dp
, XFS_ILOCK_SHARED
);
224 if (!(flags
& ATTR_SECURE
) &&
225 (error
= xfs_iaccess(dp
, S_IWUSR
, cred
))) {
226 xfs_iunlock(dp
, XFS_ILOCK_SHARED
);
227 return(XFS_ERROR(error
));
229 xfs_iunlock(dp
, XFS_ILOCK_SHARED
);
232 * Attach the dquots to the inode.
234 if ((error
= XFS_QM_DQATTACH(mp
, dp
, 0)))
238 * If the inode doesn't have an attribute fork, add one.
239 * (inode must not be locked when we call this routine)
241 if (XFS_IFORK_Q(dp
) == 0) {
242 error
= xfs_bmap_add_attrfork(dp
, rsvd
);
248 * Fill in the arg structure for this request.
250 memset((char *)&args
, 0, sizeof(args
));
252 args
.namelen
= namelen
;
254 args
.valuelen
= valuelen
;
256 args
.hashval
= xfs_da_hashname(args
.name
, args
.namelen
);
258 args
.firstblock
= &firstblock
;
260 args
.whichfork
= XFS_ATTR_FORK
;
263 /* Determine space new attribute will use, and if it will be inline
266 size
= xfs_attr_leaf_newentsize(&args
, mp
->m_sb
.sb_blocksize
, &local
);
268 nblks
= XFS_DAENTER_SPACE_RES(mp
, XFS_ATTR_FORK
);
270 if (size
> (mp
->m_sb
.sb_blocksize
>> 1)) {
271 /* Double split possible */
275 uint dblocks
= XFS_B_TO_FSB(mp
, valuelen
);
276 /* Out of line attribute, cannot double split, but make
277 * room for the attribute value itself.
280 nblks
+= XFS_NEXTENTADD_SPACE_RES(mp
, dblocks
, XFS_ATTR_FORK
);
283 /* Size is now blocks for attribute data */
287 * Start our first transaction of the day.
289 * All future transactions during this code must be "chained" off
290 * this one via the trans_dup() call. All transactions will contain
291 * the inode, and the inode will always be marked with trans_ihold().
292 * Since the inode will be locked in all transactions, we must log
293 * the inode in every transaction to let it float upward through
296 args
.trans
= xfs_trans_alloc(mp
, XFS_TRANS_ATTR_SET
);
299 * Root fork attributes can use reserved data blocks for this
300 * operation if necessary
304 args
.trans
->t_flags
|= XFS_TRANS_RESERVE
;
306 if ((error
= xfs_trans_reserve(args
.trans
, (uint
) nblks
,
307 XFS_ATTRSET_LOG_RES(mp
, nblks
),
308 0, XFS_TRANS_PERM_LOG_RES
,
309 XFS_ATTRSET_LOG_COUNT
))) {
310 xfs_trans_cancel(args
.trans
, 0);
313 xfs_ilock(dp
, XFS_ILOCK_EXCL
);
315 error
= XFS_TRANS_RESERVE_QUOTA_NBLKS(mp
, args
.trans
, dp
, nblks
, 0,
316 rsvd
? XFS_QMOPT_RES_REGBLKS
| XFS_QMOPT_FORCE_RES
:
317 XFS_QMOPT_RES_REGBLKS
);
319 xfs_iunlock(dp
, XFS_ILOCK_EXCL
);
320 xfs_trans_cancel(args
.trans
, XFS_TRANS_RELEASE_LOG_RES
);
324 xfs_trans_ijoin(args
.trans
, dp
, XFS_ILOCK_EXCL
);
325 xfs_trans_ihold(args
.trans
, dp
);
328 * If the attribute list is non-existant or a shortform list,
329 * upgrade it to a single-leaf-block attribute list.
331 if ((dp
->i_d
.di_aformat
== XFS_DINODE_FMT_LOCAL
) ||
332 ((dp
->i_d
.di_aformat
== XFS_DINODE_FMT_EXTENTS
) &&
333 (dp
->i_d
.di_anextents
== 0))) {
336 * Build initial attribute list (if required).
338 if (dp
->i_d
.di_aformat
== XFS_DINODE_FMT_EXTENTS
)
339 (void)xfs_attr_shortform_create(&args
);
342 * Try to add the attr to the attribute list in
345 error
= xfs_attr_shortform_addname(&args
);
346 if (error
!= ENOSPC
) {
348 * Commit the shortform mods, and we're done.
349 * NOTE: this is also the error path (EEXIST, etc).
351 ASSERT(args
.trans
!= NULL
);
354 * If this is a synchronous mount, make sure that
355 * the transaction goes to disk before returning
358 if (mp
->m_flags
& XFS_MOUNT_WSYNC
) {
359 xfs_trans_set_sync(args
.trans
);
361 err2
= xfs_trans_commit(args
.trans
,
362 XFS_TRANS_RELEASE_LOG_RES
,
364 xfs_iunlock(dp
, XFS_ILOCK_EXCL
);
367 * Hit the inode change time.
369 if (!error
&& (flags
& ATTR_KERNOTIME
) == 0) {
370 xfs_ichgtime(dp
, XFS_ICHGTIME_CHG
);
372 return(error
== 0 ? err2
: error
);
376 * It won't fit in the shortform, transform to a leaf block.
377 * GROT: another possible req'mt for a double-split btree op.
379 XFS_BMAP_INIT(args
.flist
, args
.firstblock
);
380 error
= xfs_attr_shortform_to_leaf(&args
);
382 error
= xfs_bmap_finish(&args
.trans
, args
.flist
,
383 *args
.firstblock
, &committed
);
388 xfs_bmap_cancel(&flist
);
393 * bmap_finish() may have committed the last trans and started
394 * a new one. We need the inode to be in all transactions.
397 xfs_trans_ijoin(args
.trans
, dp
, XFS_ILOCK_EXCL
);
398 xfs_trans_ihold(args
.trans
, dp
);
402 * Commit the leaf transformation. We'll need another (linked)
403 * transaction to add the new attribute to the leaf.
405 if ((error
= xfs_attr_rolltrans(&args
.trans
, dp
)))
410 if (xfs_bmap_one_block(dp
, XFS_ATTR_FORK
)) {
411 error
= xfs_attr_leaf_addname(&args
);
413 error
= xfs_attr_node_addname(&args
);
420 * If this is a synchronous mount, make sure that the
421 * transaction goes to disk before returning to the user.
423 if (mp
->m_flags
& XFS_MOUNT_WSYNC
) {
424 xfs_trans_set_sync(args
.trans
);
428 * Commit the last in the sequence of transactions.
430 xfs_trans_log_inode(args
.trans
, dp
, XFS_ILOG_CORE
);
431 error
= xfs_trans_commit(args
.trans
, XFS_TRANS_RELEASE_LOG_RES
,
433 xfs_iunlock(dp
, XFS_ILOCK_EXCL
);
436 * Hit the inode change time.
438 if (!error
&& (flags
& ATTR_KERNOTIME
) == 0) {
439 xfs_ichgtime(dp
, XFS_ICHGTIME_CHG
);
446 xfs_trans_cancel(args
.trans
,
447 XFS_TRANS_RELEASE_LOG_RES
|XFS_TRANS_ABORT
);
448 xfs_iunlock(dp
, XFS_ILOCK_EXCL
);
453 * Generic handler routine to remove a name from an attribute list.
454 * Transitions attribute list from Btree to shortform as necessary.
458 xfs_attr_remove(bhv_desc_t
*bdp
, char *name
, int flags
, struct cred
*cred
)
462 xfs_fsblock_t firstblock
;
463 xfs_bmap_free_t flist
;
468 ASSERT(MAXNAMELEN
-1<=0xff); /* length is stored in uint8 */
469 namelen
= strlen(name
);
470 if (namelen
>=MAXNAMELEN
)
471 return EFAULT
; /* match irix behaviour */
473 XFS_STATS_INC(xs_attr_remove
);
475 dp
= XFS_BHVTOI(bdp
);
477 if (XFS_FORCED_SHUTDOWN(mp
))
480 xfs_ilock(dp
, XFS_ILOCK_SHARED
);
481 if (!(flags
& ATTR_SECURE
) &&
482 (error
= xfs_iaccess(dp
, S_IWUSR
, cred
))) {
483 xfs_iunlock(dp
, XFS_ILOCK_SHARED
);
484 return(XFS_ERROR(error
));
485 } else if (XFS_IFORK_Q(dp
) == 0 ||
486 (dp
->i_d
.di_aformat
== XFS_DINODE_FMT_EXTENTS
&&
487 dp
->i_d
.di_anextents
== 0)) {
488 xfs_iunlock(dp
, XFS_ILOCK_SHARED
);
489 return(XFS_ERROR(ENOATTR
));
491 xfs_iunlock(dp
, XFS_ILOCK_SHARED
);
494 * Fill in the arg structure for this request.
496 memset((char *)&args
, 0, sizeof(args
));
498 args
.namelen
= namelen
;
500 args
.hashval
= xfs_da_hashname(args
.name
, args
.namelen
);
502 args
.firstblock
= &firstblock
;
505 args
.whichfork
= XFS_ATTR_FORK
;
508 * Attach the dquots to the inode.
510 if ((error
= XFS_QM_DQATTACH(mp
, dp
, 0)))
514 * Start our first transaction of the day.
516 * All future transactions during this code must be "chained" off
517 * this one via the trans_dup() call. All transactions will contain
518 * the inode, and the inode will always be marked with trans_ihold().
519 * Since the inode will be locked in all transactions, we must log
520 * the inode in every transaction to let it float upward through
523 args
.trans
= xfs_trans_alloc(mp
, XFS_TRANS_ATTR_RM
);
526 * Root fork attributes can use reserved data blocks for this
527 * operation if necessary
530 if (flags
& ATTR_ROOT
)
531 args
.trans
->t_flags
|= XFS_TRANS_RESERVE
;
533 if ((error
= xfs_trans_reserve(args
.trans
,
534 XFS_ATTRRM_SPACE_RES(mp
),
535 XFS_ATTRRM_LOG_RES(mp
),
536 0, XFS_TRANS_PERM_LOG_RES
,
537 XFS_ATTRRM_LOG_COUNT
))) {
538 xfs_trans_cancel(args
.trans
, 0);
543 xfs_ilock(dp
, XFS_ILOCK_EXCL
);
545 * No need to make quota reservations here. We expect to release some
546 * blocks not allocate in the common case.
548 xfs_trans_ijoin(args
.trans
, dp
, XFS_ILOCK_EXCL
);
549 xfs_trans_ihold(args
.trans
, dp
);
552 * Decide on what work routines to call based on the inode size.
554 if (XFS_IFORK_Q(dp
) == 0 ||
555 (dp
->i_d
.di_aformat
== XFS_DINODE_FMT_EXTENTS
&&
556 dp
->i_d
.di_anextents
== 0)) {
557 error
= XFS_ERROR(ENOATTR
);
560 if (dp
->i_d
.di_aformat
== XFS_DINODE_FMT_LOCAL
) {
561 ASSERT(dp
->i_afp
->if_flags
& XFS_IFINLINE
);
562 error
= xfs_attr_shortform_remove(&args
);
566 } else if (xfs_bmap_one_block(dp
, XFS_ATTR_FORK
)) {
567 error
= xfs_attr_leaf_removename(&args
);
569 error
= xfs_attr_node_removename(&args
);
576 * If this is a synchronous mount, make sure that the
577 * transaction goes to disk before returning to the user.
579 if (mp
->m_flags
& XFS_MOUNT_WSYNC
) {
580 xfs_trans_set_sync(args
.trans
);
584 * Commit the last in the sequence of transactions.
586 xfs_trans_log_inode(args
.trans
, dp
, XFS_ILOG_CORE
);
587 error
= xfs_trans_commit(args
.trans
, XFS_TRANS_RELEASE_LOG_RES
,
589 xfs_iunlock(dp
, XFS_ILOCK_EXCL
);
592 * Hit the inode change time.
594 if (!error
&& (flags
& ATTR_KERNOTIME
) == 0) {
595 xfs_ichgtime(dp
, XFS_ICHGTIME_CHG
);
602 xfs_trans_cancel(args
.trans
,
603 XFS_TRANS_RELEASE_LOG_RES
|XFS_TRANS_ABORT
);
604 xfs_iunlock(dp
, XFS_ILOCK_EXCL
);
609 * Generate a list of extended attribute names and optionally
610 * also value lengths. Positive return value follows the XFS
611 * convention of being an error, zero or negative return code
612 * is the length of the buffer returned (negated), indicating
616 xfs_attr_list(bhv_desc_t
*bdp
, char *buffer
, int bufsize
, int flags
,
617 attrlist_cursor_kern_t
*cursor
, struct cred
*cred
)
619 xfs_attr_list_context_t context
;
623 XFS_STATS_INC(xs_attr_list
);
626 * Validate the cursor.
628 if (cursor
->pad1
|| cursor
->pad2
)
629 return(XFS_ERROR(EINVAL
));
630 if ((cursor
->initted
== 0) &&
631 (cursor
->hashval
|| cursor
->blkno
|| cursor
->offset
))
632 return(XFS_ERROR(EINVAL
));
635 * Check for a properly aligned buffer.
637 if (((long)buffer
) & (sizeof(int)-1))
638 return(XFS_ERROR(EFAULT
));
639 if (flags
& ATTR_KERNOVAL
)
643 * Initialize the output buffer.
645 context
.dp
= dp
= XFS_BHVTOI(bdp
);
646 context
.cursor
= cursor
;
650 context
.flags
= flags
;
651 if (!(flags
& ATTR_KERNAMELS
)) {
652 context
.bufsize
= (bufsize
& ~(sizeof(int)-1)); /* align */
653 context
.firstu
= context
.bufsize
;
654 context
.alist
= (attrlist_t
*)buffer
;
655 context
.alist
->al_count
= 0;
656 context
.alist
->al_more
= 0;
657 context
.alist
->al_offset
[0] = context
.bufsize
;
660 context
.bufsize
= bufsize
;
661 context
.firstu
= context
.bufsize
;
662 context
.alist
= (attrlist_t
*)buffer
;
665 if (XFS_FORCED_SHUTDOWN(dp
->i_mount
))
668 xfs_ilock(dp
, XFS_ILOCK_SHARED
);
669 if (!(flags
& ATTR_SECURE
) &&
670 (error
= xfs_iaccess(dp
, S_IRUSR
, cred
))) {
671 xfs_iunlock(dp
, XFS_ILOCK_SHARED
);
672 return(XFS_ERROR(error
));
676 * Decide on what work routines to call based on the inode size.
678 xfs_attr_trace_l_c("syscall start", &context
);
679 if (XFS_IFORK_Q(dp
) == 0 ||
680 (dp
->i_d
.di_aformat
== XFS_DINODE_FMT_EXTENTS
&&
681 dp
->i_d
.di_anextents
== 0)) {
683 } else if (dp
->i_d
.di_aformat
== XFS_DINODE_FMT_LOCAL
) {
684 error
= xfs_attr_shortform_list(&context
);
685 } else if (xfs_bmap_one_block(dp
, XFS_ATTR_FORK
)) {
686 error
= xfs_attr_leaf_list(&context
);
688 error
= xfs_attr_node_list(&context
);
690 xfs_iunlock(dp
, XFS_ILOCK_SHARED
);
691 xfs_attr_trace_l_c("syscall end", &context
);
693 if (!(context
.flags
& (ATTR_KERNOVAL
|ATTR_KERNAMELS
))) {
696 else { /* must return negated buffer size or the error */
697 if (context
.count
< 0)
698 error
= XFS_ERROR(ERANGE
);
700 error
= -context
.count
;
707 xfs_attr_inactive(xfs_inode_t
*dp
)
714 ASSERT(! XFS_NOT_DQATTACHED(mp
, dp
));
716 xfs_ilock(dp
, XFS_ILOCK_SHARED
);
717 if ((XFS_IFORK_Q(dp
) == 0) ||
718 (dp
->i_d
.di_aformat
== XFS_DINODE_FMT_LOCAL
) ||
719 (dp
->i_d
.di_aformat
== XFS_DINODE_FMT_EXTENTS
&&
720 dp
->i_d
.di_anextents
== 0)) {
721 xfs_iunlock(dp
, XFS_ILOCK_SHARED
);
724 xfs_iunlock(dp
, XFS_ILOCK_SHARED
);
727 * Start our first transaction of the day.
729 * All future transactions during this code must be "chained" off
730 * this one via the trans_dup() call. All transactions will contain
731 * the inode, and the inode will always be marked with trans_ihold().
732 * Since the inode will be locked in all transactions, we must log
733 * the inode in every transaction to let it float upward through
736 trans
= xfs_trans_alloc(mp
, XFS_TRANS_ATTRINVAL
);
737 if ((error
= xfs_trans_reserve(trans
, 0, XFS_ATTRINVAL_LOG_RES(mp
), 0,
738 XFS_TRANS_PERM_LOG_RES
,
739 XFS_ATTRINVAL_LOG_COUNT
))) {
740 xfs_trans_cancel(trans
, 0);
743 xfs_ilock(dp
, XFS_ILOCK_EXCL
);
746 * No need to make quota reservations here. We expect to release some
747 * blocks, not allocate, in the common case.
749 xfs_trans_ijoin(trans
, dp
, XFS_ILOCK_EXCL
);
750 xfs_trans_ihold(trans
, dp
);
753 * Decide on what work routines to call based on the inode size.
755 if ((XFS_IFORK_Q(dp
) == 0) ||
756 (dp
->i_d
.di_aformat
== XFS_DINODE_FMT_LOCAL
) ||
757 (dp
->i_d
.di_aformat
== XFS_DINODE_FMT_EXTENTS
&&
758 dp
->i_d
.di_anextents
== 0)) {
762 error
= xfs_attr_root_inactive(&trans
, dp
);
766 * signal synchronous inactive transactions unless this
767 * is a synchronous mount filesystem in which case we
768 * know that we're here because we've been called out of
769 * xfs_inactive which means that the last reference is gone
770 * and the unlink transaction has already hit the disk so
771 * async inactive transactions are safe.
773 if ((error
= xfs_itruncate_finish(&trans
, dp
, 0LL, XFS_ATTR_FORK
,
774 (!(mp
->m_flags
& XFS_MOUNT_WSYNC
)
779 * Commit the last in the sequence of transactions.
781 xfs_trans_log_inode(trans
, dp
, XFS_ILOG_CORE
);
782 error
= xfs_trans_commit(trans
, XFS_TRANS_RELEASE_LOG_RES
,
784 xfs_iunlock(dp
, XFS_ILOCK_EXCL
);
789 xfs_trans_cancel(trans
, XFS_TRANS_RELEASE_LOG_RES
|XFS_TRANS_ABORT
);
790 xfs_iunlock(dp
, XFS_ILOCK_EXCL
);
796 /*========================================================================
797 * External routines when attribute list is inside the inode
798 *========================================================================*/
801 * Add a name to the shortform attribute list structure
802 * This is the external routine.
805 xfs_attr_shortform_addname(xfs_da_args_t
*args
)
809 retval
= xfs_attr_shortform_lookup(args
);
810 if ((args
->flags
& ATTR_REPLACE
) && (retval
== ENOATTR
)) {
812 } else if (retval
== EEXIST
) {
813 if (args
->flags
& ATTR_CREATE
)
815 retval
= xfs_attr_shortform_remove(args
);
819 newsize
= XFS_ATTR_SF_TOTSIZE(args
->dp
);
820 newsize
+= XFS_ATTR_SF_ENTSIZE_BYNAME(args
->namelen
, args
->valuelen
);
821 if ((newsize
<= XFS_IFORK_ASIZE(args
->dp
)) &&
822 (args
->namelen
< XFS_ATTR_SF_ENTSIZE_MAX
) &&
823 (args
->valuelen
< XFS_ATTR_SF_ENTSIZE_MAX
)) {
824 retval
= xfs_attr_shortform_add(args
);
827 return(XFS_ERROR(ENOSPC
));
833 /*========================================================================
834 * External routines when attribute list is one block
835 *========================================================================*/
838 * Add a name to the leaf attribute list structure
840 * This leaf block cannot have a "remote" value, we only call this routine
841 * if bmap_one_block() says there is only one block (ie: no remote blks).
844 xfs_attr_leaf_addname(xfs_da_args_t
*args
)
848 int retval
, error
, committed
;
851 * Read the (only) block in the attribute list in.
855 error
= xfs_da_read_buf(args
->trans
, args
->dp
, args
->blkno
, -1, &bp
,
862 * Look up the given attribute in the leaf block. Figure out if
863 * the given flags produce an error or call for an atomic rename.
865 retval
= xfs_attr_leaf_lookup_int(bp
, args
);
866 if ((args
->flags
& ATTR_REPLACE
) && (retval
== ENOATTR
)) {
867 xfs_da_brelse(args
->trans
, bp
);
869 } else if (retval
== EEXIST
) {
870 if (args
->flags
& ATTR_CREATE
) { /* pure create op */
871 xfs_da_brelse(args
->trans
, bp
);
874 args
->rename
= 1; /* an atomic rename */
875 args
->blkno2
= args
->blkno
; /* set 2nd entry info*/
876 args
->index2
= args
->index
;
877 args
->rmtblkno2
= args
->rmtblkno
;
878 args
->rmtblkcnt2
= args
->rmtblkcnt
;
882 * Add the attribute to the leaf block, transitioning to a Btree
885 retval
= xfs_attr_leaf_add(bp
, args
);
887 if (retval
== ENOSPC
) {
889 * Promote the attribute list to the Btree format, then
890 * Commit that transaction so that the node_addname() call
891 * can manage its own transactions.
893 XFS_BMAP_INIT(args
->flist
, args
->firstblock
);
894 error
= xfs_attr_leaf_to_node(args
);
896 error
= xfs_bmap_finish(&args
->trans
, args
->flist
,
897 *args
->firstblock
, &committed
);
902 xfs_bmap_cancel(args
->flist
);
907 * bmap_finish() may have committed the last trans and started
908 * a new one. We need the inode to be in all transactions.
911 xfs_trans_ijoin(args
->trans
, dp
, XFS_ILOCK_EXCL
);
912 xfs_trans_ihold(args
->trans
, dp
);
916 * Commit the current trans (including the inode) and start
919 if ((error
= xfs_attr_rolltrans(&args
->trans
, dp
)))
923 * Fob the whole rest of the problem off on the Btree code.
925 error
= xfs_attr_node_addname(args
);
930 * Commit the transaction that added the attr name so that
931 * later routines can manage their own transactions.
933 if ((error
= xfs_attr_rolltrans(&args
->trans
, dp
)))
937 * If there was an out-of-line value, allocate the blocks we
938 * identified for its storage and copy the value. This is done
939 * after we create the attribute so that we don't overflow the
940 * maximum size of a transaction and/or hit a deadlock.
942 if (args
->rmtblkno
> 0) {
943 error
= xfs_attr_rmtval_set(args
);
949 * If this is an atomic rename operation, we must "flip" the
950 * incomplete flags on the "new" and "old" attribute/value pairs
951 * so that one disappears and one appears atomically. Then we
952 * must remove the "old" attribute/value pair.
956 * In a separate transaction, set the incomplete flag on the
957 * "old" attr and clear the incomplete flag on the "new" attr.
959 error
= xfs_attr_leaf_flipflags(args
);
964 * Dismantle the "old" attribute/value pair by removing
965 * a "remote" value (if it exists).
967 args
->index
= args
->index2
;
968 args
->blkno
= args
->blkno2
;
969 args
->rmtblkno
= args
->rmtblkno2
;
970 args
->rmtblkcnt
= args
->rmtblkcnt2
;
971 if (args
->rmtblkno
) {
972 error
= xfs_attr_rmtval_remove(args
);
978 * Read in the block containing the "old" attr, then
979 * remove the "old" attr from that block (neat, huh!)
981 error
= xfs_da_read_buf(args
->trans
, args
->dp
, args
->blkno
, -1,
986 (void)xfs_attr_leaf_remove(bp
, args
);
989 * If the result is small enough, shrink it all into the inode.
991 if (xfs_attr_shortform_allfit(bp
, dp
)) {
992 XFS_BMAP_INIT(args
->flist
, args
->firstblock
);
993 error
= xfs_attr_leaf_to_shortform(bp
, args
);
994 /* bp is gone due to xfs_da_shrink_inode */
996 error
= xfs_bmap_finish(&args
->trans
,
1004 xfs_bmap_cancel(args
->flist
);
1009 * bmap_finish() may have committed the last trans
1010 * and started a new one. We need the inode to be
1011 * in all transactions.
1014 xfs_trans_ijoin(args
->trans
, dp
, XFS_ILOCK_EXCL
);
1015 xfs_trans_ihold(args
->trans
, dp
);
1018 xfs_da_buf_done(bp
);
1021 * Commit the remove and start the next trans in series.
1023 error
= xfs_attr_rolltrans(&args
->trans
, dp
);
1025 } else if (args
->rmtblkno
> 0) {
1027 * Added a "remote" value, just clear the incomplete flag.
1029 error
= xfs_attr_leaf_clearflag(args
);
1035 * Remove a name from the leaf attribute list structure
1037 * This leaf block cannot have a "remote" value, we only call this routine
1038 * if bmap_one_block() says there is only one block (ie: no remote blks).
1041 xfs_attr_leaf_removename(xfs_da_args_t
*args
)
1049 * Remove the attribute.
1053 error
= xfs_da_read_buf(args
->trans
, args
->dp
, args
->blkno
, -1, &bp
,
1060 error
= xfs_attr_leaf_lookup_int(bp
, args
);
1061 if (error
== ENOATTR
) {
1062 xfs_da_brelse(args
->trans
, bp
);
1066 (void)xfs_attr_leaf_remove(bp
, args
);
1069 * If the result is small enough, shrink it all into the inode.
1071 if (xfs_attr_shortform_allfit(bp
, dp
)) {
1072 XFS_BMAP_INIT(args
->flist
, args
->firstblock
);
1073 error
= xfs_attr_leaf_to_shortform(bp
, args
);
1074 /* bp is gone due to xfs_da_shrink_inode */
1076 error
= xfs_bmap_finish(&args
->trans
, args
->flist
,
1077 *args
->firstblock
, &committed
);
1082 xfs_bmap_cancel(args
->flist
);
1087 * bmap_finish() may have committed the last trans and started
1088 * a new one. We need the inode to be in all transactions.
1091 xfs_trans_ijoin(args
->trans
, dp
, XFS_ILOCK_EXCL
);
1092 xfs_trans_ihold(args
->trans
, dp
);
1095 xfs_da_buf_done(bp
);
1100 * Look up a name in a leaf attribute list structure.
1102 * This leaf block cannot have a "remote" value, we only call this routine
1103 * if bmap_one_block() says there is only one block (ie: no remote blks).
1106 xfs_attr_leaf_get(xfs_da_args_t
*args
)
1112 error
= xfs_da_read_buf(args
->trans
, args
->dp
, args
->blkno
, -1, &bp
,
1118 error
= xfs_attr_leaf_lookup_int(bp
, args
);
1119 if (error
!= EEXIST
) {
1120 xfs_da_brelse(args
->trans
, bp
);
1123 error
= xfs_attr_leaf_getvalue(bp
, args
);
1124 xfs_da_brelse(args
->trans
, bp
);
1125 if (!error
&& (args
->rmtblkno
> 0) && !(args
->flags
& ATTR_KERNOVAL
)) {
1126 error
= xfs_attr_rmtval_get(args
);
1132 * Copy out attribute entries for attr_list(), for leaf attribute lists.
1135 xfs_attr_leaf_list(xfs_attr_list_context_t
*context
)
1137 xfs_attr_leafblock_t
*leaf
;
1141 context
->cursor
->blkno
= 0;
1142 error
= xfs_da_read_buf(NULL
, context
->dp
, 0, -1, &bp
, XFS_ATTR_FORK
);
1147 if (unlikely(INT_GET(leaf
->hdr
.info
.magic
, ARCH_CONVERT
)
1148 != XFS_ATTR_LEAF_MAGIC
)) {
1149 XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW
,
1150 context
->dp
->i_mount
, leaf
);
1151 xfs_da_brelse(NULL
, bp
);
1152 return(XFS_ERROR(EFSCORRUPTED
));
1155 (void)xfs_attr_leaf_list_int(bp
, context
);
1156 xfs_da_brelse(NULL
, bp
);
1161 /*========================================================================
1162 * External routines when attribute list size > XFS_LBSIZE(mp).
1163 *========================================================================*/
1166 * Add a name to a Btree-format attribute list.
1168 * This will involve walking down the Btree, and may involve splitting
1169 * leaf nodes and even splitting intermediate nodes up to and including
1170 * the root node (a special case of an intermediate node).
1172 * "Remote" attribute values confuse the issue and atomic rename operations
1173 * add a whole extra layer of confusion on top of that.
1176 xfs_attr_node_addname(xfs_da_args_t
*args
)
1178 xfs_da_state_t
*state
;
1179 xfs_da_state_blk_t
*blk
;
1182 int committed
, retval
, error
;
1185 * Fill in bucket of arguments/results/context to carry around.
1190 state
= xfs_da_state_alloc();
1193 state
->blocksize
= state
->mp
->m_sb
.sb_blocksize
;
1194 state
->node_ents
= state
->mp
->m_attr_node_ents
;
1197 * Search to see if name already exists, and get back a pointer
1198 * to where it should go.
1200 error
= xfs_da_node_lookup_int(state
, &retval
);
1203 blk
= &state
->path
.blk
[ state
->path
.active
-1 ];
1204 ASSERT(blk
->magic
== XFS_ATTR_LEAF_MAGIC
);
1205 if ((args
->flags
& ATTR_REPLACE
) && (retval
== ENOATTR
)) {
1207 } else if (retval
== EEXIST
) {
1208 if (args
->flags
& ATTR_CREATE
)
1210 args
->rename
= 1; /* atomic rename op */
1211 args
->blkno2
= args
->blkno
; /* set 2nd entry info*/
1212 args
->index2
= args
->index
;
1213 args
->rmtblkno2
= args
->rmtblkno
;
1214 args
->rmtblkcnt2
= args
->rmtblkcnt
;
1216 args
->rmtblkcnt
= 0;
1219 retval
= xfs_attr_leaf_add(blk
->bp
, state
->args
);
1220 if (retval
== ENOSPC
) {
1221 if (state
->path
.active
== 1) {
1223 * Its really a single leaf node, but it had
1224 * out-of-line values so it looked like it *might*
1225 * have been a b-tree.
1227 xfs_da_state_free(state
);
1228 XFS_BMAP_INIT(args
->flist
, args
->firstblock
);
1229 error
= xfs_attr_leaf_to_node(args
);
1231 error
= xfs_bmap_finish(&args
->trans
,
1239 xfs_bmap_cancel(args
->flist
);
1244 * bmap_finish() may have committed the last trans
1245 * and started a new one. We need the inode to be
1246 * in all transactions.
1249 xfs_trans_ijoin(args
->trans
, dp
, XFS_ILOCK_EXCL
);
1250 xfs_trans_ihold(args
->trans
, dp
);
1254 * Commit the node conversion and start the next
1255 * trans in the chain.
1257 if ((error
= xfs_attr_rolltrans(&args
->trans
, dp
)))
1264 * Split as many Btree elements as required.
1265 * This code tracks the new and old attr's location
1266 * in the index/blkno/rmtblkno/rmtblkcnt fields and
1267 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
1269 XFS_BMAP_INIT(args
->flist
, args
->firstblock
);
1270 error
= xfs_da_split(state
);
1272 error
= xfs_bmap_finish(&args
->trans
, args
->flist
,
1273 *args
->firstblock
, &committed
);
1278 xfs_bmap_cancel(args
->flist
);
1283 * bmap_finish() may have committed the last trans and started
1284 * a new one. We need the inode to be in all transactions.
1287 xfs_trans_ijoin(args
->trans
, dp
, XFS_ILOCK_EXCL
);
1288 xfs_trans_ihold(args
->trans
, dp
);
1292 * Addition succeeded, update Btree hashvals.
1294 xfs_da_fixhashpath(state
, &state
->path
);
1298 * Kill the state structure, we're done with it and need to
1299 * allow the buffers to come back later.
1301 xfs_da_state_free(state
);
1305 * Commit the leaf addition or btree split and start the next
1306 * trans in the chain.
1308 if ((error
= xfs_attr_rolltrans(&args
->trans
, dp
)))
1312 * If there was an out-of-line value, allocate the blocks we
1313 * identified for its storage and copy the value. This is done
1314 * after we create the attribute so that we don't overflow the
1315 * maximum size of a transaction and/or hit a deadlock.
1317 if (args
->rmtblkno
> 0) {
1318 error
= xfs_attr_rmtval_set(args
);
1324 * If this is an atomic rename operation, we must "flip" the
1325 * incomplete flags on the "new" and "old" attribute/value pairs
1326 * so that one disappears and one appears atomically. Then we
1327 * must remove the "old" attribute/value pair.
1331 * In a separate transaction, set the incomplete flag on the
1332 * "old" attr and clear the incomplete flag on the "new" attr.
1334 error
= xfs_attr_leaf_flipflags(args
);
1339 * Dismantle the "old" attribute/value pair by removing
1340 * a "remote" value (if it exists).
1342 args
->index
= args
->index2
;
1343 args
->blkno
= args
->blkno2
;
1344 args
->rmtblkno
= args
->rmtblkno2
;
1345 args
->rmtblkcnt
= args
->rmtblkcnt2
;
1346 if (args
->rmtblkno
) {
1347 error
= xfs_attr_rmtval_remove(args
);
1353 * Re-find the "old" attribute entry after any split ops.
1354 * The INCOMPLETE flag means that we will find the "old"
1355 * attr, not the "new" one.
1357 args
->flags
|= XFS_ATTR_INCOMPLETE
;
1358 state
= xfs_da_state_alloc();
1361 state
->blocksize
= state
->mp
->m_sb
.sb_blocksize
;
1362 state
->node_ents
= state
->mp
->m_attr_node_ents
;
1364 error
= xfs_da_node_lookup_int(state
, &retval
);
1369 * Remove the name and update the hashvals in the tree.
1371 blk
= &state
->path
.blk
[ state
->path
.active
-1 ];
1372 ASSERT(blk
->magic
== XFS_ATTR_LEAF_MAGIC
);
1373 error
= xfs_attr_leaf_remove(blk
->bp
, args
);
1374 xfs_da_fixhashpath(state
, &state
->path
);
1377 * Check to see if the tree needs to be collapsed.
1379 if (retval
&& (state
->path
.active
> 1)) {
1380 XFS_BMAP_INIT(args
->flist
, args
->firstblock
);
1381 error
= xfs_da_join(state
);
1383 error
= xfs_bmap_finish(&args
->trans
,
1391 xfs_bmap_cancel(args
->flist
);
1396 * bmap_finish() may have committed the last trans
1397 * and started a new one. We need the inode to be
1398 * in all transactions.
1401 xfs_trans_ijoin(args
->trans
, dp
, XFS_ILOCK_EXCL
);
1402 xfs_trans_ihold(args
->trans
, dp
);
1407 * Commit and start the next trans in the chain.
1409 if ((error
= xfs_attr_rolltrans(&args
->trans
, dp
)))
1412 } else if (args
->rmtblkno
> 0) {
1414 * Added a "remote" value, just clear the incomplete flag.
1416 error
= xfs_attr_leaf_clearflag(args
);
1424 xfs_da_state_free(state
);
1431 * Remove a name from a B-tree attribute list.
1433 * This will involve walking down the Btree, and may involve joining
1434 * leaf nodes and even joining intermediate nodes up to and including
1435 * the root node (a special case of an intermediate node).
1438 xfs_attr_node_removename(xfs_da_args_t
*args
)
1440 xfs_da_state_t
*state
;
1441 xfs_da_state_blk_t
*blk
;
1444 int retval
, error
, committed
;
1447 * Tie a string around our finger to remind us where we are.
1450 state
= xfs_da_state_alloc();
1452 state
->mp
= dp
->i_mount
;
1453 state
->blocksize
= state
->mp
->m_sb
.sb_blocksize
;
1454 state
->node_ents
= state
->mp
->m_attr_node_ents
;
1457 * Search to see if name exists, and get back a pointer to it.
1459 error
= xfs_da_node_lookup_int(state
, &retval
);
1460 if (error
|| (retval
!= EEXIST
)) {
1467 * If there is an out-of-line value, de-allocate the blocks.
1468 * This is done before we remove the attribute so that we don't
1469 * overflow the maximum size of a transaction and/or hit a deadlock.
1471 blk
= &state
->path
.blk
[ state
->path
.active
-1 ];
1472 ASSERT(blk
->bp
!= NULL
);
1473 ASSERT(blk
->magic
== XFS_ATTR_LEAF_MAGIC
);
1474 if (args
->rmtblkno
> 0) {
1476 * Fill in disk block numbers in the state structure
1477 * so that we can get the buffers back after we commit
1478 * several transactions in the following calls.
1480 error
= xfs_attr_fillstate(state
);
1485 * Mark the attribute as INCOMPLETE, then bunmapi() the
1488 error
= xfs_attr_leaf_setflag(args
);
1491 error
= xfs_attr_rmtval_remove(args
);
1496 * Refill the state structure with buffers, the prior calls
1497 * released our buffers.
1499 error
= xfs_attr_refillstate(state
);
1505 * Remove the name and update the hashvals in the tree.
1507 blk
= &state
->path
.blk
[ state
->path
.active
-1 ];
1508 ASSERT(blk
->magic
== XFS_ATTR_LEAF_MAGIC
);
1509 retval
= xfs_attr_leaf_remove(blk
->bp
, args
);
1510 xfs_da_fixhashpath(state
, &state
->path
);
1513 * Check to see if the tree needs to be collapsed.
1515 if (retval
&& (state
->path
.active
> 1)) {
1516 XFS_BMAP_INIT(args
->flist
, args
->firstblock
);
1517 error
= xfs_da_join(state
);
1519 error
= xfs_bmap_finish(&args
->trans
, args
->flist
,
1520 *args
->firstblock
, &committed
);
1525 xfs_bmap_cancel(args
->flist
);
1530 * bmap_finish() may have committed the last trans and started
1531 * a new one. We need the inode to be in all transactions.
1534 xfs_trans_ijoin(args
->trans
, dp
, XFS_ILOCK_EXCL
);
1535 xfs_trans_ihold(args
->trans
, dp
);
1539 * Commit the Btree join operation and start a new trans.
1541 if ((error
= xfs_attr_rolltrans(&args
->trans
, dp
)))
1546 * If the result is small enough, push it all into the inode.
1548 if (xfs_bmap_one_block(dp
, XFS_ATTR_FORK
)) {
1550 * Have to get rid of the copy of this dabuf in the state.
1552 ASSERT(state
->path
.active
== 1);
1553 ASSERT(state
->path
.blk
[0].bp
);
1554 xfs_da_buf_done(state
->path
.blk
[0].bp
);
1555 state
->path
.blk
[0].bp
= NULL
;
1557 error
= xfs_da_read_buf(args
->trans
, args
->dp
, 0, -1, &bp
,
1561 ASSERT(INT_GET(((xfs_attr_leafblock_t
*)
1562 bp
->data
)->hdr
.info
.magic
, ARCH_CONVERT
)
1563 == XFS_ATTR_LEAF_MAGIC
);
1565 if (xfs_attr_shortform_allfit(bp
, dp
)) {
1566 XFS_BMAP_INIT(args
->flist
, args
->firstblock
);
1567 error
= xfs_attr_leaf_to_shortform(bp
, args
);
1568 /* bp is gone due to xfs_da_shrink_inode */
1570 error
= xfs_bmap_finish(&args
->trans
,
1578 xfs_bmap_cancel(args
->flist
);
1583 * bmap_finish() may have committed the last trans
1584 * and started a new one. We need the inode to be
1585 * in all transactions.
1588 xfs_trans_ijoin(args
->trans
, dp
, XFS_ILOCK_EXCL
);
1589 xfs_trans_ihold(args
->trans
, dp
);
1592 xfs_da_brelse(args
->trans
, bp
);
1597 xfs_da_state_free(state
);
1602 * Fill in the disk block numbers in the state structure for the buffers
1603 * that are attached to the state structure.
1604 * This is done so that we can quickly reattach ourselves to those buffers
1605 * after some set of transaction commit's has released these buffers.
1608 xfs_attr_fillstate(xfs_da_state_t
*state
)
1610 xfs_da_state_path_t
*path
;
1611 xfs_da_state_blk_t
*blk
;
1615 * Roll down the "path" in the state structure, storing the on-disk
1616 * block number for those buffers in the "path".
1618 path
= &state
->path
;
1619 ASSERT((path
->active
>= 0) && (path
->active
< XFS_DA_NODE_MAXDEPTH
));
1620 for (blk
= path
->blk
, level
= 0; level
< path
->active
; blk
++, level
++) {
1622 blk
->disk_blkno
= xfs_da_blkno(blk
->bp
);
1623 xfs_da_buf_done(blk
->bp
);
1626 blk
->disk_blkno
= 0;
1631 * Roll down the "altpath" in the state structure, storing the on-disk
1632 * block number for those buffers in the "altpath".
1634 path
= &state
->altpath
;
1635 ASSERT((path
->active
>= 0) && (path
->active
< XFS_DA_NODE_MAXDEPTH
));
1636 for (blk
= path
->blk
, level
= 0; level
< path
->active
; blk
++, level
++) {
1638 blk
->disk_blkno
= xfs_da_blkno(blk
->bp
);
1639 xfs_da_buf_done(blk
->bp
);
1642 blk
->disk_blkno
= 0;
1650 * Reattach the buffers to the state structure based on the disk block
1651 * numbers stored in the state structure.
1652 * This is done after some set of transaction commit's has released those
1653 * buffers from our grip.
1656 xfs_attr_refillstate(xfs_da_state_t
*state
)
1658 xfs_da_state_path_t
*path
;
1659 xfs_da_state_blk_t
*blk
;
1663 * Roll down the "path" in the state structure, storing the on-disk
1664 * block number for those buffers in the "path".
1666 path
= &state
->path
;
1667 ASSERT((path
->active
>= 0) && (path
->active
< XFS_DA_NODE_MAXDEPTH
));
1668 for (blk
= path
->blk
, level
= 0; level
< path
->active
; blk
++, level
++) {
1669 if (blk
->disk_blkno
) {
1670 error
= xfs_da_read_buf(state
->args
->trans
,
1672 blk
->blkno
, blk
->disk_blkno
,
1673 &blk
->bp
, XFS_ATTR_FORK
);
1682 * Roll down the "altpath" in the state structure, storing the on-disk
1683 * block number for those buffers in the "altpath".
1685 path
= &state
->altpath
;
1686 ASSERT((path
->active
>= 0) && (path
->active
< XFS_DA_NODE_MAXDEPTH
));
1687 for (blk
= path
->blk
, level
= 0; level
< path
->active
; blk
++, level
++) {
1688 if (blk
->disk_blkno
) {
1689 error
= xfs_da_read_buf(state
->args
->trans
,
1691 blk
->blkno
, blk
->disk_blkno
,
1692 &blk
->bp
, XFS_ATTR_FORK
);
1704 * Look up a filename in a node attribute list.
1706 * This routine gets called for any attribute fork that has more than one
1707 * block, ie: both true Btree attr lists and for single-leaf-blocks with
1708 * "remote" values taking up more blocks.
1711 xfs_attr_node_get(xfs_da_args_t
*args
)
1713 xfs_da_state_t
*state
;
1714 xfs_da_state_blk_t
*blk
;
1718 state
= xfs_da_state_alloc();
1720 state
->mp
= args
->dp
->i_mount
;
1721 state
->blocksize
= state
->mp
->m_sb
.sb_blocksize
;
1722 state
->node_ents
= state
->mp
->m_attr_node_ents
;
1725 * Search to see if name exists, and get back a pointer to it.
1727 error
= xfs_da_node_lookup_int(state
, &retval
);
1730 } else if (retval
== EEXIST
) {
1731 blk
= &state
->path
.blk
[ state
->path
.active
-1 ];
1732 ASSERT(blk
->bp
!= NULL
);
1733 ASSERT(blk
->magic
== XFS_ATTR_LEAF_MAGIC
);
1736 * Get the value, local or "remote"
1738 retval
= xfs_attr_leaf_getvalue(blk
->bp
, args
);
1739 if (!retval
&& (args
->rmtblkno
> 0)
1740 && !(args
->flags
& ATTR_KERNOVAL
)) {
1741 retval
= xfs_attr_rmtval_get(args
);
1746 * If not in a transaction, we have to release all the buffers.
1748 for (i
= 0; i
< state
->path
.active
; i
++) {
1749 xfs_da_brelse(args
->trans
, state
->path
.blk
[i
].bp
);
1750 state
->path
.blk
[i
].bp
= NULL
;
1753 xfs_da_state_free(state
);
1757 STATIC
int /* error */
1758 xfs_attr_node_list(xfs_attr_list_context_t
*context
)
1760 attrlist_cursor_kern_t
*cursor
;
1761 xfs_attr_leafblock_t
*leaf
;
1762 xfs_da_intnode_t
*node
;
1763 xfs_da_node_entry_t
*btree
;
1767 cursor
= context
->cursor
;
1768 cursor
->initted
= 1;
1771 * Do all sorts of validation on the passed-in cursor structure.
1772 * If anything is amiss, ignore the cursor and look up the hashval
1773 * starting from the btree root.
1776 if (cursor
->blkno
> 0) {
1777 error
= xfs_da_read_buf(NULL
, context
->dp
, cursor
->blkno
, -1,
1778 &bp
, XFS_ATTR_FORK
);
1779 if ((error
!= 0) && (error
!= EFSCORRUPTED
))
1783 switch (INT_GET(node
->hdr
.info
.magic
, ARCH_CONVERT
)) {
1784 case XFS_DA_NODE_MAGIC
:
1785 xfs_attr_trace_l_cn("wrong blk", context
, node
);
1786 xfs_da_brelse(NULL
, bp
);
1789 case XFS_ATTR_LEAF_MAGIC
:
1791 if (cursor
->hashval
>
1792 INT_GET(leaf
->entries
[
1793 INT_GET(leaf
->hdr
.count
,
1794 ARCH_CONVERT
)-1].hashval
,
1796 xfs_attr_trace_l_cl("wrong blk",
1798 xfs_da_brelse(NULL
, bp
);
1800 } else if (cursor
->hashval
<=
1801 INT_GET(leaf
->entries
[0].hashval
,
1803 xfs_attr_trace_l_cl("maybe wrong blk",
1805 xfs_da_brelse(NULL
, bp
);
1810 xfs_attr_trace_l_c("wrong blk - ??", context
);
1811 xfs_da_brelse(NULL
, bp
);
1818 * We did not find what we expected given the cursor's contents,
1819 * so we start from the top and work down based on the hash value.
1820 * Note that start of node block is same as start of leaf block.
1825 error
= xfs_da_read_buf(NULL
, context
->dp
,
1826 cursor
->blkno
, -1, &bp
,
1830 if (unlikely(bp
== NULL
)) {
1831 XFS_ERROR_REPORT("xfs_attr_node_list(2)",
1833 context
->dp
->i_mount
);
1834 return(XFS_ERROR(EFSCORRUPTED
));
1837 if (INT_GET(node
->hdr
.info
.magic
, ARCH_CONVERT
)
1838 == XFS_ATTR_LEAF_MAGIC
)
1840 if (unlikely(INT_GET(node
->hdr
.info
.magic
, ARCH_CONVERT
)
1841 != XFS_DA_NODE_MAGIC
)) {
1842 XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)",
1844 context
->dp
->i_mount
,
1846 xfs_da_brelse(NULL
, bp
);
1847 return(XFS_ERROR(EFSCORRUPTED
));
1849 btree
= node
->btree
;
1851 i
< INT_GET(node
->hdr
.count
, ARCH_CONVERT
);
1854 <= INT_GET(btree
->hashval
,
1856 cursor
->blkno
= INT_GET(btree
->before
, ARCH_CONVERT
);
1857 xfs_attr_trace_l_cb("descending",
1862 if (i
== INT_GET(node
->hdr
.count
, ARCH_CONVERT
)) {
1863 xfs_da_brelse(NULL
, bp
);
1866 xfs_da_brelse(NULL
, bp
);
1872 * Roll upward through the blocks, processing each leaf block in
1873 * order. As long as there is space in the result buffer, keep
1874 * adding the information.
1878 if (unlikely(INT_GET(leaf
->hdr
.info
.magic
, ARCH_CONVERT
)
1879 != XFS_ATTR_LEAF_MAGIC
)) {
1880 XFS_CORRUPTION_ERROR("xfs_attr_node_list(4)",
1882 context
->dp
->i_mount
, leaf
);
1883 xfs_da_brelse(NULL
, bp
);
1884 return(XFS_ERROR(EFSCORRUPTED
));
1886 error
= xfs_attr_leaf_list_int(bp
, context
);
1887 if (error
|| !leaf
->hdr
.info
.forw
)
1888 break; /* not really an error, buffer full or EOF */
1889 cursor
->blkno
= INT_GET(leaf
->hdr
.info
.forw
, ARCH_CONVERT
);
1890 xfs_da_brelse(NULL
, bp
);
1891 error
= xfs_da_read_buf(NULL
, context
->dp
, cursor
->blkno
, -1,
1892 &bp
, XFS_ATTR_FORK
);
1895 if (unlikely((bp
== NULL
))) {
1896 XFS_ERROR_REPORT("xfs_attr_node_list(5)",
1898 context
->dp
->i_mount
);
1899 return(XFS_ERROR(EFSCORRUPTED
));
1902 xfs_da_brelse(NULL
, bp
);
1907 /*========================================================================
1908 * External routines for manipulating out-of-line attribute values.
1909 *========================================================================*/
1912 * Read the value associated with an attribute from the out-of-line buffer
1913 * that we stored it in.
1916 xfs_attr_rmtval_get(xfs_da_args_t
*args
)
1918 xfs_bmbt_irec_t map
[ATTR_RMTVALUE_MAPSIZE
];
1923 int nmap
, error
, tmp
, valuelen
, blkcnt
, i
;
1926 ASSERT(!(args
->flags
& ATTR_KERNOVAL
));
1928 mp
= args
->dp
->i_mount
;
1930 valuelen
= args
->valuelen
;
1931 lblkno
= args
->rmtblkno
;
1932 while (valuelen
> 0) {
1933 nmap
= ATTR_RMTVALUE_MAPSIZE
;
1934 error
= xfs_bmapi(args
->trans
, args
->dp
, (xfs_fileoff_t
)lblkno
,
1936 XFS_BMAPI_ATTRFORK
| XFS_BMAPI_METADATA
,
1937 NULL
, 0, map
, &nmap
, NULL
);
1942 for (i
= 0; (i
< nmap
) && (valuelen
> 0); i
++) {
1943 ASSERT((map
[i
].br_startblock
!= DELAYSTARTBLOCK
) &&
1944 (map
[i
].br_startblock
!= HOLESTARTBLOCK
));
1945 dblkno
= XFS_FSB_TO_DADDR(mp
, map
[i
].br_startblock
);
1946 blkcnt
= XFS_FSB_TO_BB(mp
, map
[i
].br_blockcount
);
1947 error
= xfs_read_buf(mp
, mp
->m_ddev_targp
, dblkno
,
1948 blkcnt
, XFS_BUF_LOCK
, &bp
);
1952 tmp
= (valuelen
< XFS_BUF_SIZE(bp
))
1953 ? valuelen
: XFS_BUF_SIZE(bp
);
1954 xfs_biomove(bp
, 0, tmp
, dst
, XFS_B_READ
);
1959 lblkno
+= map
[i
].br_blockcount
;
1962 ASSERT(valuelen
== 0);
1967 * Write the value associated with an attribute into the out-of-line buffer
1968 * that we have defined for it.
1971 xfs_attr_rmtval_set(xfs_da_args_t
*args
)
1974 xfs_fileoff_t lfileoff
;
1976 xfs_bmbt_irec_t map
;
1981 int blkcnt
, valuelen
, nmap
, error
, tmp
, committed
;
1988 * Find a "hole" in the attribute address space large enough for
1989 * us to drop the new attribute's value into.
1991 blkcnt
= XFS_B_TO_FSB(mp
, args
->valuelen
);
1993 error
= xfs_bmap_first_unused(args
->trans
, args
->dp
, blkcnt
, &lfileoff
,
1998 args
->rmtblkno
= lblkno
= (xfs_dablk_t
)lfileoff
;
1999 args
->rmtblkcnt
= blkcnt
;
2002 * Roll through the "value", allocating blocks on disk as required.
2004 while (blkcnt
> 0) {
2006 * Allocate a single extent, up to the size of the value.
2008 XFS_BMAP_INIT(args
->flist
, args
->firstblock
);
2010 error
= xfs_bmapi(args
->trans
, dp
, (xfs_fileoff_t
)lblkno
,
2012 XFS_BMAPI_ATTRFORK
| XFS_BMAPI_METADATA
|
2014 args
->firstblock
, args
->total
, &map
, &nmap
,
2017 error
= xfs_bmap_finish(&args
->trans
, args
->flist
,
2018 *args
->firstblock
, &committed
);
2023 xfs_bmap_cancel(args
->flist
);
2028 * bmap_finish() may have committed the last trans and started
2029 * a new one. We need the inode to be in all transactions.
2032 xfs_trans_ijoin(args
->trans
, dp
, XFS_ILOCK_EXCL
);
2033 xfs_trans_ihold(args
->trans
, dp
);
2037 ASSERT((map
.br_startblock
!= DELAYSTARTBLOCK
) &&
2038 (map
.br_startblock
!= HOLESTARTBLOCK
));
2039 lblkno
+= map
.br_blockcount
;
2040 blkcnt
-= map
.br_blockcount
;
2043 * Start the next trans in the chain.
2045 if ((error
= xfs_attr_rolltrans(&args
->trans
, dp
)))
2050 * Roll through the "value", copying the attribute value to the
2051 * already-allocated blocks. Blocks are written synchronously
2052 * so that we can know they are all on disk before we turn off
2053 * the INCOMPLETE flag.
2055 lblkno
= args
->rmtblkno
;
2056 valuelen
= args
->valuelen
;
2057 while (valuelen
> 0) {
2059 * Try to remember where we decided to put the value.
2061 XFS_BMAP_INIT(args
->flist
, args
->firstblock
);
2063 error
= xfs_bmapi(NULL
, dp
, (xfs_fileoff_t
)lblkno
,
2065 XFS_BMAPI_ATTRFORK
| XFS_BMAPI_METADATA
,
2066 args
->firstblock
, 0, &map
, &nmap
, NULL
);
2071 ASSERT((map
.br_startblock
!= DELAYSTARTBLOCK
) &&
2072 (map
.br_startblock
!= HOLESTARTBLOCK
));
2074 dblkno
= XFS_FSB_TO_DADDR(mp
, map
.br_startblock
),
2075 blkcnt
= XFS_FSB_TO_BB(mp
, map
.br_blockcount
);
2077 bp
= xfs_buf_get_flags(mp
->m_ddev_targp
, dblkno
,
2078 blkcnt
, XFS_BUF_LOCK
);
2080 ASSERT(!XFS_BUF_GETERROR(bp
));
2082 tmp
= (valuelen
< XFS_BUF_SIZE(bp
)) ? valuelen
:
2084 xfs_biomove(bp
, 0, tmp
, src
, XFS_B_WRITE
);
2085 if (tmp
< XFS_BUF_SIZE(bp
))
2086 xfs_biozero(bp
, tmp
, XFS_BUF_SIZE(bp
) - tmp
);
2087 if ((error
= xfs_bwrite(mp
, bp
))) {/* GROT: NOTE: synchronous write */
2093 lblkno
+= map
.br_blockcount
;
2095 ASSERT(valuelen
== 0);
2100 * Remove the value associated with an attribute by deleting the
2101 * out-of-line buffer that it is stored on.
2104 xfs_attr_rmtval_remove(xfs_da_args_t
*args
)
2107 xfs_bmbt_irec_t map
;
2111 int valuelen
, blkcnt
, nmap
, error
, done
, committed
;
2113 mp
= args
->dp
->i_mount
;
2116 * Roll through the "value", invalidating the attribute value's
2119 lblkno
= args
->rmtblkno
;
2120 valuelen
= args
->rmtblkcnt
;
2121 while (valuelen
> 0) {
2123 * Try to remember where we decided to put the value.
2125 XFS_BMAP_INIT(args
->flist
, args
->firstblock
);
2127 error
= xfs_bmapi(NULL
, args
->dp
, (xfs_fileoff_t
)lblkno
,
2129 XFS_BMAPI_ATTRFORK
| XFS_BMAPI_METADATA
,
2130 args
->firstblock
, 0, &map
, &nmap
,
2136 ASSERT((map
.br_startblock
!= DELAYSTARTBLOCK
) &&
2137 (map
.br_startblock
!= HOLESTARTBLOCK
));
2139 dblkno
= XFS_FSB_TO_DADDR(mp
, map
.br_startblock
),
2140 blkcnt
= XFS_FSB_TO_BB(mp
, map
.br_blockcount
);
2143 * If the "remote" value is in the cache, remove it.
2145 bp
= xfs_incore(mp
->m_ddev_targp
, dblkno
, blkcnt
,
2146 XFS_INCORE_TRYLOCK
);
2149 XFS_BUF_UNDELAYWRITE(bp
);
2154 valuelen
-= map
.br_blockcount
;
2156 lblkno
+= map
.br_blockcount
;
2160 * Keep de-allocating extents until the remote-value region is gone.
2162 lblkno
= args
->rmtblkno
;
2163 blkcnt
= args
->rmtblkcnt
;
2166 XFS_BMAP_INIT(args
->flist
, args
->firstblock
);
2167 error
= xfs_bunmapi(args
->trans
, args
->dp
, lblkno
, blkcnt
,
2168 XFS_BMAPI_ATTRFORK
| XFS_BMAPI_METADATA
,
2169 1, args
->firstblock
, args
->flist
, &done
);
2171 error
= xfs_bmap_finish(&args
->trans
, args
->flist
,
2172 *args
->firstblock
, &committed
);
2177 xfs_bmap_cancel(args
->flist
);
2182 * bmap_finish() may have committed the last trans and started
2183 * a new one. We need the inode to be in all transactions.
2186 xfs_trans_ijoin(args
->trans
, args
->dp
, XFS_ILOCK_EXCL
);
2187 xfs_trans_ihold(args
->trans
, args
->dp
);
2191 * Close out trans and start the next one in the chain.
2193 if ((error
= xfs_attr_rolltrans(&args
->trans
, args
->dp
)))
2199 #if defined(XFS_ATTR_TRACE)
2201 * Add a trace buffer entry for an attr_list context structure.
2204 xfs_attr_trace_l_c(char *where
, struct xfs_attr_list_context
*context
)
2206 xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C
, where
,
2207 (__psunsigned_t
)context
->dp
,
2208 (__psunsigned_t
)context
->cursor
->hashval
,
2209 (__psunsigned_t
)context
->cursor
->blkno
,
2210 (__psunsigned_t
)context
->cursor
->offset
,
2211 (__psunsigned_t
)context
->alist
,
2212 (__psunsigned_t
)context
->bufsize
,
2213 (__psunsigned_t
)context
->count
,
2214 (__psunsigned_t
)context
->firstu
,
2216 ((context
->count
> 0) &&
2217 !(context
->flags
& (ATTR_KERNAMELS
|ATTR_KERNOVAL
)))
2218 ? (ATTR_ENTRY(context
->alist
,
2219 context
->count
-1)->a_valuelen
)
2221 (__psunsigned_t
)context
->dupcnt
,
2222 (__psunsigned_t
)context
->flags
,
2223 (__psunsigned_t
)NULL
,
2224 (__psunsigned_t
)NULL
,
2225 (__psunsigned_t
)NULL
);
2229 * Add a trace buffer entry for a context structure and a Btree node.
2232 xfs_attr_trace_l_cn(char *where
, struct xfs_attr_list_context
*context
,
2233 struct xfs_da_intnode
*node
)
2235 xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN
, where
,
2236 (__psunsigned_t
)context
->dp
,
2237 (__psunsigned_t
)context
->cursor
->hashval
,
2238 (__psunsigned_t
)context
->cursor
->blkno
,
2239 (__psunsigned_t
)context
->cursor
->offset
,
2240 (__psunsigned_t
)context
->alist
,
2241 (__psunsigned_t
)context
->bufsize
,
2242 (__psunsigned_t
)context
->count
,
2243 (__psunsigned_t
)context
->firstu
,
2245 ((context
->count
> 0) &&
2246 !(context
->flags
& (ATTR_KERNAMELS
|ATTR_KERNOVAL
)))
2247 ? (ATTR_ENTRY(context
->alist
,
2248 context
->count
-1)->a_valuelen
)
2250 (__psunsigned_t
)context
->dupcnt
,
2251 (__psunsigned_t
)context
->flags
,
2252 (__psunsigned_t
)INT_GET(node
->hdr
.count
, ARCH_CONVERT
),
2253 (__psunsigned_t
)INT_GET(node
->btree
[0].hashval
, ARCH_CONVERT
),
2254 (__psunsigned_t
)INT_GET(node
->btree
[INT_GET(node
->hdr
.count
, ARCH_CONVERT
)-1].hashval
, ARCH_CONVERT
));
2258 * Add a trace buffer entry for a context structure and a Btree element.
2261 xfs_attr_trace_l_cb(char *where
, struct xfs_attr_list_context
*context
,
2262 struct xfs_da_node_entry
*btree
)
2264 xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB
, where
,
2265 (__psunsigned_t
)context
->dp
,
2266 (__psunsigned_t
)context
->cursor
->hashval
,
2267 (__psunsigned_t
)context
->cursor
->blkno
,
2268 (__psunsigned_t
)context
->cursor
->offset
,
2269 (__psunsigned_t
)context
->alist
,
2270 (__psunsigned_t
)context
->bufsize
,
2271 (__psunsigned_t
)context
->count
,
2272 (__psunsigned_t
)context
->firstu
,
2274 ((context
->count
> 0) &&
2275 !(context
->flags
& (ATTR_KERNAMELS
|ATTR_KERNOVAL
)))
2276 ? (ATTR_ENTRY(context
->alist
,
2277 context
->count
-1)->a_valuelen
)
2279 (__psunsigned_t
)context
->dupcnt
,
2280 (__psunsigned_t
)context
->flags
,
2281 (__psunsigned_t
)INT_GET(btree
->hashval
, ARCH_CONVERT
),
2282 (__psunsigned_t
)INT_GET(btree
->before
, ARCH_CONVERT
),
2283 (__psunsigned_t
)NULL
);
2287 * Add a trace buffer entry for a context structure and a leaf block.
2290 xfs_attr_trace_l_cl(char *where
, struct xfs_attr_list_context
*context
,
2291 struct xfs_attr_leafblock
*leaf
)
2293 xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL
, where
,
2294 (__psunsigned_t
)context
->dp
,
2295 (__psunsigned_t
)context
->cursor
->hashval
,
2296 (__psunsigned_t
)context
->cursor
->blkno
,
2297 (__psunsigned_t
)context
->cursor
->offset
,
2298 (__psunsigned_t
)context
->alist
,
2299 (__psunsigned_t
)context
->bufsize
,
2300 (__psunsigned_t
)context
->count
,
2301 (__psunsigned_t
)context
->firstu
,
2303 ((context
->count
> 0) &&
2304 !(context
->flags
& (ATTR_KERNAMELS
|ATTR_KERNOVAL
)))
2305 ? (ATTR_ENTRY(context
->alist
,
2306 context
->count
-1)->a_valuelen
)
2308 (__psunsigned_t
)context
->dupcnt
,
2309 (__psunsigned_t
)context
->flags
,
2310 (__psunsigned_t
)INT_GET(leaf
->hdr
.count
, ARCH_CONVERT
),
2311 (__psunsigned_t
)INT_GET(leaf
->entries
[0].hashval
, ARCH_CONVERT
),
2312 (__psunsigned_t
)INT_GET(leaf
->entries
[INT_GET(leaf
->hdr
.count
, ARCH_CONVERT
)-1].hashval
, ARCH_CONVERT
));
2316 * Add a trace buffer entry for the arguments given to the routine,
2320 xfs_attr_trace_enter(int type
, char *where
,
2321 __psunsigned_t a2
, __psunsigned_t a3
,
2322 __psunsigned_t a4
, __psunsigned_t a5
,
2323 __psunsigned_t a6
, __psunsigned_t a7
,
2324 __psunsigned_t a8
, __psunsigned_t a9
,
2325 __psunsigned_t a10
, __psunsigned_t a11
,
2326 __psunsigned_t a12
, __psunsigned_t a13
,
2327 __psunsigned_t a14
, __psunsigned_t a15
)
2329 ASSERT(xfs_attr_trace_buf
);
2330 ktrace_enter(xfs_attr_trace_buf
, (void *)((__psunsigned_t
)type
),
2332 (void *)a2
, (void *)a3
, (void *)a4
,
2333 (void *)a5
, (void *)a6
, (void *)a7
,
2334 (void *)a8
, (void *)a9
, (void *)a10
,
2335 (void *)a11
, (void *)a12
, (void *)a13
,
2336 (void *)a14
, (void *)a15
);
2338 #endif /* XFS_ATTR_TRACE */
2341 /*========================================================================
2342 * System (pseudo) namespace attribute interface routines.
2343 *========================================================================*/
2346 posix_acl_access_set(
2347 vnode_t
*vp
, char *name
, void *data
, size_t size
, int xflags
)
2349 return xfs_acl_vset(vp
, data
, size
, _ACL_TYPE_ACCESS
);
2353 posix_acl_access_remove(
2354 struct vnode
*vp
, char *name
, int xflags
)
2356 return xfs_acl_vremove(vp
, _ACL_TYPE_ACCESS
);
2360 posix_acl_access_get(
2361 vnode_t
*vp
, char *name
, void *data
, size_t size
, int xflags
)
2363 return xfs_acl_vget(vp
, data
, size
, _ACL_TYPE_ACCESS
);
2367 posix_acl_access_exists(
2370 return xfs_acl_vhasacl_access(vp
);
2374 posix_acl_default_set(
2375 vnode_t
*vp
, char *name
, void *data
, size_t size
, int xflags
)
2377 return xfs_acl_vset(vp
, data
, size
, _ACL_TYPE_DEFAULT
);
2381 posix_acl_default_get(
2382 vnode_t
*vp
, char *name
, void *data
, size_t size
, int xflags
)
2384 return xfs_acl_vget(vp
, data
, size
, _ACL_TYPE_DEFAULT
);
2388 posix_acl_default_remove(
2389 struct vnode
*vp
, char *name
, int xflags
)
2391 return xfs_acl_vremove(vp
, _ACL_TYPE_DEFAULT
);
2395 posix_acl_default_exists(
2398 return xfs_acl_vhasacl_default(vp
);
2401 struct attrnames posix_acl_access
= {
2402 .attr_name
= "posix_acl_access",
2403 .attr_namelen
= sizeof("posix_acl_access") - 1,
2404 .attr_get
= posix_acl_access_get
,
2405 .attr_set
= posix_acl_access_set
,
2406 .attr_remove
= posix_acl_access_remove
,
2407 .attr_exists
= posix_acl_access_exists
,
2410 struct attrnames posix_acl_default
= {
2411 .attr_name
= "posix_acl_default",
2412 .attr_namelen
= sizeof("posix_acl_default") - 1,
2413 .attr_get
= posix_acl_default_get
,
2414 .attr_set
= posix_acl_default_set
,
2415 .attr_remove
= posix_acl_default_remove
,
2416 .attr_exists
= posix_acl_default_exists
,
2419 struct attrnames
*attr_system_names
[] =
2420 { &posix_acl_access
, &posix_acl_default
};
2423 /*========================================================================
2424 * Namespace-prefix-style attribute name interface routines.
2425 *========================================================================*/
2429 struct vnode
*vp
, char *name
, void *data
, size_t size
, int xflags
)
2433 VOP_ATTR_SET(vp
, name
, data
, size
, xflags
, NULL
, error
);
2439 struct vnode
*vp
, char *name
, void *data
, size_t size
, int xflags
)
2441 int error
, asize
= size
;
2443 VOP_ATTR_GET(vp
, name
, data
, &asize
, xflags
, NULL
, error
);
2450 attr_generic_remove(
2451 struct vnode
*vp
, char *name
, int xflags
)
2455 VOP_ATTR_REMOVE(vp
, name
, xflags
, NULL
, error
);
2460 attr_generic_listadd(
2461 attrnames_t
*prefix
,
2462 attrnames_t
*namesp
,
2467 char *p
= data
+ *result
;
2469 *result
+= prefix
->attr_namelen
;
2470 *result
+= namesp
->attr_namelen
+ 1;
2475 strcpy(p
, prefix
->attr_name
);
2476 p
+= prefix
->attr_namelen
;
2477 strcpy(p
, namesp
->attr_name
);
2478 p
+= namesp
->attr_namelen
+ 1;
2489 attrnames_t
*namesp
;
2492 for (i
= 0; i
< ATTR_SYSCOUNT
; i
++) {
2493 namesp
= attr_system_names
[i
];
2494 if (!namesp
->attr_exists
|| !namesp
->attr_exists(vp
))
2496 error
= attr_generic_listadd(&attr_system
, namesp
,
2497 data
, size
, result
);
2506 struct vnode
*vp
, void *data
, size_t size
, int xflags
, ssize_t
*result
)
2508 attrlist_cursor_kern_t cursor
= { 0 };
2511 VOP_ATTR_LIST(vp
, data
, size
, xflags
, &cursor
, NULL
, error
);
2515 return attr_system_list(vp
, data
, size
, result
);
2519 attr_lookup_namespace(
2521 struct attrnames
**names
,
2526 for (i
= 0; i
< nnames
; i
++)
2527 if (!strncmp(name
, names
[i
]->attr_name
, names
[i
]->attr_namelen
))
2533 * Some checks to prevent people abusing EAs to get over quota:
2534 * - Don't allow modifying user EAs on devices/symlinks;
2535 * - Don't allow modifying user EAs if sticky bit set;
2542 struct inode
*inode
= LINVFS_GET_IP(vp
);
2544 if (IS_IMMUTABLE(inode
) || IS_APPEND(inode
))
2546 if (!S_ISREG(inode
->i_mode
) && !S_ISDIR(inode
->i_mode
) &&
2547 !capable(CAP_SYS_ADMIN
))
2549 if (S_ISDIR(inode
->i_mode
) && (inode
->i_mode
& S_ISVTX
) &&
2550 (current_fsuid(cred
) != inode
->i_uid
) && !capable(CAP_FOWNER
))
2556 attr_trusted_capable(
2560 struct inode
*inode
= LINVFS_GET_IP(vp
);
2562 if (IS_IMMUTABLE(inode
) || IS_APPEND(inode
))
2564 if (!capable(CAP_SYS_ADMIN
))
2570 attr_secure_capable(
2574 return -ENOSECURITY
;
2579 struct vnode
*vp
, char *name
, void *data
, size_t size
, int xflags
)
2581 attrnames_t
*namesp
;
2584 if (xflags
& ATTR_CREATE
)
2587 namesp
= attr_lookup_namespace(name
, attr_system_names
, ATTR_SYSCOUNT
);
2590 error
= namesp
->attr_set(vp
, name
, data
, size
, xflags
);
2592 error
= vn_revalidate(vp
);
2598 struct vnode
*vp
, char *name
, void *data
, size_t size
, int xflags
)
2600 attrnames_t
*namesp
;
2602 namesp
= attr_lookup_namespace(name
, attr_system_names
, ATTR_SYSCOUNT
);
2605 return namesp
->attr_get(vp
, name
, data
, size
, xflags
);
2610 struct vnode
*vp
, char *name
, int xflags
)
2612 attrnames_t
*namesp
;
2614 namesp
= attr_lookup_namespace(name
, attr_system_names
, ATTR_SYSCOUNT
);
2617 return namesp
->attr_remove(vp
, name
, xflags
);
2620 struct attrnames attr_system
= {
2621 .attr_name
= "system.",
2622 .attr_namelen
= sizeof("system.") - 1,
2623 .attr_flag
= ATTR_SYSTEM
,
2624 .attr_get
= attr_system_get
,
2625 .attr_set
= attr_system_set
,
2626 .attr_remove
= attr_system_remove
,
2627 .attr_capable
= (attrcapable_t
)fs_noerr
,
2630 struct attrnames attr_trusted
= {
2631 .attr_name
= "trusted.",
2632 .attr_namelen
= sizeof("trusted.") - 1,
2633 .attr_flag
= ATTR_ROOT
,
2634 .attr_get
= attr_generic_get
,
2635 .attr_set
= attr_generic_set
,
2636 .attr_remove
= attr_generic_remove
,
2637 .attr_capable
= attr_trusted_capable
,
2640 struct attrnames attr_secure
= {
2641 .attr_name
= "security.",
2642 .attr_namelen
= sizeof("security.") - 1,
2643 .attr_flag
= ATTR_SECURE
,
2644 .attr_get
= attr_generic_get
,
2645 .attr_set
= attr_generic_set
,
2646 .attr_remove
= attr_generic_remove
,
2647 .attr_capable
= attr_secure_capable
,
2650 struct attrnames attr_user
= {
2651 .attr_name
= "user.",
2652 .attr_namelen
= sizeof("user.") - 1,
2653 .attr_get
= attr_generic_get
,
2654 .attr_set
= attr_generic_set
,
2655 .attr_remove
= attr_generic_remove
,
2656 .attr_capable
= attr_user_capable
,
2659 struct attrnames
*attr_namespaces
[] =
2660 { &attr_system
, &attr_trusted
, &attr_secure
, &attr_user
};