summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/coda/coda_vfsops.c1
-rw-r--r--sys/conf/NOTES5
-rw-r--r--sys/conf/files1
-rw-r--r--sys/conf/options5
-rw-r--r--sys/contrib/softupdates/ffs_softdep.c1
-rw-r--r--sys/fs/coda/coda_vfsops.c1
-rw-r--r--sys/gnu/ext2fs/ext2_bmap.c1
-rw-r--r--sys/gnu/ext2fs/ext2_mount.h2
-rw-r--r--sys/gnu/fs/ext2fs/ext2_bmap.c1
-rw-r--r--sys/gnu/fs/ext2fs/ext2_mount.h2
-rw-r--r--sys/i386/conf/LINT5
-rw-r--r--sys/i386/conf/NOTES5
-rw-r--r--sys/ufs/ffs/ffs_alloc.c1
-rw-r--r--sys/ufs/ffs/ffs_inode.c1
-rw-r--r--sys/ufs/ffs/ffs_softdep.c1
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c14
-rw-r--r--sys/ufs/ffs/ffs_vnops.c7
-rw-r--r--sys/ufs/mfs/mfs_vfsops.c1
-rw-r--r--sys/ufs/ufs/extattr.h100
-rw-r--r--sys/ufs/ufs/ufs_bmap.c1
-rw-r--r--sys/ufs/ufs/ufs_extattr.c787
-rw-r--r--sys/ufs/ufs/ufs_inode.c5
-rw-r--r--sys/ufs/ufs/ufs_lookup.c1
-rw-r--r--sys/ufs/ufs/ufs_quota.c1
-rw-r--r--sys/ufs/ufs/ufs_vfsops.c1
-rw-r--r--sys/ufs/ufs/ufs_vnops.c1
-rw-r--r--sys/ufs/ufs/ufsmount.h2
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 */
OpenPOWER on IntegriCloud