diff options
-rw-r--r-- | sys/coda/coda_vfsops.c | 1 | ||||
-rw-r--r-- | sys/conf/NOTES | 5 | ||||
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/conf/options | 5 | ||||
-rw-r--r-- | sys/contrib/softupdates/ffs_softdep.c | 1 | ||||
-rw-r--r-- | sys/fs/coda/coda_vfsops.c | 1 | ||||
-rw-r--r-- | sys/gnu/ext2fs/ext2_bmap.c | 1 | ||||
-rw-r--r-- | sys/gnu/ext2fs/ext2_mount.h | 2 | ||||
-rw-r--r-- | sys/gnu/fs/ext2fs/ext2_bmap.c | 1 | ||||
-rw-r--r-- | sys/gnu/fs/ext2fs/ext2_mount.h | 2 | ||||
-rw-r--r-- | sys/i386/conf/LINT | 5 | ||||
-rw-r--r-- | sys/i386/conf/NOTES | 5 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_alloc.c | 1 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_inode.c | 1 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 1 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 14 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vnops.c | 7 | ||||
-rw-r--r-- | sys/ufs/mfs/mfs_vfsops.c | 1 | ||||
-rw-r--r-- | sys/ufs/ufs/extattr.h | 100 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_bmap.c | 1 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_extattr.c | 787 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_inode.c | 5 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_lookup.c | 1 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_quota.c | 1 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_vfsops.c | 1 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_vnops.c | 1 | ||||
-rw-r--r-- | sys/ufs/ufs/ufsmount.h | 2 |
27 files changed, 954 insertions, 0 deletions
diff --git a/sys/coda/coda_vfsops.c b/sys/coda/coda_vfsops.c index 7450c97..c9e7d59 100644 --- a/sys/coda/coda_vfsops.c +++ b/sys/coda/coda_vfsops.c @@ -502,6 +502,7 @@ getNewVnode(vpp) NULL, NULL); } +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/ufsmount.h> /* get the mount structure corresponding to a given device. Assume diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 629eebf..d68acb8 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -632,6 +632,11 @@ options DEVFS #devices filesystem # #options SOFTUPDATES +# Extended attributes allow additional data to be associated with files, +# and is used for ACLs, Capabilities, and MAC labels +# +options FFS_EXTATTR + # Make space in the kernel for a root filesystem on a md device. # Define to the number of kilobytes to reserve for the filesystem. options MD_ROOT_SIZE=10 diff --git a/sys/conf/files b/sys/conf/files index a0e1514..937b46b 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -857,6 +857,7 @@ ufs/mfs/mfs_vfsops.c optional mfs ufs/mfs/mfs_vnops.c optional mfs ufs/ufs/ufs_bmap.c standard ufs/ufs/ufs_disksubr.c standard +ufs/ufs/ufs_extattr.c standard ufs/ufs/ufs_ihash.c standard ufs/ufs/ufs_inode.c standard ufs/ufs/ufs_lookup.c standard diff --git a/sys/conf/options b/sys/conf/options index c200a94..d58c413 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -117,6 +117,11 @@ NWFS # otherwise a STUB module will be compiled in. SOFTUPDATES opt_ffs.h +# Enabling this option turns on support for extended attributes +# in FFS, which can be used to support high security configurations +# as well as new file system features. +FFS_EXTATTR opt_ffs.h + # The above static dependencies are planned removed, with a # <filesystem>_ROOT option to control if it usable as root. This list # allows these options to be present in config files already (though diff --git a/sys/contrib/softupdates/ffs_softdep.c b/sys/contrib/softupdates/ffs_softdep.c index a6535cd..4b3807d 100644 --- a/sys/contrib/softupdates/ffs_softdep.c +++ b/sys/contrib/softupdates/ffs_softdep.c @@ -77,6 +77,7 @@ #include <sys/vnode.h> #include <sys/conf.h> #include <ufs/ufs/dir.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufsmount.h> diff --git a/sys/fs/coda/coda_vfsops.c b/sys/fs/coda/coda_vfsops.c index 7450c97..c9e7d59 100644 --- a/sys/fs/coda/coda_vfsops.c +++ b/sys/fs/coda/coda_vfsops.c @@ -502,6 +502,7 @@ getNewVnode(vpp) NULL, NULL); } +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/ufsmount.h> /* get the mount structure corresponding to a given device. Assume diff --git a/sys/gnu/ext2fs/ext2_bmap.c b/sys/gnu/ext2fs/ext2_bmap.c index d8c61b1..32ba53c 100644 --- a/sys/gnu/ext2fs/ext2_bmap.c +++ b/sys/gnu/ext2fs/ext2_bmap.c @@ -48,6 +48,7 @@ #include <sys/resourcevar.h> #include <sys/conf.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufsmount.h> diff --git a/sys/gnu/ext2fs/ext2_mount.h b/sys/gnu/ext2fs/ext2_mount.h index 0652545..900c81e 100644 --- a/sys/gnu/ext2fs/ext2_mount.h +++ b/sys/gnu/ext2fs/ext2_mount.h @@ -69,6 +69,7 @@ struct ucred; struct uio; struct vnode; struct netexport; +struct ufs_extattr_per_mount; /* This structure describes the UFS specific mount structure data. */ struct ufsmount { @@ -86,6 +87,7 @@ struct ufsmount { struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */ struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */ + struct ufs_extattr_per_mount um_extattr; /* extended attrs */ u_long um_nindir; /* indirect ptrs per block */ u_long um_bptrtodb; /* indir ptr to disk block */ u_long um_seqinc; /* inc between seq blocks */ diff --git a/sys/gnu/fs/ext2fs/ext2_bmap.c b/sys/gnu/fs/ext2fs/ext2_bmap.c index d8c61b1..32ba53c 100644 --- a/sys/gnu/fs/ext2fs/ext2_bmap.c +++ b/sys/gnu/fs/ext2fs/ext2_bmap.c @@ -48,6 +48,7 @@ #include <sys/resourcevar.h> #include <sys/conf.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufsmount.h> diff --git a/sys/gnu/fs/ext2fs/ext2_mount.h b/sys/gnu/fs/ext2fs/ext2_mount.h index 0652545..900c81e 100644 --- a/sys/gnu/fs/ext2fs/ext2_mount.h +++ b/sys/gnu/fs/ext2fs/ext2_mount.h @@ -69,6 +69,7 @@ struct ucred; struct uio; struct vnode; struct netexport; +struct ufs_extattr_per_mount; /* This structure describes the UFS specific mount structure data. */ struct ufsmount { @@ -86,6 +87,7 @@ struct ufsmount { struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */ struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */ + struct ufs_extattr_per_mount um_extattr; /* extended attrs */ u_long um_nindir; /* indirect ptrs per block */ u_long um_bptrtodb; /* indir ptr to disk block */ u_long um_seqinc; /* inc between seq blocks */ diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index 629eebf..d68acb8 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -632,6 +632,11 @@ options DEVFS #devices filesystem # #options SOFTUPDATES +# Extended attributes allow additional data to be associated with files, +# and is used for ACLs, Capabilities, and MAC labels +# +options FFS_EXTATTR + # Make space in the kernel for a root filesystem on a md device. # Define to the number of kilobytes to reserve for the filesystem. options MD_ROOT_SIZE=10 diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 629eebf..d68acb8 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -632,6 +632,11 @@ options DEVFS #devices filesystem # #options SOFTUPDATES +# Extended attributes allow additional data to be associated with files, +# and is used for ACLs, Capabilities, and MAC labels +# +options FFS_EXTATTR + # Make space in the kernel for a root filesystem on a md device. # Define to the number of kilobytes to reserve for the filesystem. options MD_ROOT_SIZE=10 diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index 361d887..0b06479 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -47,6 +47,7 @@ #include <sys/sysctl.h> #include <sys/syslog.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufs_extern.h> diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c index 4081c76..78b8f7e 100644 --- a/sys/ufs/ffs/ffs_inode.c +++ b/sys/ufs/ffs/ffs_inode.c @@ -49,6 +49,7 @@ #include <vm/vm.h> #include <vm/vm_extern.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/ufsmount.h> #include <ufs/ufs/inode.h> diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index a6535cd..4b3807d 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -77,6 +77,7 @@ #include <sys/vnode.h> #include <sys/conf.h> #include <ufs/ufs/dir.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufsmount.h> diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 511c827..39a0831 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -34,6 +34,7 @@ * $FreeBSD$ */ +#include "opt_ffs.h" #include "opt_quota.h" #include <sys/param.h> @@ -49,6 +50,7 @@ #include <sys/disklabel.h> #include <sys/malloc.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/ufsmount.h> #include <ufs/ufs/inode.h> @@ -84,7 +86,11 @@ static struct vfsops ufs_vfsops = { ffs_vptofh, ffs_init, vfs_stduninit, +#ifdef FFS_EXTATTR + ufs_extattrctl, +#else vfs_stdextattrctl, +#endif }; VFS_SET(ufs_vfsops, ufs, 0); @@ -710,6 +716,9 @@ ffs_mountfs(devvp, mp, p, malloctype) ump->um_seqinc = fs->fs_frag; for (i = 0; i < MAXQUOTAS; i++) ump->um_quotas[i] = NULLVP; +#ifdef FFS_EXTATTR + ufs_extattr_uepm_init(&ump->um_extattr); +#endif devvp->v_specmountpoint = mp; ffs_oldfscompat(fs); @@ -808,6 +817,11 @@ ffs_unmount(mp, mntflags, p) if (mntflags & MNT_FORCE) { flags |= FORCECLOSE; } +#ifdef FFS_EXTATTR + if ((error = ufs_extattr_stop(mp, p))) { + printf("ffs_unmonut: ufs_extattr_stop returned %d\n", error); + } +#endif if (mp->mnt_flag & MNT_SOFTDEP) { if ((error = softdep_flushfiles(mp, flags, p)) != 0) return (error); diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 5a7ce0b..1964a75 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -34,6 +34,8 @@ * $FreeBSD$ */ +#include "opt_ffs.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/resourcevar.h> @@ -53,6 +55,7 @@ #include <vm/vm_object.h> #include <vm/vm_extern.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufsmount.h> @@ -78,6 +81,10 @@ static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { { &vop_balloc_desc, (vop_t *) ffs_balloc }, { &vop_reallocblks_desc, (vop_t *) ffs_reallocblks }, { &vop_write_desc, (vop_t *) ffs_write }, +#ifdef FFS_EXTATTR + { &vop_getextattr_desc, (vop_t *) ufs_vop_getextattr }, + { &vop_setextattr_desc, (vop_t *) ufs_vop_setextattr }, +#endif { NULL, NULL } }; static struct vnodeopv_desc ffs_vnodeop_opv_desc = diff --git a/sys/ufs/mfs/mfs_vfsops.c b/sys/ufs/mfs/mfs_vfsops.c index 6e034d1..2739f87 100644 --- a/sys/ufs/mfs/mfs_vfsops.c +++ b/sys/ufs/mfs/mfs_vfsops.c @@ -49,6 +49,7 @@ #include <sys/malloc.h> #include <sys/linker.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufsmount.h> diff --git a/sys/ufs/ufs/extattr.h b/sys/ufs/ufs/extattr.h new file mode 100644 index 0000000..4d3626d --- /dev/null +++ b/sys/ufs/ufs/extattr.h @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 1999, 2000 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +/* + * TrustedBSD Project - extended attribute support for UFS-like file systems + */ + +#ifndef _UFS_UFS_EXTATTR_H_ +#define _UFS_UFS_EXTATTR_H_ + +#define UFS_EXTATTR_FSROOTSUBDIR ".attributes" +#define UFS_EXTATTR_MAXEXTATTRNAME 33 /* including null */ +#define UFS_EXTATTR_MAXEXTATTRSIZE 1024 /* bytes */ + +#define UFS_EXTATTR_ATTR_FLAG_INUSE 0x00000001 /* attr has been set */ +#define UFS_EXTATTR_PERM_KERNEL 0x00000000 +#define UFS_EXTATTR_PERM_ROOT 0x00000001 +#define UFS_EXTATTR_PERM_OWNER 0x00000002 +#define UFS_EXTATTR_PERM_ANYONE 0x00000003 + +#define UFS_EXTATTR_UEPM_INITIALIZED 0x00000001 +#define UFS_EXTATTR_UEPM_STARTED 0x00000002 + +#define UFS_EXTATTR_CMD_START 0x00000001 +#define UFS_EXTATTR_CMD_STOP 0x00000002 +#define UFS_EXTATTR_CMD_ENABLE 0x00000003 +#define UFS_EXTATTR_CMD_DISABLE 0x00000004 + +struct ufs_extattr_fileheader { + u_int uef_size; /* size of attributes, w/o header */ + u_int uef_read_perm; /* permissions to read attribute */ + u_int uef_write_perm; /* permissions to write attribute */ +}; + +struct ufs_extattr_header { + u_int ueh_flags; /* flags for attribute */ + u_int ueh_len; /* local defined length; <= uef_size */ + /* data follows the header */ +}; + +#ifdef _KERNEL + +#ifdef MALLOC_DECLARE +MALLOC_DECLARE(M_EXTATTR); +#endif + +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; + char uele_attrname[UFS_EXTATTR_MAXEXTATTRNAME]; + struct vnode *uele_backing_vnode; +}; + +struct lock; +struct ucred; +struct ufs_extattr_per_mount { + struct lock uepm_lock; + struct ufs_extattr_list_head uepm_list; + struct ucred *uepm_ucred; + int uepm_flags; +}; + +void ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm); +int ufs_extattr_start(struct mount *mp, struct proc *p); +int ufs_extattr_stop(struct mount *mp, struct proc *p); +int ufs_extattrctl(struct mount *mp, int cmd, char *attrname, + caddr_t arg, 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); + +#endif /* !_KERNEL */ + +#endif /* !_UFS_UFS_EXTATTR_H_ */ diff --git a/sys/ufs/ufs/ufs_bmap.c b/sys/ufs/ufs/ufs_bmap.c index d8c61b1..32ba53c 100644 --- a/sys/ufs/ufs/ufs_bmap.c +++ b/sys/ufs/ufs/ufs_bmap.c @@ -48,6 +48,7 @@ #include <sys/resourcevar.h> #include <sys/conf.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufsmount.h> diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c new file mode 100644 index 0000000..1576f3e --- /dev/null +++ b/sys/ufs/ufs/ufs_extattr.c @@ -0,0 +1,787 @@ +/*- + * Copyright (c) 1999, 2000 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +/* + * TrustedBSD Project - extended attribute support for UFS-like file systems + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/fcntl.h> +#include <sys/proc.h> +#include <sys/vnode.h> +#include <sys/mount.h> +#include <sys/lock.h> + +#include <ufs/ufs/extattr.h> +#include <ufs/ufs/quota.h> +#include <ufs/ufs/ufsmount.h> +#include <ufs/ufs/inode.h> + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +static MALLOC_DEFINE(M_UFS_EXTATTR, "ufs_extattr", "ufs extended attribute"); + +static int ufs_extattr_credcheck(struct ufs_extattr_list_entry *uele, + u_int32_t fowner, struct ucred *cred, struct proc *p, int access); +static int ufs_extattr_enable(struct ufsmount *ump, char *attrname, + struct vnode *backing_vnode, struct proc *p); +static int ufs_extattr_disable(struct ufsmount *ump, char *attrname, + struct proc *p); +static int ufs_extattr_get(struct vnode *vp, char *name, struct uio *uio, + struct ucred *cred, struct proc *p); +static int ufs_extattr_set(struct vnode *vp, char *name, struct uio *uio, + struct ucred *cred, struct proc *p); +static int ufs_extattr_rm(struct vnode *vp, char *name, + struct ucred *cred, struct proc *p); + +/* + * Per-FS attribute lock protecting attribute operations + * XXX Right now there is a lot of lock contention due to having a single + * lock per-FS; really, this should be far more fine-grained. + */ +static void +ufs_extattr_uepm_lock(struct ufsmount *ump, struct proc *p) +{ + + /* ideally, LK_CANRECURSE would not be used, here */ + lockmgr(&ump->um_extattr.uepm_lock, LK_EXCLUSIVE | LK_RETRY | + LK_CANRECURSE, 0, p); +} + +static void +ufs_extattr_uepm_unlock(struct ufsmount *ump, struct proc *p) +{ + + lockmgr(&ump->um_extattr.uepm_lock, LK_RELEASE, 0, p); +} + +/* + * Locate an attribute given a name and mountpoint. + * Must be holding uepm lock for the mount point. + */ +static struct ufs_extattr_list_entry * +ufs_exttatr_find_attr(struct ufsmount *ump, char *attrname) +{ + struct ufs_extattr_list_entry *search_attribute; + + for (search_attribute = ump->um_extattr.uepm_list.lh_first; + search_attribute; + search_attribute = search_attribute->uele_entries.le_next) { + if (!(strncmp(attrname, search_attribute->uele_attrname, + UFS_EXTATTR_MAXEXTATTRNAME))) { + return (search_attribute); + } + } + + return (0); +} + +/* + * Initialize per-FS structures supporting extended attributes. Do not + * start extended attributes yet. + */ +void +ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm) +{ + + uepm->uepm_flags = 0; + + LIST_INIT(&uepm->uepm_list); + /* XXX is PVFS right, here? */ + lockinit(&uepm->uepm_lock, PVFS, "extattr", 0, 0); + uepm->uepm_flags |= UFS_EXTATTR_UEPM_INITIALIZED; +} + +/* + * Start extended attribute support on an FS + */ +int +ufs_extattr_start(struct mount *mp, struct proc *p) +{ + struct ufsmount *ump; + int error = 0; + + ump = VFSTOUFS(mp); + + ufs_extattr_uepm_lock(ump, p); + + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED)) { + error = EOPNOTSUPP; + goto unlock; + } + if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED) { + error = EBUSY; + goto unlock; + } + + ump->um_extattr.uepm_flags |= UFS_EXTATTR_UEPM_STARTED; + + crhold(p->p_ucred); + ump->um_extattr.uepm_ucred = p->p_ucred; + +unlock: + ufs_extattr_uepm_unlock(ump, p); + + return (error); +} + +/* + * Stop extended attribute support on an FS + */ +int +ufs_extattr_stop(struct mount *mp, struct proc *p) +{ + struct ufs_extattr_list_entry *uele; + struct ufsmount *ump = VFSTOUFS(mp); + int error = 0; + + ufs_extattr_uepm_lock(ump, p); + + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) { + error = EOPNOTSUPP; + goto unlock; + } + + while (ump->um_extattr.uepm_list.lh_first != NULL) { + uele = ump->um_extattr.uepm_list.lh_first; + ufs_extattr_disable(ump, uele->uele_attrname, p); + } + + ump->um_extattr.uepm_flags &= ~UFS_EXTATTR_UEPM_STARTED; + + crfree(ump->um_extattr.uepm_ucred); + ump->um_extattr.uepm_ucred = NULL; + +unlock: + ufs_extattr_uepm_unlock(ump, p); + + return (error); +} + +/* + * Enable a named attribute on the specified file system; provide a + * backing vnode to hold the attribute data. + */ +static int +ufs_extattr_enable(struct ufsmount *ump, char *attrname, + struct vnode *backing_vnode, struct proc *p) +{ + struct ufs_extattr_list_entry *attribute; + struct iovec aiov; + struct uio auio; + int error = 0; + + if (backing_vnode->v_type != VREG) + return (EINVAL); + + MALLOC(attribute, struct ufs_extattr_list_entry *, + sizeof(struct ufs_extattr_list_entry), M_UFS_EXTATTR, M_WAITOK); + if (attribute == NULL) + return (ENOMEM); + + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) { + error = EOPNOTSUPP; + goto free_exit; + } + + if (ufs_exttatr_find_attr(ump, attrname)) { + error = EOPNOTSUPP; + goto free_exit; + } + + strncpy(attribute->uele_attrname, attrname, UFS_EXTATTR_MAXEXTATTRNAME); + bzero(&attribute->uele_fileheader, + sizeof(struct ufs_extattr_fileheader)); + + attribute->uele_backing_vnode = backing_vnode; + backing_vnode->v_flag |= VSYSTEM; + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = (caddr_t) &attribute->uele_fileheader; + aiov.iov_len = sizeof(struct ufs_extattr_fileheader); + auio.uio_resid = sizeof(struct ufs_extattr_fileheader); + auio.uio_offset = (off_t) 0; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_READ; + auio.uio_procp = (struct proc *) p; + + VOP_LEASE(backing_vnode, p, p->p_cred->pc_ucred, LEASE_WRITE); + vn_lock(backing_vnode, LK_SHARED | LK_NOPAUSE | LK_RETRY, p); + error = VOP_READ(backing_vnode, &auio, 0, ump->um_extattr.uepm_ucred); + VOP_UNLOCK(backing_vnode, 0, p); + + if (error) { + goto free_exit; + } + + if (auio.uio_resid != 0) { + printf("ufs_extattr_enable: malformed attribute header\n"); + error = EINVAL; + goto free_exit; + } + + LIST_INSERT_HEAD(&ump->um_extattr.uepm_list, attribute, uele_entries); + + return (0); + +free_exit: + FREE(attribute, M_UFS_EXTATTR); + return (error); +} + +/* + * Disable extended attribute support on an FS + */ +static int +ufs_extattr_disable(struct ufsmount *ump, char *attrname, struct proc *p) +{ + struct ufs_extattr_list_entry *uele; + int error = 0; + + uele = ufs_exttatr_find_attr(ump, attrname); + if (!uele) + return (ENOENT); + + LIST_REMOVE(uele, uele_entries); + + uele->uele_backing_vnode->v_flag &= ~VSYSTEM; + error = vn_close(uele->uele_backing_vnode, FREAD|FWRITE, p->p_ucred, p); + + FREE(uele, M_UFS_EXTATTR); + + return (error); +} + +/* + * VFS call to manage extended attributes in UFS + * attrname, arg are userspace pointers from the syscall + */ +int +ufs_extattrctl(struct mount *mp, int cmd, char *attrname, + caddr_t arg, struct proc *p) +{ + struct nameidata nd; + struct ufsmount *ump = VFSTOUFS(mp); + struct vnode *vp; + char local_attrname[UFS_EXTATTR_MAXEXTATTRNAME]; /* inc null */ + char *filename; + int error, len; + + if ((error = suser_xxx(p->p_cred->pc_ucred, p, 0))) + return (error); + + switch(cmd) { + case UFS_EXTATTR_CMD_START: + error = ufs_extattr_start(mp, p); + + return (error); + + case UFS_EXTATTR_CMD_STOP: + return (ufs_extattr_stop(mp, p)); + + 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); + error = vn_open(&nd, FREAD|FWRITE, 0); + if (error) + return (error); + + vp = nd.ni_vp; + VOP_UNLOCK(vp, 0, p); + + ufs_extattr_uepm_lock(ump, p); + error = ufs_extattr_enable(ump, local_attrname, vp, p); + ufs_extattr_uepm_unlock(ump, p); + + return (error); + + case UFS_EXTATTR_CMD_DISABLE: + error = copyinstr(attrname, local_attrname, + UFS_EXTATTR_MAXEXTATTRNAME, &len); + + ufs_extattr_uepm_lock(ump, p); + error = ufs_extattr_disable(ump, local_attrname, p); + ufs_extattr_uepm_unlock(ump, p); + + return (error); + + default: + return (EINVAL); + } +} + +/* + * Credential check based on process requesting service, and per-attribute + * permissions. + */ +static int +ufs_extattr_credcheck(struct ufs_extattr_list_entry *uele, u_int32_t fowner, + struct ucred *cred, struct proc *p, int access) +{ + u_int uef_perm; + + switch(access) { + case IREAD: + uef_perm = uele->uele_fileheader.uef_read_perm; + break; + case IWRITE: + uef_perm = uele->uele_fileheader.uef_write_perm; + break; + default: + return (EACCES); + } + + /* Kernel sponsoring request does so without passing a cred */ + if (!cred) + return (0); + + /* XXX there might eventually be a capability check here */ + + /* If it's set to root-only, check for suser(p) */ + if (uef_perm == UFS_EXTATTR_PERM_ROOT && !suser(p)) + return (0); + + /* Allow the owner if appropriate */ + if (uef_perm == UFS_EXTATTR_PERM_OWNER && cred->cr_uid == fowner) + return (0); + + /* Allow anyone if appropriate */ + if (uef_perm == UFS_EXTATTR_PERM_ANYONE) + return (0); + + return (EACCES); +} + +/* + * Vnode operating to retrieve a named extended attribute + */ +int +ufs_vop_getextattr(struct vop_getextattr_args *ap) +/* +vop_getextattr { + IN struct vnode *a_vp; + IN char *a_name; + INOUT struct uio *a_uio; + IN struct ucred *a_cred; + IN struct proc *a_p; +}; +*/ +{ + struct mount *mp = ap->a_vp->v_mount; + struct ufsmount *ump = VFSTOUFS(mp); + int error; + + 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); + + ufs_extattr_uepm_unlock(ump, ap->a_p); + + return (error); +} + +/* + * Real work associated with retrieving a named attribute--assumes that + * the attribute lock has already been grabbed. + */ +static int +ufs_extattr_get(struct vnode *vp, char *name, struct uio *uio, + struct ucred *cred, struct proc *p) +{ + struct ufs_extattr_list_entry *attribute; + struct ufs_extattr_header ueh; + struct iovec local_aiov; + struct uio local_aio; + struct mount *mp = vp->v_mount; + struct ufsmount *ump = VFSTOUFS(mp); + struct inode *ip = VTOI(vp); + off_t base_offset, old_offset, offset; + size_t size, old_size; + int error = 0; + + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) + return (EOPNOTSUPP); + + attribute = ufs_exttatr_find_attr(ump, name); + if (!attribute) + return (ENOENT); + + if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred, p, + IREAD))) + return (error); + + /* + * Early rejection of offsets that are invalid + */ + if (uio->uio_offset >= attribute->uele_fileheader.uef_size || + uio->uio_offset < 0) + return (ENXIO); + + /* + * Find base offset of header in file based on file header size, and + * data header size + maximum data size, indexed by inode number + */ + base_offset = sizeof(struct ufs_extattr_fileheader) + + ip->i_number * (sizeof(struct ufs_extattr_header) + + attribute->uele_fileheader.uef_size); + + /* + * Read in the data header to see if the data is defined, and if so + * how much. + */ + bzero(&ueh, sizeof(struct ufs_extattr_header)); + local_aiov.iov_base = (caddr_t) &ueh; + local_aiov.iov_len = sizeof(struct ufs_extattr_header); + local_aio.uio_iov = &local_aiov; + local_aio.uio_iovcnt = 1; + local_aio.uio_rw = UIO_READ; + local_aio.uio_segflg = UIO_SYSSPACE; + local_aio.uio_procp = p; + local_aio.uio_offset = base_offset; + local_aio.uio_resid = sizeof(struct ufs_extattr_header); + + VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_READ); + vn_lock(attribute->uele_backing_vnode, LK_SHARED | LK_NOPAUSE | + LK_RETRY, p); + + error = VOP_READ(attribute->uele_backing_vnode, &local_aio, 0, + ump->um_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + /* defined? */ + if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) { + error = ENOENT; + goto vopunlock_exit; + } + + /* local size consistency check */ + if (ueh.ueh_len > attribute->uele_fileheader.uef_size) { + error = ENXIO; + goto vopunlock_exit; + } + + if (ueh.ueh_len < uio->uio_offset) { + error = 0; + goto vopunlock_exit; + } + + /* allow for offset into the attr data */ + offset = base_offset + sizeof(struct ufs_extattr_header) + + uio->uio_offset; + + /* + * Figure out maximum to transfer -- use buffer size and local data + * limit. + */ + size = MIN(uio->uio_resid, ueh.ueh_len - uio->uio_offset); + + old_offset = uio->uio_offset; + uio->uio_offset = offset; + old_size = uio->uio_resid; + uio->uio_resid = size; + + error = VOP_READ(attribute->uele_backing_vnode, uio, 0, + ump->um_extattr.uepm_ucred); + if (error) { + uio->uio_offset = old_offset; + goto vopunlock_exit; + } + + uio->uio_offset = old_offset; + uio->uio_resid = old_size - (size - uio->uio_resid); + +vopunlock_exit: + VOP_UNLOCK(attribute->uele_backing_vnode, 0, p); + + return (error); +} + +/* + * Vnode operation to set a named attribute + */ +int +ufs_vop_setextattr(struct vop_setextattr_args *ap) +/* +vop_setextattr { + IN struct vnode *a_vp; + IN char *a_name; + INOUT struct uio *a_uio; + IN struct ucred *a_cred; + IN struct proc *a_p; +}; +*/ +{ + struct mount *mp = ap->a_vp->v_mount; + struct ufsmount *ump = VFSTOUFS(mp); + + int error; + + ufs_extattr_uepm_lock(ump, ap->a_p); + + if (ap->a_uio) + error = ufs_extattr_set(ap->a_vp, 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); + + ufs_extattr_uepm_unlock(ump, ap->a_p); + + return (error); +} + +/* + * Real work associated with setting a vnode's extended attributes; + * assumes that the attribute lock has already been grabbed. + */ +static int +ufs_extattr_set(struct vnode *vp, char *name, struct uio *uio, + struct ucred *cred, struct proc *p) +{ + struct ufs_extattr_list_entry *attribute; + struct ufs_extattr_header ueh; + struct iovec local_aiov; + struct uio local_aio; + struct mount *mp = vp->v_mount; + struct ufsmount *ump = VFSTOUFS(mp); + struct inode *ip = VTOI(vp); + off_t base_offset; + + int error = 0; + + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) + return (EOPNOTSUPP); + + attribute = ufs_exttatr_find_attr(ump, name); + if (!attribute) + return (ENOENT); + + if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred, + p, IWRITE))) + return (error); + + /* + * Early rejection of invalid offsets/lengths + * Reject: any offset but 0 (replace) + * Any size greater than attribute size limit + */ + if (uio->uio_offset != 0 || + uio->uio_resid > attribute->uele_fileheader.uef_size) + return (ENXIO); + + /* + * Find base offset of header in file based on file header size, and + * data header size + maximum data size, indexed by inode number + */ + base_offset = sizeof(struct ufs_extattr_fileheader) + + ip->i_number * (sizeof(struct ufs_extattr_header) + + attribute->uele_fileheader.uef_size); + + /* + * Write out a data header for the data + */ + ueh.ueh_len = uio->uio_resid; + ueh.ueh_flags = UFS_EXTATTR_ATTR_FLAG_INUSE; + local_aiov.iov_base = (caddr_t) &ueh; + local_aiov.iov_len = sizeof(struct ufs_extattr_header); + local_aio.uio_iov = &local_aiov; + local_aio.uio_iovcnt = 1; + local_aio.uio_rw = UIO_WRITE; + local_aio.uio_segflg = UIO_SYSSPACE; + local_aio.uio_procp = p; + local_aio.uio_offset = base_offset; + local_aio.uio_resid = sizeof(struct ufs_extattr_header); + + /* + * Acquire locks + */ + VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_WRITE); + + /* + * Don't need to get a lock on the backing file if the setattr is + * being applied to the backing file, as the lock is already held + */ + if (attribute->uele_backing_vnode != vp) + vn_lock(attribute->uele_backing_vnode, + LK_EXCLUSIVE | LK_NOPAUSE | LK_RETRY, p); + + error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, 0, + ump->um_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + if (local_aio.uio_resid != 0) + error = ENXIO; + goto vopunlock_exit; + + /* + * Write out user data + */ + uio->uio_offset = base_offset + sizeof(struct ufs_extattr_header); + + error = VOP_WRITE(attribute->uele_backing_vnode, uio, 0, + ump->um_extattr.uepm_ucred); + +vopunlock_exit: + uio->uio_offset = 0; + VOP_UNLOCK(attribute->uele_backing_vnode, 0, p); + + return (error); +} + +/* + * Real work associated with removing an extended attribute from a vnode. + * Assumes the attribute lock has already been grabbed. + */ +static int +ufs_extattr_rm(struct vnode *vp, char *name, struct ucred *cred, + struct proc *p) +{ + struct ufs_extattr_list_entry *attribute; + struct ufs_extattr_header ueh; + struct iovec local_aiov; + struct uio local_aio; + struct mount *mp = vp->v_mount; + struct ufsmount *ump = VFSTOUFS(mp); + struct inode *ip = VTOI(vp); + off_t base_offset; + int error = 0; + + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) + return (EOPNOTSUPP); + + attribute = ufs_exttatr_find_attr(ump, name); + if (!attribute) + return (ENOENT); + + if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred, p, + IWRITE))) + return (error); + + /* + * Find base offset of header in file based on file header size, and + * data header size + maximum data size, indexed by inode number + */ + base_offset = sizeof(struct ufs_extattr_fileheader) + + ip->i_number * (sizeof(struct ufs_extattr_header) + + attribute->uele_fileheader.uef_size); + + /* + * Read in the data header to see if the data is defined + */ + bzero(&ueh, sizeof(struct ufs_extattr_header)); + + local_aiov.iov_base = (caddr_t) &ueh; + local_aiov.iov_len = sizeof(struct ufs_extattr_header); + local_aio.uio_iov = &local_aiov; + local_aio.uio_iovcnt = 1; + local_aio.uio_rw = UIO_READ; + local_aio.uio_segflg = UIO_SYSSPACE; + local_aio.uio_procp = p; + local_aio.uio_offset = base_offset; + local_aio.uio_resid = sizeof(struct ufs_extattr_header); + + VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_WRITE); + + /* + * Don't need to get the lock on the backing vnode if the vnode we're + * modifying is it, as we already hold the lock. + */ + if (attribute->uele_backing_vnode != vp) + vn_lock(attribute->uele_backing_vnode, + LK_EXCLUSIVE | LK_NOPAUSE | LK_RETRY, p); + + error = VOP_READ(attribute->uele_backing_vnode, &local_aio, 0, + ump->um_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + /* defined? */ + if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) { + error = ENOENT; + goto vopunlock_exit; + } + + /* flag it as not in use */ + ueh.ueh_flags = 0; + + error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, 0, + ump->um_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + if (local_aio.uio_resid != 0) + error = ENXIO; + +vopunlock_exit: + VOP_UNLOCK(attribute->uele_backing_vnode, 0, p); + + return (error); +} + +/* + * Called by UFS when an inode is no longer active and should have its + * attributes stripped. + */ +void +ufs_extattr_vnode_inactive(struct vnode *vp, struct proc *p) +{ + struct ufs_extattr_list_entry *uele; + struct mount *mp = vp->v_mount; + struct ufsmount *ump = VFSTOUFS(mp); + + ufs_extattr_uepm_lock(ump, p); + + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) { + ufs_extattr_uepm_unlock(ump, p); + return; + } + + for (uele = ump->um_extattr.uepm_list.lh_first; uele != NULL; + uele = uele->uele_entries.le_next) + ufs_extattr_rm(vp, uele->uele_attrname, 0, p); + + ufs_extattr_uepm_unlock(ump, p); +} diff --git a/sys/ufs/ufs/ufs_inode.c b/sys/ufs/ufs/ufs_inode.c index edb8c15..c0a78f7 100644 --- a/sys/ufs/ufs/ufs_inode.c +++ b/sys/ufs/ufs/ufs_inode.c @@ -39,6 +39,7 @@ * $FreeBSD$ */ +#include "opt_ffs.h" #include "opt_quota.h" #include <sys/param.h> @@ -46,6 +47,7 @@ #include <sys/mount.h> #include <sys/malloc.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufsmount.h> @@ -81,6 +83,9 @@ ufs_inactive(ap) if (!getinoquota(ip)) (void)chkiq(ip, -1, NOCRED, 0); #endif +#ifdef FFS_EXTATTR + ufs_extattr_vnode_inactive(ap->a_vp, ap->a_p); +#endif error = UFS_TRUNCATE(vp, (off_t)0, 0, NOCRED, p); ip->i_rdev = 0; mode = ip->i_mode; diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c index fa2b623..fd9d609 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -53,6 +53,7 @@ #include <vm/vm.h> #include <vm/vm_extern.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/dir.h> diff --git a/sys/ufs/ufs/ufs_quota.c b/sys/ufs/ufs/ufs_quota.c index c9865f5..1baf165 100644 --- a/sys/ufs/ufs/ufs_quota.c +++ b/sys/ufs/ufs/ufs_quota.c @@ -48,6 +48,7 @@ #include <sys/mount.h> #include <vm/vm_zone.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufsmount.h> diff --git a/sys/ufs/ufs/ufs_vfsops.c b/sys/ufs/ufs/ufs_vfsops.c index 22cc9cc..906a402 100644 --- a/sys/ufs/ufs/ufs_vfsops.c +++ b/sys/ufs/ufs/ufs_vfsops.c @@ -48,6 +48,7 @@ #include <sys/malloc.h> #include <sys/vnode.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufsmount.h> diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index c2cac4a..7ab8429 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -65,6 +65,7 @@ #include <miscfs/fifofs/fifo.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/dir.h> diff --git a/sys/ufs/ufs/ufsmount.h b/sys/ufs/ufs/ufsmount.h index 0652545..900c81e 100644 --- a/sys/ufs/ufs/ufsmount.h +++ b/sys/ufs/ufs/ufsmount.h @@ -69,6 +69,7 @@ struct ucred; struct uio; struct vnode; struct netexport; +struct ufs_extattr_per_mount; /* This structure describes the UFS specific mount structure data. */ struct ufsmount { @@ -86,6 +87,7 @@ struct ufsmount { struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */ struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */ + struct ufs_extattr_per_mount um_extattr; /* extended attrs */ u_long um_nindir; /* indirect ptrs per block */ u_long um_bptrtodb; /* indir ptr to disk block */ u_long um_seqinc; /* inc between seq blocks */ |