summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2000-04-15 03:34:27 +0000
committerrwatson <rwatson@FreeBSD.org>2000-04-15 03:34:27 +0000
commita0dd5ab0fdc3b34857eb18eae8dae879d1e5b8cf (patch)
tree4c1ff739a8025b89f8c9ed37caf68cd1a78eaedd
parente7f9f3a94cc8b0fedca28cad6fd0d3a6c248d6d8 (diff)
downloadFreeBSD-src-a0dd5ab0fdc3b34857eb18eae8dae879d1e5b8cf.zip
FreeBSD-src-a0dd5ab0fdc3b34857eb18eae8dae879d1e5b8cf.tar.gz
Introduce extended attribute support for FFS, allowing arbitrary
(name, value) pairs to be associated with inodes. This support is used for ACLs, MAC labels, and Capabilities in the TrustedBSD security extensions, which are currently under development. In this implementation, attributes are backed to data vnodes in the style of the quota support in FFS. Support for FFS extended attributes may be enabled using the FFS_EXTATTR kernel option (disabled by default). Userland utilities and man pages will be committed in the next batch. VFS interfaces and man pages have been in the repo since 4.0-RELEASE and are unchanged. o ufs/ufs/extattr.h: UFS-specific extattr defines o ufs/ufs/ufs_extattr.c: bulk of support routines o ufs/{ufs,ffs,mfs}/*.[ch]: hooks and extattr.h includes o contrib/softupdates/ffs_softdep.c: extattr.h includes o conf/options, conf/files, i386/conf/LINT: added FFS_EXTATTR o coda/coda_vfsops.c: XXX required extattr.h due to ufsmount.h (This should not be the case, and will be fixed in a future commit) Currently attributes are not supported in MFS. This will be fixed. Reviewed by: adrian, bp, freebsd-fs, other unthanked souls Obtained from: TrustedBSD Project
-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