diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2002-02-22 20:37:47 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2002-02-22 20:37:47 +0000 |
commit | ee9702d877ed9cc007f77da8cbcb7ea74f9f4dc0 (patch) | |
tree | 6a5edf89be5ae684d40781673d7ec545b4db57a2 /sys/ufs | |
parent | ea91a65c1e79695fea7cb80d2acfa092fc947b3d (diff) |
Extended Attribute support from FreeBSD/TrustedBSD ok art@, deraadt@
Diffstat (limited to 'sys/ufs')
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_bmap.c | 3 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_inode.c | 3 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_lookup.c | 3 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_vfsops.c | 6 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_vnops.c | 3 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_alloc.c | 3 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_inode.c | 3 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 3 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_softdep_stub.c | 3 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_subr.c | 3 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 38 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vnops.c | 17 | ||||
-rw-r--r-- | sys/ufs/lfs/lfs_vfsops.c | 5 | ||||
-rw-r--r-- | sys/ufs/mfs/mfs_vfsops.c | 6 | ||||
-rw-r--r-- | sys/ufs/ufs/extattr.h | 109 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_bmap.c | 3 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_extattr.c | 1338 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_inode.c | 3 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_lookup.c | 3 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_quota.c | 3 |
20 files changed, 1535 insertions, 23 deletions
diff --git a/sys/ufs/ext2fs/ext2fs_bmap.c b/sys/ufs/ext2fs/ext2fs_bmap.c index 84a05ace5aa..8f247adf707 100644 --- a/sys/ufs/ext2fs/ext2fs_bmap.c +++ b/sys/ufs/ext2fs/ext2fs_bmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_bmap.c,v 1.6 2001/09/18 00:22:31 art Exp $ */ +/* $OpenBSD: ext2fs_bmap.c,v 1.7 2002/02/22 20:37:45 drahn Exp $ */ /* $NetBSD: ext2fs_bmap.c,v 1.5 2000/03/30 12:41:11 augustss Exp $ */ /* @@ -53,6 +53,7 @@ #include <miscfs/specfs/specdev.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/ext2fs/ext2fs_inode.c b/sys/ufs/ext2fs/ext2fs_inode.c index 0e2a975e333..f7eac005b0d 100644 --- a/sys/ufs/ext2fs/ext2fs_inode.c +++ b/sys/ufs/ext2fs/ext2fs_inode.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_inode.c,v 1.19 2001/12/19 08:58:07 art Exp $ */ +/* $OpenBSD: ext2fs_inode.c,v 1.20 2002/02/22 20:37:45 drahn Exp $ */ /* $NetBSD: ext2fs_inode.c,v 1.24 2001/06/19 12:59:18 wiz Exp $ */ /* @@ -51,6 +51,7 @@ #include <uvm/uvm_extern.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/ext2fs/ext2fs_lookup.c b/sys/ufs/ext2fs/ext2fs_lookup.c index 82bd81c7dbd..663d5ef8a83 100644 --- a/sys/ufs/ext2fs/ext2fs_lookup.c +++ b/sys/ufs/ext2fs/ext2fs_lookup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_lookup.c,v 1.11 2001/09/18 01:21:55 art Exp $ */ +/* $OpenBSD: ext2fs_lookup.c,v 1.12 2002/02/22 20:37:45 drahn Exp $ */ /* $NetBSD: ext2fs_lookup.c,v 1.16 2000/08/03 20:29:26 thorpej Exp $ */ /* @@ -62,6 +62,7 @@ #include <sys/malloc.h> #include <sys/dirent.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/ext2fs/ext2fs_vfsops.c b/sys/ufs/ext2fs/ext2fs_vfsops.c index 6f404d98157..09df6e06183 100644 --- a/sys/ufs/ext2fs/ext2fs_vfsops.c +++ b/sys/ufs/ext2fs/ext2fs_vfsops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_vfsops.c,v 1.20 2001/12/19 08:58:07 art Exp $ */ +/* $OpenBSD: ext2fs_vfsops.c,v 1.21 2002/02/22 20:37:45 drahn Exp $ */ /* $NetBSD: ext2fs_vfsops.c,v 1.1 1997/06/11 09:34:07 bouyer Exp $ */ /* @@ -59,6 +59,7 @@ #include <miscfs/specfs/specdev.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/ufsmount.h> #include <ufs/ufs/inode.h> @@ -97,7 +98,8 @@ struct vfsops ext2fs_vfsops = { ext2fs_vptofh, ext2fs_init, ext2fs_sysctl, - ufs_check_export + ufs_check_export, + vfs_stdextattrctl }; struct pool ext2fs_inode_pool; diff --git a/sys/ufs/ext2fs/ext2fs_vnops.c b/sys/ufs/ext2fs/ext2fs_vnops.c index d85d4eba5d9..43ef065c46f 100644 --- a/sys/ufs/ext2fs/ext2fs_vnops.c +++ b/sys/ufs/ext2fs/ext2fs_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_vnops.c,v 1.21 2001/12/19 08:58:07 art Exp $ */ +/* $OpenBSD: ext2fs_vnops.c,v 1.22 2002/02/22 20:37:45 drahn Exp $ */ /* $NetBSD: ext2fs_vnops.c,v 1.1 1997/06/11 09:34:09 bouyer Exp $ */ /* @@ -65,6 +65,7 @@ #include <miscfs/fifofs/fifo.h> #include <miscfs/specfs/specdev.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_alloc.c b/sys/ufs/ffs/ffs_alloc.c index c42897ac4d4..a8233c33036 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ffs_alloc.c,v 1.38 2001/12/19 08:58:07 art Exp $ */ +/* $OpenBSD: ffs_alloc.c,v 1.39 2002/02/22 20:37:46 drahn Exp $ */ /* $NetBSD: ffs_alloc.c,v 1.11 1996/05/11 18:27:09 mycroft Exp $ */ /* @@ -49,6 +49,7 @@ #include <dev/rndvar.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 cb6e60a956a..9ee61587054 100644 --- a/sys/ufs/ffs/ffs_inode.c +++ b/sys/ufs/ffs/ffs_inode.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ffs_inode.c,v 1.30 2002/01/04 03:53:23 nordin Exp $ */ +/* $OpenBSD: ffs_inode.c,v 1.31 2002/02/22 20:37:46 drahn Exp $ */ /* $NetBSD: ffs_inode.c,v 1.10 1996/05/11 18:27:19 mycroft Exp $ */ /* @@ -49,6 +49,7 @@ #include <uvm/uvm_extern.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_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 027a3f42693..2589c800a3c 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ffs_softdep.c,v 1.35 2002/01/29 14:31:59 millert Exp $ */ +/* $OpenBSD: ffs_softdep.c,v 1.36 2002/02/22 20:37:46 drahn Exp $ */ /* * Copyright 1998, 2000 Marshall Kirk McKusick. All Rights Reserved. * @@ -58,6 +58,7 @@ #include <sys/systm.h> #include <sys/vnode.h> #include <miscfs/specfs/specdev.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/dir.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> diff --git a/sys/ufs/ffs/ffs_softdep_stub.c b/sys/ufs/ffs/ffs_softdep_stub.c index 2eabe90e9b3..fb29626b96e 100644 --- a/sys/ufs/ffs/ffs_softdep_stub.c +++ b/sys/ufs/ffs/ffs_softdep_stub.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ffs_softdep_stub.c,v 1.3 2001/02/21 23:24:31 csapuntz Exp $ */ +/* $OpenBSD: ffs_softdep_stub.c,v 1.4 2002/02/22 20:37:46 drahn Exp $ */ /* * Copyright 1998 Marshall Kirk McKusick. All Rights Reserved. @@ -41,6 +41,7 @@ #include <sys/param.h> #include <sys/vnode.h> #include <sys/systm.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ffs/ffs_extern.h> diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c index 50916fca74a..b70795e06d3 100644 --- a/sys/ufs/ffs/ffs_subr.c +++ b/sys/ufs/ffs/ffs_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ffs_subr.c,v 1.10 2001/12/01 19:12:25 deraadt Exp $ */ +/* $OpenBSD: ffs_subr.c,v 1.11 2002/02/22 20:37:46 drahn Exp $ */ /* $NetBSD: ffs_subr.c,v 1.6 1996/03/17 02:16:23 christos Exp $ */ /* @@ -43,6 +43,7 @@ #include <sys/systm.h> #include <sys/vnode.h> #include <sys/buf.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ffs/ffs_extern.h> diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index f4374c79bec..03293113e61 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ffs_vfsops.c,v 1.50 2002/01/25 02:30:27 millert Exp $ */ +/* $OpenBSD: ffs_vfsops.c,v 1.51 2002/02/22 20:37:46 drahn Exp $ */ /* $NetBSD: ffs_vfsops.c,v 1.19 1996/02/09 22:22:26 christos Exp $ */ /* @@ -58,6 +58,7 @@ #include <miscfs/specfs/specdev.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/ufsmount.h> #include <ufs/ufs/inode.h> @@ -84,7 +85,12 @@ struct vfsops ffs_vfsops = { ffs_vptofh, ffs_init, ffs_sysctl, - ufs_check_export + ufs_check_export, +#ifdef UFS_EXTATTR + ufs_extattrctl, +#else + vfs_stdextattrctl, +#endif }; struct inode_vtbl ffs_vtbl = { @@ -746,6 +752,10 @@ ffs_mountfs(devvp, mp, p) ump->um_seqinc = fs->fs_frag; for (i = 0; i < MAXQUOTAS; i++) ump->um_quotas[i] = NULLVP; +#ifdef UFS_EXTATTR + ufs_extattr_uepm_init(&ump->um_extattr); +#endif + devvp->v_specmountpoint = mp; ffs_oldfscompat(fs); @@ -796,6 +806,21 @@ ffs_mountfs(devvp, mp, p) fs->fs_flags &= ~FS_DOSOFTDEP; (void) ffs_sbupdate(ump, MNT_WAIT); } +#ifdef UFS_EXTATTR +#ifdef UFS_EXTATTR_AUTOSTART + /* + * + * Auto-starting does the following: + * - check for /.attribute in the fs, and extattr_start if so + * - for each file in .attribute, enable that file with + * an attribute of the same name. + * Not clear how to report errors -- probably eat them. + * This would all happen while the file system was busy/not + * available, so would effectively be "atomic". + */ + (void) ufs_extattr_autostart(mp, p); +#endif /* !UFS_EXTATTR_AUTOSTART */ +#endif /* !UFS_EXTATTR */ return (0); out: devvp->v_specmountpoint = NULL; @@ -862,6 +887,15 @@ ffs_unmount(mp, mntflags, p) ump = VFSTOUFS(mp); fs = ump->um_fs; +#ifdef UFS_EXTATTR + if ((error = ufs_extattr_stop(mp, p))) { + if (error != EOPNOTSUPP) + printf("ffs_unmount: ufs_extattr_stop returned %d\n", + error); + } else { + ufs_extattr_uepm_destroy(&ump->um_extattr); + } +#endif if (mp->mnt_flag & MNT_SOFTDEP) error = softdep_flushfiles(mp, flags, p); else diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 1020b14a2bb..8e9ce74b9ba 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ffs_vnops.c,v 1.25 2001/12/19 08:58:07 art Exp $ */ +/* $OpenBSD: ffs_vnops.c,v 1.26 2002/02/22 20:37:46 drahn Exp $ */ /* $NetBSD: ffs_vnops.c,v 1.7 1996/05/11 18:27:24 mycroft Exp $ */ /* @@ -56,6 +56,7 @@ #include <miscfs/specfs/specdev.h> #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> @@ -107,7 +108,11 @@ struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { { &vop_advlock_desc, ufs_advlock }, /* advlock */ { &vop_reallocblks_desc, ffs_reallocblks }, /* reallocblks */ { &vop_bwrite_desc, vop_generic_bwrite }, - { (struct vnodeop_desc*)NULL, (int(*) __P((void*)))NULL } +#ifdef UFS_EXTATTR + { &vop_getextattr_desc, ufs_vop_getextattr }, + { &vop_setextattr_desc, ufs_vop_setextattr }, +#endif + { NULL, NULL } }; struct vnodeopv_desc ffs_vnodeop_opv_desc = { &ffs_vnodeop_p, ffs_vnodeop_entries }; @@ -152,6 +157,10 @@ struct vnodeopv_entry_desc ffs_specop_entries[] = { { &vop_advlock_desc, spec_advlock }, /* advlock */ { &vop_reallocblks_desc, spec_reallocblks }, /* reallocblks */ { &vop_bwrite_desc, vop_generic_bwrite }, +#ifdef UFS_EXTATTR + { &vop_getextattr_desc, ufs_vop_getextattr }, + { &vop_setextattr_desc, ufs_vop_setextattr }, +#endif { NULL, NULL } }; struct vnodeopv_desc ffs_specop_opv_desc = @@ -198,6 +207,10 @@ struct vnodeopv_entry_desc ffs_fifoop_entries[] = { { &vop_advlock_desc, fifo_advlock }, /* advlock */ { &vop_reallocblks_desc, fifo_reallocblks }, /* reallocblks */ { &vop_bwrite_desc, vop_generic_bwrite }, +#ifdef UFS_EXTATTR + { &vop_getextattr_desc, ufs_vop_getextattr }, + { &vop_setextattr_desc, ufs_vop_setextattr }, +#endif { NULL, NULL } }; struct vnodeopv_desc ffs_fifoop_opv_desc = diff --git a/sys/ufs/lfs/lfs_vfsops.c b/sys/ufs/lfs/lfs_vfsops.c index 825129518c6..940918be139 100644 --- a/sys/ufs/lfs/lfs_vfsops.c +++ b/sys/ufs/lfs/lfs_vfsops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lfs_vfsops.c,v 1.13 2001/02/20 01:50:12 assar Exp $ */ +/* $OpenBSD: lfs_vfsops.c,v 1.14 2002/02/22 20:37:46 drahn Exp $ */ /* $NetBSD: lfs_vfsops.c,v 1.11 1996/03/25 12:53:35 pk Exp $ */ /* @@ -77,7 +77,8 @@ struct vfsops lfs_vfsops = { lfs_vptofh, lfs_init, lfs_sysctl, - ufs_check_export + ufs_check_export, + vfs_stdextattrctl }; int diff --git a/sys/ufs/mfs/mfs_vfsops.c b/sys/ufs/mfs/mfs_vfsops.c index 63259f5408e..134f3c6c2fa 100644 --- a/sys/ufs/mfs/mfs_vfsops.c +++ b/sys/ufs/mfs/mfs_vfsops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mfs_vfsops.c,v 1.17 2002/02/18 09:23:26 ericj Exp $ */ +/* $OpenBSD: mfs_vfsops.c,v 1.18 2002/02/22 20:37:46 drahn Exp $ */ /* $NetBSD: mfs_vfsops.c,v 1.10 1996/02/09 22:31:28 christos Exp $ */ /* @@ -48,6 +48,7 @@ #include <sys/malloc.h> #include <sys/kthread.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufsmount.h> @@ -82,7 +83,8 @@ struct vfsops mfs_vfsops = { ffs_vptofh, mfs_init, ffs_sysctl, - mfs_checkexp + mfs_checkexp, + vfs_stdextattrctl }; /* diff --git a/sys/ufs/ufs/extattr.h b/sys/ufs/ufs/extattr.h new file mode 100644 index 00000000000..da32ed3f57c --- /dev/null +++ b/sys/ufs/ufs/extattr.h @@ -0,0 +1,109 @@ +/* $OpenBSD: extattr.h,v 1.1 2002/02/22 20:37:46 drahn Exp $ */ +/*- + * Copyright (c) 1999, 2000, 2001 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: extattr.h,v 1.14 2001/09/12 08:38:10 julian Exp $ + */ +/* + * TrustedBSD Project - extended attribute support for UFS-like file systems + */ + +#ifndef _UFS_UFS_EXTATTR_H_ +#define _UFS_UFS_EXTATTR_H_ + +#define UFS_EXTATTR_MAGIC 0x00b5d5ec +#define UFS_EXTATTR_VERSION 0x00000003 +#define UFS_EXTATTR_FSROOTSUBDIR ".attribute" +#define UFS_EXTATTR_SUBDIR_SYSTEM "system" +#define UFS_EXTATTR_SUBDIR_USER "user" +#define UFS_EXTATTR_MAXEXTATTRNAME 65 /* including null */ + +#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_magic; /* magic number for sanity checking */ + u_int uef_version; /* version of attribute file */ + u_int uef_size; /* size of attributes, w/o header */ +}; + +struct ufs_extattr_header { + u_int ueh_flags; /* flags for attribute */ + u_int ueh_len; /* local defined length; <= uef_size */ + u_int32_t ueh_i_gen; /* generation number for sanity */ + /* 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; + int uele_attrnamespace; + 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); +void ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm); +int ufs_extattr_start(struct mount *mp, struct proc *p); +int ufs_extattr_autostart(struct mount *mp, struct proc *p); +int ufs_extattr_stop(struct mount *mp, struct proc *p); +int ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename, + int attrnamespace, const char *attrname, struct proc *p); +void ufs_extattr_vnode_inactive(struct vnode *vp, struct proc *p); + +int ufs_vop_getextattr(void *); +int ufs_vop_setextattr(void *); + +#endif /* !_KERNEL */ + +#endif /* !_UFS_UFS_EXTATTR_H_ */ diff --git a/sys/ufs/ufs/ufs_bmap.c b/sys/ufs/ufs/ufs_bmap.c index fa060e3c6b8..fd8b1c397b3 100644 --- a/sys/ufs/ufs/ufs_bmap.c +++ b/sys/ufs/ufs/ufs_bmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ufs_bmap.c,v 1.12 2001/12/19 08:58:07 art Exp $ */ +/* $OpenBSD: ufs_bmap.c,v 1.13 2002/02/22 20:37:46 drahn Exp $ */ /* $NetBSD: ufs_bmap.c,v 1.3 1996/02/09 22:36:00 christos Exp $ */ /* @@ -51,6 +51,7 @@ #include <miscfs/specfs/specdev.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 00000000000..25f39aae254 --- /dev/null +++ b/sys/ufs/ufs/ufs_extattr.c @@ -0,0 +1,1338 @@ +/* $OpenBSD: ufs_extattr.c,v 1.1 2002/02/22 20:37:46 drahn Exp $ */ +/*- + * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson + * Copyright (c) 2002 Networks Associates Technologies, Inc. + * All rights reserved. + * + * This software was developed by Robert Watson for the TrustedBSD Project. + * + * This software was developed for the FreeBSD Project in part by NAI Labs, + * the Security Research Division of Network Associates, Inc. under + * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA + * CHATS research program. + * + * 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. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * 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: ufs_extattr.c,v 1.44 2002/02/10 04:57:08 rwatson Exp $ + */ +/* + * Developed by the TrustedBSD Project. + * Support for file system extended attribute: UFS-specific support functions. + */ + + +#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 <sys/dirent.h> +#include <sys/extattr.h> +#include <sys/sysctl.h> + +#include <ufs/ufs/dir.h> +#include <ufs/ufs/extattr.h> +#include <ufs/ufs/quota.h> +#include <ufs/ufs/ufsmount.h> +#include <ufs/ufs/inode.h> +#include <ufs/ufs/ufs_extern.h> + +#ifdef UFS_EXTATTR +#ifdef __OpenBSD__ +#define static +#endif +#ifndef LK_NOPAUSE +#define LK_NOPAUSE 0 +#endif /* LK_NOPAUSE */ + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +/* -XXX +static MALLOC_DEFINE(M_UFS_EXTATTR, "ufs_extattr", "ufs extended attribute"); +*/ + +static int ufs_extattr_sync = 0; +/* -XXX +SYSCTL_INT(_debug, OID_AUTO, ufs_extattr_sync, CTLFLAG_RW, &ufs_extattr_sync, + 0, ""); +*/ + +static int ufs_extattr_valid_attrname(int attrnamespace, + const char *attrname); +static int ufs_extattr_credcheck(struct vnode *vp, + struct ufs_extattr_list_entry *uele, struct ucred *cred, struct proc *p, + int access); +static int ufs_extattr_enable_with_open(struct ufsmount *ump, + struct vnode *vp, int attrnamespace, const char *attrname, struct proc *p); +static int ufs_extattr_enable(struct ufsmount *ump, int attrnamespace, + const char *attrname, struct vnode *backing_vnode, struct proc *p); +static int ufs_extattr_disable(struct ufsmount *ump, int attrnamespace, + const char *attrname, struct proc *p); +static int ufs_extattr_get(struct vnode *vp, int attrnamespace, + const char *name, struct uio *uio, size_t *size, struct ucred *cred, + struct proc *p); +static int ufs_extattr_set(struct vnode *vp, int attrnamespace, + const char *name, struct uio *uio, struct ucred *cred, struct proc *p); +static int ufs_extattr_rm(struct vnode *vp, int attrnamespace, + const char *name, struct ucred *cred, struct proc *p); + +static void ufs_extattr_uepm_lock(struct ufsmount *ump, struct proc *p); +static void ufs_extattr_uepm_unlock(struct ufsmount *ump, struct proc *p); +static struct ufs_extattr_list_entry * +ufs_extattr_find_attr(struct ufsmount *ump, int attrnamespace, + const char *attrname); +/* + * 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); +} + +/* + * Determine whether the name passed is a valid name for an actual + * attribute. + * + * Invalid currently consists of: + * NULL pointer for attrname + * zero-length attrname (used to retrieve application attribute list) + */ +static int +ufs_extattr_valid_attrname(int attrnamespace, const char *attrname) +{ + + if (attrname == NULL) + return (0); + if (strlen(attrname) == 0) + return (0); + return (1); +} + +/* + * Locate an attribute given a name and mountpoint. + * Must be holding uepm lock for the mount point. + */ +static struct ufs_extattr_list_entry * +ufs_extattr_find_attr(struct ufsmount *ump, int attrnamespace, + const char *attrname) +{ + struct ufs_extattr_list_entry *search_attribute; + + for (search_attribute = LIST_FIRST(&ump->um_extattr.uepm_list); + search_attribute; + search_attribute = LIST_NEXT(search_attribute, uele_entries)) { + if (!(strncmp(attrname, search_attribute->uele_attrname, + UFS_EXTATTR_MAXEXTATTRNAME)) && + (attrnamespace == search_attribute->uele_attrnamespace)) { + 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; +} + +/* + * Destroy per-FS structures supporting extended attributes. Assumes + * that EAs have already been stopped, and will panic if not. + */ +void +ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm) +{ + + if (!(uepm->uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED)) + panic("ufs_extattr_uepm_destroy: not initialized"); + + if ((uepm->uepm_flags & UFS_EXTATTR_UEPM_STARTED)) + panic("ufs_extattr_uepm_destroy: called while still started"); + + /* + * It's not clear that either order for the next two lines is + * ideal, and it should never be a problem if this is only called + * during unmount, and with vfs_busy(). + */ + uepm->uepm_flags &= ~UFS_EXTATTR_UEPM_INITIALIZED; + /* - XXX + lockdestroy(&uepm->uepm_lock); + */ +} + +/* + * 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); +} + +#ifdef UFS_EXTATTR_AUTOSTART +static int +ufs_extattr_lookup(struct vnode *start_dvp, int lockparent, char *dirname, + struct vnode **vp, struct proc *p); +/* + * Helper routine: given a locked parent directory and filename, return + * the locked vnode of the inode associated with the name. Will not + * follow symlinks, may return any type of vnode. Lock on parent will + * be released even in the event of a failure. In the event that the + * target is the parent (i.e., "."), there will be two references and + * one lock, requiring the caller to possibly special-case. + */ +#define UE_GETDIR_LOCKPARENT 1 +#define UE_GETDIR_LOCKPARENT_DONT 2 +static int +ufs_extattr_lookup(struct vnode *start_dvp, int lockparent, char *dirname, + struct vnode **vp, struct proc *p) +{ + struct vop_lookup_args vargs; + struct componentname cnp; + struct vnode *target_vp; + int error; + + bzero(&cnp, sizeof(cnp)); + cnp.cn_nameiop = LOOKUP; + cnp.cn_flags = ISLASTCN; + if (lockparent == UE_GETDIR_LOCKPARENT) + cnp.cn_flags |= LOCKPARENT; + cnp.cn_proc = p; + cnp.cn_cred = p->p_ucred; + MALLOC(cnp.cn_pnbuf, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + + cnp.cn_nameptr = cnp.cn_pnbuf; + error = copystr(dirname, cnp.cn_pnbuf, MAXPATHLEN, + (size_t *) &cnp.cn_namelen); + if (error) { + if (lockparent == UE_GETDIR_LOCKPARENT_DONT) { + VOP_UNLOCK(start_dvp, 0, p); + } + FREE(cnp.cn_pnbuf, M_NAMEI); + printf("ufs_extattr_lookup: copystr failed\n"); + return (error); + } + cnp.cn_namelen--; /* trim nul termination */ + vargs.a_desc = NULL; + vargs.a_dvp = start_dvp; + vargs.a_vpp = &target_vp; + vargs.a_cnp = &cnp; + error = ufs_lookup(&vargs); + FREE(cnp.cn_pnbuf, M_NAMEI); + + if (error) { +#if 0 + /* -XXX does OpenBSD ufs_lookup always unlock on error? */ + /* + * Error condition, may have to release the lock on the parent + * if ufs_lookup() didn't. + */ + if (!(cnp.cn_flags & PDIRUNLOCK) && + (lockparent == UE_GETDIR_LOCKPARENT_DONT)) + VOP_UNLOCK(start_dvp, 0, p); + + /* + * Check that ufs_lookup() didn't release the lock when we + * didn't want it to. + */ + if ((cnp.cn_flags & PDIRUNLOCK) && + (lockparent == UE_GETDIR_LOCKPARENT)) + panic("ufs_extattr_lookup: lockparent but PDIRUNLOCK"); +#endif + + return (error); + } +/* + if (target_vp == start_dvp) + panic("ufs_extattr_lookup: target_vp == start_dvp"); +*/ + +#if 0 + /* PDIRUNLOCK does not exist on OpenBSD */ + if (target_vp != start_dvp && + !(cnp.cn_flags & PDIRUNLOCK) && + (lockparent == UE_GETDIR_LOCKPARENT_DONT)) + panic("ufs_extattr_lookup: !lockparent but !PDIRUNLOCK"); + + if ((cnp.cn_flags & PDIRUNLOCK) && + (lockparent == UE_GETDIR_LOCKPARENT)) + panic("ufs_extattr_lookup: lockparent but PDIRUNLOCK"); +#endif + + /* printf("ufs_extattr_lookup: success\n"); */ + *vp = target_vp; + return (0); +} +#endif /* !UFS_EXTATTR_AUTOSTART */ + +/* + * Enable an EA using the passed file system, backing vnode, attribute name, + * namespace, and proc. Will perform a VOP_OPEN() on the vp, so expects vp + * to be locked when passed in. The vnode will be returned unlocked, + * regardless of success/failure of the function. As a result, the caller + * will always need to vrele(), but not vput(). + */ +static int +ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp, + int attrnamespace, const char *attrname, struct proc *p) +{ + int error; + + error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p); + if (error) { + printf("ufs_extattr_enable_with_open.VOP_OPEN(): failed " + "with %d\n", error); + VOP_UNLOCK(vp, 0, p); + return (error); + } + +#if 0 + /* - XXX */ + /* + * XXX: Note, should VOP_CLOSE() if vfs_object_create() fails, but due + * to a similar piece of code in vn_open(), we don't. + */ + if (vn_canvmio(vp) == TRUE) + if ((error = vfs_object_create(vp, p, p->p_ucred)) != 0) { + /* + * XXX: bug replicated from vn_open(): should + * VOP_CLOSE() here. + */ + VOP_UNLOCK(vp, 0, p); + return (error); + } +#endif + + vp->v_writecount++; + + vref(vp); + + VOP_UNLOCK(vp, 0, p); + + error = ufs_extattr_enable(ump, attrnamespace, attrname, vp, p); + if (error != 0) + vn_close(vp, FREAD|FWRITE, p->p_ucred, p); + return (error); +} + +#ifdef UFS_EXTATTR_AUTOSTART +static int +ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp, + int attrnamespace, struct proc *p); +/* + * Given a locked directory vnode, iterate over the names in the directory + * and use ufs_extattr_lookup() to retrieve locked vnodes of potential + * attribute files. Then invoke ufs_extattr_enable_with_open() on each + * to attempt to start the attribute. Leaves the directory locked on + * exit. + */ +static int +ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp, + int attrnamespace, struct proc *p) +{ + struct vop_readdir_args vargs; + struct dirent *dp, *edp; + struct vnode *attr_vp; + struct uio auio; + struct iovec aiov; + char *dirbuf; + int error, eofflag = 0; + + if (dvp->v_type != VDIR) + return (ENOTDIR); + + MALLOC(dirbuf, char *, DIRBLKSIZ, M_TEMP, M_WAITOK); + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_procp = p; + auio.uio_offset = 0; + + vargs.a_desc = NULL; + vargs.a_vp = dvp; + vargs.a_uio = &auio; + vargs.a_cred = p->p_ucred; + vargs.a_eofflag = &eofflag; + vargs.a_ncookies = NULL; + vargs.a_cookies = NULL; + + while (!eofflag) { + auio.uio_resid = DIRBLKSIZ; + aiov.iov_base = dirbuf; + aiov.iov_len = DIRBLKSIZ; + error = ufs_readdir(&vargs); + if (error) { + printf("ufs_extattr_iterate_directory: ufs_readdir " + "%d\n", error); + return (error); + } + + edp = (struct dirent *)&dirbuf[DIRBLKSIZ]; + for (dp = (struct dirent *)dirbuf; dp < edp; ) { +#if (BYTE_ORDER == LITTLE_ENDIAN) + dp->d_type = dp->d_namlen; + dp->d_namlen = 0; +#else + dp->d_type = 0; +#endif + if (dp->d_reclen == 0) + break; + error = ufs_extattr_lookup(dvp, UE_GETDIR_LOCKPARENT, + dp->d_name, &attr_vp, p); + if (error) { + printf("ufs_extattr_iterate_directory: lookup " + "%s %d\n", dp->d_name, error); + } else if (attr_vp == dvp) { + vrele(attr_vp); + } else if (attr_vp->v_type != VREG) { +/* + * Eventually, this will be uncommented, but in the mean time, the ".." + * entry causes unnecessary console warnings. + printf("ufs_extattr_iterate_directory: " + "%s not VREG\n", dp->d_name); +*/ + vput(attr_vp); + } else { + error = ufs_extattr_enable_with_open(ump, + attr_vp, attrnamespace, dp->d_name, p); + vrele(attr_vp); + if (error) { + printf("ufs_extattr_iterate_directory: " + "enable %s %d\n", dp->d_name, + error); + } else { +/* + * While it's nice to have some visual output here, skip for the time-being. + * Probably should be enabled by -v at boot. + printf("Autostarted %s\n", dp->d_name); + */ +printf("Autostarted %s\n", dp->d_name); /* XXX - debug*/ + } + } + dp = (struct dirent *) ((char *)dp + dp->d_reclen); + if (dp >= edp) + break; + } + } + FREE(dirbuf, M_TEMP); + + return (0); +} + +/* + * Auto-start of extended attributes, to be executed (optionally) at + * mount-time. + */ +int +ufs_extattr_autostart(struct mount *mp, struct proc *p) +{ + struct vnode *rvp, *attr_dvp, *attr_system_dvp, *attr_user_dvp; + int error; + + /* + * Does UFS_EXTATTR_FSROOTSUBDIR exist off the file system root? + * If so, automatically start EA's. + */ + error = VFS_ROOT(mp, &rvp); + if (error) { + printf("ufs_extattr_autostart.VFS_ROOT() returned %d\n", error); + return (error); + } + + error = ufs_extattr_lookup(rvp, UE_GETDIR_LOCKPARENT_DONT, + UFS_EXTATTR_FSROOTSUBDIR, &attr_dvp, p); + if (error) { + /* rvp ref'd but now unlocked */ + vrele(rvp); + return (error); + } + if (rvp == attr_dvp) { + /* Should never happen. */ + vrele(attr_dvp); + vput(rvp); + return (EINVAL); + } + vrele(rvp); + + if (attr_dvp->v_type != VDIR) { + printf("ufs_extattr_autostart: %s != VDIR\n", + UFS_EXTATTR_FSROOTSUBDIR); + goto return_vput_attr_dvp; + } + + error = ufs_extattr_start(mp, p); + if (error) { + printf("ufs_extattr_autostart: ufs_extattr_start failed (%d)\n", + error); + goto return_vput_attr_dvp; + } + + /* + * Look for two subdirectories: UFS_EXTATTR_SUBDIR_SYSTEM, + * UFS_EXTATTR_SUBDIR_USER. For each, iterate over the sub-directory, + * and start with appropriate type. Failures in either don't + * result in an over-all failure. attr_dvp is left locked to + * be cleaned up on exit. + */ + error = ufs_extattr_lookup(attr_dvp, UE_GETDIR_LOCKPARENT, + UFS_EXTATTR_SUBDIR_SYSTEM, &attr_system_dvp, p); + if (!error) { + error = ufs_extattr_iterate_directory(VFSTOUFS(mp), + attr_system_dvp, EXTATTR_NAMESPACE_SYSTEM, p); + if (error) + printf("ufs_extattr_iterate_directory returned %d\n", + error); + vput(attr_system_dvp); + } + + error = ufs_extattr_lookup(attr_dvp, UE_GETDIR_LOCKPARENT, + UFS_EXTATTR_SUBDIR_USER, &attr_user_dvp, p); + if (!error) { + error = ufs_extattr_iterate_directory(VFSTOUFS(mp), + attr_user_dvp, EXTATTR_NAMESPACE_USER, p); + if (error) + printf("ufs_extattr_iterate_directory returned %d\n", + error); + vput(attr_user_dvp); + } + + /* Mask startup failures in sub-directories. */ + error = 0; + +return_vput_attr_dvp: + vput(attr_dvp); + + return (error); +} +#endif /* !UFS_EXTATTR_AUTOSTART */ + +/* + * 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 (LIST_FIRST(&ump->um_extattr.uepm_list) != NULL) { + uele = LIST_FIRST(&ump->um_extattr.uepm_list); + ufs_extattr_disable(ump, uele->uele_attrnamespace, + 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 an + * unlocked backing vnode to hold the attribute data. + */ +static int +ufs_extattr_enable(struct ufsmount *ump, int attrnamespace, + const 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 (!ufs_extattr_valid_attrname(attrnamespace, attrname)) + return (EINVAL); + 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_extattr_find_attr(ump, attrnamespace, attrname)) { + error = EEXIST; + goto free_exit; + } + + strncpy(attribute->uele_attrname, attrname, UFS_EXTATTR_MAXEXTATTRNAME); + attribute->uele_attrnamespace = attrnamespace; + bzero(&attribute->uele_fileheader, + sizeof(struct ufs_extattr_fileheader)); + + attribute->uele_backing_vnode = backing_vnode; + + 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 = p; + + VOP_LEASE(backing_vnode, p, p->p_ucred, LEASE_WRITE); + vn_lock(backing_vnode, LK_SHARED | LK_NOPAUSE | LK_RETRY, p); + error = VOP_READ(backing_vnode, &auio, IO_NODELOCKED, + 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; + } + + if (attribute->uele_fileheader.uef_magic != UFS_EXTATTR_MAGIC) { + printf("ufs_extattr_enable: invalid attribute header magic\n"); + error = EINVAL; + goto free_exit; + } + + if (attribute->uele_fileheader.uef_version != UFS_EXTATTR_VERSION) { + printf("ufs_extattr_enable: incorrect attribute header " + "version\n"); + error = EINVAL; + goto free_exit; + } + + backing_vnode->v_flag |= VSYSTEM; + 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, int attrnamespace, + const char *attrname, struct proc *p) +{ + struct ufs_extattr_list_entry *uele; + int error = 0; + + if (!ufs_extattr_valid_attrname(attrnamespace, attrname)) + return (EINVAL); + + uele = ufs_extattr_find_attr(ump, attrnamespace, 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. If filename_vp is + * non-NULL, it must be passed in locked, and regardless of errors in + * processing, will be unlocked. + */ +int +ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, + int attrnamespace, const char *attrname, struct proc *p) +{ + struct ufsmount *ump = VFSTOUFS(mp); + int error; + +#if 0 + /* jail? -XXX */ + /* + * Processes with privilege, but in jail, are not allowed to + * configure extended attributes. + */ + if ((error = suser_xxx(p->p_ucred, p, 0))) { + if (filename_vp != NULL) + VOP_UNLOCK(filename_vp, 0, p); + return (error); + } +#endif + + switch(cmd) { + case UFS_EXTATTR_CMD_START: + if (filename_vp != NULL) { + VOP_UNLOCK(filename_vp, 0, p); + return (EINVAL); + } + if (attrname != NULL) + return (EINVAL); + + error = ufs_extattr_start(mp, p); + + return (error); + + case UFS_EXTATTR_CMD_STOP: + if (filename_vp != NULL) { + VOP_UNLOCK(filename_vp, 0, p); + return (EINVAL); + } + if (attrname != NULL) + return (EINVAL); + + error = ufs_extattr_stop(mp, p); + + return (error); + + case UFS_EXTATTR_CMD_ENABLE: + + if (filename_vp == NULL) + return (EINVAL); + if (attrname == NULL) { + VOP_UNLOCK(filename_vp, 0, p); + return (EINVAL); + } + + /* + * ufs_extattr_enable_with_open() will always unlock the + * vnode, regardless of failure. + */ + ufs_extattr_uepm_lock(ump, p); + error = ufs_extattr_enable_with_open(ump, filename_vp, + attrnamespace, attrname, p); + ufs_extattr_uepm_unlock(ump, p); + + return (error); + + case UFS_EXTATTR_CMD_DISABLE: + + if (filename_vp != NULL) { + VOP_UNLOCK(filename_vp, 0, p); + return (EINVAL); + } + if (attrname == NULL) + return (EINVAL); + + ufs_extattr_uepm_lock(ump, p); + error = ufs_extattr_disable(ump, attrnamespace, 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 vnode *vp, struct ufs_extattr_list_entry *uele, + struct ucred *cred, struct proc *p, int access) +{ + + /* + * Kernel-invoked always succeeds. + */ + if (cred == NULL) + return (0); + + /* + * Do not allow privileged processes in jail to directly + * manipulate system attributes. + * + * XXX What capability should apply here? + * Probably CAP_SYS_SETFFLAG. + */ + switch (uele->uele_attrnamespace) { + case EXTATTR_NAMESPACE_SYSTEM: + return (suser(cred, &p->p_acflag)); + case EXTATTR_NAMESPACE_USER: + return (VOP_ACCESS(vp, access, cred, p)); + default: + return (EPERM); + } +} + +/* + * Vnode operating to retrieve a named extended attribute. + */ +int +ufs_vop_getextattr(void *v) +{ + struct vop_getextattr_args /* { + IN struct vnode *a_vp; + IN int a_attrnamespace; + IN const char *a_name; + INOUT struct uio *a_uio; + OUT struct size_t *a_size; + IN struct ucred *a_cred; + IN struct proc *a_p; + } */ *ap = v; + 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_attrnamespace, ap->a_name, + ap->a_uio, ap->a_size, 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, int attrnamespace, const char *name, + struct uio *uio, size_t *size, 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; + size_t len, old_len; + int error = 0; + + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) + return (EOPNOTSUPP); + + if (strlen(name) == 0) { + /* XXX retrieve attribute lists. */ + /* XXX should probably be checking for name == NULL? */ + return (EINVAL); + } + + attribute = ufs_extattr_find_attr(ump, attrnamespace, name); + if (!attribute) + /* XXX: ENOENT here will eventually be ENOATTR. */ + return (ENOENT); + + if ((error = ufs_extattr_credcheck(vp, attribute, cred, p, IREAD))) + return (error); + + /* + * Allow only offsets of zero to encourage the read/replace + * extended attribute semantic. Otherwise we can't guarantee + * atomicity, as we don't provide locks for extended attributes. + */ + if (uio != NULL && 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); + + /* + * Acquire locks. + */ + VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_READ); + /* + * Don't need to get a lock on the backing file if the getattr 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_SHARED | + LK_NOPAUSE | LK_RETRY, p); + + error = VOP_READ(attribute->uele_backing_vnode, &local_aio, + IO_NODELOCKED, ump->um_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + /* Defined? */ + if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) { + /* XXX: ENOENT here will eventually be ENOATTR. */ + error = ENOENT; + goto vopunlock_exit; + } + + /* Valid for the current inode generation? */ + if (ueh.ueh_i_gen != ip->i_ffs_gen) { + /* + * The inode itself has a different generation number + * than the attribute data. For now, the best solution + * is to coerce this to undefined, and let it get cleaned + * up by the next write or extattrctl clean. + */ + printf("ufs_extattr_get: inode number inconsistency (%d, %d)\n", + ueh.ueh_i_gen, ip->i_ffs_gen); + /* XXX: ENOENT here will eventually be ENOATTR. */ + error = ENOENT; + goto vopunlock_exit; + } + + /* Local size consistency check. */ + if (ueh.ueh_len > attribute->uele_fileheader.uef_size) { + error = ENXIO; + goto vopunlock_exit; + } + + /* Return full data size if caller requested it. */ + if (size != NULL) + *size = ueh.ueh_len; + + /* Return data if the caller requested it. */ + if (uio != NULL) { + /* Allow for offset into the attribute data. */ + uio->uio_offset = base_offset + sizeof(struct + ufs_extattr_header); + + /* + * Figure out maximum to transfer -- use buffer size and + * local data limit. + */ + len = MIN(uio->uio_resid, ueh.ueh_len); + old_len = uio->uio_resid; + uio->uio_resid = len; + + error = VOP_READ(attribute->uele_backing_vnode, uio, + IO_NODELOCKED, ump->um_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + uio->uio_resid = old_len - (len - uio->uio_resid); + } + +vopunlock_exit: + + if (uio != NULL) + uio->uio_offset = 0; + + if (attribute->uele_backing_vnode != vp) + VOP_UNLOCK(attribute->uele_backing_vnode, 0, p); + + return (error); +} + +/* + * Vnode operation to set a named attribute. + */ +int +ufs_vop_setextattr(void *v) +{ + struct vop_setextattr_args /* { + IN struct vnode *a_vp; + IN int a_attrnamespace; + IN const char *a_name; + INOUT struct uio *a_uio; + IN struct ucred *a_cred; + IN struct proc *a_p; + } */ *ap = v; + 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 != NULL) + error = ufs_extattr_set(ap->a_vp, ap->a_attrnamespace, + ap->a_name, ap->a_uio, ap->a_cred, ap->a_p); + else + error = ufs_extattr_rm(ap->a_vp, ap->a_attrnamespace, + 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, int attrnamespace, const 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, ioflag; + + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) + return (EOPNOTSUPP); + if (!ufs_extattr_valid_attrname(attrnamespace, name)) + return (EINVAL); + + attribute = ufs_extattr_find_attr(ump, attrnamespace, name); + if (!attribute) + /* XXX: ENOENT here will eventually be ENOATTR. */ + return (ENOENT); + + if ((error = ufs_extattr_credcheck(vp, attribute, cred, p, IWRITE))) + return (error); + + /* + * Early rejection of invalid offsets/length. + * 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; + ueh.ueh_i_gen = ip->i_ffs_gen; + 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); + + ioflag = IO_NODELOCKED; + if (ufs_extattr_sync) + ioflag |= IO_SYNC; + error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag, + 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); + + ioflag = IO_NODELOCKED; + if (ufs_extattr_sync) + ioflag |= IO_SYNC; + error = VOP_WRITE(attribute->uele_backing_vnode, uio, ioflag, + ump->um_extattr.uepm_ucred); + +vopunlock_exit: + uio->uio_offset = 0; + + if (attribute->uele_backing_vnode != vp) + 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, int attrnamespace, const 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, ioflag; + + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) + return (EOPNOTSUPP); + if (!ufs_extattr_valid_attrname(attrnamespace, name)) + return (EINVAL); + + attribute = ufs_extattr_find_attr(ump, attrnamespace, name); + if (!attribute) + /* XXX: ENOENT here will eventually be ENOATTR. */ + return (ENOENT); + + if ((error = ufs_extattr_credcheck(vp, attribute, 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); + + /* + * Check to see if currently 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, + IO_NODELOCKED, ump->um_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + /* Defined? */ + if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) { + /* XXX: ENOENT here will eventually be ENOATTR. */ + error = ENOENT; + goto vopunlock_exit; + } + + /* Valid for the current inode generation? */ + if (ueh.ueh_i_gen != ip->i_ffs_gen) { + /* + * The inode itself has a different generation number than + * the attribute data. For now, the best solution is to + * coerce this to undefined, and let it get cleaned up by + * the next write or extattrctl clean. + */ + printf("ufs_extattr_rm: inode number inconsistency (%d, %d)\n", + ueh.ueh_i_gen, ip->i_ffs_gen); + /* XXX: ENOENT here will eventually be ENOATTR. */ + error = ENOENT; + goto vopunlock_exit; + } + + /* Flag it as not in use. */ + ueh.ueh_flags = 0; + ueh.ueh_len = 0; + + 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); + + ioflag = IO_NODELOCKED; + if (ufs_extattr_sync) + ioflag |= IO_SYNC; + error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag, + 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); + + /* + * In that case, we cannot lock. We should not have any active vnodes + * on the fs if this is not yet initialized but is going to be, so + * this can go unlocked. + */ + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED)) + return; + + ufs_extattr_uepm_lock(ump, p); + + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) { + ufs_extattr_uepm_unlock(ump, p); + return; + } + + LIST_FOREACH(uele, &ump->um_extattr.uepm_list, uele_entries) + ufs_extattr_rm(vp, uele->uele_attrnamespace, + uele->uele_attrname, NULL, p); + + ufs_extattr_uepm_unlock(ump, p); +} + +#endif /* !UFS_EXTATTR */ diff --git a/sys/ufs/ufs/ufs_inode.c b/sys/ufs/ufs/ufs_inode.c index dd2c6574d30..cdcbd6ecb6f 100644 --- a/sys/ufs/ufs/ufs_inode.c +++ b/sys/ufs/ufs/ufs_inode.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ufs_inode.c,v 1.16 2001/12/19 08:58:07 art Exp $ */ +/* $OpenBSD: ufs_inode.c,v 1.17 2002/02/22 20:37:46 drahn Exp $ */ /* $NetBSD: ufs_inode.c,v 1.7 1996/05/11 18:27:52 mycroft Exp $ */ /* @@ -50,6 +50,7 @@ #include <sys/malloc.h> #include <sys/namei.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_lookup.c b/sys/ufs/ufs/ufs_lookup.c index b7d5802ddc8..1d3f46edf38 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ufs_lookup.c,v 1.18 2001/11/06 19:53:21 miod Exp $ */ +/* $OpenBSD: ufs_lookup.c,v 1.19 2002/02/22 20:37:46 drahn Exp $ */ /* $NetBSD: ufs_lookup.c,v 1.7 1996/02/09 22:36:06 christos Exp $ */ /* @@ -53,6 +53,7 @@ #include <uvm/uvm_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 a2fe18d2753..ab7ff29b562 100644 --- a/sys/ufs/ufs/ufs_quota.c +++ b/sys/ufs/ufs/ufs_quota.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ufs_quota.c,v 1.10 2002/02/20 18:40:49 csapuntz Exp $ */ +/* $OpenBSD: ufs_quota.c,v 1.11 2002/02/22 20:37:46 drahn Exp $ */ /* $NetBSD: ufs_quota.c,v 1.8 1996/02/09 22:36:09 christos Exp $ */ /* @@ -48,6 +48,7 @@ #include <sys/vnode.h> #include <sys/mount.h> +#include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufsmount.h> |