1 /* $NetBSD: ulfs_extattr.c,v 1.7 2014/02/07 15:29:23 hannken Exp $ */
2 /* from NetBSD: ufs_extattr.c,v 1.41 2012/12/08 13:42:36 manu Exp */
5 * Copyright (c) 1999-2002 Robert N. M. Watson
6 * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
9 * This software was developed by Robert Watson for the TrustedBSD Project.
11 * This software was developed for the FreeBSD Project in part by Network
12 * Associates Laboratories, the Security Research Division of Network
13 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
14 * as part of the DARPA CHATS research program.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * Support for file system extended attributes on the ULFS1 file system.
42 * Extended attributes are defined in the form name=value, where name is
43 * a nul-terminated string in the style of a file name, and value is a
44 * binary blob of zero or more bytes. The ULFS1 extended attribute service
45 * layers support for extended attributes onto a backing file, in the style
46 * of the quota implementation, meaning that it requires no underlying format
47 * changes to the file system. This design choice exchanges simplicity,
48 * usability, and easy deployment for performance.
51 #include <sys/cdefs.h>
52 __KERNEL_RCSID(0, "$NetBSD: ulfs_extattr.c,v 1.7 2014/02/07 15:29:23 hannken Exp $");
58 #include <sys/param.h>
59 #include <sys/systm.h>
60 #include <sys/reboot.h>
61 #include <sys/kauth.h>
62 #include <sys/kernel.h>
63 #include <sys/namei.h>
65 #include <sys/fcntl.h>
67 #include <sys/vnode.h>
68 #include <sys/mount.h>
70 #include <sys/dirent.h>
71 #include <sys/extattr.h>
72 #include <sys/sysctl.h>
74 #include <ufs/lfs/ulfs_extattr.h>
75 #include <ufs/lfs/ulfsmount.h>
76 #include <ufs/lfs/ulfs_inode.h>
77 #include <ufs/lfs/ulfs_bswap.h>
78 #include <ufs/lfs/ulfs_extern.h>
80 int ulfs_extattr_sync
= 1;
81 int ulfs_extattr_autocreate
= 1024;
83 static int ulfs_extattr_valid_attrname(int attrnamespace
,
84 const char *attrname
);
85 static int ulfs_extattr_enable_with_open(struct ulfsmount
*ump
,
86 struct vnode
*vp
, int attrnamespace
, const char *attrname
,
88 static int ulfs_extattr_enable(struct ulfsmount
*ump
, int attrnamespace
,
89 const char *attrname
, struct vnode
*backing_vnode
,
91 static int ulfs_extattr_disable(struct ulfsmount
*ump
, int attrnamespace
,
92 const char *attrname
, struct lwp
*l
);
93 static int ulfs_extattr_get(struct vnode
*vp
, int attrnamespace
,
94 const char *name
, struct uio
*uio
, size_t *size
,
95 kauth_cred_t cred
, struct lwp
*l
);
96 static int ulfs_extattr_list(struct vnode
*vp
, int attrnamespace
,
97 struct uio
*uio
, size_t *size
, int flag
,
98 kauth_cred_t cred
, struct lwp
*l
);
99 static int ulfs_extattr_set(struct vnode
*vp
, int attrnamespace
,
100 const char *name
, struct uio
*uio
, kauth_cred_t cred
,
102 static int ulfs_extattr_rm(struct vnode
*vp
, int attrnamespace
,
103 const char *name
, kauth_cred_t cred
, struct lwp
*l
);
104 static struct ulfs_extattr_list_entry
*ulfs_extattr_find_attr(struct ulfsmount
*,
106 static int ulfs_extattr_get_header(struct vnode
*,
107 struct ulfs_extattr_list_entry
*,
108 struct ulfs_extattr_header
*, off_t
*);
111 * Convert a FreeBSD extended attribute and namespace to a consistent string
114 * The returned value, if not NULL, is guaranteed to be an allocated object
115 * of its size as returned by strlen() + 1 and must be freed by the caller.
118 from_freebsd_extattr(int attrnamespace
, const char *attrname
)
120 const char *namespace;
124 if (attrnamespace
== EXTATTR_NAMESPACE_SYSTEM
)
125 namespace = "system";
126 else if (attrnamespace
== EXTATTR_NAMESPACE_USER
)
131 /* <namespace>.<attrname>\0 */
132 len
= strlen(namespace) + 1 + strlen(attrname
) + 1;
134 attr
= kmem_alloc(len
, KM_SLEEP
);
136 snprintf(attr
, len
, "%s.%s", namespace, attrname
);
142 * Internal wrapper around a conversion-check-free sequence.
145 internal_extattr_check_cred(vnode_t
*vp
, int attrnamespace
, const char *name
,
146 kauth_cred_t cred
, int access_mode
)
151 attr
= from_freebsd_extattr(attrnamespace
, name
);
155 error
= extattr_check_cred(vp
, attr
, cred
, access_mode
);
157 kmem_free(attr
, strlen(attr
) + 1);
163 * Per-FS attribute lock protecting attribute operations.
164 * XXX Right now there is a lot of lock contention due to having a single
165 * lock per-FS; really, this should be far more fine-grained.
168 ulfs_extattr_uepm_lock(struct ulfsmount
*ump
)
171 /* XXX Why does this need to be recursive? */
172 if (mutex_owned(&ump
->um_extattr
.uepm_lock
)) {
173 ump
->um_extattr
.uepm_lockcnt
++;
176 mutex_enter(&ump
->um_extattr
.uepm_lock
);
180 ulfs_extattr_uepm_unlock(struct ulfsmount
*ump
)
183 if (ump
->um_extattr
.uepm_lockcnt
!= 0) {
184 KASSERT(mutex_owned(&ump
->um_extattr
.uepm_lock
));
185 ump
->um_extattr
.uepm_lockcnt
--;
188 mutex_exit(&ump
->um_extattr
.uepm_lock
);
192 * Determine whether the name passed is a valid name for an actual
195 * Invalid currently consists of:
196 * NULL pointer for attrname
197 * zero-length attrname (used to retrieve application attribute list)
200 ulfs_extattr_valid_attrname(int attrnamespace
, const char *attrname
)
203 if (attrname
== NULL
)
205 if (strlen(attrname
) == 0)
211 * Autocreate an attribute storage
213 static struct ulfs_extattr_list_entry
*
214 ulfs_extattr_autocreate_attr(struct vnode
*vp
, int attrnamespace
,
215 const char *attrname
, struct lwp
*l
)
217 struct mount
*mp
= vp
->v_mount
;
218 struct ulfsmount
*ump
= VFSTOULFS(mp
);
219 struct vnode
*backing_vp
;
223 struct ulfs_extattr_fileheader uef
;
224 struct ulfs_extattr_list_entry
*uele
;
230 * We only support system and user namespace autocreation
232 switch (attrnamespace
) {
233 case EXTATTR_NAMESPACE_SYSTEM
:
234 (void)snprintf(path
, PATH_MAX
, "%s/%s/%s/%s",
235 mp
->mnt_stat
.f_mntonname
,
236 ULFS_EXTATTR_FSROOTSUBDIR
,
237 ULFS_EXTATTR_SUBDIR_SYSTEM
,
240 case EXTATTR_NAMESPACE_USER
:
241 (void)snprintf(path
, PATH_MAX
, "%s/%s/%s/%s",
242 mp
->mnt_stat
.f_mntonname
,
243 ULFS_EXTATTR_FSROOTSUBDIR
,
244 ULFS_EXTATTR_SUBDIR_USER
,
254 * XXX unlock/lock should only be done when setting extattr
255 * on backing store or one of its parent directory
256 * including root, but we always do it for now.
258 KASSERT(VOP_ISLOCKED(vp
) == LK_EXCLUSIVE
);
261 pb
= pathbuf_create(path
);
262 NDINIT(&nd
, CREATE
, LOCKPARENT
, pb
);
264 error
= vn_open(&nd
, O_CREAT
|O_RDWR
, 0600);
267 * Reacquire the lock on the vnode
269 KASSERT(VOP_ISLOCKED(vp
) == 0);
270 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
278 KASSERT(nd
.ni_vp
!= NULL
);
279 KASSERT(VOP_ISLOCKED(nd
.ni_vp
) == LK_EXCLUSIVE
);
280 KASSERT(VOP_ISLOCKED(nd
.ni_dvp
) == 0);
283 * backing_vp is the backing store.
285 backing_vp
= nd
.ni_vp
;
289 uef
.uef_magic
= ULFS_EXTATTR_MAGIC
;
290 uef
.uef_version
= ULFS_EXTATTR_VERSION
;
291 uef
.uef_size
= ulfs_extattr_autocreate
;
293 error
= vn_rdwr(UIO_WRITE
, backing_vp
, &uef
, sizeof(uef
), 0,
294 UIO_SYSSPACE
, IO_NODELOCKED
|IO_APPEND
,
297 VOP_UNLOCK(backing_vp
);
300 printf("%s: write uef header failed for %s, error = %d\n",
301 __func__
, attrname
, error
);
302 vn_close(backing_vp
, FREAD
|FWRITE
, l
->l_cred
);
307 * Now enable attribute.
309 error
= ulfs_extattr_enable(ump
,attrnamespace
, attrname
, backing_vp
, l
);
310 KASSERT(VOP_ISLOCKED(backing_vp
) == 0);
313 printf("%s: enable %s failed, error %d\n",
314 __func__
, attrname
, error
);
315 vn_close(backing_vp
, FREAD
|FWRITE
, l
->l_cred
);
319 uele
= ulfs_extattr_find_attr(ump
, attrnamespace
, attrname
);
321 printf("%s: atttribute %s created but not found!\n",
323 vn_close(backing_vp
, FREAD
|FWRITE
, l
->l_cred
);
327 printf("%s: EA backing store autocreated for %s\n",
328 mp
->mnt_stat
.f_mntonname
, attrname
);
334 * Locate an attribute given a name and mountpoint.
335 * Must be holding uepm lock for the mount point.
337 static struct ulfs_extattr_list_entry
*
338 ulfs_extattr_find_attr(struct ulfsmount
*ump
, int attrnamespace
,
339 const char *attrname
)
341 struct ulfs_extattr_list_entry
*search_attribute
;
343 for (search_attribute
= LIST_FIRST(&ump
->um_extattr
.uepm_list
);
344 search_attribute
!= NULL
;
345 search_attribute
= LIST_NEXT(search_attribute
, uele_entries
)) {
346 if (!(strncmp(attrname
, search_attribute
->uele_attrname
,
347 ULFS_EXTATTR_MAXEXTATTRNAME
)) &&
348 (attrnamespace
== search_attribute
->uele_attrnamespace
)) {
349 return (search_attribute
);
357 * Initialize per-FS structures supporting extended attributes. Do not
358 * start extended attributes yet.
361 ulfs_extattr_uepm_init(struct ulfs_extattr_per_mount
*uepm
)
364 uepm
->uepm_flags
= 0;
365 uepm
->uepm_lockcnt
= 0;
367 LIST_INIT(&uepm
->uepm_list
);
368 mutex_init(&uepm
->uepm_lock
, MUTEX_DEFAULT
, IPL_NONE
);
369 uepm
->uepm_flags
|= ULFS_EXTATTR_UEPM_INITIALIZED
;
373 * Destroy per-FS structures supporting extended attributes. Assumes
374 * that EAs have already been stopped, and will panic if not.
377 ulfs_extattr_uepm_destroy(struct ulfs_extattr_per_mount
*uepm
)
380 if (!(uepm
->uepm_flags
& ULFS_EXTATTR_UEPM_INITIALIZED
))
381 panic("ulfs_extattr_uepm_destroy: not initialized");
383 if ((uepm
->uepm_flags
& ULFS_EXTATTR_UEPM_STARTED
))
384 panic("ulfs_extattr_uepm_destroy: called while still started");
387 * It's not clear that either order for the next two lines is
388 * ideal, and it should never be a problem if this is only called
389 * during unmount, and with vfs_busy().
391 uepm
->uepm_flags
&= ~ULFS_EXTATTR_UEPM_INITIALIZED
;
392 mutex_destroy(&uepm
->uepm_lock
);
396 * Start extended attribute support on an FS.
399 ulfs_extattr_start(struct mount
*mp
, struct lwp
*l
)
401 struct ulfsmount
*ump
;
406 ulfs_extattr_uepm_lock(ump
);
408 if (!(ump
->um_extattr
.uepm_flags
& ULFS_EXTATTR_UEPM_INITIALIZED
)) {
412 if (ump
->um_extattr
.uepm_flags
& ULFS_EXTATTR_UEPM_STARTED
) {
417 ump
->um_extattr
.uepm_flags
|= ULFS_EXTATTR_UEPM_STARTED
;
419 ump
->um_extattr
.uepm_ucred
= l
->l_cred
;
420 kauth_cred_hold(ump
->um_extattr
.uepm_ucred
);
423 ulfs_extattr_uepm_unlock(ump
);
429 * Helper routine: given a locked parent directory and filename, return
430 * the locked vnode of the inode associated with the name. Will not
431 * follow symlinks, may return any type of vnode. Lock on parent will
432 * be released even in the event of a failure. In the event that the
433 * target is the parent (i.e., "."), there will be two references and
434 * one lock, requiring the caller to possibly special-case.
437 ulfs_extattr_lookup(struct vnode
*start_dvp
, int lockparent
, const char *dirname
,
438 struct vnode
**vp
, struct lwp
*l
)
440 struct vop_lookup_v2_args vargs
;
441 struct componentname cnp
;
442 struct vnode
*target_vp
;
446 KASSERT(VOP_ISLOCKED(start_dvp
) == LK_EXCLUSIVE
);
450 memset(&cnp
, 0, sizeof(cnp
));
451 cnp
.cn_nameiop
= LOOKUP
;
452 cnp
.cn_flags
= ISLASTCN
| lockparent
;
453 cnp
.cn_cred
= l
->l_cred
;
454 cnp
.cn_nameptr
= pnbuf
;
455 error
= copystr(dirname
, pnbuf
, MAXPATHLEN
, &cnp
.cn_namelen
);
457 if (lockparent
== 0) {
458 VOP_UNLOCK(start_dvp
);
461 printf("ulfs_extattr_lookup: copystr failed\n");
464 cnp
.cn_namelen
--; /* trim nul termination */
466 vargs
.a_dvp
= start_dvp
;
467 vargs
.a_vpp
= &target_vp
;
469 error
= ulfs_lookup(&vargs
);
472 if (lockparent
== 0) {
473 VOP_UNLOCK(start_dvp
);
478 if (target_vp
== start_dvp
)
479 panic("ulfs_extattr_lookup: target_vp == start_dvp");
482 if (target_vp
!= start_dvp
) {
483 error
= vn_lock(target_vp
, LK_EXCLUSIVE
);
485 VOP_UNLOCK(start_dvp
);
492 KASSERT(VOP_ISLOCKED(target_vp
) == LK_EXCLUSIVE
);
498 * Enable an EA using the passed filesystem, backing vnode, attribute name,
499 * namespace, and proc. Will perform a VOP_OPEN() on the vp, so expects vp
500 * to be locked when passed in. The vnode will be returned unlocked,
501 * regardless of success/failure of the function. As a result, the caller
502 * will always need to vrele(), but not vput().
505 ulfs_extattr_enable_with_open(struct ulfsmount
*ump
, struct vnode
*vp
,
506 int attrnamespace
, const char *attrname
, struct lwp
*l
)
510 error
= VOP_OPEN(vp
, FREAD
|FWRITE
, l
->l_cred
);
512 printf("ulfs_extattr_enable_with_open.VOP_OPEN(): failed "
518 mutex_enter(vp
->v_interlock
);
520 mutex_exit(vp
->v_interlock
);
526 error
= ulfs_extattr_enable(ump
, attrnamespace
, attrname
, vp
, l
);
528 vn_close(vp
, FREAD
|FWRITE
, l
->l_cred
);
533 * Given a locked directory vnode, iterate over the names in the directory
534 * and use ulfs_extattr_lookup() to retrieve locked vnodes of potential
535 * attribute files. Then invoke ulfs_extattr_enable_with_open() on each
536 * to attempt to start the attribute. Leaves the directory locked on
540 ulfs_extattr_iterate_directory(struct ulfsmount
*ump
, struct vnode
*dvp
,
541 int attrnamespace
, struct lwp
*l
)
543 struct vop_readdir_args vargs
;
544 struct statvfs
*sbp
= &ump
->um_mountp
->mnt_stat
;
545 struct dirent
*dp
, *edp
;
546 struct vnode
*attr_vp
;
550 int error
, eofflag
= 0;
552 if (dvp
->v_type
!= VDIR
)
555 dirbuf
= kmem_alloc(LFS_DIRBLKSIZ
, KM_SLEEP
);
557 auio
.uio_iov
= &aiov
;
559 auio
.uio_rw
= UIO_READ
;
561 UIO_SETUP_SYSSPACE(&auio
);
566 vargs
.a_cred
= l
->l_cred
;
567 vargs
.a_eofflag
= &eofflag
;
568 vargs
.a_ncookies
= NULL
;
569 vargs
.a_cookies
= NULL
;
572 auio
.uio_resid
= LFS_DIRBLKSIZ
;
573 aiov
.iov_base
= dirbuf
;
574 aiov
.iov_len
= LFS_DIRBLKSIZ
;
575 error
= ulfs_readdir(&vargs
);
577 printf("ulfs_extattr_iterate_directory: ulfs_readdir "
583 * XXXRW: While in LFS, we always get LFS_DIRBLKSIZ returns from
584 * the directory code on success, on other file systems this
585 * may not be the case. For portability, we should check the
586 * read length on return from ulfs_readdir().
588 edp
= (struct dirent
*)&dirbuf
[LFS_DIRBLKSIZ
];
589 for (dp
= (struct dirent
*)dirbuf
; dp
< edp
; ) {
590 if (dp
->d_reclen
== 0)
592 /* Skip "." and ".." */
593 if (dp
->d_name
[0] == '.' &&
594 (dp
->d_name
[1] == '\0' ||
595 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
597 error
= ulfs_extattr_lookup(dvp
, LOCKPARENT
,
598 dp
->d_name
, &attr_vp
, l
);
599 if (error
== ENOENT
) {
600 goto next
; /* keep silent */
602 printf("ulfs_extattr_iterate_directory: lookup "
603 "%s %d\n", dp
->d_name
, error
);
604 } else if (attr_vp
== dvp
) {
606 } else if (attr_vp
->v_type
!= VREG
) {
609 error
= ulfs_extattr_enable_with_open(ump
,
610 attr_vp
, attrnamespace
, dp
->d_name
, l
);
613 printf("ulfs_extattr_iterate_directory: "
614 "enable %s %d\n", dp
->d_name
,
616 } else if (bootverbose
) {
617 printf("%s: EA %s loaded\n",
618 sbp
->f_mntonname
, dp
->d_name
);
622 dp
= (struct dirent
*) ((char *)dp
+ dp
->d_reclen
);
627 kmem_free(dirbuf
, LFS_DIRBLKSIZ
);
633 * Auto-start of extended attributes, to be executed (optionally) at
637 ulfs_extattr_autostart(struct mount
*mp
, struct lwp
*l
)
639 struct vnode
*rvp
, *attr_dvp
, *attr_system_dvp
, *attr_user_dvp
;
643 * Does ULFS_EXTATTR_FSROOTSUBDIR exist off the filesystem root?
644 * If so, automatically start EA's.
646 error
= VFS_ROOT(mp
, &rvp
);
648 printf("ulfs_extattr_autostart.VFS_ROOT() returned %d\n",
653 KASSERT(VOP_ISLOCKED(rvp
) == LK_EXCLUSIVE
);
655 error
= ulfs_extattr_lookup(rvp
, 0,
656 ULFS_EXTATTR_FSROOTSUBDIR
, &attr_dvp
, l
);
658 /* rvp ref'd but now unlocked */
659 KASSERT(VOP_ISLOCKED(rvp
) == 0);
663 if (rvp
== attr_dvp
) {
664 /* Should never happen. */
665 KASSERT(VOP_ISLOCKED(rvp
) == LK_EXCLUSIVE
);
670 KASSERT(VOP_ISLOCKED(rvp
) == 0);
673 KASSERT(VOP_ISLOCKED(attr_dvp
) == LK_EXCLUSIVE
);
675 if (attr_dvp
->v_type
!= VDIR
) {
676 printf("ulfs_extattr_autostart: %s != VDIR\n",
677 ULFS_EXTATTR_FSROOTSUBDIR
);
678 goto return_vput_attr_dvp
;
681 error
= ulfs_extattr_start(mp
, l
);
683 printf("ulfs_extattr_autostart: ulfs_extattr_start failed (%d)\n",
685 goto return_vput_attr_dvp
;
689 * Look for two subdirectories: ULFS_EXTATTR_SUBDIR_SYSTEM,
690 * ULFS_EXTATTR_SUBDIR_USER. For each, iterate over the sub-directory,
691 * and start with appropriate type. Failures in either don't
692 * result in an over-all failure. attr_dvp is left locked to
693 * be cleaned up on exit.
695 error
= ulfs_extattr_lookup(attr_dvp
, LOCKPARENT
,
696 ULFS_EXTATTR_SUBDIR_SYSTEM
, &attr_system_dvp
, l
);
697 KASSERT(VOP_ISLOCKED(attr_dvp
) == LK_EXCLUSIVE
);
699 KASSERT(VOP_ISLOCKED(attr_system_dvp
) == LK_EXCLUSIVE
);
700 error
= ulfs_extattr_iterate_directory(VFSTOULFS(mp
),
701 attr_system_dvp
, EXTATTR_NAMESPACE_SYSTEM
, l
);
703 printf("ulfs_extattr_iterate_directory returned %d\n",
705 KASSERT(VOP_ISLOCKED(attr_system_dvp
) == LK_EXCLUSIVE
);
706 vput(attr_system_dvp
);
709 error
= ulfs_extattr_lookup(attr_dvp
, LOCKPARENT
,
710 ULFS_EXTATTR_SUBDIR_USER
, &attr_user_dvp
, l
);
711 KASSERT(VOP_ISLOCKED(attr_dvp
) == LK_EXCLUSIVE
);
713 KASSERT(VOP_ISLOCKED(attr_user_dvp
) == LK_EXCLUSIVE
);
714 error
= ulfs_extattr_iterate_directory(VFSTOULFS(mp
),
715 attr_user_dvp
, EXTATTR_NAMESPACE_USER
, l
);
717 printf("ulfs_extattr_iterate_directory returned %d\n",
719 KASSERT(VOP_ISLOCKED(attr_user_dvp
) == LK_EXCLUSIVE
);
723 /* Mask startup failures in sub-directories. */
726 return_vput_attr_dvp
:
727 KASSERT(VOP_ISLOCKED(attr_dvp
) == LK_EXCLUSIVE
);
734 * Stop extended attribute support on an FS.
737 ulfs_extattr_stop(struct mount
*mp
, struct lwp
*l
)
739 struct ulfs_extattr_list_entry
*uele
;
740 struct ulfsmount
*ump
= VFSTOULFS(mp
);
742 ulfs_extattr_uepm_lock(ump
);
745 * If we haven't been started, no big deal. Just short-circuit
746 * the processing work.
748 if (!(ump
->um_extattr
.uepm_flags
& ULFS_EXTATTR_UEPM_STARTED
)) {
752 while (LIST_FIRST(&ump
->um_extattr
.uepm_list
) != NULL
) {
753 uele
= LIST_FIRST(&ump
->um_extattr
.uepm_list
);
754 ulfs_extattr_disable(ump
, uele
->uele_attrnamespace
,
755 uele
->uele_attrname
, l
);
758 ump
->um_extattr
.uepm_flags
&= ~ULFS_EXTATTR_UEPM_STARTED
;
760 kauth_cred_free(ump
->um_extattr
.uepm_ucred
);
761 ump
->um_extattr
.uepm_ucred
= NULL
;
764 ulfs_extattr_uepm_unlock(ump
);
768 * Enable a named attribute on the specified filesystem; provide an
769 * unlocked backing vnode to hold the attribute data.
772 ulfs_extattr_enable(struct ulfsmount
*ump
, int attrnamespace
,
773 const char *attrname
, struct vnode
*backing_vnode
, struct lwp
*l
)
775 struct ulfs_extattr_list_entry
*attribute
;
780 if (!ulfs_extattr_valid_attrname(attrnamespace
, attrname
))
782 if (backing_vnode
->v_type
!= VREG
)
785 attribute
= kmem_zalloc(sizeof(*attribute
), KM_SLEEP
);
787 if (!(ump
->um_extattr
.uepm_flags
& ULFS_EXTATTR_UEPM_STARTED
)) {
792 if (ulfs_extattr_find_attr(ump
, attrnamespace
, attrname
)) {
797 strncpy(attribute
->uele_attrname
, attrname
,
798 ULFS_EXTATTR_MAXEXTATTRNAME
);
799 attribute
->uele_attrnamespace
= attrnamespace
;
800 memset(&attribute
->uele_fileheader
, 0,
801 sizeof(struct ulfs_extattr_fileheader
));
803 attribute
->uele_backing_vnode
= backing_vnode
;
805 auio
.uio_iov
= &aiov
;
807 aiov
.iov_base
= (void *) &attribute
->uele_fileheader
;
808 aiov
.iov_len
= sizeof(struct ulfs_extattr_fileheader
);
809 auio
.uio_resid
= sizeof(struct ulfs_extattr_fileheader
);
810 auio
.uio_offset
= (off_t
) 0;
811 auio
.uio_rw
= UIO_READ
;
812 UIO_SETUP_SYSSPACE(&auio
);
814 vn_lock(backing_vnode
, LK_SHARED
| LK_RETRY
);
815 error
= VOP_READ(backing_vnode
, &auio
, IO_NODELOCKED
,
816 ump
->um_extattr
.uepm_ucred
);
819 goto unlock_free_exit
;
821 if (auio
.uio_resid
!= 0) {
822 printf("ulfs_extattr_enable: malformed attribute header\n");
824 goto unlock_free_exit
;
828 * Try to determine the byte order of the attribute file.
830 if (attribute
->uele_fileheader
.uef_magic
!= ULFS_EXTATTR_MAGIC
) {
831 attribute
->uele_flags
|= UELE_F_NEEDSWAP
;
832 attribute
->uele_fileheader
.uef_magic
=
833 ulfs_rw32(attribute
->uele_fileheader
.uef_magic
,
834 UELE_NEEDSWAP(attribute
));
835 if (attribute
->uele_fileheader
.uef_magic
!= ULFS_EXTATTR_MAGIC
) {
836 printf("ulfs_extattr_enable: invalid attribute header "
839 goto unlock_free_exit
;
842 attribute
->uele_fileheader
.uef_version
=
843 ulfs_rw32(attribute
->uele_fileheader
.uef_version
,
844 UELE_NEEDSWAP(attribute
));
845 attribute
->uele_fileheader
.uef_size
=
846 ulfs_rw32(attribute
->uele_fileheader
.uef_size
,
847 UELE_NEEDSWAP(attribute
));
849 if (attribute
->uele_fileheader
.uef_version
!= ULFS_EXTATTR_VERSION
) {
850 printf("ulfs_extattr_enable: incorrect attribute header "
853 goto unlock_free_exit
;
856 LIST_INSERT_HEAD(&ump
->um_extattr
.uepm_list
, attribute
,
859 VOP_UNLOCK(backing_vnode
);
863 VOP_UNLOCK(backing_vnode
);
866 kmem_free(attribute
, sizeof(*attribute
));
871 * Disable extended attribute support on an FS.
874 ulfs_extattr_disable(struct ulfsmount
*ump
, int attrnamespace
,
875 const char *attrname
, struct lwp
*l
)
877 struct ulfs_extattr_list_entry
*uele
;
880 if (!ulfs_extattr_valid_attrname(attrnamespace
, attrname
))
883 uele
= ulfs_extattr_find_attr(ump
, attrnamespace
, attrname
);
887 LIST_REMOVE(uele
, uele_entries
);
889 error
= vn_close(uele
->uele_backing_vnode
, FREAD
|FWRITE
,
892 kmem_free(uele
, sizeof(*uele
));
898 * VFS call to manage extended attributes in ULFS. If filename_vp is
899 * non-NULL, it must be passed in locked, and regardless of errors in
900 * processing, will be unlocked.
903 ulfs_extattrctl(struct mount
*mp
, int cmd
, struct vnode
*filename_vp
,
904 int attrnamespace
, const char *attrname
)
906 struct lwp
*l
= curlwp
;
907 struct ulfsmount
*ump
= VFSTOULFS(mp
);
911 * Only privileged processes can configure extended attributes.
913 error
= kauth_authorize_system(l
->l_cred
, KAUTH_SYSTEM_FS_EXTATTR
,
916 if (filename_vp
!= NULL
)
917 VOP_UNLOCK(filename_vp
);
922 case ULFS_EXTATTR_CMD_START
:
923 if (filename_vp
!= NULL
) {
924 VOP_UNLOCK(filename_vp
);
927 if (attrname
!= NULL
)
930 error
= ulfs_extattr_autostart(mp
, l
);
933 case ULFS_EXTATTR_CMD_STOP
:
934 if (filename_vp
!= NULL
) {
935 VOP_UNLOCK(filename_vp
);
938 if (attrname
!= NULL
)
941 ulfs_extattr_stop(mp
, l
);
944 case ULFS_EXTATTR_CMD_ENABLE
:
945 if (filename_vp
== NULL
)
947 if (attrname
== NULL
) {
948 VOP_UNLOCK(filename_vp
);
953 * ulfs_extattr_enable_with_open() will always unlock the
954 * vnode, regardless of failure.
956 ulfs_extattr_uepm_lock(ump
);
957 error
= ulfs_extattr_enable_with_open(ump
, filename_vp
,
958 attrnamespace
, attrname
, l
);
959 ulfs_extattr_uepm_unlock(ump
);
962 case ULFS_EXTATTR_CMD_DISABLE
:
963 if (filename_vp
!= NULL
) {
964 VOP_UNLOCK(filename_vp
);
967 if (attrname
== NULL
)
970 ulfs_extattr_uepm_lock(ump
);
971 error
= ulfs_extattr_disable(ump
, attrnamespace
, attrname
, l
);
972 ulfs_extattr_uepm_unlock(ump
);
981 * Read extended attribute header for a given vnode and attribute.
982 * Backing vnode should be locked and unlocked by caller.
985 ulfs_extattr_get_header(struct vnode
*vp
, struct ulfs_extattr_list_entry
*uele
,
986 struct ulfs_extattr_header
*ueh
, off_t
*bap
)
988 struct mount
*mp
= vp
->v_mount
;
989 struct ulfsmount
*ump
= VFSTOULFS(mp
);
990 struct inode
*ip
= VTOI(vp
);
997 * Find base offset of header in file based on file header size, and
998 * data header size + maximum data size, indexed by inode number.
1000 base_offset
= sizeof(struct ulfs_extattr_fileheader
) +
1001 ip
->i_number
* (sizeof(struct ulfs_extattr_header
) +
1002 uele
->uele_fileheader
.uef_size
);
1005 * Read in the data header to see if the data is defined, and if so
1008 memset(ueh
, 0, sizeof(struct ulfs_extattr_header
));
1009 aiov
.iov_base
= ueh
;
1010 aiov
.iov_len
= sizeof(struct ulfs_extattr_header
);
1011 aio
.uio_iov
= &aiov
;
1013 aio
.uio_rw
= UIO_READ
;
1014 aio
.uio_offset
= base_offset
;
1015 aio
.uio_resid
= sizeof(struct ulfs_extattr_header
);
1016 UIO_SETUP_SYSSPACE(&aio
);
1018 error
= VOP_READ(uele
->uele_backing_vnode
, &aio
,
1019 IO_NODELOCKED
, ump
->um_extattr
.uepm_ucred
);
1024 * Attribute headers are kept in file system byte order.
1025 * XXX What about the blob of data?
1027 ueh
->ueh_flags
= ulfs_rw32(ueh
->ueh_flags
, UELE_NEEDSWAP(uele
));
1028 ueh
->ueh_len
= ulfs_rw32(ueh
->ueh_len
, UELE_NEEDSWAP(uele
));
1029 ueh
->ueh_i_gen
= ulfs_rw32(ueh
->ueh_i_gen
, UELE_NEEDSWAP(uele
));
1032 if ((ueh
->ueh_flags
& ULFS_EXTATTR_ATTR_FLAG_INUSE
) == 0)
1035 /* Valid for the current inode generation? */
1036 if (ueh
->ueh_i_gen
!= ip
->i_gen
) {
1038 * The inode itself has a different generation number
1039 * than the uele data. For now, the best solution
1040 * is to coerce this to undefined, and let it get cleaned
1041 * up by the next write or extattrctl clean.
1043 printf("%s (%s): inode gen inconsistency (%u, %jd)\n",
1044 __func__
, mp
->mnt_stat
.f_mntonname
, ueh
->ueh_i_gen
,
1045 (intmax_t)ip
->i_gen
);
1049 /* Local size consistency check. */
1050 if (ueh
->ueh_len
> uele
->uele_fileheader
.uef_size
)
1053 /* Return base offset */
1061 * Vnode operation to retrieve a named extended attribute.
1064 ulfs_getextattr(struct vop_getextattr_args
*ap
)
1067 IN struct vnode *a_vp;
1068 IN int a_attrnamespace;
1069 IN const char *a_name;
1070 INOUT struct uio *a_uio;
1072 IN kauth_cred_t a_cred;
1076 struct mount
*mp
= ap
->a_vp
->v_mount
;
1077 struct ulfsmount
*ump
= VFSTOULFS(mp
);
1080 ulfs_extattr_uepm_lock(ump
);
1082 error
= ulfs_extattr_get(ap
->a_vp
, ap
->a_attrnamespace
, ap
->a_name
,
1083 ap
->a_uio
, ap
->a_size
, ap
->a_cred
, curlwp
);
1085 ulfs_extattr_uepm_unlock(ump
);
1091 * Real work associated with retrieving a named attribute--assumes that
1092 * the attribute lock has already been grabbed.
1095 ulfs_extattr_get(struct vnode
*vp
, int attrnamespace
, const char *name
,
1096 struct uio
*uio
, size_t *size
, kauth_cred_t cred
, struct lwp
*l
)
1098 struct ulfs_extattr_list_entry
*attribute
;
1099 struct ulfs_extattr_header ueh
;
1100 struct mount
*mp
= vp
->v_mount
;
1101 struct ulfsmount
*ump
= VFSTOULFS(mp
);
1103 size_t len
, old_len
;
1106 if (!(ump
->um_extattr
.uepm_flags
& ULFS_EXTATTR_UEPM_STARTED
))
1107 return (EOPNOTSUPP
);
1109 if (strlen(name
) == 0)
1112 error
= internal_extattr_check_cred(vp
, attrnamespace
, name
, cred
,
1117 attribute
= ulfs_extattr_find_attr(ump
, attrnamespace
, name
);
1122 * Allow only offsets of zero to encourage the read/replace
1123 * extended attribute semantic. Otherwise we can't guarantee
1124 * atomicity, as we don't provide locks for extended attributes.
1126 if (uio
!= NULL
&& uio
->uio_offset
!= 0)
1130 * Don't need to get a lock on the backing file if the getattr is
1131 * being applied to the backing file, as the lock is already held.
1133 if (attribute
->uele_backing_vnode
!= vp
)
1134 vn_lock(attribute
->uele_backing_vnode
, LK_SHARED
| LK_RETRY
);
1136 error
= ulfs_extattr_get_header(vp
, attribute
, &ueh
, &base_offset
);
1138 goto vopunlock_exit
;
1140 /* Return full data size if caller requested it. */
1142 *size
= ueh
.ueh_len
;
1144 /* Return data if the caller requested it. */
1146 /* Allow for offset into the attribute data. */
1147 uio
->uio_offset
= base_offset
+ sizeof(struct
1148 ulfs_extattr_header
);
1151 * Figure out maximum to transfer -- use buffer size and
1154 len
= MIN(uio
->uio_resid
, ueh
.ueh_len
);
1155 old_len
= uio
->uio_resid
;
1156 uio
->uio_resid
= len
;
1158 error
= VOP_READ(attribute
->uele_backing_vnode
, uio
,
1159 IO_NODELOCKED
, ump
->um_extattr
.uepm_ucred
);
1161 goto vopunlock_exit
;
1163 uio
->uio_resid
= old_len
- (len
- uio
->uio_resid
);
1169 uio
->uio_offset
= 0;
1171 if (attribute
->uele_backing_vnode
!= vp
)
1172 VOP_UNLOCK(attribute
->uele_backing_vnode
);
1178 * Vnode operation to list extended attribute for a vnode
1181 ulfs_listextattr(struct vop_listextattr_args
*ap
)
1184 IN struct vnode *a_vp;
1185 IN int a_attrnamespace;
1186 INOUT struct uio *a_uio;
1189 IN kauth_cred_t a_cred;
1194 struct mount
*mp
= ap
->a_vp
->v_mount
;
1195 struct ulfsmount
*ump
= VFSTOULFS(mp
);
1198 ulfs_extattr_uepm_lock(ump
);
1200 error
= ulfs_extattr_list(ap
->a_vp
, ap
->a_attrnamespace
,
1201 ap
->a_uio
, ap
->a_size
, ap
->a_flag
, ap
->a_cred
, curlwp
);
1203 ulfs_extattr_uepm_unlock(ump
);
1209 * Real work associated with retrieving list of attributes--assumes that
1210 * the attribute lock has already been grabbed.
1213 ulfs_extattr_list(struct vnode
*vp
, int attrnamespace
,
1214 struct uio
*uio
, size_t *size
, int flag
,
1215 kauth_cred_t cred
, struct lwp
*l
)
1217 struct ulfs_extattr_list_entry
*uele
;
1218 struct ulfs_extattr_header ueh
;
1219 struct mount
*mp
= vp
->v_mount
;
1220 struct ulfsmount
*ump
= VFSTOULFS(mp
);
1221 size_t listsize
= 0;
1224 if (!(ump
->um_extattr
.uepm_flags
& ULFS_EXTATTR_UEPM_STARTED
))
1225 return (EOPNOTSUPP
);
1228 * XXX: We can move this inside the loop and iterate on individual
1231 error
= internal_extattr_check_cred(vp
, attrnamespace
, "", cred
,
1236 LIST_FOREACH(uele
, &ump
->um_extattr
.uepm_list
, uele_entries
) {
1237 unsigned char attrnamelen
;
1239 if (uele
->uele_attrnamespace
!= attrnamespace
)
1242 error
= ulfs_extattr_get_header(vp
, uele
, &ueh
, NULL
);
1243 if (error
== ENODATA
)
1249 * Don't need to get a lock on the backing file if
1250 * the listattr is being applied to the backing file,
1251 * as the lock is already held.
1253 if (uele
->uele_backing_vnode
!= vp
)
1254 vn_lock(uele
->uele_backing_vnode
, LK_SHARED
| LK_RETRY
);
1257 * +1 for trailing NUL (listxattr flavor)
1258 * or leading name length (extattr_list_file flavor)
1260 attrnamelen
= strlen(uele
->uele_attrname
);
1261 listsize
+= attrnamelen
+ 1;
1263 /* Return data if the caller requested it. */
1266 * We support two flavors. Either NUL-terminated
1267 * strings (a la listxattr), or non NUL-terminated,
1268 * one byte length prefixed strings (for
1269 * extattr_list_file). EXTATTR_LIST_LENPREFIX switches
1270 * that second behavior.
1272 if (flag
& EXTATTR_LIST_LENPREFIX
) {
1273 uint8_t len
= (uint8_t)attrnamelen
;
1275 /* Copy leading name length */
1276 error
= uiomove(&len
, sizeof(len
), uio
);
1280 /* Include trailing NULL */
1284 error
= uiomove(uele
->uele_attrname
,
1285 (size_t)attrnamelen
, uio
);
1290 if (uele
->uele_backing_vnode
!= vp
)
1291 VOP_UNLOCK(uele
->uele_backing_vnode
);
1298 uio
->uio_offset
= 0;
1300 /* Return full data size if caller requested it. */
1308 * Vnode operation to remove a named attribute.
1311 ulfs_deleteextattr(struct vop_deleteextattr_args
*ap
)
1314 IN struct vnode *a_vp;
1315 IN int a_attrnamespace;
1316 IN const char *a_name;
1317 IN kauth_cred_t a_cred;
1321 struct mount
*mp
= ap
->a_vp
->v_mount
;
1322 struct ulfsmount
*ump
= VFSTOULFS(mp
);
1325 ulfs_extattr_uepm_lock(ump
);
1327 error
= ulfs_extattr_rm(ap
->a_vp
, ap
->a_attrnamespace
, ap
->a_name
,
1328 ap
->a_cred
, curlwp
);
1330 ulfs_extattr_uepm_unlock(ump
);
1336 * Vnode operation to set a named attribute.
1339 ulfs_setextattr(struct vop_setextattr_args
*ap
)
1342 IN struct vnode *a_vp;
1343 IN int a_attrnamespace;
1344 IN const char *a_name;
1345 INOUT struct uio *a_uio;
1346 IN kauth_cred_t a_cred;
1350 struct mount
*mp
= ap
->a_vp
->v_mount
;
1351 struct ulfsmount
*ump
= VFSTOULFS(mp
);
1354 ulfs_extattr_uepm_lock(ump
);
1357 * XXX: No longer a supported way to delete extended attributes.
1359 if (ap
->a_uio
== NULL
) {
1360 ulfs_extattr_uepm_unlock(ump
);
1364 error
= ulfs_extattr_set(ap
->a_vp
, ap
->a_attrnamespace
, ap
->a_name
,
1365 ap
->a_uio
, ap
->a_cred
, curlwp
);
1367 ulfs_extattr_uepm_unlock(ump
);
1373 * Real work associated with setting a vnode's extended attributes;
1374 * assumes that the attribute lock has already been grabbed.
1377 ulfs_extattr_set(struct vnode
*vp
, int attrnamespace
, const char *name
,
1378 struct uio
*uio
, kauth_cred_t cred
, struct lwp
*l
)
1380 struct ulfs_extattr_list_entry
*attribute
;
1381 struct ulfs_extattr_header ueh
;
1382 struct iovec local_aiov
;
1383 struct uio local_aio
;
1384 struct mount
*mp
= vp
->v_mount
;
1385 struct ulfsmount
*ump
= VFSTOULFS(mp
);
1386 struct inode
*ip
= VTOI(vp
);
1388 int error
= 0, ioflag
;
1390 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1392 if (!(ump
->um_extattr
.uepm_flags
& ULFS_EXTATTR_UEPM_STARTED
))
1393 return (EOPNOTSUPP
);
1394 if (!ulfs_extattr_valid_attrname(attrnamespace
, name
))
1397 error
= internal_extattr_check_cred(vp
, attrnamespace
, name
, cred
,
1402 attribute
= ulfs_extattr_find_attr(ump
, attrnamespace
, name
);
1404 attribute
= ulfs_extattr_autocreate_attr(vp
, attrnamespace
,
1411 * Early rejection of invalid offsets/length.
1412 * Reject: any offset but 0 (replace)
1413 * Any size greater than attribute size limit
1415 if (uio
->uio_offset
!= 0 ||
1416 uio
->uio_resid
> attribute
->uele_fileheader
.uef_size
)
1420 * Find base offset of header in file based on file header size, and
1421 * data header size + maximum data size, indexed by inode number.
1423 base_offset
= sizeof(struct ulfs_extattr_fileheader
) +
1424 ip
->i_number
* (sizeof(struct ulfs_extattr_header
) +
1425 attribute
->uele_fileheader
.uef_size
);
1428 * Write out a data header for the data.
1430 ueh
.ueh_len
= ulfs_rw32((uint32_t) uio
->uio_resid
,
1431 UELE_NEEDSWAP(attribute
));
1432 ueh
.ueh_flags
= ulfs_rw32(ULFS_EXTATTR_ATTR_FLAG_INUSE
,
1433 UELE_NEEDSWAP(attribute
));
1434 ueh
.ueh_i_gen
= ulfs_rw32(ip
->i_gen
, UELE_NEEDSWAP(attribute
));
1435 local_aiov
.iov_base
= &ueh
;
1436 local_aiov
.iov_len
= sizeof(struct ulfs_extattr_header
);
1437 local_aio
.uio_iov
= &local_aiov
;
1438 local_aio
.uio_iovcnt
= 1;
1439 local_aio
.uio_rw
= UIO_WRITE
;
1440 local_aio
.uio_offset
= base_offset
;
1441 local_aio
.uio_resid
= sizeof(struct ulfs_extattr_header
);
1442 UIO_SETUP_SYSSPACE(&local_aio
);
1445 * Don't need to get a lock on the backing file if the setattr is
1446 * being applied to the backing file, as the lock is already held.
1448 if (attribute
->uele_backing_vnode
!= vp
)
1449 vn_lock(attribute
->uele_backing_vnode
,
1450 LK_EXCLUSIVE
| LK_RETRY
);
1452 ioflag
= IO_NODELOCKED
;
1453 if (ulfs_extattr_sync
)
1455 error
= VOP_WRITE(attribute
->uele_backing_vnode
, &local_aio
, ioflag
,
1456 ump
->um_extattr
.uepm_ucred
);
1458 goto vopunlock_exit
;
1460 if (local_aio
.uio_resid
!= 0) {
1462 goto vopunlock_exit
;
1466 * Write out user data.
1467 * XXX NOT ATOMIC WITH RESPECT TO THE HEADER.
1469 uio
->uio_offset
= base_offset
+ sizeof(struct ulfs_extattr_header
);
1471 ioflag
= IO_NODELOCKED
;
1472 if (ulfs_extattr_sync
)
1474 error
= VOP_WRITE(attribute
->uele_backing_vnode
, uio
, ioflag
,
1475 ump
->um_extattr
.uepm_ucred
);
1478 uio
->uio_offset
= 0;
1480 if (attribute
->uele_backing_vnode
!= vp
)
1481 VOP_UNLOCK(attribute
->uele_backing_vnode
);
1487 * Real work associated with removing an extended attribute from a vnode.
1488 * Assumes the attribute lock has already been grabbed.
1491 ulfs_extattr_rm(struct vnode
*vp
, int attrnamespace
, const char *name
,
1492 kauth_cred_t cred
, struct lwp
*l
)
1494 struct ulfs_extattr_list_entry
*attribute
;
1495 struct ulfs_extattr_header ueh
;
1496 struct mount
*mp
= vp
->v_mount
;
1497 struct ulfsmount
*ump
= VFSTOULFS(mp
);
1498 struct iovec local_aiov
;
1499 struct uio local_aio
;
1501 int error
= 0, ioflag
;
1503 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1505 if (!(ump
->um_extattr
.uepm_flags
& ULFS_EXTATTR_UEPM_STARTED
))
1506 return (EOPNOTSUPP
);
1507 if (!ulfs_extattr_valid_attrname(attrnamespace
, name
))
1510 error
= internal_extattr_check_cred(vp
, attrnamespace
, name
, cred
,
1515 attribute
= ulfs_extattr_find_attr(ump
, attrnamespace
, name
);
1520 * Don't need to get a lock on the backing file if the getattr is
1521 * being applied to the backing file, as the lock is already held.
1523 if (attribute
->uele_backing_vnode
!= vp
)
1524 vn_lock(attribute
->uele_backing_vnode
, LK_EXCLUSIVE
| LK_RETRY
);
1526 error
= ulfs_extattr_get_header(vp
, attribute
, &ueh
, &base_offset
);
1528 goto vopunlock_exit
;
1530 /* Flag it as not in use. */
1531 ueh
.ueh_flags
= 0; /* No need to byte swap 0 */
1532 ueh
.ueh_len
= 0; /* ...ditto... */
1534 local_aiov
.iov_base
= &ueh
;
1535 local_aiov
.iov_len
= sizeof(struct ulfs_extattr_header
);
1536 local_aio
.uio_iov
= &local_aiov
;
1537 local_aio
.uio_iovcnt
= 1;
1538 local_aio
.uio_rw
= UIO_WRITE
;
1539 local_aio
.uio_offset
= base_offset
;
1540 local_aio
.uio_resid
= sizeof(struct ulfs_extattr_header
);
1541 UIO_SETUP_SYSSPACE(&local_aio
);
1543 ioflag
= IO_NODELOCKED
;
1544 if (ulfs_extattr_sync
)
1546 error
= VOP_WRITE(attribute
->uele_backing_vnode
, &local_aio
, ioflag
,
1547 ump
->um_extattr
.uepm_ucred
);
1549 goto vopunlock_exit
;
1551 if (local_aio
.uio_resid
!= 0)
1555 VOP_UNLOCK(attribute
->uele_backing_vnode
);
1561 * Called by ULFS when an inode is no longer active and should have its
1562 * attributes stripped.
1565 ulfs_extattr_vnode_inactive(struct vnode
*vp
, struct lwp
*l
)
1567 struct ulfs_extattr_list_entry
*uele
;
1568 struct mount
*mp
= vp
->v_mount
;
1569 struct ulfsmount
*ump
= VFSTOULFS(mp
);
1572 * In that case, we cannot lock. We should not have any active vnodes
1573 * on the fs if this is not yet initialized but is going to be, so
1574 * this can go unlocked.
1576 if (!(ump
->um_extattr
.uepm_flags
& ULFS_EXTATTR_UEPM_INITIALIZED
))
1579 ulfs_extattr_uepm_lock(ump
);
1581 if (!(ump
->um_extattr
.uepm_flags
& ULFS_EXTATTR_UEPM_STARTED
)) {
1582 ulfs_extattr_uepm_unlock(ump
);
1586 LIST_FOREACH(uele
, &ump
->um_extattr
.uepm_list
, uele_entries
)
1587 ulfs_extattr_rm(vp
, uele
->uele_attrnamespace
,
1588 uele
->uele_attrname
, lwp0
.l_cred
, l
);
1590 ulfs_extattr_uepm_unlock(ump
);
1594 ulfs_extattr_init(void)
1600 ulfs_extattr_done(void)