diff options
-rw-r--r-- | sys/fs/nullfs/null_vfsops.c | 13 | ||||
-rw-r--r-- | sys/fs/umapfs/umap_vfsops.c | 12 | ||||
-rw-r--r-- | sys/kern/syscalls.master | 13 | ||||
-rw-r--r-- | sys/kern/vfs_default.c | 5 | ||||
-rw-r--r-- | sys/kern/vfs_extattr.c | 63 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 63 | ||||
-rw-r--r-- | sys/kern/vfs_vnops.c | 17 | ||||
-rw-r--r-- | sys/kern/vnode_if.src | 2 | ||||
-rw-r--r-- | sys/miscfs/nullfs/null_vfsops.c | 13 | ||||
-rw-r--r-- | sys/miscfs/umapfs/umap_vfsops.c | 12 | ||||
-rw-r--r-- | sys/sys/acl.h | 8 | ||||
-rw-r--r-- | sys/sys/capability.h | 5 | ||||
-rw-r--r-- | sys/sys/extattr.h | 22 | ||||
-rw-r--r-- | sys/sys/mount.h | 12 | ||||
-rw-r--r-- | sys/sys/vnode.h | 12 | ||||
-rw-r--r-- | sys/ufs/ufs/extattr.h | 11 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_extattr.c | 222 |
17 files changed, 333 insertions, 172 deletions
diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c index b852cc4..c9a6801 100644 --- a/sys/fs/nullfs/null_vfsops.c +++ b/sys/fs/nullfs/null_vfsops.c @@ -73,7 +73,9 @@ static int nullfs_unmount(struct mount *mp, int mntflags, struct proc *p); static int nullfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp); static int nullfs_vptofh(struct vnode *vp, struct fid *fhp); static int nullfs_extattrctl(struct mount *mp, int cmd, - const char *attrname, caddr_t arg, struct proc *p); + struct vnode *filename_vp, + int namespace, const char *attrname, + struct proc *p); /* * Mount null layer @@ -408,15 +410,16 @@ nullfs_vptofh(vp, fhp) } static int -nullfs_extattrctl(mp, cmd, attrname, arg, p) +nullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, p) struct mount *mp; int cmd; + struct vnode *filename_vp; + int namespace; const char *attrname; - caddr_t arg; struct proc *p; { - return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, attrname, - arg, p); + return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, filename_vp, + namespace, attrname, p); } diff --git a/sys/fs/umapfs/umap_vfsops.c b/sys/fs/umapfs/umap_vfsops.c index 768ad48..abd1b07 100644 --- a/sys/fs/umapfs/umap_vfsops.c +++ b/sys/fs/umapfs/umap_vfsops.c @@ -74,7 +74,8 @@ static int umapfs_vget __P((struct mount *mp, ino_t ino, struct vnode **vpp)); static int umapfs_vptofh __P((struct vnode *vp, struct fid *fhp)); static int umapfs_extattrctl __P((struct mount *mp, int cmd, - const char *attrname, caddr_t arg, + struct vnode *filename_vp, + int namespace, const char *attrname, struct proc *p)); /* @@ -430,15 +431,16 @@ umapfs_vptofh(vp, fhp) } static int -umapfs_extattrctl(mp, cmd, attrname, arg, p) +umapfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, p) struct mount *mp; int cmd; + struct vnode *filename_vp; + int namespace; const char *attrname; - caddr_t arg; struct proc *p; { - return (VFS_EXTATTRCTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, attrname, - arg, p)); + return (VFS_EXTATTRCTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, + filename_vp, namespace, attrname, p)); } diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 2c54df2..6e834d4 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -508,15 +508,16 @@ 354 STD BSD { int __acl_aclcheck_fd(int filedes, acl_type_t type, \ struct acl *aclp); } 355 STD BSD { int extattrctl(const char *path, int cmd, \ - const char *attrname, char *arg); } + const char *filename, int namespace, \ + const char *attrname); } 356 STD BSD { int extattr_set_file(const char *path, \ - const char *attrname, struct iovec *iovp, \ - unsigned iovcnt); } + int namespace, const char *attrname, \ + struct iovec *iovp, unsigned iovcnt); } 357 STD BSD { int extattr_get_file(const char *path, \ - const char *attrname, struct iovec *iovp, \ - unsigned iovcnt); } + int namespace, const char *attrname, \ + struct iovec *iovp, unsigned iovcnt); } 358 STD BSD { int extattr_delete_file(const char *path, \ - const char *attrname); } + int namespace, const char *attrname); } 359 STD BSD { int aio_waitcomplete(struct aiocb **aiocbp, struct timespec *timeout); } 360 STD BSD { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); } 361 STD BSD { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); } diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index 3e9fc75..ee56c83 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -739,11 +739,12 @@ vfs_stduninit (vfsp) } int -vfs_stdextattrctl(mp, cmd, attrname, arg, p) +vfs_stdextattrctl(mp, cmd, filename_vp, namespace, attrname, p) struct mount *mp; int cmd; + struct vnode *filename_vp; + int namespace; const char *attrname; - caddr_t arg; struct proc *p; { return(EOPNOTSUPP); diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index a6c9887..79abaf4 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -3681,20 +3681,65 @@ extattrctl(p, uap) struct proc *p; struct extattrctl_args *uap; { + struct vnode *filename_vp; struct nameidata nd; struct mount *mp; + char attrname[EXTATTR_MAXNAMELEN]; int error; + /* + * SCARG(uap, attrname) not always defined. We check again later + * when we invoke the VFS call so as to pass in NULL there if needed. + */ + if (SCARG(uap, attrname) != NULL) { + error = copyinstr(SCARG(uap, attrname), attrname, + EXTATTR_MAXNAMELEN, NULL); + if (error) + return (error); + } + + /* + * SCARG(uap, filename) not always defined. If it is, grab + * a vnode lock, which VFS_EXTATTRCTL() will later release. + */ + filename_vp = NULL; + if (SCARG(uap, filename) != NULL) { + NDINIT(&nd, LOOKUP | LOCKLEAF, FOLLOW, UIO_USERSPACE, + SCARG(uap, filename), p); + if ((error = namei(&nd)) != 0) + return (error); + filename_vp = nd.ni_vp; + NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK); + } + + /* SCARG(uap, path) always defined. */ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); if ((error = namei(&nd)) != 0) return (error); error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); NDFREE(&nd, 0); - if (error) + if (error) { + if (filename_vp) + vrele(filename_vp); return (error); - error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname), - SCARG(uap, arg), p); + } + + if (SCARG(uap, attrname) != NULL) { + error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp, + SCARG(uap, namespace), attrname, p); + } else { + error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp, + SCARG(uap, namespace), NULL, p); + } + vn_finished_write(mp); + /* + * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, + * filename_vp, so vrele it if it is defined. + */ + if (filename_vp != NULL) + vrele(filename_vp); + return (error); } @@ -3756,8 +3801,8 @@ extattr_set_file(p, uap) iov++; } cnt = auio.uio_resid; - error = VOP_SETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred, - p); + error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, namespace), attrname, + &auio, p->p_cred->pc_ucred, p); cnt -= auio.uio_resid; p->p_retval[0] = cnt; done: @@ -3823,8 +3868,8 @@ extattr_get_file(p, uap) iov++; } cnt = auio.uio_resid; - error = VOP_GETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred, - p); + error = VOP_GETEXTATTR(nd.ni_vp, SCARG(uap, namespace), attrname, + &auio, p->p_cred->pc_ucred, p); cnt -= auio.uio_resid; p->p_retval[0] = cnt; done: @@ -3859,8 +3904,8 @@ extattr_delete_file(p, uap) NDFREE(&nd, 0); return (error); } - error = VOP_SETEXTATTR(nd.ni_vp, attrname, NULL, p->p_cred->pc_ucred, - p); + error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, namespace), attrname, + NULL, p->p_cred->pc_ucred, p); NDFREE(&nd, 0); vn_finished_write(mp); return(error); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index a6c9887..79abaf4 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -3681,20 +3681,65 @@ extattrctl(p, uap) struct proc *p; struct extattrctl_args *uap; { + struct vnode *filename_vp; struct nameidata nd; struct mount *mp; + char attrname[EXTATTR_MAXNAMELEN]; int error; + /* + * SCARG(uap, attrname) not always defined. We check again later + * when we invoke the VFS call so as to pass in NULL there if needed. + */ + if (SCARG(uap, attrname) != NULL) { + error = copyinstr(SCARG(uap, attrname), attrname, + EXTATTR_MAXNAMELEN, NULL); + if (error) + return (error); + } + + /* + * SCARG(uap, filename) not always defined. If it is, grab + * a vnode lock, which VFS_EXTATTRCTL() will later release. + */ + filename_vp = NULL; + if (SCARG(uap, filename) != NULL) { + NDINIT(&nd, LOOKUP | LOCKLEAF, FOLLOW, UIO_USERSPACE, + SCARG(uap, filename), p); + if ((error = namei(&nd)) != 0) + return (error); + filename_vp = nd.ni_vp; + NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK); + } + + /* SCARG(uap, path) always defined. */ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); if ((error = namei(&nd)) != 0) return (error); error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); NDFREE(&nd, 0); - if (error) + if (error) { + if (filename_vp) + vrele(filename_vp); return (error); - error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname), - SCARG(uap, arg), p); + } + + if (SCARG(uap, attrname) != NULL) { + error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp, + SCARG(uap, namespace), attrname, p); + } else { + error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp, + SCARG(uap, namespace), NULL, p); + } + vn_finished_write(mp); + /* + * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, + * filename_vp, so vrele it if it is defined. + */ + if (filename_vp != NULL) + vrele(filename_vp); + return (error); } @@ -3756,8 +3801,8 @@ extattr_set_file(p, uap) iov++; } cnt = auio.uio_resid; - error = VOP_SETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred, - p); + error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, namespace), attrname, + &auio, p->p_cred->pc_ucred, p); cnt -= auio.uio_resid; p->p_retval[0] = cnt; done: @@ -3823,8 +3868,8 @@ extattr_get_file(p, uap) iov++; } cnt = auio.uio_resid; - error = VOP_GETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred, - p); + error = VOP_GETEXTATTR(nd.ni_vp, SCARG(uap, namespace), attrname, + &auio, p->p_cred->pc_ucred, p); cnt -= auio.uio_resid; p->p_retval[0] = cnt; done: @@ -3859,8 +3904,8 @@ extattr_delete_file(p, uap) NDFREE(&nd, 0); return (error); } - error = VOP_SETEXTATTR(nd.ni_vp, attrname, NULL, p->p_cred->pc_ucred, - p); + error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, namespace), attrname, + NULL, p->p_cred->pc_ucred, p); NDFREE(&nd, 0); vn_finished_write(mp); return(error); diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 760df67..6c8c0f9 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -808,8 +808,8 @@ vn_kqfilter(struct file *fp, struct knote *kn) * Set IO_NODELOCKED in ioflg if the vnode is already locked. */ int -vn_extattr_get(struct vnode *vp, int ioflg, const char *attrname, int *buflen, - char *buf, struct proc *p) +vn_extattr_get(struct vnode *vp, int ioflg, int namespace, + const char *attrname, int *buflen, char *buf, struct proc *p) { struct uio auio; struct iovec iov; @@ -830,7 +830,7 @@ vn_extattr_get(struct vnode *vp, int ioflg, const char *attrname, int *buflen, vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* authorize attribute retrieval as kernel */ - error = VOP_GETEXTATTR(vp, attrname, &auio, NULL, p); + error = VOP_GETEXTATTR(vp, namespace, attrname, &auio, NULL, p); if ((ioflg & IO_NODELOCKED) == 0) VOP_UNLOCK(vp, 0, p); @@ -846,8 +846,8 @@ vn_extattr_get(struct vnode *vp, int ioflg, const char *attrname, int *buflen, * XXX failure mode if partially written? */ int -vn_extattr_set(struct vnode *vp, int ioflg, const char *attrname, int buflen, - char *buf, struct proc *p) +vn_extattr_set(struct vnode *vp, int ioflg, int namespace, + const char *attrname, int buflen, char *buf, struct proc *p) { struct uio auio; struct iovec iov; @@ -872,7 +872,7 @@ vn_extattr_set(struct vnode *vp, int ioflg, const char *attrname, int buflen, } /* authorize attribute setting as kernel */ - error = VOP_SETEXTATTR(vp, attrname, &auio, NULL, p); + error = VOP_SETEXTATTR(vp, namespace, attrname, &auio, NULL, p); if ((ioflg & IO_NODELOCKED) == 0) { vn_finished_write(mp); @@ -883,7 +883,8 @@ vn_extattr_set(struct vnode *vp, int ioflg, const char *attrname, int buflen, } int -vn_extattr_rm(struct vnode *vp, int ioflg, const char *attrname, struct proc *p) +vn_extattr_rm(struct vnode *vp, int ioflg, int namespace, const char *attrname, + struct proc *p) { struct mount *mp; int error; @@ -895,7 +896,7 @@ vn_extattr_rm(struct vnode *vp, int ioflg, const char *attrname, struct proc *p) } /* authorize attribute removal as kernel */ - error = VOP_SETEXTATTR(vp, attrname, NULL, NULL, p); + error = VOP_SETEXTATTR(vp, namespace, attrname, NULL, NULL, p); if ((ioflg & IO_NODELOCKED) == 0) { vn_finished_write(mp); diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src index 87fe31c..9cbe079 100644 --- a/sys/kern/vnode_if.src +++ b/sys/kern/vnode_if.src @@ -529,6 +529,7 @@ vop_aclcheck { # vop_getextattr { IN struct vnode *vp; + IN int namespace; IN const char *name; INOUT struct uio *uio; IN struct ucred *cred; @@ -540,6 +541,7 @@ vop_getextattr { # vop_setextattr { IN struct vnode *vp; + IN int namespace; IN const char *name; INOUT struct uio *uio; IN struct ucred *cred; diff --git a/sys/miscfs/nullfs/null_vfsops.c b/sys/miscfs/nullfs/null_vfsops.c index b852cc4..c9a6801 100644 --- a/sys/miscfs/nullfs/null_vfsops.c +++ b/sys/miscfs/nullfs/null_vfsops.c @@ -73,7 +73,9 @@ static int nullfs_unmount(struct mount *mp, int mntflags, struct proc *p); static int nullfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp); static int nullfs_vptofh(struct vnode *vp, struct fid *fhp); static int nullfs_extattrctl(struct mount *mp, int cmd, - const char *attrname, caddr_t arg, struct proc *p); + struct vnode *filename_vp, + int namespace, const char *attrname, + struct proc *p); /* * Mount null layer @@ -408,15 +410,16 @@ nullfs_vptofh(vp, fhp) } static int -nullfs_extattrctl(mp, cmd, attrname, arg, p) +nullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, p) struct mount *mp; int cmd; + struct vnode *filename_vp; + int namespace; const char *attrname; - caddr_t arg; struct proc *p; { - return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, attrname, - arg, p); + return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, filename_vp, + namespace, attrname, p); } diff --git a/sys/miscfs/umapfs/umap_vfsops.c b/sys/miscfs/umapfs/umap_vfsops.c index 768ad48..abd1b07 100644 --- a/sys/miscfs/umapfs/umap_vfsops.c +++ b/sys/miscfs/umapfs/umap_vfsops.c @@ -74,7 +74,8 @@ static int umapfs_vget __P((struct mount *mp, ino_t ino, struct vnode **vpp)); static int umapfs_vptofh __P((struct vnode *vp, struct fid *fhp)); static int umapfs_extattrctl __P((struct mount *mp, int cmd, - const char *attrname, caddr_t arg, + struct vnode *filename_vp, + int namespace, const char *attrname, struct proc *p)); /* @@ -430,15 +431,16 @@ umapfs_vptofh(vp, fhp) } static int -umapfs_extattrctl(mp, cmd, attrname, arg, p) +umapfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, p) struct mount *mp; int cmd; + struct vnode *filename_vp; + int namespace; const char *attrname; - caddr_t arg; struct proc *p; { - return (VFS_EXTATTRCTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, attrname, - arg, p)); + return (VFS_EXTATTRCTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, + filename_vp, namespace, attrname, p)); } diff --git a/sys/sys/acl.h b/sys/sys/acl.h index 26483fc..fdb6235 100644 --- a/sys/sys/acl.h +++ b/sys/sys/acl.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1999-2001 Robert N. M. Watson + * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,8 +37,10 @@ * POSIX.1e ACL types and related constants. */ -#define POSIX1E_ACL_ACCESS_EXTATTR_NAME "$posix1e.acl_access" -#define POSIX1E_ACL_DEFAULT_EXTATTR_NAME "$posix1e.acl_default" +#define POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM +#define POSIX1E_ACL_ACCESS_EXTATTR_NAME "posix1e.acl_access" +#define POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM +#define POSIX1E_ACL_DEFAULT_EXTATTR_NAME "posix1e.acl_default" #define ACL_MAX_ENTRIES 32 /* maximum entries in an ACL */ #define _POSIX_ACL_PATH_MAX ACL_MAX_ENTRIES diff --git a/sys/sys/capability.h b/sys/sys/capability.h index cc56c58..8661595 100644 --- a/sys/sys/capability.h +++ b/sys/sys/capability.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000 Robert N. M. Watson + * Copyright (c) 2000, 2001 Robert N. M. Watson * All rights reserved. * * Copyright (c) 1999 Ilmar S. Habibulin @@ -36,7 +36,8 @@ #ifndef _SYS_CAPABILITY_H #define _SYS_CAPABILITY_H -#define POSIX1E_CAPABILITY_EXTATTR_NAME "$posix1e.cap" +#define POSIX1E_CAPABILITY_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM +#define POSIX1E_CAPABILITY_EXTATTR_NAME "posix1e.cap" typedef int cap_flag_t; typedef int cap_flag_value_t; diff --git a/sys/sys/extattr.h b/sys/sys/extattr.h index d03d4fb..4b545da 100644 --- a/sys/sys/extattr.h +++ b/sys/sys/extattr.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1999 Robert N. M. Watson + * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,6 +41,12 @@ #ifndef _SYS_EXTATTR_H_ #define _SYS_EXTATTR_H_ + +#define EXTATTR_NAMESPACE_USER 0x00000001 +#define EXTATTR_NAMESPACE_USER_STRING "user" +#define EXTATTR_NAMESPACE_SYSTEM 0x00000002 +#define EXTATTR_NAMESPACE_SYSTEM_STRING "system" + #ifdef _KERNEL #define EXTATTR_MAXNAMELEN NAME_MAX @@ -51,12 +57,14 @@ struct iovec; __BEGIN_DECLS -int extattrctl(const char *path, int cmd, const char *attrname, char *arg); -int extattr_delete_file(const char *path, const char *attrname); -int extattr_get_file(const char *path, const char *attrname, - struct iovec *iovp, unsigned iovcnt); -int extattr_set_file(const char *path, const char *attrname, - struct iovec *iovp, unsigned iovcnt); +int extattrctl(const char *path, int cmd, const char *filename, + int namespace, const char *attrname); +int extattr_delete_file(const char *path, int namespace, + const char *attrname); +int extattr_get_file(const char *path, int namespace, + const char *attrname, struct iovec *iovp, unsigned iovcnt); +int extattr_set_file(const char *path, int namespace, + const char *attrname, struct iovec *iovp, unsigned iovcnt); __END_DECLS #endif /* !_KERNEL */ diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 70d84f3..8858529 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -339,7 +339,8 @@ struct vfsops { int (*vfs_init) __P((struct vfsconf *)); int (*vfs_uninit) __P((struct vfsconf *)); int (*vfs_extattrctl) __P((struct mount *mp, int cmd, - const char *attrname, caddr_t arg, + struct vnode *filename_vp, + int namespace, const char *attrname, struct proc *p)); }; @@ -357,8 +358,8 @@ struct vfsops { #define VFS_VPTOFH(VP, FIDP) (*(VP)->v_mount->mnt_op->vfs_vptofh)(VP, FIDP) #define VFS_CHECKEXP(MP, NAM, EXFLG, CRED) \ (*(MP)->mnt_op->vfs_checkexp)(MP, NAM, EXFLG, CRED) -#define VFS_EXTATTRCTL(MP, C, N, A, P) \ - (*(MP)->mnt_op->vfs_extattrctl)(MP, C, N, A, P) +#define VFS_EXTATTRCTL(MP, C, FN, NS, N, P) \ + (*(MP)->mnt_op->vfs_extattrctl)(MP, C, FN, NS, N, P) #include <sys/module.h> @@ -453,8 +454,9 @@ int vfs_stdcheckexp __P((struct mount *mp, struct sockaddr *nam, int vfs_stdvptofh __P((struct vnode *vp, struct fid *fhp)); int vfs_stdinit __P((struct vfsconf *)); int vfs_stduninit __P((struct vfsconf *)); -int vfs_stdextattrctl __P((struct mount *mp, int cmd, const char *attrname, - caddr_t arg, struct proc *p)); +int vfs_stdextattrctl __P((struct mount *mp, int cmd, + struct vnode *filename_vp, int namespace, const char *attrname, + struct proc *p)); /* XXX - these should be indirect functions!!! */ int softdep_process_worklist __P((struct mount *)); diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 7ff2c31..76093ae 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -607,12 +607,12 @@ dev_t vn_todev __P((struct vnode *vp)); int vn_write_suspend_wait __P((struct vnode *vp, struct mount *mp, int flags)); int vn_writechk __P((struct vnode *vp)); -int vn_extattr_get __P((struct vnode *vp, int ioflg, const char *attrname, - int *buflen, char *buf, struct proc *p)); -int vn_extattr_set __P((struct vnode *vp, int ioflg, const char *attrname, - int buflen, char *buf, struct proc *p)); -int vn_extattr_rm(struct vnode *vp, int ioflg, const char *attrname, - struct proc *p); +int vn_extattr_get __P((struct vnode *vp, int ioflg, int namespace, + const char *attrname, int *buflen, char *buf, struct proc *p)); +int vn_extattr_set __P((struct vnode *vp, int ioflg, int namespace, + const char *attrname, int buflen, char *buf, struct proc *p)); +int vn_extattr_rm(struct vnode *vp, int ioflg, int namespace, + const char *attrname, struct proc *p); int vfs_cache_lookup __P((struct vop_lookup_args *ap)); int vfs_object_create __P((struct vnode *vp, struct proc *p, struct ucred *cred)); diff --git a/sys/ufs/ufs/extattr.h b/sys/ufs/ufs/extattr.h index 849e632..f7cbfaa 100644 --- a/sys/ufs/ufs/extattr.h +++ b/sys/ufs/ufs/extattr.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1999, 2000 Robert N. M. Watson + * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,8 +73,9 @@ MALLOC_DECLARE(M_EXTATTR); struct vnode; LIST_HEAD(ufs_extattr_list_head, ufs_extattr_list_entry); struct ufs_extattr_list_entry { - LIST_ENTRY(ufs_extattr_list_entry) uele_entries; - struct ufs_extattr_fileheader uele_fileheader; + LIST_ENTRY(ufs_extattr_list_entry) uele_entries; + struct ufs_extattr_fileheader uele_fileheader; + int uele_namespace; char uele_attrname[UFS_EXTATTR_MAXEXTATTRNAME]; struct vnode *uele_backing_vnode; }; @@ -93,8 +94,8 @@ void ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm); int ufs_extattr_start(struct mount *mp, struct proc *p); int ufs_extattr_autostart(struct mount *mp, struct proc *p); int ufs_extattr_stop(struct mount *mp, struct proc *p); -int ufs_extattrctl(struct mount *mp, int cmd, const char *attrname, - caddr_t arg, struct proc *p); +int ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename, + int namespace, const char *attrname, struct proc *p); int ufs_vop_getextattr(struct vop_getextattr_args *ap); int ufs_vop_setextattr(struct vop_setextattr_args *ap); void ufs_extattr_vnode_inactive(struct vnode *vp, struct proc *p); diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c index 2c00b95..24d4a03 100644 --- a/sys/ufs/ufs/ufs_extattr.c +++ b/sys/ufs/ufs/ufs_extattr.c @@ -40,6 +40,7 @@ #include <sys/mount.h> #include <sys/lock.h> #include <sys/dirent.h> +#include <sys/extattr.h> #include <vm/vm_zone.h> @@ -52,6 +53,8 @@ #include "opt_ffs.h" +#ifdef FFS_EXTATTR + #define MIN(a,b) (((a)<(b))?(a):(b)) static MALLOC_DEFINE(M_UFS_EXTATTR, "ufs_extattr", "ufs extended attribute"); @@ -60,16 +63,18 @@ static int ufs_extattr_valid_attrname(const char *attrname); static int ufs_extattr_credcheck(struct vnode *vp, struct ufs_extattr_list_entry *uele, struct ucred *cred, struct proc *p, int access); -static int ufs_extattr_enable(struct ufsmount *ump, const char *attrname, - struct vnode *backing_vnode, struct proc *p); -static int ufs_extattr_disable(struct ufsmount *ump, const char *attrname, - struct proc *p); -static int ufs_extattr_get(struct vnode *vp, const char *name, - struct uio *uio, struct ucred *cred, struct proc *p); -static int ufs_extattr_set(struct vnode *vp, const char *name, - struct uio *uio, struct ucred *cred, struct proc *p); -static int ufs_extattr_rm(struct vnode *vp, const char *name, - struct ucred *cred, struct proc *p); +static int ufs_extattr_enable_with_open(struct ufsmount *ump, + struct vnode *vp, int namespace, const char *attrname, struct proc *p); +static int ufs_extattr_enable(struct ufsmount *ump, int namespace, + const char *attrname, struct vnode *backing_vnode, struct proc *p); +static int ufs_extattr_disable(struct ufsmount *ump, int namespace, + const char *attrname, struct proc *p); +static int ufs_extattr_get(struct vnode *vp, int namespace, + const char *name, struct uio *uio, struct ucred *cred, struct proc *p); +static int ufs_extattr_set(struct vnode *vp, int namespace, + const char *name, struct uio *uio, struct ucred *cred, struct proc *p); +static int ufs_extattr_rm(struct vnode *vp, int namespace, + const char *name, struct ucred *cred, struct proc *p); /* * Per-FS attribute lock protecting attribute operations. @@ -119,7 +124,8 @@ ufs_extattr_valid_attrname(const char *attrname) * Must be holding uepm lock for the mount point. */ static struct ufs_extattr_list_entry * -ufs_extattr_find_attr(struct ufsmount *ump, const char *attrname) +ufs_extattr_find_attr(struct ufsmount *ump, int namespace, + const char *attrname) { struct ufs_extattr_list_entry *search_attribute; @@ -127,7 +133,8 @@ ufs_extattr_find_attr(struct ufsmount *ump, const char *attrname) search_attribute; search_attribute = LIST_NEXT(search_attribute, uele_entries)) { if (!(strncmp(attrname, search_attribute->uele_attrname, - UFS_EXTATTR_MAXEXTATTRNAME))) { + UFS_EXTATTR_MAXEXTATTRNAME)) && + (namespace == search_attribute->uele_namespace)) { return (search_attribute); } } @@ -291,17 +298,18 @@ ufs_extattr_lookup(struct vnode *start_dvp, int lockparent, char *dirname, *vp = target_vp; return (0); } +#endif /* !FFS_EXTATTR_AUTOSTART */ /* * Enable an EA using the passed file system, backing vnode, attribute name, - * and proc. Will perform a VOP_OPEN() on the vp, so expects vp to be locked - * when passed in. Will unlock vp, and grab its own reference, so the caller - * needs to vrele(), just not vput(). If the call fails, the lock is not - * released. + * namespace, and proc. Will perform a VOP_OPEN() on the vp, so expects vp + * to be locked when passed in. Will unlock vp, and grab its own reference, + * so the caller needs to vrele(), just not vput(). The unlock the vnode + * regardless of call success or failure. */ static int ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp, - char *attrname, struct proc *p) + int namespace, const char *attrname, struct proc *p) { int error; @@ -309,6 +317,7 @@ ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp, if (error) { printf("ufs_extattr_enable_with_open.VOP_OPEN(): failed " "with %d\n", error); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -322,6 +331,7 @@ ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp, * XXX: bug replicated from vn_open(): should * VOP_CLOSE() here. */ + VOP_UNLOCK(vp, 0, p); return (error); } @@ -331,9 +341,10 @@ ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp, VOP_UNLOCK(vp, 0, p); - return (ufs_extattr_enable(ump, attrname, vp, p)); + return (ufs_extattr_enable(ump, namespace, attrname, vp, p)); } +#ifdef FFS_EXTATTR_AUTOSTART /* * Given a locked directory vnode, iterate over the names in the directory * and use ufs_extattr_lookup() to retrieve locked vnodes of potential @@ -344,7 +355,7 @@ ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp, */ static int ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp, - struct proc *p) + int namespace, struct proc *p) { struct vop_readdir_args vargs; struct dirent *dp, *edp; @@ -412,19 +423,18 @@ ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp, vput(attr_vp); } else { error = ufs_extattr_enable_with_open(ump, - attr_vp, dp->d_name, p); + attr_vp, namespace, dp->d_name, p); + vrele(attr_vp); if (error) { printf("ufs_extattr_iterate_directory: " "enable %s %d\n", dp->d_name, error); - vput(attr_vp); } else { /* * While it's nice to have some visual output here, skip for the time-being. * Probably should be enabled by -v at boot. printf("Autostarted %s\n", dp->d_name); */ - vrele(attr_vp); } } dp = (struct dirent *) ((char *)dp + dp->d_reclen); @@ -448,8 +458,8 @@ ufs_extattr_autostart(struct mount *mp, struct proc *p) int error; /* - * Does ".attribute" exist off the file system root? If so, - * automatically start EA's. + * Does UFS_EXTATTR_FSROOTSUBDIR exist off the file system root? + * If so, automatically start EA's. */ error = VFS_ROOT(mp, &rvp); if (error) { @@ -458,7 +468,7 @@ ufs_extattr_autostart(struct mount *mp, struct proc *p) } error = ufs_extattr_lookup(rvp, UE_GETDIR_LOCKPARENT_DONT, - ".attribute", &attr_dvp, p); + UFS_EXTATTR_FSROOTSUBDIR, &attr_dvp, p); if (error) { /* rvp ref'd but now unlocked */ vrele(rvp); @@ -473,7 +483,8 @@ ufs_extattr_autostart(struct mount *mp, struct proc *p) vrele(rvp); if (attr_dvp->v_type != VDIR) { - printf("ufs_extattr_autostart: .attribute != VDIR\n"); + printf("ufs_extattr_autostart: %s != VDIR\n", + UFS_EXTATTR_FSROOTSUBDIR); goto return_vput; } @@ -485,10 +496,15 @@ ufs_extattr_autostart(struct mount *mp, struct proc *p) } /* - * Iterate over the directory. Eventually we may lookup sub-directories - * and iterate over them independently. + * Iterate over the directory. Eventually we will lookup sub- + * directories and iterate over them independently with different + * EA namespaces. + * + * XXX: Right now, assert that all attributes are in the system + * namespace. */ - error = ufs_extattr_iterate_directory(VFSTOUFS(mp), attr_dvp, p); + error = ufs_extattr_iterate_directory(VFSTOUFS(mp), attr_dvp, + EXTATTR_NAMESPACE_SYSTEM, p); if (error) printf("ufs_extattr_iterate_directory returned %d\n", error); @@ -521,7 +537,8 @@ ufs_extattr_stop(struct mount *mp, struct proc *p) while (LIST_FIRST(&ump->um_extattr.uepm_list) != NULL) { uele = LIST_FIRST(&ump->um_extattr.uepm_list); - ufs_extattr_disable(ump, uele->uele_attrname, p); + ufs_extattr_disable(ump, uele->uele_namespace, + uele->uele_attrname, p); } ump->um_extattr.uepm_flags &= ~UFS_EXTATTR_UEPM_STARTED; @@ -536,11 +553,11 @@ unlock: } /* - * Enable a named attribute on the specified file system; provide a - * backing vnode to hold the attribute data. + * Enable a named attribute on the specified file system; provide an + * unlocked backing vnode to hold the attribute data. */ static int -ufs_extattr_enable(struct ufsmount *ump, const char *attrname, +ufs_extattr_enable(struct ufsmount *ump, int namespace, const char *attrname, struct vnode *backing_vnode, struct proc *p) { struct ufs_extattr_list_entry *attribute; @@ -563,12 +580,13 @@ ufs_extattr_enable(struct ufsmount *ump, const char *attrname, goto free_exit; } - if (ufs_extattr_find_attr(ump, attrname)) { + if (ufs_extattr_find_attr(ump, namespace, attrname)) { error = EEXIST; goto free_exit; } strncpy(attribute->uele_attrname, attrname, UFS_EXTATTR_MAXEXTATTRNAME); + attribute->uele_namespace = namespace; bzero(&attribute->uele_fileheader, sizeof(struct ufs_extattr_fileheader)); @@ -590,9 +608,8 @@ ufs_extattr_enable(struct ufsmount *ump, const char *attrname, ump->um_extattr.uepm_ucred); VOP_UNLOCK(backing_vnode, 0, p); - if (error) { + if (error) goto free_exit; - } if (auio.uio_resid != 0) { printf("ufs_extattr_enable: malformed attribute header\n"); @@ -627,7 +644,8 @@ free_exit: * Disable extended attribute support on an FS. */ static int -ufs_extattr_disable(struct ufsmount *ump, const char *attrname, struct proc *p) +ufs_extattr_disable(struct ufsmount *ump, int namespace, const char *attrname, + struct proc *p) { struct ufs_extattr_list_entry *uele; int error = 0; @@ -635,7 +653,7 @@ ufs_extattr_disable(struct ufsmount *ump, const char *attrname, struct proc *p) if (!ufs_extattr_valid_attrname(attrname)) return (EINVAL); - uele = ufs_extattr_find_attr(ump, attrname); + uele = ufs_extattr_find_attr(ump, namespace, attrname); if (!uele) return (ENOENT); @@ -650,65 +668,83 @@ ufs_extattr_disable(struct ufsmount *ump, const char *attrname, struct proc *p) } /* - * VFS call to manage extended attributes in UFS. - * attrname, arg are userspace pointers from the syscall. + * VFS call to manage extended attributes in UFS. If filename_vp is + * non-NULL, it must be passed in locked, and regardless of errors in + * processing, will be unlocked. */ int -ufs_extattrctl(struct mount *mp, int cmd, const char *attrname, - caddr_t arg, struct proc *p) +ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, + int namespace, const char *attrname, struct proc *p) { - struct nameidata nd; struct ufsmount *ump = VFSTOUFS(mp); - struct vnode *vp; - char local_attrname[UFS_EXTATTR_MAXEXTATTRNAME]; /* Incl. null. */ - char *filename; - int error, flags; - size_t len; + int error; /* * Processes with privilege, but in jail, are not allowed to * configure extended attributes. */ - if ((error = suser_xxx(p->p_cred->pc_ucred, p, 0))) + if ((error = suser_xxx(p->p_cred->pc_ucred, p, 0))) { + if (filename_vp != NULL) + VOP_UNLOCK(filename_vp, 0, p); return (error); + } switch(cmd) { case UFS_EXTATTR_CMD_START: + if (filename_vp != NULL) { + VOP_UNLOCK(filename_vp, 0, p); + return (EINVAL); + } + if (attrname != NULL) + return (EINVAL); + error = ufs_extattr_start(mp, p); return (error); case UFS_EXTATTR_CMD_STOP: - return (ufs_extattr_stop(mp, p)); + if (filename_vp != NULL) { + VOP_UNLOCK(filename_vp, 0, p); + return (EINVAL); + } + if (attrname != NULL) + return (EINVAL); + + error = ufs_extattr_stop(mp, p); + + return (error); case UFS_EXTATTR_CMD_ENABLE: - error = copyinstr(attrname, local_attrname, - UFS_EXTATTR_MAXEXTATTRNAME, &len); - if (error) - return (error); - filename = (char *) arg; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, filename, p); - flags = FREAD | FWRITE; - error = vn_open(&nd, &flags, 0); - if (error) - return (error); + if (filename_vp == NULL) + return (EINVAL); + if (attrname == NULL) { + VOP_UNLOCK(filename_vp, 0, p); + return (EINVAL); + } - vp = nd.ni_vp; - VOP_UNLOCK(vp, 0, p); - + /* + * ufs_extattr_enable_with_open() will always unlock the + * vnode, regardless of failure. + */ ufs_extattr_uepm_lock(ump, p); - error = ufs_extattr_enable(ump, local_attrname, vp, p); + error = ufs_extattr_enable_with_open(ump, filename_vp, + namespace, attrname, p); ufs_extattr_uepm_unlock(ump, p); return (error); case UFS_EXTATTR_CMD_DISABLE: - error = copyinstr(attrname, local_attrname, - UFS_EXTATTR_MAXEXTATTRNAME, &len); + + if (filename_vp != NULL) { + VOP_UNLOCK(filename_vp, 0, p); + return (EINVAL); + } + if (attrname == NULL) + return (EINVAL); ufs_extattr_uepm_lock(ump, p); - error = ufs_extattr_disable(ump, local_attrname, p); + error = ufs_extattr_disable(ump, namespace, attrname, p); ufs_extattr_uepm_unlock(ump, p); return (error); @@ -726,10 +762,6 @@ static int ufs_extattr_credcheck(struct vnode *vp, struct ufs_extattr_list_entry *uele, struct ucred *cred, struct proc *p, int access) { - int system_namespace; - - system_namespace = (strlen(uele->uele_attrname) >= 1 && - uele->uele_attrname[0] == '$'); /* * Kernel-invoked always succeeds. @@ -744,10 +776,14 @@ ufs_extattr_credcheck(struct vnode *vp, struct ufs_extattr_list_entry *uele, * XXX What capability should apply here? * Probably CAP_SYS_SETFFLAG. */ - if (system_namespace) + switch (uele->uele_namespace) { + case EXTATTR_NAMESPACE_SYSTEM: return (suser_xxx(cred, p, 0)); - else + case EXTATTR_NAMESPACE_USER: return (VOP_ACCESS(vp, access, cred, p)); + default: + return (EPERM); + } } /* @@ -758,6 +794,7 @@ ufs_vop_getextattr(struct vop_getextattr_args *ap) /* vop_getextattr { IN struct vnode *a_vp; + IN int a_namespace; IN const char *a_name; INOUT struct uio *a_uio; IN struct ucred *a_cred; @@ -771,8 +808,8 @@ vop_getextattr { ufs_extattr_uepm_lock(ump, ap->a_p); - error = ufs_extattr_get(ap->a_vp, ap->a_name, ap->a_uio, ap->a_cred, - ap->a_p); + error = ufs_extattr_get(ap->a_vp, ap->a_namespace, ap->a_name, + ap->a_uio, ap->a_cred, ap->a_p); ufs_extattr_uepm_unlock(ump, ap->a_p); @@ -784,8 +821,8 @@ vop_getextattr { * the attribute lock has already been grabbed. */ static int -ufs_extattr_get(struct vnode *vp, const char *name, struct uio *uio, - struct ucred *cred, struct proc *p) +ufs_extattr_get(struct vnode *vp, int namespace, const char *name, + struct uio *uio, struct ucred *cred, struct proc *p) { struct ufs_extattr_list_entry *attribute; struct ufs_extattr_header ueh; @@ -801,12 +838,13 @@ ufs_extattr_get(struct vnode *vp, const char *name, struct uio *uio, if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) return (EOPNOTSUPP); - if (strlen(name) == 0 || (strlen(name) == 1 && name[0] == '$')) { + if (strlen(name) == 0) { /* XXX retrieve attribute lists. */ + /* XXX should probably be checking for name == NULL? */ return (EINVAL); } - attribute = ufs_extattr_find_attr(ump, name); + attribute = ufs_extattr_find_attr(ump, namespace, name); if (!attribute) return (ENOENT); @@ -923,6 +961,7 @@ ufs_vop_setextattr(struct vop_setextattr_args *ap) /* vop_setextattr { IN struct vnode *a_vp; + IN int a_namespace; IN const char *a_name; INOUT struct uio *a_uio; IN struct ucred *a_cred; @@ -938,11 +977,11 @@ vop_setextattr { ufs_extattr_uepm_lock(ump, ap->a_p); if (ap->a_uio != NULL) - error = ufs_extattr_set(ap->a_vp, ap->a_name, ap->a_uio, - ap->a_cred, ap->a_p); + error = ufs_extattr_set(ap->a_vp, ap->a_namespace, ap->a_name, + ap->a_uio, ap->a_cred, ap->a_p); else - error = ufs_extattr_rm(ap->a_vp, ap->a_name, ap->a_cred, - ap->a_p); + error = ufs_extattr_rm(ap->a_vp, ap->a_namespace, ap->a_name, + ap->a_cred, ap->a_p); ufs_extattr_uepm_unlock(ump, ap->a_p); @@ -954,8 +993,8 @@ vop_setextattr { * assumes that the attribute lock has already been grabbed. */ static int -ufs_extattr_set(struct vnode *vp, const char *name, struct uio *uio, - struct ucred *cred, struct proc *p) +ufs_extattr_set(struct vnode *vp, int namespace, const char *name, + struct uio *uio, struct ucred *cred, struct proc *p) { struct ufs_extattr_list_entry *attribute; struct ufs_extattr_header ueh; @@ -974,7 +1013,7 @@ ufs_extattr_set(struct vnode *vp, const char *name, struct uio *uio, if (!ufs_extattr_valid_attrname(name)) return (EINVAL); - attribute = ufs_extattr_find_attr(ump, name); + attribute = ufs_extattr_find_attr(ump, namespace, name); if (!attribute) return (ENOENT); @@ -1059,8 +1098,8 @@ vopunlock_exit: * Assumes the attribute lock has already been grabbed. */ static int -ufs_extattr_rm(struct vnode *vp, const char *name, struct ucred *cred, - struct proc *p) +ufs_extattr_rm(struct vnode *vp, int namespace, const char *name, + struct ucred *cred, struct proc *p) { struct ufs_extattr_list_entry *attribute; struct ufs_extattr_header ueh; @@ -1079,7 +1118,7 @@ ufs_extattr_rm(struct vnode *vp, const char *name, struct ucred *cred, if (!ufs_extattr_valid_attrname(name)) return (EINVAL); - attribute = ufs_extattr_find_attr(ump, name); + attribute = ufs_extattr_find_attr(ump, namespace, name); if (!attribute) return (ENOENT); @@ -1191,7 +1230,10 @@ ufs_extattr_vnode_inactive(struct vnode *vp, struct proc *p) } LIST_FOREACH(uele, &ump->um_extattr.uepm_list, uele_entries) - ufs_extattr_rm(vp, uele->uele_attrname, NULL, p); + ufs_extattr_rm(vp, uele->uele_namespace, uele->uele_attrname, + NULL, p); ufs_extattr_uepm_unlock(ump, p); } + +#endif /* !FFS_EXTATTR */ |