From: Sascha Wildner Date: Mon, 21 Dec 2015 20:33:03 +0000 (+0100) Subject: kernel: Remove the old unionfs that was unhooked from the build since 2004. X-Git-Tag: v4.6.0rc~1149 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/55358b9856f7becc0f794a896e04f3a10d93921f?ds=sidebyside kernel: Remove the old unionfs that was unhooked from the build since 2004. Approved-by: dillon --- diff --git a/Makefile_upgrade.inc b/Makefile_upgrade.inc index e071cf1332..b623fb09c4 100644 --- a/Makefile_upgrade.inc +++ b/Makefile_upgrade.inc @@ -2264,6 +2264,9 @@ TO_REMOVE+=/usr/include/sys/syslink_vfs.h TO_REMOVE+=/usr/share/man/man4/i386 TO_REMOVE+=/usr/share/man/man8/i386 TO_REMOVE+=/usr/share/man/man9/i386 +TO_REMOVE+=/boot/kernel/union.ko +TO_REMOVE+=/sbin/mount_union +TO_REMOVE+=/usr/share/man/man8/mount_union.8.gz .if !defined(WANT_INSTALLER) TO_REMOVE+=/usr/sbin/dfuibe_installer diff --git a/contrib/smbfs/mount_smbfs/mntopts.h b/contrib/smbfs/mount_smbfs/mntopts.h index c14b27cf04..29da868053 100644 --- a/contrib/smbfs/mount_smbfs/mntopts.h +++ b/contrib/smbfs/mount_smbfs/mntopts.h @@ -54,7 +54,6 @@ struct mntopt { #endif #define MOPT_RDONLY { "rdonly", 0, MNT_RDONLY, 0 } #define MOPT_SYNC { "sync", 0, MNT_SYNCHRONOUS, 0 } -#define MOPT_UNION { "union", 0, MNT_UNION, 0 } #define MOPT_USERQUOTA { "userquota", 0, 0, 0 } #define MOPT_GROUPQUOTA { "groupquota", 0, 0, 0 } #ifndef APPLE @@ -100,7 +99,6 @@ struct mntopt { MOPT_NOSUID, \ MOPT_NOSYMFOLLOW, \ MOPT_RDONLY, \ - MOPT_UNION, \ MOPT_NOCLUSTERR, \ MOPT_NOCLUSTERW #endif /* APPLE */ diff --git a/include/mntopts.h b/include/mntopts.h index 8f53008a32..18d52daaec 100644 --- a/include/mntopts.h +++ b/include/mntopts.h @@ -56,7 +56,6 @@ struct mntopt { #define MOPT_TRIM { "trim", 0, MNT_TRIM, 0 } #define MOPT_RDONLY { "rdonly", 0, MNT_RDONLY, 0 } #define MOPT_SYNC { "sync", 0, MNT_SYNCHRONOUS, 0 } -#define MOPT_UNION { "union", 0, MNT_UNION, 0 } #define MOPT_USERQUOTA { "userquota", 0, 0, 0 } #define MOPT_GROUPQUOTA { "groupquota", 0, 0, 0 } #define MOPT_NOCLUSTERR { "clusterr", 1, MNT_NOCLUSTERR, 0 } @@ -93,7 +92,6 @@ struct mntopt { MOPT_NOSUID, \ MOPT_NOSYMFOLLOW, \ MOPT_RDONLY, \ - MOPT_UNION, \ MOPT_NOCLUSTERR, \ MOPT_NOCLUSTERW, \ MOPT_IGNORE diff --git a/lib/libc/sys/chflags.2 b/lib/libc/sys/chflags.2 index 920c6bbd4e..e1cbb96a15 100644 --- a/lib/libc/sys/chflags.2 +++ b/lib/libc/sys/chflags.2 @@ -221,7 +221,6 @@ The underlying file system does not support file flags. .Xr fflagstostr 3 , .Xr strtofflags 3 , .Xr init 8 , -.Xr mount_union 8 , .Xr swapcache 8 .Sh HISTORY The diff --git a/lib/libc/sys/undelete.2 b/lib/libc/sys/undelete.2 index 425541ae6b..6bf81a5a4f 100644 --- a/lib/libc/sys/undelete.2 +++ b/lib/libc/sys/undelete.2 @@ -28,7 +28,6 @@ .\" .\" @(#)undelete.2 8.4 (Berkeley) 10/18/94 .\" $FreeBSD: src/lib/libc/sys/undelete.2,v 1.4.2.5 2001/12/14 18:34:02 ru Exp $ -.\" $DragonFly: src/lib/libc/sys/undelete.2,v 1.2 2003/06/17 04:26:47 dillon Exp $ .\" .Dd October 18, 1994 .Dt UNDELETE 2 @@ -92,8 +91,7 @@ The name resides on a read-only file system. points outside the process's allocated address space. .El .Sh SEE ALSO -.Xr unlink 2 , -.Xr mount_union 8 +.Xr unlink 2 .Sh HISTORY An .Fn undelete diff --git a/sbin/Makefile b/sbin/Makefile index f31bfe5bc7..123e3003c6 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -64,7 +64,6 @@ SUBDIR= adjkerntz \ mount_std \ mount_tmpfs \ mount_udf \ - mount_union \ mountd \ natacontrol \ natd \ diff --git a/sbin/mount/mount.8 b/sbin/mount/mount.8 index 3bacd61a58..bf6e63c865 100644 --- a/sbin/mount/mount.8 +++ b/sbin/mount/mount.8 @@ -220,13 +220,6 @@ for more information. The same as .Fl u ; indicate that the status of an already mounted file system should be changed. -.It Cm union -Causes the namespace at the mount point to appear as the union -of the mounted filesystem root and the existing directory. -Lookups will be done in the mounted filesystem first. -If those operations fail due to a non-existent file the underlying -directory is then accessed. -All creates are done in the mounted filesystem. .It Cm ignore Will be ignored by .Xr df 1 . @@ -421,7 +414,6 @@ have permission to load the module. .Xr mount_std 8 , .Xr mount_tmpfs 8 , .Xr mount_udf 8 , -.Xr mount_union 8 , .Xr sysctl 8 , .Xr umount 8 .Sh HISTORY diff --git a/sbin/mount/mount.c b/sbin/mount/mount.c index 5fe9e97f92..da33b1c002 100644 --- a/sbin/mount/mount.c +++ b/sbin/mount/mount.c @@ -750,7 +750,6 @@ flags2opts(int flags) if (flags & MNT_NOEXEC) res = catopt(res, "noexec"); if (flags & MNT_NOSUID) res = catopt(res, "nosuid"); if (flags & MNT_NODEV) res = catopt(res, "nodev"); - if (flags & MNT_UNION) res = catopt(res, "union"); if (flags & MNT_ASYNC) res = catopt(res, "async"); if (flags & MNT_NOATIME) res = catopt(res, "noatime"); if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr"); diff --git a/sbin/mount_std/mount_std.8 b/sbin/mount_std/mount_std.8 index 884d805cf4..1fd2e67fd5 100644 --- a/sbin/mount_std/mount_std.8 +++ b/sbin/mount_std/mount_std.8 @@ -68,9 +68,8 @@ options .Dq rw , .Dq nodev , .Dq noexec , -.Dq nosuid , and -.Dq union . +.Dq nosuid . .It has a kernel filesystem module name the same as its user-visible name. .It diff --git a/sbin/mount_ufs/mount.c b/sbin/mount_ufs/mount.c index a03dd733bf..adfb66c682 100644 --- a/sbin/mount_ufs/mount.c +++ b/sbin/mount_ufs/mount.c @@ -719,7 +719,6 @@ flags2opts(int flags) if (flags & MNT_NOEXEC) res = catopt(res, "noexec"); if (flags & MNT_NOSUID) res = catopt(res, "nosuid"); if (flags & MNT_NODEV) res = catopt(res, "nodev"); - if (flags & MNT_UNION) res = catopt(res, "union"); if (flags & MNT_ASYNC) res = catopt(res, "async"); if (flags & MNT_NOATIME) res = catopt(res, "noatime"); if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr"); diff --git a/sbin/mount_ufs/mount_ufs.8 b/sbin/mount_ufs/mount_ufs.8 index f777f2747f..0fde195c65 100644 --- a/sbin/mount_ufs/mount_ufs.8 +++ b/sbin/mount_ufs/mount_ufs.8 @@ -220,13 +220,6 @@ for more information. The same as .Fl u ; indicate that the status of an already mounted file system should be changed. -.It Cm union -Causes the namespace at the mount point to appear as the union -of the mounted filesystem root and the existing directory. -Lookups will be done in the mounted filesystem first. -If those operations fail due to a non-existent file the underlying -directory is then accessed. -All creates are done in the mounted filesystem. .It Cm ignore Will be ignored by .Xr df 1 . @@ -421,7 +414,6 @@ have permission to load the module. .Xr mount_std 8 , .Xr mount_tmpfs 8 , .Xr mount_udf 8 , -.Xr mount_union 8 , .Xr sysctl 8 , .Xr umount 8 .Sh HISTORY diff --git a/sbin/mount_union/Makefile b/sbin/mount_union/Makefile deleted file mode 100644 index 75c7663c80..0000000000 --- a/sbin/mount_union/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# @(#)Makefile 8.3 (Berkeley) 3/27/94 -# $FreeBSD: src/sbin/mount_union/Makefile,v 1.6.6.1 2001/04/25 10:58:40 ru Exp $ - -PROG= mount_union -MAN= mount_union.8 - -LDADD= -lutil -DPADD= ${LIBUTIL} - -CFLAGS+=-I${.CURDIR}/../../sys - -.include diff --git a/sbin/mount_union/mount_union.8 b/sbin/mount_union/mount_union.8 deleted file mode 100644 index fd871b8f38..0000000000 --- a/sbin/mount_union/mount_union.8 +++ /dev/null @@ -1,214 +0,0 @@ -.\" Copyright (c) 1994 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" This code is derived from software donated to Berkeley by -.\" Jan-Simon Pendry. -.\" -.\" 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. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. -.\" -.\" @(#)mount_union.8 8.6 (Berkeley) 3/27/94 -.\" $FreeBSD: src/sbin/mount_union/mount_union.8,v 1.6.2.2 2001/12/20 16:46:05 ru Exp $ -.\" -.Dd March 27, 1994 -.Dt MOUNT_UNION 8 -.Os -.Sh NAME -.Nm mount_union -.Nd mount union filesystems -.Sh SYNOPSIS -.Nm -.Op Fl br -.Op Fl o Ar options -.Ar directory -.Ar uniondir -.Sh DESCRIPTION -The -.Nm -command -attaches -.Ar directory -above -.Ar uniondir -in such a way that the contents of both directory trees remain visible. -By default, -.Ar directory -becomes the -.Em upper -layer and -.Ar uniondir -becomes the -.Em lower -layer. -.Pp -The options are as follows: -.Bl -tag -width indent -.It Fl b -Invert the default position, so that -.Ar directory -becomes the lower layer and -.Ar uniondir -becomes the upper layer. -However, -.Ar uniondir -remains the mount point. -.It Fl o -Options are specified with a -.Fl o -flag followed by a comma separated string of options. -See the -.Xr mount 8 -man page for possible options and their meanings. -.It Fl r -Hide the lower layer completely in the same way as mounting with -.Xr mount_null 8 . -.El -.Pp -To enforce filesystem security, the user mounting the filesystem -must be superuser or else have write permission on the mounted-on -directory. -In addition, the -.Va vfs.usermount -.Xr sysctl 3 -variable must be set to 1 to permit file system mounting by ordinary users. -.Pp -Filenames are looked up in the upper layer and then in the -lower layer. -If a directory is found in the lower layer, and there is no entry -in the upper layer, then a -.Em shadow -directory will be created in the upper layer. -It will be owned by the user who originally did the union mount, -with mode -.Dq rwxrwxrwx -(0777) modified by the umask in effect at that time. -.Pp -If a file exists in the upper layer then there is no way to access -a file with the same name in the lower layer. -If necessary, a combination of loopback and union mounts can be made -which will still allow the lower files to be accessed by a different -pathname. -.Pp -Except in the case of a directory, -access to an object is granted via the normal filesystem access checks. -For directories, the current user must have access to both the upper -and lower directories (should they both exist). -.Pp -Requests to create or modify objects in -.Ar uniondir -are passed to the upper layer with the exception of a few special cases. -An attempt to open for writing a file which exists in the lower layer -causes a copy of the -.Em entire -file to be made to the upper layer, and then for the upper layer copy -to be opened. -Similarly, an attempt to truncate a lower layer file to zero length -causes an empty file to be created in the upper layer. -Any other operation which would ultimately require modification to -the lower layer fails with -.Er EROFS . -.Pp -The union filesystem manipulates the namespace, rather than -individual filesystems. -The union operation applies recursively down the directory tree -now rooted at -.Ar uniondir . -Thus any filesystems which are mounted under -.Ar uniondir -will take part in the union operation. -This differs from the -.Em union -option to -.Xr mount 8 -which only applies the union operation to the mount point itself, -and then only for lookups. -.Sh EXAMPLES -The commands -.Bd -literal -offset indent -mount -t cd9660 -o ro /dev/cd0a /usr/src -mount -t union /var/obj /usr/src -.Ed -.Pp -mount the CD-ROM drive -.Pa /dev/cd0a -on -.Pa /usr/src -and then attaches -.Pa /var/obj -on top. -For most purposes the effect of this is to make the -source tree appear writable -even though it is stored on a CD-ROM. -.Pp -The command -.Bd -literal -offset indent -mount -t union -o -b /sys $HOME/sys -.Ed -.Pp -attaches the system source tree below the -.Pa sys -directory in the user's home directory. -This allows individual users to make private changes -to the source, and build new kernels, without those -changes becoming visible to other users. -Note that the files in the lower layer remain -accessible via -.Pa /sys . -.Sh SEE ALSO -.Xr intro 2 , -.Xr mount 2 , -.Xr unmount 2 , -.Xr fstab 5 , -.Xr mount 8 , -.Xr mount_null 8 -.Sh HISTORY -The -.Nm -command first appeared in -.Bx 4.4 . -It first worked in -.Fx Ns -(fill this in) . -.Sh BUGS -THIS FILESYSTEM TYPE IS NOT YET FULLY SUPPORTED (READ: IT DOESN'T WORK) -AND USING IT MAY, IN FACT, DESTROY DATA ON YOUR SYSTEM. USE AT YOUR -OWN RISK. BEWARE OF DOG. SLIPPERY WHEN WET. -.Pp -This code also needs an owner in order to be less dangerous - serious -hackers can apply by sending mail to -.Aq Mt kernel@crater.dragonflybsd.org -and announcing -their intent to take it over. -.Pp -Without whiteout support from the filesystem backing the upper layer, -there is no way that delete and rename operations on lower layer -objects can be done. -.Er EROFS -is returned for this kind of operations along with any others -which would make modifications to the lower layer, such as -.Xr chmod 1 . -.Pp -Running -.Xr find 1 -over a union tree has the side-effect of creating -a tree of shadow directories in the upper layer. diff --git a/sbin/mount_union/mount_union.c b/sbin/mount_union/mount_union.c deleted file mode 100644 index cb13c1744b..0000000000 --- a/sbin/mount_union/mount_union.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software donated to Berkeley by - * Jan-Simon Pendry. - * - * 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. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. - * - * @(#) Copyright (c) 1992, 1993, 1994 The Regents of the University of California. All rights reserved. - * @(#)mount_union.c 8.5 (Berkeley) 3/27/94 - * $FreeBSD: src/sbin/mount_union/mount_union.c,v 1.12 1999/10/09 11:54:14 phk Exp $ - */ - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -static struct mntopt mopts[] = { - MOPT_STDOPTS, - MOPT_NULL -}; - -static int subdir(const char *, const char *); -static void usage(void) __dead2; - -int -main(int argc, char **argv) -{ - struct union_args args; - int ch, mntflags; - char source[MAXPATHLEN]; - char target[MAXPATHLEN]; - struct vfsconf vfc; - int error; - - mntflags = 0; - args.mntflags = UNMNT_ABOVE; - while ((ch = getopt(argc, argv, "bo:r")) != -1) - switch (ch) { - case 'b': - args.mntflags &= ~UNMNT_OPMASK; - args.mntflags |= UNMNT_BELOW; - break; - case 'o': - getmntopts(optarg, mopts, &mntflags, 0); - break; - case 'r': - args.mntflags &= ~UNMNT_OPMASK; - args.mntflags |= UNMNT_REPLACE; - break; - case '?': - default: - usage(); - /* NOTREACHED */ - } - argc -= optind; - argv += optind; - - if (argc != 2) - usage(); - - /* resolve both target and source with realpath(3) */ - checkpath(argv[0], target); - checkpath(argv[1], source); - - if (subdir(target, source) || subdir(source, target)) - errx(EX_USAGE, "%s (%s) and %s (%s) are not distinct paths", - argv[0], target, argv[1], source); - - args.target = target; - - error = getvfsbyname("union", &vfc); - if (error && vfsisloadable("union")) { - if (vfsload("union")) - err(EX_OSERR, "vfsload(union)"); - endvfsent(); /* flush cache */ - error = getvfsbyname("union", &vfc); - } - if (error) - errx(EX_OSERR, "union filesystem is not available"); - - if (mount(vfc.vfc_name, source, mntflags, &args)) - err(EX_OSERR, "%s", target); - exit(0); -} - -static int -subdir(const char *p, const char *dir) -{ - int l; - - l = strlen(dir); - if (l <= 1) - return (1); - - if ((strncmp(p, dir, l) == 0) && (p[l] == '/' || p[l] == '\0')) - return (1); - - return (0); -} - -static void -usage(void) -{ - fprintf(stderr, - "usage: mount_union [-br] [-o options] target_fs mount_point\n"); - exit(EX_USAGE); -} diff --git a/sys/conf/files b/sys/conf/files index 3b1840cc3f..d1a2102797 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1224,9 +1224,6 @@ vfs/procfs/procfs_type.c optional procfs vfs/procfs/procfs_vfsops.c optional procfs vfs/procfs/procfs_vnops.c optional procfs vfs/procfs/procfs_rlimit.c optional procfs -vfs/union/union_subr.c optional union -vfs/union/union_vfsops.c optional union -vfs/union/union_vnops.c optional union vfs/hpfs/hpfs_alsubr.c optional hpfs vfs/hpfs/hpfs_hash.c optional hpfs vfs/hpfs/hpfs_lookup.c optional hpfs diff --git a/sys/conf/options b/sys/conf/options index 6f8d0aeede..862139712c 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -169,10 +169,6 @@ UFS_DIRHASH opt_ufs.h FFS_ROOT opt_ffs.h NFS_ROOT opt_nfsroot.h -# The union static file system has bogus static dependencies, so it isn't -# hidden yet. -UNION - # Options used only in subr_param.c. HZ opt_param.h MAXFILES opt_param.h diff --git a/sys/config/LINT64 b/sys/config/LINT64 index 7ea2440a07..4b7d335cd3 100644 --- a/sys/config/LINT64 +++ b/sys/config/LINT64 @@ -494,10 +494,10 @@ options IFPOLL_ENABLE # cannot currently be demand-loaded.) Some people still prefer # to statically compile other filesystems as well. # -# NB: The PORTAL and UNION filesystems are known to be +# NB: The PORTAL filesystem is known to be # buggy, and WILL panic your system if you attempt to do anything with -# them. They are included here as an incentive for some enterprising -# soul to sit down and fix them. +# it. It is included here as an incentive for some enterprising +# soul to sit down and fix it. # # One of these is mandatory: @@ -520,8 +520,6 @@ options SMBFS #SMB/CIFS filesystem options TMPFS #Temporary filesystem options UDF #UDF filesystem -# YYY-DR Till we rework the VOP methods for this filesystem -#options UNION #Union filesystem # The xFS_ROOT options REQUIRE the associated ``options xFS'' options FFS_ROOT #FFS usable as root device options NFS_ROOT #NFS usable as root device diff --git a/sys/emulation/43bsd/43bsd_file.c b/sys/emulation/43bsd/43bsd_file.c index 3415f0e0ea..d137a1df7a 100644 --- a/sys/emulation/43bsd/43bsd_file.c +++ b/sys/emulation/43bsd/43bsd_file.c @@ -33,9 +33,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/emulation/43bsd/43bsd_file.c,v 1.11 2006/09/05 00:55:44 dillon Exp $ - * from: DragonFly kern/vfs_syscalls.c,v 1.20 - * * These syscalls used to live in kern/vfs_syscalls.c. They are modified * to use the new split syscalls. */ @@ -61,8 +58,6 @@ #include -#include - /* * MPALMOSTSAFE */ diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index fb0d326d03..d822584266 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1841,7 +1841,6 @@ vfs_flagstostr(int flags, const struct mountctl_opt *optp, { MNT_QUOTA, "with-quotas" }, { MNT_RDONLY, "read-only" }, { MNT_SYNCHRONOUS, "synchronous" }, - { MNT_UNION, "union" }, { MNT_NOCLUSTERR, "noclusterr" }, { MNT_NOCLUSTERW, "noclusterw" }, { MNT_SUIDDIR, "suiddir" }, diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index a15f0d0543..2c1c68c2a3 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -76,8 +76,6 @@ #include #include -#include - static void mount_warning(struct mount *mp, const char *ctl, ...) __printflike(2, 3); static int mount_path(struct proc *p, struct mount *mp, char **rb, char **fb); @@ -94,8 +92,6 @@ static int setutimes (struct vnode *, struct vattr *, const struct timespec *, int); static int usermount = 0; /* if 1, non-root can mount fs. */ -int (*union_dircheckp) (struct thread *, struct vnode **, struct file *); - SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, "Allow non-root users to mount filesystems"); @@ -358,11 +354,11 @@ update: else if (mp->mnt_flag & MNT_RDONLY) mp->mnt_kern_flag |= MNTK_WANTRDWR; mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | - MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME | + MNT_SYNCHRONOUS | MNT_ASYNC | MNT_NOATIME | MNT_NOSYMFOLLOW | MNT_IGNORE | MNT_TRIM | MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR); mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | - MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE | + MNT_NODEV | MNT_SYNCHRONOUS | MNT_ASYNC | MNT_FORCE | MNT_NOSYMFOLLOW | MNT_IGNORE | MNT_TRIM | MNT_NOATIME | MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR); /* @@ -4243,7 +4239,6 @@ kern_getdirentries(int fd, char *buf, u_int count, long *basep, int *res, goto done; } vp = (struct vnode *)fp->f_data; -unionread: if (vp->v_type != VDIR) { error = EINVAL; goto done; @@ -4261,27 +4256,6 @@ unionread: fp->f_offset = auio.uio_offset; if (error) goto done; - if (count == auio.uio_resid) { - if (union_dircheckp) { - error = union_dircheckp(td, &vp, fp); - if (error == -1) - goto unionread; - if (error) - goto done; - } -#if 0 - if ((vp->v_flag & VROOT) && - (vp->v_mount->mnt_flag & MNT_UNION)) { - struct vnode *tvp = vp; - vp = vp->v_mount->mnt_vnodecovered; - vref(vp); - fp->f_data = vp; - fp->f_offset = 0; - vrele(tvp); - goto unionread; - } -#endif - } /* * WARNING! *basep may not be wide enough to accomodate the diff --git a/sys/sys/mount.h b/sys/sys/mount.h index bccccfa480..fd6b01e58c 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -267,7 +267,6 @@ struct mount { #define MNT_NOEXEC 0x00000004 /* can't exec from filesystem */ #define MNT_NOSUID 0x00000008 /* don't honor setuid bits on fs */ #define MNT_NODEV 0x00000010 /* don't interpret special files */ -#define MNT_UNION 0x00000020 /* union with underlying filesystem */ #define MNT_ASYNC 0x00000040 /* file system written asynchronously */ #define MNT_SUIDDIR 0x00100000 /* special handling of SUID on dirs */ #define MNT_SOFTDEP 0x00200000 /* soft updates being done */ @@ -304,7 +303,7 @@ struct mount { * but the 'mount' program may need changing to handle this. */ #define MNT_VISFLAGMASK (MNT_RDONLY | MNT_SYNCHRONOUS | MNT_NOEXEC | \ - MNT_NOSUID | MNT_NODEV | MNT_UNION | \ + MNT_NOSUID | MNT_NODEV | \ MNT_ASYNC | MNT_EXRDONLY | MNT_EXPORTED | \ MNT_DEFEXPORTED | MNT_EXPORTANON| MNT_EXKERB | \ MNT_LOCAL | MNT_USER | MNT_QUOTA | \ diff --git a/sys/vfs/union/Makefile b/sys/vfs/union/Makefile deleted file mode 100644 index 9061e5a8f8..0000000000 --- a/sys/vfs/union/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# $FreeBSD: src/sys/modules/union/Makefile,v 1.7 1999/12/12 20:34:11 peter Exp $ -# $DragonFly: src/sys/vfs/union/Makefile,v 1.4 2004/08/13 17:51:14 dillon Exp $ - -KMOD= union -SRCS= union_subr.c union_vfsops.c union_vnops.c - -.include diff --git a/sys/vfs/union/union.h b/sys/vfs/union/union.h deleted file mode 100644 index 0b9f7ff386..0000000000 --- a/sys/vfs/union/union.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994 Jan-Simon Pendry. - * All rights reserved. - * - * This code is derived from software donated to Berkeley by - * Jan-Simon Pendry. - * - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. - * - * @(#)union.h 8.9 (Berkeley) 12/10/94 - * $FreeBSD: src/sys/miscfs/union/union.h,v 1.17 1999/12/29 04:54:48 peter Exp $ - * $DragonFly: src/sys/vfs/union/union.h,v 1.9 2006/12/23 00:41:30 swildner Exp $ - */ - -struct union_args { - char *target; /* Target of loopback */ - int mntflags; /* Options on the mount */ -}; - -#define UNMNT_ABOVE 0x0001 /* Target appears below mount point */ -#define UNMNT_BELOW 0x0002 /* Target appears below mount point */ -#define UNMNT_REPLACE 0x0003 /* Target replaces mount point */ -#define UNMNT_OPMASK 0x0003 - -struct union_mount { - struct vnode *um_uppervp; /* UN_ULOCK holds locking state */ - struct vnode *um_lowervp; /* Left unlocked */ - struct ucred *um_cred; /* Credentials of user calling mount */ - int um_cmode; /* cmask from mount process */ - int um_op; /* Operation mode */ -}; - -#ifdef _KERNEL - -#ifndef DIAGNOSTIC -#define DIAGNOSTIC -#endif - -#endif - -#if defined(_KERNEL) || defined(_KERNEL_STRUCTURES) - -/* - * DEFDIRMODE is the mode bits used to create a shadow directory. - */ -#define VRWXMODE (VREAD|VWRITE|VEXEC) -#define VRWMODE (VREAD|VWRITE) -#define UN_DIRMODE ((VRWXMODE)|(VRWXMODE>>3)|(VRWXMODE>>6)) -#define UN_FILEMODE ((VRWMODE)|(VRWMODE>>3)|(VRWMODE>>6)) - -/* - * A cache of vnode references (hangs off v_data) - */ -struct union_node { - LIST_ENTRY(union_node) un_cache; /* Hash chain */ - struct vnode *un_vnode; /* Back pointer */ - struct vnode *un_uppervp; /* overlaying object */ - struct vnode *un_lowervp; /* underlying object */ - struct vnode *un_dirvp; /* Parent dir of uppervp */ - struct vnode *un_pvp; /* Parent vnode */ - char *un_path; /* saved component name */ - int un_openl; /* # of opens on lowervp */ - int un_exclcnt; /* exclusive count */ - unsigned int un_flags; - struct vnode **un_dircache; /* cached union stack */ - off_t un_uppersz; /* size of upper object */ - off_t un_lowersz; /* size of lower object */ -#ifdef DIAGNOSTIC - pid_t un_pid; -#endif -}; - -/* - * XXX UN_ULOCK - indicates that the uppervp is locked - * - * UN_CACHED - node is in the union cache - */ - -/*#define UN_ULOCK 0x04*/ /* Upper node is locked */ -#define UN_CACHED 0x10 /* In union cache */ - -/* - * Hash table locking flags - */ - -#define UNVP_WANT 0x01 -#define UNVP_LOCKED 0x02 - -#define MOUNTTOUNIONMOUNT(mp) ((struct union_mount *)((mp)->mnt_data)) -#define VTOUNION(vp) ((struct union_node *)(vp)->v_data) -#define UNIONTOV(un) ((un)->un_vnode) -#define LOWERVP(vp) (VTOUNION(vp)->un_lowervp) -#define UPPERVP(vp) (VTOUNION(vp)->un_uppervp) -#define OTHERVP(vp) (UPPERVP(vp) ? UPPERVP(vp) : LOWERVP(vp)) - -#define UDEBUG(x) if (uniondebug) kprintf x -#define UDEBUG_ENABLED 1 - -#endif - -#ifdef _KERNEL - -extern int union_allocvp (struct vnode **, struct mount *, - struct vnode *, - struct vnode *, - struct componentname *, struct vnode *, - struct vnode *, int); -extern int union_freevp (struct vnode *); -extern struct vnode *union_dircache (struct vnode *, struct thread *); -extern int union_copyup (struct union_node *, int, struct ucred *, - struct thread *); -extern int union_dowhiteout (struct union_node *, struct ucred *, - struct thread *); -extern int union_mkshadow (struct union_mount *, struct vnode *, - struct componentname *, struct vnode **); -extern int union_mkwhiteout (struct union_mount *, struct vnode *, - struct componentname *, char *); -extern int union_cn_close (struct vnode *, int, struct ucred *, - struct thread *); -extern void union_removed_upper (struct union_node *un); -extern struct vnode *union_lowervp (struct vnode *); -extern void union_newsize (struct vnode *, off_t, off_t); -extern void union_vm_coherency (struct vnode *, struct uio *, int); - -extern int (*union_dircheckp) (struct thread *, struct vnode **, - struct file *); - -extern struct vfsops union_vfsops; -extern int uniondebug; - -#endif /* _KERNEL */ diff --git a/sys/vfs/union/union_subr.c b/sys/vfs/union/union_subr.c deleted file mode 100644 index c2260c9c35..0000000000 --- a/sys/vfs/union/union_subr.c +++ /dev/null @@ -1,1289 +0,0 @@ -/* - * Copyright (c) 1994 Jan-Simon Pendry - * Copyright (c) 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * 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. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. - * - * @(#)union_subr.c 8.20 (Berkeley) 5/20/95 - * $FreeBSD: src/sys/miscfs/union/union_subr.c,v 1.43.2.2 2001/12/25 01:44:45 dillon Exp $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for vnode_pager_setsize */ -#include -#include /* for vm cache coherency */ -#include "union.h" - -extern int union_init (void); - -/* must be power of two, otherwise change UNION_HASH() */ -#define NHASH 32 - -/* unsigned int ... */ -#define UNION_HASH(u, l) \ - (((((uintptr_t) (u)) + ((uintptr_t) l)) >> 8) & (NHASH-1)) - -static LIST_HEAD(unhead, union_node) unhead[NHASH]; -static int unvplock[NHASH]; - -static void union_dircache_r (struct vnode *vp, struct vnode ***vppp, - int *cntp); -static int union_list_lock (int ix); -static void union_list_unlock (int ix); -static int union_relookup (struct union_mount *um, struct vnode *dvp, - struct vnode **vpp, - struct componentname *cnp, - struct componentname *cn, char *path, - int pathlen); -static void union_updatevp (struct union_node *un, - struct vnode *uppervp, - struct vnode *lowervp); -static void union_newlower (struct union_node *, struct vnode *); -static void union_newupper (struct union_node *, struct vnode *); -static int union_copyfile (struct vnode *, struct vnode *, - struct ucred *, struct thread *); -static int union_vn_create (struct vnode **, struct union_node *, - struct thread *); -static int union_vn_close (struct vnode *, int, struct ucred *); - -int -union_init(void) -{ - int i; - - for (i = 0; i < NHASH; i++) - LIST_INIT(&unhead[i]); - bzero((caddr_t)unvplock, sizeof(unvplock)); - return (0); -} - -static int -union_list_lock(int ix) -{ - if (unvplock[ix] & UNVP_LOCKED) { - unvplock[ix] |= UNVP_WANT; - (void) tsleep((caddr_t) &unvplock[ix], 0, "unllck", 0); - return (1); - } - unvplock[ix] |= UNVP_LOCKED; - return (0); -} - -static void -union_list_unlock(int ix) -{ - unvplock[ix] &= ~UNVP_LOCKED; - - if (unvplock[ix] & UNVP_WANT) { - unvplock[ix] &= ~UNVP_WANT; - wakeup((caddr_t) &unvplock[ix]); - } -} - -/* - * union_updatevp: - * - * The uppervp, if not NULL, must be referenced and not locked by us - * The lowervp, if not NULL, must be referenced. - * - * if uppervp and lowervp match pointers already installed, nothing - * happens. The passed vp's (when matching) are not adjusted. This - * routine may only be called by union_newupper() and union_newlower(). - */ - -static void -union_updatevp(struct union_node *un, struct vnode *uppervp, - struct vnode *lowervp) -{ - int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp); - int nhash = UNION_HASH(uppervp, lowervp); - int docache = (lowervp != NULLVP || uppervp != NULLVP); - int lhash, uhash; - - /* - * Ensure locking is ordered from lower to higher - * to avoid deadlocks. - */ - if (nhash < ohash) { - lhash = nhash; - uhash = ohash; - } else { - lhash = ohash; - uhash = nhash; - } - - if (lhash != uhash) { - while (union_list_lock(lhash)) - continue; - } - - while (union_list_lock(uhash)) - continue; - - if (ohash != nhash || !docache) { - if (un->un_flags & UN_CACHED) { - un->un_flags &= ~UN_CACHED; - LIST_REMOVE(un, un_cache); - } - } - - if (ohash != nhash) - union_list_unlock(ohash); - - if (un->un_lowervp != lowervp) { - if (un->un_lowervp) { - vrele(un->un_lowervp); - if (un->un_path) { - kfree(un->un_path, M_TEMP); - un->un_path = 0; - } - } - un->un_lowervp = lowervp; - un->un_lowersz = VNOVAL; - } - - if (un->un_uppervp != uppervp) { - if (un->un_uppervp) - vrele(un->un_uppervp); - un->un_uppervp = uppervp; - un->un_uppersz = VNOVAL; - } - - if (docache && (ohash != nhash)) { - LIST_INSERT_HEAD(&unhead[nhash], un, un_cache); - un->un_flags |= UN_CACHED; - } - - union_list_unlock(nhash); -} - -/* - * Set a new lowervp. The passed lowervp must be referenced and will be - * stored in the vp in a referenced state. - */ - -static void -union_newlower(struct union_node *un, struct vnode *lowervp) -{ - union_updatevp(un, un->un_uppervp, lowervp); -} - -/* - * Set a new uppervp. The passed uppervp must be locked and will be - * stored in the vp in a locked state. The caller should not unlock - * uppervp. - */ - -static void -union_newupper(struct union_node *un, struct vnode *uppervp) -{ - union_updatevp(un, uppervp, un->un_lowervp); -} - -/* - * Keep track of size changes in the underlying vnodes. - * If the size changes, then callback to the vm layer - * giving priority to the upper layer size. - */ -void -union_newsize(struct vnode *vp, off_t uppersz, off_t lowersz) -{ - struct union_node *un; - off_t sz; - - /* only interested in regular files */ - if (vp->v_type != VREG) - return; - - un = VTOUNION(vp); - sz = VNOVAL; - - if ((uppersz != VNOVAL) && (un->un_uppersz != uppersz)) { - un->un_uppersz = uppersz; - if (sz == VNOVAL) - sz = un->un_uppersz; - } - - if ((lowersz != VNOVAL) && (un->un_lowersz != lowersz)) { - un->un_lowersz = lowersz; - if (sz == VNOVAL) - sz = un->un_lowersz; - } - - if (sz != VNOVAL) { - UDEBUG(("union: %s size now %ld\n", - (uppersz != VNOVAL ? "upper" : "lower"), (long)sz)); - vnode_pager_setsize(vp, sz); - } -} - -/* - * union_allocvp: allocate a union_node and associate it with a - * parent union_node and one or two vnodes. - * - * vpp Holds the returned vnode locked and referenced if no - * error occurs. - * - * mp Holds the mount point. mp may or may not be busied. - * allocvp makes no changes to mp. - * - * dvp Holds the parent union_node to the one we wish to create. - * XXX may only be used to traverse an uncopied lowervp-based - * tree? XXX - * - * dvp may or may not be locked. allocvp makes no changes - * to dvp. - * - * upperdvp Holds the parent vnode to uppervp, generally used along - * with path component information to create a shadow of - * lowervp when uppervp does not exist. - * - * upperdvp is referenced but unlocked on entry, and will be - * dereferenced on return. - * - * uppervp Holds the new uppervp vnode to be stored in the - * union_node we are allocating. uppervp is referenced but - * not locked, and will be dereferenced on return. - * - * lowervp Holds the new lowervp vnode to be stored in the - * union_node we are allocating. lowervp is referenced but - * not locked, and will be dereferenced on return. - * - * cnp Holds path component information to be coupled with - * lowervp and upperdvp to allow unionfs to create an uppervp - * later on. Only used if lowervp is valid. The conents - * of cnp is only valid for the duration of the call. - * - * docache Determine whether this node should be entered in the - * cache or whether it should be destroyed as soon as possible. - * - * all union_nodes are maintained on a singly-linked - * list. new nodes are only allocated when they cannot - * be found on this list. entries on the list are - * removed when the vfs reclaim entry is called. - * - * a single lock is kept for the entire list. this is - * needed because the getnewvnode() function can block - * waiting for a vnode to become free, in which case there - * may be more than one process trying to get the same - * vnode. this lock is only taken if we are going to - * call getnewvnode, since the kernel itself is single-threaded. - * - * if an entry is found on the list, then call vget() to - * take a reference. this is done because there may be - * zero references to it and so it needs to removed from - * the vnode free list. - */ - -int -union_allocvp(struct vnode **vpp, - struct mount *mp, - struct vnode *dvp, /* parent union vnode */ - struct vnode *upperdvp, /* parent vnode of uppervp */ - struct componentname *cnp, /* may be null */ - struct vnode *uppervp, /* may be null */ - struct vnode *lowervp, /* may be null */ - int docache) -{ - int error; - struct union_node *un = NULL; - struct union_mount *um = MOUNTTOUNIONMOUNT(mp); - struct thread *td = (cnp) ? cnp->cn_td : curthread; /* XXX */ - int hash = 0; - int vflag; - int try; - - if (uppervp == NULLVP && lowervp == NULLVP) - panic("union: unidentifiable allocation"); - - if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) { - vrele(lowervp); - lowervp = NULLVP; - } - - /* detect the root vnode (and aliases) */ - vflag = 0; - if ((uppervp == um->um_uppervp) && - ((lowervp == NULLVP) || lowervp == um->um_lowervp)) { - if (lowervp == NULLVP) { - lowervp = um->um_lowervp; - if (lowervp != NULLVP) - vref(lowervp); - } - vflag = VROOT; - } - -loop: - if (!docache) { - un = NULL; - } else for (try = 0; try < 3; try++) { - switch (try) { - case 0: - if (lowervp == NULLVP) - continue; - hash = UNION_HASH(uppervp, lowervp); - break; - - case 1: - if (uppervp == NULLVP) - continue; - hash = UNION_HASH(uppervp, NULLVP); - break; - - case 2: - if (lowervp == NULLVP) - continue; - hash = UNION_HASH(NULLVP, lowervp); - break; - } - - while (union_list_lock(hash)) - continue; - - for (un = unhead[hash].lh_first; un != NULL; - un = un->un_cache.le_next) { - if ((un->un_lowervp == lowervp || - un->un_lowervp == NULLVP) && - (un->un_uppervp == uppervp || - un->un_uppervp == NULLVP) && - (UNIONTOV(un)->v_mount == mp)) { - if (vget(UNIONTOV(un), LK_EXCLUSIVE|LK_SLEEPFAIL)) { - union_list_unlock(hash); - goto loop; - } - break; - } - } - - union_list_unlock(hash); - - if (un) - break; - } - - if (un) { - /* - * Obtain a lock on the union_node. Everything is unlocked - * except for dvp, so check that case. If they match, our - * new un is already locked. Otherwise we have to lock our - * new un. - * - * A potential deadlock situation occurs when we are holding - * one lock while trying to get another. We must follow - * strict ordering rules to avoid it. We try to locate dvp - * by scanning up from un_vnode, since the most likely - * scenario is un being under dvp. - */ - - if (dvp && un->un_vnode != dvp) { - struct vnode *scan = un->un_vnode; - - do { - scan = VTOUNION(scan)->un_pvp; - } while (scan && scan->v_tag == VT_UNION && scan != dvp); - if (scan != dvp) { - /* - * our new un is above dvp (we never saw dvp - * while moving up the tree). - */ - vref(dvp); - vn_unlock(dvp); - error = vn_lock(un->un_vnode, LK_EXCLUSIVE | - LK_FAILRECLAIM); - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); - vrele(dvp); - } else { - /* - * our new un is under dvp - */ - error = vn_lock(un->un_vnode, LK_EXCLUSIVE | - LK_FAILRECLAIM); - } - } else if (dvp == NULLVP) { - /* - * dvp is NULL, we need to lock un. - */ - error = vn_lock(un->un_vnode, LK_EXCLUSIVE | - LK_FAILRECLAIM); - } else { - /* - * dvp == un->un_vnode, we are already locked. - */ - error = 0; - } - - if (error) - goto loop; - - /* - * At this point, the union_node is locked and referenced. - * - * uppervp is locked and referenced or NULL, lowervp is - * referenced or NULL. - */ - UDEBUG(("Modify existing un %p vn %p upper %p(refs %d) -> %p(refs %d)\n", - un, un->un_vnode, un->un_uppervp, - (un->un_uppervp ? VREFCNT(un->un_uppervp) : -99), - uppervp, - (uppervp ? VREFCNT(uppervp) : -99) - )); - - if (uppervp != un->un_uppervp) { - KASSERT(uppervp == NULL || VREFCNT(uppervp) > 0, - ("union_allocvp: too few refs %d (at least 1 " - "required) on uppervp", - VREFCNT(uppervp))); - union_newupper(un, uppervp); - } else if (uppervp) { - KASSERT(VREFCNT(uppervp) > 1, - ("union_allocvp: too few refs %d (at least " - "2 required) on uppervp", - VREFCNT(uppervp))); - vrele(uppervp); - } - - /* - * Save information about the lower layer. - * This needs to keep track of pathname - * and directory information which union_vn_create - * might need. - */ - if (lowervp != un->un_lowervp) { - union_newlower(un, lowervp); - if (cnp && (lowervp != NULLVP)) { - un->un_path = malloc(cnp->cn_namelen+1, - M_TEMP, M_WAITOK); - bcopy(cnp->cn_nameptr, un->un_path, - cnp->cn_namelen); - un->un_path[cnp->cn_namelen] = '\0'; - } - } else if (lowervp) { - vrele(lowervp); - } - - /* - * and upperdvp - */ - if (upperdvp != un->un_dirvp) { - if (un->un_dirvp) - vrele(un->un_dirvp); - un->un_dirvp = upperdvp; - } else if (upperdvp) { - vrele(upperdvp); - } - - *vpp = UNIONTOV(un); - return (0); - } - - if (docache) { - /* - * otherwise lock the vp list while we call getnewvnode - * since that can block. - */ - hash = UNION_HASH(uppervp, lowervp); - - if (union_list_lock(hash)) - goto loop; - } - - /* - * Create new node rather then replace old node - */ - - error = getnewvnode(VT_UNION, mp, vpp, 0, 0); - if (error) { - /* - * If an error occurs clear out vnodes. - */ - if (lowervp) - vrele(lowervp); - if (uppervp) - vrele(uppervp); - if (upperdvp) - vrele(upperdvp); - *vpp = NULL; - goto out; - } - - (*vpp)->v_data = kmalloc(sizeof(struct union_node), M_TEMP, M_WAITOK); - - vsetflags(*vpp, vflag); - if (uppervp) - (*vpp)->v_type = uppervp->v_type; - else - (*vpp)->v_type = lowervp->v_type; - - un = VTOUNION(*vpp); - bzero(un, sizeof(*un)); - - un->un_vnode = *vpp; - un->un_uppervp = uppervp; - un->un_uppersz = VNOVAL; - un->un_lowervp = lowervp; - un->un_lowersz = VNOVAL; - un->un_dirvp = upperdvp; - un->un_pvp = dvp; /* only parent dir in new allocation */ - if (dvp != NULLVP) - vref(dvp); - un->un_dircache = 0; - un->un_openl = 0; - - if (cnp && (lowervp != NULLVP)) { - un->un_path = kmalloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); - bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); - un->un_path[cnp->cn_namelen] = '\0'; - } else { - un->un_path = 0; - un->un_dirvp = NULL; - } - - if (docache) { - LIST_INSERT_HEAD(&unhead[hash], un, un_cache); - un->un_flags |= UN_CACHED; - } - - /* - * locked refd vpp is returned - */ - -out: - if (docache) - union_list_unlock(hash); - - return (error); -} - -int -union_freevp(struct vnode *vp) -{ - struct union_node *un = VTOUNION(vp); - - vp->v_data = NULL; - if (un->un_flags & UN_CACHED) { - un->un_flags &= ~UN_CACHED; - LIST_REMOVE(un, un_cache); - } - if (un->un_pvp != NULLVP) { - vrele(un->un_pvp); - un->un_pvp = NULL; - } - if (un->un_uppervp != NULLVP) { - vrele(un->un_uppervp); - un->un_uppervp = NULL; - } - if (un->un_lowervp != NULLVP) { - vrele(un->un_lowervp); - un->un_lowervp = NULL; - } - if (un->un_dirvp != NULLVP) { - vrele(un->un_dirvp); - un->un_dirvp = NULL; - } - if (un->un_path) { - kfree(un->un_path, M_TEMP); - un->un_path = NULL; - } - kfree(un, M_TEMP); - return (0); -} - -/* - * copyfile. copy the vnode (fvp) to the vnode (tvp) - * using a sequence of reads and writes. both (fvp) - * and (tvp) are locked on entry and exit. - * - * fvp and tvp are both exclusive locked on call, but their refcount's - * haven't been bumped at all. - */ -static int -union_copyfile(struct vnode *fvp, struct vnode *tvp, struct ucred *cred, - struct thread *td) -{ - char *buf; - struct uio uio; - struct iovec iov; - int error = 0; - - /* - * strategy: - * allocate a buffer of size MAXBSIZE. - * loop doing reads and writes, keeping track - * of the current uio offset. - * give up at the first sign of trouble. - */ - - bzero(&uio, sizeof(uio)); - - uio.uio_td = td; - uio.uio_segflg = UIO_SYSSPACE; - uio.uio_offset = 0; - - buf = kmalloc(MAXBSIZE, M_TEMP, M_WAITOK); - - /* ugly loop follows... */ - do { - off_t offset = uio.uio_offset; - int count; - int bufoffset; - - /* - * Setup for big read - */ - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - iov.iov_base = buf; - iov.iov_len = MAXBSIZE; - uio.uio_resid = iov.iov_len; - uio.uio_rw = UIO_READ; - - if ((error = VOP_READ(fvp, &uio, 0, cred)) != 0) - break; - - /* - * Get bytes read, handle read eof case and setup for - * write loop - */ - if ((count = MAXBSIZE - uio.uio_resid) == 0) - break; - bufoffset = 0; - - /* - * Write until an error occurs or our buffer has been - * exhausted, then update the offset for the next read. - */ - while (bufoffset < count) { - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - iov.iov_base = buf + bufoffset; - iov.iov_len = count - bufoffset; - uio.uio_offset = offset + bufoffset; - uio.uio_rw = UIO_WRITE; - uio.uio_resid = iov.iov_len; - - if ((error = VOP_WRITE(tvp, &uio, 0, cred)) != 0) - break; - bufoffset += (count - bufoffset) - uio.uio_resid; - } - uio.uio_offset = offset + bufoffset; - } while (error == 0); - - kfree(buf, M_TEMP); - return (error); -} - -/* - * - * un's vnode is assumed to be locked on entry and remains locked on exit. - */ - -int -union_copyup(struct union_node *un, int docopy, struct ucred *cred, - struct thread *td) -{ - int error; - struct vnode *lvp, *uvp; - - /* - * If the user does not have read permission, the vnode should not - * be copied to upper layer. - */ - vn_lock(un->un_lowervp, LK_EXCLUSIVE | LK_RETRY); - error = VOP_EACCESS(un->un_lowervp, VREAD, cred); - vn_unlock(un->un_lowervp); - if (error) - return (error); - - error = union_vn_create(&uvp, un, td); - if (error) - return (error); - - lvp = un->un_lowervp; - - KASSERT(VREFCNT(uvp) > 0, - ("copy: uvp refcount 0: %d", VREFCNT(uvp))); - if (docopy) { - /* - * XX - should not ignore errors - * from VOP_CLOSE - */ - vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY); - error = VOP_OPEN(lvp, FREAD, cred, NULL); - if (error == 0) { - error = union_copyfile(lvp, uvp, cred, td); - (void) VOP_CLOSE(lvp, FREAD); - vn_unlock(lvp); - } - if (error == 0) - UDEBUG(("union: copied up %s\n", un->un_path)); - - } - vn_unlock(uvp); - union_newupper(un, uvp); - KASSERT(VREFCNT(uvp) > 0, ("copy: uvp refcount 0: %d", VREFCNT(uvp))); - union_vn_close(uvp, FWRITE, cred); - KASSERT(VREFCNT(uvp) > 0, ("copy: uvp refcount 0: %d", VREFCNT(uvp))); - /* - * Subsequent IOs will go to the top layer, so - * call close on the lower vnode and open on the - * upper vnode to ensure that the filesystem keeps - * its references counts right. This doesn't do - * the right thing with (cred) and (FREAD) though. - * Ignoring error returns is not right, either. - */ - if (error == 0) { - int i; - - for (i = 0; i < un->un_openl; i++) { - vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY); - VOP_CLOSE(lvp, FREAD); - vn_unlock(lvp); - vn_lock(uvp, LK_EXCLUSIVE | LK_RETRY); - VOP_OPEN(uvp, FREAD, cred, NULL); - vn_unlock(uvp); - } - un->un_openl = 0; - } - - return (error); - -} - -/* - * union_relookup: - * - * dvp should be locked on entry and will be locked on return. No - * net change in the ref count will occur. - * - * If an error is returned, *vpp will be invalid, otherwise it - * will hold a locked, referenced vnode. If *vpp == dvp then - * remember that only one exclusive lock is held. - */ - -static int -union_relookup(struct union_mount *um, struct vnode *dvp, struct vnode **vpp, - struct componentname *cnp, struct componentname *cn, char *path, - int pathlen) -{ - int error; - - /* - * A new componentname structure must be faked up because - * there is no way to know where the upper level cnp came - * from or what it is being used for. This must duplicate - * some of the work done by NDINIT, some of the work done - * by namei, some of the work done by lookup and some of - * the work done by VOP_LOOKUP when given a CREATE flag. - * Conclusion: Horrible. - */ - cn->cn_namelen = pathlen; - cn->cn_nameptr = objcache_get(namei_oc, M_WAITOK); - bcopy(path, cn->cn_nameptr, cn->cn_namelen); - cn->cn_nameptr[cn->cn_namelen] = '\0'; - - cn->cn_nameiop = NAMEI_CREATE; - cn->cn_flags = CNP_LOCKPARENT; - cn->cn_td = cnp->cn_td; - if (um->um_op == UNMNT_ABOVE) - cn->cn_cred = cnp->cn_cred; - else - cn->cn_cred = um->um_cred; - cn->cn_consume = cnp->cn_consume; - - vref(dvp); - vn_unlock(dvp); - - /* - * Pass dvp unlocked and referenced on call to relookup(). - * - * If an error occurs, dvp will be returned unlocked and dereferenced. - */ - - if ((error = relookup(dvp, vpp, cn)) != 0) { - objcache_put(namei_oc, cn->cn_nameptr); - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); - return(error); - } - objcache_put(namei_oc, cn->cn_nameptr); - - /* - * If no error occurs, dvp will be returned locked with the reference - * left as before, and vpp will be returned referenced and locked. - * - * We want to return with dvp as it was passed to us, so we get - * rid of our reference. - */ - vrele(dvp); - return (0); -} - -/* - * Create a shadow directory in the upper layer. - * The new vnode is returned locked. - * - * (um) points to the union mount structure for access to the - * the mounting process's credentials. - * (dvp) is the directory in which to create the shadow directory, - * it is locked (but not ref'd) on entry and return. - * (cnp) is the componentname to be created. - * (vpp) is the returned newly created shadow directory, which - * is returned locked and ref'd - */ -int -union_mkshadow(struct union_mount *um, struct vnode *dvp, - struct componentname *cnp, struct vnode **vpp) -{ - int error; - struct vattr va; - struct thread *td = cnp->cn_td; - struct componentname cn; - - error = union_relookup(um, dvp, vpp, cnp, &cn, - cnp->cn_nameptr, cnp->cn_namelen); - if (error) - return (error); - - if (*vpp) { - if (dvp == *vpp) - vrele(*vpp); - else - vput(*vpp); - *vpp = NULLVP; - return (EEXIST); - } - - /* - * policy: when creating the shadow directory in the - * upper layer, create it owned by the user who did - * the mount, group from parent directory, and mode - * 777 modified by umask (ie mostly identical to the - * mkdir syscall). (jsp, kb) - */ - - VATTR_NULL(&va); - va.va_type = VDIR; - va.va_mode = um->um_cmode; - - error = VOP_MKDIR(dvp, vpp, &cn, &va); - /*vput(dvp);*/ - return (error); -} - -/* - * Create a whiteout entry in the upper layer. - * - * (um) points to the union mount structure for access to the - * the mounting process's credentials. - * (dvp) is the directory in which to create the whiteout. - * it is locked on entry and return. - * (cnp) is the componentname to be created. - */ -int -union_mkwhiteout(struct union_mount *um, struct vnode *dvp, - struct componentname *cnp, char *path) -{ - int error; - struct thread *td = cnp->cn_td; - struct vnode *wvp; - struct componentname cn; - - KKASSERT(td->td_proc); - - error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path)); - if (error) - return (error); - - if (wvp) { - if (wvp == dvp) - vrele(wvp); - else - vput(wvp); - return (EEXIST); - } - - error = VOP_WHITEOUT(dvp, &cn, NAMEI_CREATE); - return (error); -} - -/* - * union_vn_create: creates and opens a new shadow file - * on the upper union layer. this function is similar - * in spirit to calling vn_open but it avoids calling namei(). - * the problem with calling namei is that a) it locks too many - * things, and b) it doesn't start at the "right" directory, - * whereas relookup is told where to start. - * - * On entry, the vnode associated with un is locked. It remains locked - * on return. - * - * If no error occurs, *vpp contains a locked referenced vnode for your - * use. If an error occurs *vpp iis undefined. - */ -static int -union_vn_create(struct vnode **vpp, struct union_node *un, struct thread *td) -{ - struct vnode *vp; - struct ucred *cred; - struct vattr vat; - struct vattr *vap = &vat; - int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL); - int error; - int cmode; - struct componentname cn; - - KKASSERT(td->td_proc); - cred = td->td_proc->p_ucred; - cmode = UN_FILEMODE & ~td->td_proc->p_fd->fd_cmask; - - *vpp = NULLVP; - - /* - * Build a new componentname structure (for the same - * reasons outlines in union_mkshadow). - * The difference here is that the file is owned by - * the current user, rather than by the person who - * did the mount, since the current user needs to be - * able to write the file (that's why it is being - * copied in the first place). - */ - cn.cn_namelen = strlen(un->un_path); - cn.cn_nameptr = objcache_get(namei_oc, M_WAITOK); - bcopy(un->un_path, cn.cn_nameptr, cn.cn_namelen+1); - cn.cn_nameiop = NAMEI_CREATE; - cn.cn_flags = CNP_LOCKPARENT; - cn.cn_td = td; - cn.cn_cred = cred; - cn.cn_consume = 0; - - /* - * Pass dvp unlocked and referenced on call to relookup(). - * - * If an error occurs, dvp will be returned unlocked and dereferenced. - */ - vref(un->un_dirvp); - error = relookup(un->un_dirvp, &vp, &cn); - objcache_put(namei_oc, cn.cn_nameptr); - if (error) - return (error); - - /* - * If no error occurs, dvp will be returned locked with the reference - * left as before, and vpp will be returned referenced and locked. - */ - if (vp) { - vput(un->un_dirvp); - if (vp == un->un_dirvp) - vrele(vp); - else - vput(vp); - return (EEXIST); - } - - /* - * Good - there was no race to create the file - * so go ahead and create it. The permissions - * on the file will be 0666 modified by the - * current user's umask. Access to the file, while - * it is unioned, will require access to the top *and* - * bottom files. Access when not unioned will simply - * require access to the top-level file. - * TODO: confirm choice of access permissions. - */ - VATTR_NULL(vap); - vap->va_type = VREG; - vap->va_mode = cmode; - error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap); - vput(un->un_dirvp); - if (error) - return (error); - - error = VOP_OPEN(vp, fmode, cred, NULL); - if (error) { - vput(vp); - return (error); - } - *vpp = vp; - return (0); -} - -static int -union_vn_close(struct vnode *vp, int fmode, struct ucred *cred) -{ - return (VOP_CLOSE(vp, fmode)); -} - -#if 0 - -/* - * union_removed_upper: - * - * called with union_node unlocked. XXX - */ - -void -union_removed_upper(struct union_node *un) -{ - struct thread *td = curthread; /* XXX */ - struct vnode **vpp; - - /* - * Do not set the uppervp to NULLVP. If lowervp is NULLVP, - * union node will have neither uppervp nor lowervp. We remove - * the union node from cache, so that it will not be referrenced. - */ - union_newupper(un, NULLVP); - if (un->un_dircache != 0) { - for (vpp = un->un_dircache; *vpp != NULLVP; vpp++) - vrele(*vpp); - kfree(un->un_dircache, M_TEMP); - un->un_dircache = 0; - } - - if (un->un_flags & UN_CACHED) { - un->un_flags &= ~UN_CACHED; - LIST_REMOVE(un, un_cache); - } -} - -#endif - -/* - * determine whether a whiteout is needed - * during a remove/rmdir operation. - */ -int -union_dowhiteout(struct union_node *un, struct ucred *cred, struct thread *td) -{ - struct vattr va; - - if (un->un_lowervp != NULLVP) - return (1); - - if (VOP_GETATTR(un->un_uppervp, &va) == 0 && - (va.va_flags & OPAQUE)) - return (1); - - return (0); -} - -static void -union_dircache_r(struct vnode *vp, struct vnode ***vppp, int *cntp) -{ - struct union_node *un; - - if (vp->v_tag != VT_UNION) { - if (vppp) { - vref(vp); - *(*vppp)++ = vp; - if (--(*cntp) == 0) - panic("union: dircache table too small"); - } else { - (*cntp)++; - } - - return; - } - - un = VTOUNION(vp); - if (un->un_uppervp != NULLVP) - union_dircache_r(un->un_uppervp, vppp, cntp); - if (un->un_lowervp != NULLVP) - union_dircache_r(un->un_lowervp, vppp, cntp); -} - -struct vnode * -union_dircache(struct vnode *vp, struct thread *td) -{ - int cnt; - struct vnode *nvp; - struct vnode **vpp; - struct vnode **dircache; - struct union_node *un; - int error; - - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - dircache = VTOUNION(vp)->un_dircache; - - nvp = NULLVP; - - if (dircache == NULL) { - cnt = 0; - union_dircache_r(vp, 0, &cnt); - cnt++; - dircache = malloc(cnt * sizeof(struct vnode *), - M_TEMP, M_WAITOK); - vpp = dircache; - union_dircache_r(vp, &vpp, &cnt); - *vpp = NULLVP; - vpp = dircache + 1; - } else { - vpp = dircache; - do { - if (*vpp++ == VTOUNION(vp)->un_uppervp) - break; - } while (*vpp != NULLVP); - } - - if (*vpp == NULLVP) - goto out; - - /*vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);*/ - UDEBUG(("ALLOCVP-3 %p ref %08x\n", - *vpp, (*vpp ? (*vpp)->v_refcnt : -99))); - vref(*vpp); - error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, NULL, *vpp, NULLVP, 0); - UDEBUG(("ALLOCVP-3B %p ref %08x\n", - nvp, (*vpp ? (*vpp)->v_refcnt : -99))); - if (error) - goto out; - - VTOUNION(vp)->un_dircache = 0; - un = VTOUNION(nvp); - un->un_dircache = dircache; - -out: - vn_unlock(vp); - return (nvp); -} - -/* - * Guarentee coherency with the VM cache by invalidating any clean VM pages - * associated with this write and updating any dirty VM pages. Since our - * vnode is locked, other processes will not be able to read the pages in - * again until after our write completes. - * - * We also have to be coherent with reads, by flushing any pending dirty - * pages prior to issuing the read. - * - * XXX this is somewhat of a hack at the moment. To support this properly - * we would have to be able to run VOP_READ and VOP_WRITE through the VM - * cache. Then we wouldn't need to worry about coherency. - */ - -void -union_vm_coherency(struct vnode *vp, struct uio *uio, int cleanfls) -{ - vm_object_t object; - vm_pindex_t pstart; - vm_pindex_t pend; - int pgoff; - - if ((object = vp->v_object) == NULL) - return; - - pgoff = uio->uio_offset & PAGE_MASK; - pstart = uio->uio_offset / PAGE_SIZE; - pend = pstart + (uio->uio_resid + pgoff + PAGE_MASK) / PAGE_SIZE; - - vm_object_page_clean(object, pstart, pend, OBJPC_SYNC); - if (cleanfls) - vm_object_page_remove(object, pstart, pend, TRUE); -} - -/* - * Module glue to remove #ifdef UNION from vfs_syscalls.c - */ -static int -union_dircheck(struct thread *td, struct vnode **vp, struct file *fp) -{ - int error = 0; - - if ((*vp)->v_tag == VT_UNION) { - struct vnode *lvp; - - lvp = union_dircache(*vp, td); - if (lvp != NULLVP) { - struct vattr va; - - /* - * If the directory is opaque, - * then don't show lower entries - */ - error = VOP_GETATTR(*vp, &va); - if (va.va_flags & OPAQUE) { - vput(lvp); - lvp = NULL; - } - } - - if (lvp != NULLVP) { - error = VOP_OPEN(lvp, FREAD, fp->f_cred, NULL); - if (error) { - vput(lvp); - return (error); - } - vn_unlock(lvp); - fp->f_data = lvp; - fp->f_offset = 0; - error = vn_close(*vp, FREAD); - if (error) - return (error); - *vp = lvp; - return -1; /* goto unionread */ - } - } - return error; -} - -static int -union_modevent(module_t mod, int type, void *data) -{ - switch (type) { - case MOD_LOAD: - union_dircheckp = union_dircheck; - break; - case MOD_UNLOAD: - union_dircheckp = NULL; - break; - default: - break; - } - return 0; -} - -static moduledata_t union_mod = { - "union_dircheck", - union_modevent, - NULL -}; - -DECLARE_MODULE(union_dircheck, union_mod, SI_SUB_VFS, SI_ORDER_ANY); diff --git a/sys/vfs/union/union_vfsops.c b/sys/vfs/union/union_vfsops.c deleted file mode 100644 index a856adbafb..0000000000 --- a/sys/vfs/union/union_vfsops.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Copyright (c) 1994, 1995 The Regents of the University of California. - * Copyright (c) 1994, 1995 Jan-Simon Pendry. - * All rights reserved. - * - * This code is derived from software donated to Berkeley by - * Jan-Simon Pendry. - * - * 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. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. - * - * @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95 - * $FreeBSD: src/sys/miscfs/union/union_vfsops.c,v 1.39.2.2 2001/10/25 19:18:53 dillon Exp $ - */ - -/* - * Union Layer - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "union.h" -#include - -extern struct vop_ops union_vnode_vops; - -static MALLOC_DEFINE(M_UNIONFSMNT, "UNION mount", "UNION mount structure"); - -extern int union_init (struct vfsconf *); -static int union_mount (struct mount *mp, char *path, caddr_t data, - struct ucred *cred); -static int union_root (struct mount *mp, struct vnode **vpp); -static int union_statfs (struct mount *mp, struct statfs *sbp, - struct ucred *cred); -static int union_unmount (struct mount *mp, int mntflags); - -/* - * Mount union filesystem - */ -static int -union_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) -{ - int error = 0; - struct union_args args; - struct vnode *lowerrootvp = NULLVP; - struct vnode *upperrootvp = NULLVP; - struct union_mount *um = NULL; - struct ucred *cred = NULL; - struct nlookupdata nd; - char *cp = NULL; - int len; - u_int size; - - UDEBUG(("union_mount(mp = %p)\n", (void *)mp)); - - /* - * Disable clustered write, otherwise system becomes unstable. - */ - mp->mnt_flag |= MNT_NOCLUSTERW; - - /* - * Update is a no-op - */ - if (mp->mnt_flag & MNT_UPDATE) { - /* - * Need to provide. - * 1. a way to convert between rdonly and rdwr mounts. - * 2. support for nfs exports. - */ - error = EOPNOTSUPP; - goto bad; - } - - /* - * Get argument - */ - error = copyin(data, (caddr_t)&args, sizeof(struct union_args)); - if (error) - goto bad; - - /* - * Obtain lower vnode. - */ - - lowerrootvp = mp->mnt_vnodecovered; - vref(lowerrootvp); - -#if 0 - /* - * Unlock lower node to avoid deadlock. - */ - if (lowerrootvp->v_tag == VT_UNION) - vn_unlock(lowerrootvp); -#endif - - /* - * Obtain upper vnode by calling nlookup() on the path. The - * upperrootvp will be turned referenced but not locked. - */ - error = nlookup_init(&nd, args.target, UIO_USERSPACE, NLC_FOLLOW); - if (error == 0) - error = nlookup(&nd); - if (error == 0) - error = cache_vref(&nd.nl_nch, nd.nl_cred, &upperrootvp); - nlookup_done(&nd); - if (error) - goto bad; - - UDEBUG(("mount_root UPPERVP %p locked = %d\n", upperrootvp, - vn_islocked(upperrootvp))); - - /* - * Check multi union mount to avoid `lock myself again' panic. - * Also require that it be a directory. - */ - if (upperrootvp == VTOUNION(lowerrootvp)->un_uppervp) { -#ifdef DIAGNOSTIC - kprintf("union_mount: multi union mount?\n"); -#endif - error = EDEADLK; - goto bad; - } - - if (upperrootvp->v_type != VDIR) { - error = EINVAL; - goto bad; - } - - /* - * Allocate our union_mount structure and populate the fields. - * The vnode references are stored in the union_mount as held, - * unlocked references. Depending on the _BELOW flag, the - * filesystems are viewed in a different order. In effect this - * is the same as providing a mount-under option to the mount - * syscall. - */ - - um = (struct union_mount *) malloc(sizeof(struct union_mount), - M_UNIONFSMNT, M_WAITOK); - - bzero(um, sizeof(struct union_mount)); - - um->um_op = args.mntflags & UNMNT_OPMASK; - - switch (um->um_op) { - case UNMNT_ABOVE: - um->um_lowervp = lowerrootvp; - um->um_uppervp = upperrootvp; - upperrootvp = NULL; - lowerrootvp = NULL; - break; - - case UNMNT_BELOW: - um->um_lowervp = upperrootvp; - um->um_uppervp = lowerrootvp; - upperrootvp = NULL; - lowerrootvp = NULL; - break; - - case UNMNT_REPLACE: - vrele(lowerrootvp); - lowerrootvp = NULL; - um->um_uppervp = upperrootvp; - um->um_lowervp = lowerrootvp; - upperrootvp = NULL; - break; - - default: - error = EINVAL; - goto bad; - } - - /* - * Unless the mount is readonly, ensure that the top layer - * supports whiteout operations - */ - if ((mp->mnt_flag & MNT_RDONLY) == 0) { - error = VOP_WHITEOUT(um->um_uppervp, NULL, NAMEI_LOOKUP); - if (error) - goto bad; - } - - /* - * File creds and modes for shadowed files are based on the user - * that did the mount. - */ - um->um_cred = crhold(cred); - um->um_cmode = UN_DIRMODE; - if (curproc) - um->um_cmode &= ~curproc->p_fd->fd_cmask; - - /* - * Depending on what you think the MNT_LOCAL flag might mean, - * you may want the && to be || on the conditional below. - * At the moment it has been defined that the filesystem is - * only local if it is all local, ie the MNT_LOCAL flag implies - * that the entire namespace is local. If you think the MNT_LOCAL - * flag implies that some of the files might be stored locally - * then you will want to change the conditional. - */ - if (um->um_op == UNMNT_ABOVE) { - if (((um->um_lowervp == NULLVP) || - (um->um_lowervp->v_mount->mnt_flag & MNT_LOCAL)) && - (um->um_uppervp->v_mount->mnt_flag & MNT_LOCAL)) - mp->mnt_flag |= MNT_LOCAL; - } - - /* - * Copy in the upper layer's RDONLY flag. This is for the benefit - * of lookup() which explicitly checks the flag, rather than asking - * the filesystem for its own opinion. This means, that an update - * mount of the underlying filesystem to go from rdonly to rdwr - * will leave the unioned view as read-only. - */ - mp->mnt_flag |= (um->um_uppervp->v_mount->mnt_flag & MNT_RDONLY); - - mp->mnt_data = (qaddr_t) um; - vfs_getnewfsid(mp); - - switch (um->um_op) { - case UNMNT_ABOVE: - cp = ":"; - break; - case UNMNT_BELOW: - cp = ":"; - break; - case UNMNT_REPLACE: - cp = ""; - break; - } - len = strlen(cp); - bcopy(cp, mp->mnt_stat.f_mntfromname, len); - - cp = mp->mnt_stat.f_mntfromname + len; - len = MNAMELEN - len; - - (void) copyinstr(args.target, cp, len - 1, &size); - bzero(cp + size, len - size); - - vfs_add_vnodeops(mp, &union_vnode_vops, &mp->mnt_vn_norm_ops); - - (void)union_statfs(mp, &mp->mnt_stat, cred); - - return (0); - -bad: - if (um) { - if (um->um_uppervp) - vrele(um->um_uppervp); - if (um->um_lowervp) - vrele(um->um_lowervp); - /* XXX other fields */ - kfree(um, M_UNIONFSMNT); - } - if (cred) - crfree(cred); - if (upperrootvp) - vrele(upperrootvp); - if (lowerrootvp) - vrele(lowerrootvp); - return (error); -} - -/* - * Free reference to union layer - */ -static int -union_unmount(struct mount *mp, int mntflags) -{ - struct union_mount *um = MOUNTTOUNIONMOUNT(mp); - int error; - int freeing; - int flags = 0; - - UDEBUG(("union_unmount(mp = %p)\n", (void *)mp)); - - if (mntflags & MNT_FORCE) - flags |= FORCECLOSE; - - /* - * Keep flushing vnodes from the mount list. - * This is needed because of the un_pvp held - * reference to the parent vnode. - * If more vnodes have been freed on a given pass, - * the try again. The loop will iterate at most - * (d) times, where (d) is the maximum tree depth - * in the filesystem. - */ - for (freeing = 0; (error = vflush(mp, 0, flags)) != 0;) { - int n = mp->mnt_nvnodelistsize; - - /* if this is unchanged then stop */ - if (n == freeing) - break; - - /* otherwise try once more time */ - freeing = n; - } - - /* If the most recent vflush failed, the filesystem is still busy. */ - if (error) - return (error); - - /* - * Discard references to upper and lower target vnodes. - */ - if (um->um_lowervp) - vrele(um->um_lowervp); - vrele(um->um_uppervp); - crfree(um->um_cred); - /* - * Finally, throw away the union_mount structure - */ - kfree(mp->mnt_data, M_UNIONFSMNT); /* XXX */ - mp->mnt_data = 0; - return (0); -} - -static int -union_root(struct mount *mp, struct vnode **vpp) -{ - struct union_mount *um = MOUNTTOUNIONMOUNT(mp); - int error; - - /* - * Supply an unlocked reference to um_uppervp and to um_lowervp. It - * is possible for um_uppervp to be locked without the associated - * root union_node being locked. We let union_allocvp() deal with - * it. - */ - UDEBUG(("union_root UPPERVP %p locked = %d\n", um->um_uppervp, - vn_islocked(um->um_uppervp))); - - vref(um->um_uppervp); - if (um->um_lowervp) - vref(um->um_lowervp); - - error = union_allocvp(vpp, mp, NULLVP, NULLVP, NULL, - um->um_uppervp, um->um_lowervp, 1); - UDEBUG(("error %d\n", error)); - UDEBUG(("union_root2 UPPERVP %p locked = %d\n", um->um_uppervp, - vn_islocked(um->um_uppervp))); - - return (error); -} - -static int -union_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) -{ - int error; - struct union_mount *um = MOUNTTOUNIONMOUNT(mp); - struct statfs mstat; - int lbsize; - - UDEBUG(("union_statfs(mp = %p, lvp = %p, uvp = %p)\n", - (void *)mp, (void *)um->um_lowervp, (void *)um->um_uppervp)); - - bzero(&mstat, sizeof(mstat)); - - if (um->um_lowervp) { - error = VFS_STATFS(um->um_lowervp->v_mount, &mstat, cred); - if (error) - return (error); - } - - /* now copy across the "interesting" information and fake the rest */ -#if 0 - sbp->f_type = mstat.f_type; - sbp->f_flags = mstat.f_flags; - sbp->f_bsize = mstat.f_bsize; - sbp->f_iosize = mstat.f_iosize; -#endif - lbsize = mstat.f_bsize; - sbp->f_blocks = mstat.f_blocks; - sbp->f_bfree = mstat.f_bfree; - sbp->f_bavail = mstat.f_bavail; - sbp->f_files = mstat.f_files; - sbp->f_ffree = mstat.f_ffree; - - error = VFS_STATFS(um->um_uppervp->v_mount, &mstat, cred); - if (error) - return (error); - - sbp->f_flags = mstat.f_flags; - sbp->f_bsize = mstat.f_bsize; - sbp->f_iosize = mstat.f_iosize; - - /* - * if the lower and upper blocksizes differ, then frig the - * block counts so that the sizes reported by df make some - * kind of sense. none of this makes sense though. - */ - - if (mstat.f_bsize != lbsize) - sbp->f_blocks = ((off_t) sbp->f_blocks * lbsize) / mstat.f_bsize; - - /* - * The "total" fields count total resources in all layers, - * the "free" fields count only those resources which are - * free in the upper layer (since only the upper layer - * is writeable). - */ - sbp->f_blocks += mstat.f_blocks; - sbp->f_bfree = mstat.f_bfree; - sbp->f_bavail = mstat.f_bavail; - sbp->f_files += mstat.f_files; - sbp->f_ffree = mstat.f_ffree; - - if (sbp != &mp->mnt_stat) { - sbp->f_type = mp->mnt_vfc->vfc_typenum; - bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); - } - return (0); -} - -static struct vfsops union_vfsops = { - .vfs_mount = union_mount, - .vfs_unmount = union_unmount, - .vfs_root = union_root, - .vfs_statfs = union_statfs, - .vfs_sync = vfs_stdsync, - .vfs_init = union_init -}; - -VFS_SET(union_vfsops, union, VFCF_LOOPBACK); diff --git a/sys/vfs/union/union_vnops.c b/sys/vfs/union/union_vnops.c deleted file mode 100644 index 479aa0b0ea..0000000000 --- a/sys/vfs/union/union_vnops.c +++ /dev/null @@ -1,1795 +0,0 @@ -/* - * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry. - * Copyright (c) 1992, 1993, 1994, 1995 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * 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. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. - * - * @(#)union_vnops.c 8.32 (Berkeley) 6/23/95 - * $FreeBSD: src/sys/miscfs/union/union_vnops.c,v 1.72 1999/12/15 23:02:14 eivind Exp $ - * $DragonFly: src/sys/vfs/union/union_vnops.c,v 1.39 2007/11/20 21:03:51 dillon Exp $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "union.h" - -#include -#include - -#include -#include - -int uniondebug = 0; - -#if UDEBUG_ENABLED -SYSCTL_INT(_vfs, OID_AUTO, uniondebug, CTLFLAG_RW, &uniondebug, 0, ""); -#else -SYSCTL_INT(_vfs, OID_AUTO, uniondebug, CTLFLAG_RD, &uniondebug, 0, ""); -#endif - -static int union_access (struct vop_access_args *ap); -static int union_advlock (struct vop_advlock_args *ap); -static int union_bmap (struct vop_bmap_args *ap); -static int union_close (struct vop_close_args *ap); -static int union_create (struct vop_old_create_args *ap); -static int union_fsync (struct vop_fsync_args *ap); -static int union_getattr (struct vop_getattr_args *ap); -static int union_inactive (struct vop_inactive_args *ap); -static int union_ioctl (struct vop_ioctl_args *ap); -static int union_link (struct vop_old_link_args *ap); -static int union_lookup (struct vop_old_lookup_args *ap); -static int union_lookup1 (struct vnode *udvp, struct vnode **dvp, - struct vnode **vpp, - struct componentname *cnp); -static int union_mkdir (struct vop_old_mkdir_args *ap); -static int union_mknod (struct vop_old_mknod_args *ap); -static int union_mmap (struct vop_mmap_args *ap); -static int union_open (struct vop_open_args *ap); -static int union_pathconf (struct vop_pathconf_args *ap); -static int union_print (struct vop_print_args *ap); -static int union_read (struct vop_read_args *ap); -static int union_readdir (struct vop_readdir_args *ap); -static int union_readlink (struct vop_readlink_args *ap); -static int union_reclaim (struct vop_reclaim_args *ap); -static int union_remove (struct vop_old_remove_args *ap); -static int union_rename (struct vop_old_rename_args *ap); -static int union_rmdir (struct vop_old_rmdir_args *ap); -static int union_poll (struct vop_poll_args *ap); -static int union_setattr (struct vop_setattr_args *ap); -static int union_strategy (struct vop_strategy_args *ap); -static int union_getpages (struct vop_getpages_args *ap); -static int union_putpages (struct vop_putpages_args *ap); -static int union_symlink (struct vop_old_symlink_args *ap); -static int union_whiteout (struct vop_old_whiteout_args *ap); -static int union_write (struct vop_read_args *ap); - -static __inline -struct vnode * -union_lock_upper(struct union_node *un, struct thread *td) -{ - struct vnode *uppervp; - - if ((uppervp = un->un_uppervp) != NULL) { - vref(uppervp); - vn_lock(uppervp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY); - } - KASSERT((uppervp == NULL || VREFCNT(uppervp) > 0), - ("uppervp usecount is 0")); - return(uppervp); -} - -static __inline -struct vnode * -union_ref_upper(struct union_node *un) -{ - struct vnode *uppervp; - - if ((uppervp = un->un_uppervp) != NULL) { - vref(uppervp); - if (uppervp->v_flag & VRECLAIMED) { - vrele(uppervp); - return (NULLVP); - } - } - return (uppervp); -} - -static __inline -void -union_unlock_upper(struct vnode *uppervp, struct thread *td) -{ - vput(uppervp); -} - -static __inline -struct vnode * -union_lock_other(struct union_node *un, struct thread *td) -{ - struct vnode *vp; - - if (un->un_uppervp != NULL) { - vp = union_lock_upper(un, td); - } else if ((vp = un->un_lowervp) != NULL) { - vref(vp); - vn_lock(vp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY); - } - return(vp); -} - -static __inline -void -union_unlock_other(struct vnode *vp, struct thread *td) -{ - vput(vp); -} - -/* - * union_lookup: - * - * udvp must be exclusively locked on call and will remain - * exclusively locked on return. This is the mount point - * for out filesystem. - * - * dvp Our base directory, locked and referenced. - * The passed dvp will be dereferenced and unlocked on return - * and a new dvp will be returned which is locked and - * referenced in the same variable. - * - * vpp is filled in with the result if no error occured, - * locked and ref'd. - * - * If an error is returned, *vpp is set to NULLVP. If no - * error occurs, *vpp is returned with a reference and an - * exclusive lock. - */ - -static int -union_lookup1(struct vnode *udvp, struct vnode **pdvp, struct vnode **vpp, - struct componentname *cnp) -{ - int error; - struct thread *td = cnp->cn_td; - struct vnode *dvp = *pdvp; - struct vnode *tdvp; - struct mount *mp; - - /* - * If stepping up the directory tree, check for going - * back across the mount point, in which case do what - * lookup would do by stepping back down the mount - * hierarchy. - */ - if (cnp->cn_flags & CNP_ISDOTDOT) { - while ((dvp != udvp) && (dvp->v_flag & VROOT)) { - /* - * Don't do the NOCROSSMOUNT check - * at this level. By definition, - * union fs deals with namespaces, not - * filesystems. - */ - tdvp = dvp; - dvp = dvp->v_mount->mnt_vnodecovered; - vref(dvp); - vput(tdvp); - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); - } - } - - /* - * Set return dvp to be the upperdvp 'parent directory. - */ - *pdvp = dvp; - - /* - * If the VOP_LOOKUP call generates an error, tdvp is invalid and no - * changes will have been made to dvp, so we are set to return. - */ - - error = VOP_LOOKUP(dvp, &tdvp, cnp); - if (error) { - UDEBUG(("dvp %p error %d flags %lx\n", dvp, error, cnp->cn_flags)); - *vpp = NULL; - return (error); - } - - /* - * The parent directory will have been unlocked, unless lookup - * found the last component or if dvp == tdvp (tdvp must be locked). - * - * We want our dvp to remain locked and ref'd. We also want tdvp - * to remain locked and ref'd. - */ - UDEBUG(("parentdir %p result %p flag %lx\n", dvp, tdvp, cnp->cn_flags)); - -#if 0 - if (dvp != tdvp && (cnp->cn_flags & CNP_XXXISLASTCN) == 0) - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); -#endif - - /* - * Lastly check if the current node is a mount point in - * which case walk up the mount hierarchy making sure not to - * bump into the root of the mount tree (ie. dvp != udvp). - * - * We use dvp as a temporary variable here, it is no longer related - * to the dvp above. However, we have to ensure that both *pdvp and - * tdvp are locked on return. - */ - - dvp = tdvp; - while ( - dvp != udvp && - (dvp->v_type == VDIR) && - (mp = dvp->v_mountedhere) - ) { - int relock_pdvp = 0; - - if (vfs_busy(mp, 0)) - continue; - - if (dvp == *pdvp) - relock_pdvp = 1; - vput(dvp); - dvp = NULL; - error = VFS_ROOT(mp, &dvp); - - vfs_unbusy(mp); - - if (relock_pdvp) - vn_lock(*pdvp, LK_EXCLUSIVE | LK_RETRY); - - if (error) { - *vpp = NULL; - return (error); - } - } - *vpp = dvp; - return (0); -} - -/* - * union_lookup(struct vnode *a_dvp, struct vnode **a_vpp, - * struct componentname *a_cnp) - */ -static int -union_lookup(struct vop_old_lookup_args *ap) -{ - int error; - int uerror, lerror; - struct vnode *uppervp, *lowervp; - struct vnode *upperdvp, *lowerdvp; - struct vnode *dvp = ap->a_dvp; /* starting dir */ - struct union_node *dun = VTOUNION(dvp); /* associated union node */ - struct componentname *cnp = ap->a_cnp; - struct thread *td = cnp->cn_td; - int lockparent = cnp->cn_flags & CNP_LOCKPARENT; - struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount); - struct ucred *saved_cred = NULL; - int iswhiteout; - struct vattr va; - - *ap->a_vpp = NULLVP; - - /* - * Disallow write attemps to the filesystem mounted read-only. - */ - if ((dvp->v_mount->mnt_flag & MNT_RDONLY) && - (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) { - return (EROFS); - } - - /* - * For any lookup's we do, always return with the parent locked - */ - cnp->cn_flags |= CNP_LOCKPARENT; - - lowerdvp = dun->un_lowervp; - uppervp = NULLVP; - lowervp = NULLVP; - iswhiteout = 0; - - uerror = ENOENT; - lerror = ENOENT; - - /* - * Get a private lock on uppervp and a reference, effectively - * taking it out of the union_node's control. - * - * We must lock upperdvp while holding our lock on dvp - * to avoid a deadlock. - */ - upperdvp = union_lock_upper(dun, td); - - /* - * do the lookup in the upper level. - * if that level comsumes additional pathnames, - * then assume that something special is going - * on and just return that vnode. - */ - if (upperdvp != NULLVP) { - /* - * We do not have to worry about the DOTDOT case, we've - * already unlocked dvp. - */ - UDEBUG(("A %p\n", upperdvp)); - - /* - * Do the lookup. We must supply a locked and referenced - * upperdvp to the function and will get a new locked and - * referenced upperdvp back with the old having been - * dereferenced. - * - * If an error is returned, uppervp will be NULLVP. If no - * error occurs, uppervp will be the locked and referenced - * return vnode or possibly NULL, depending on what is being - * requested. It is possible that the returned uppervp - * will be the same as upperdvp. - */ - uerror = union_lookup1(um->um_uppervp, &upperdvp, &uppervp, cnp); - UDEBUG(( - "uerror %d upperdvp %p %d/%d, uppervp %p ref=%d/lck=%d\n", - uerror, - upperdvp, - VREFCNT(upperdvp), - vn_islocked(upperdvp), - uppervp, - (uppervp ? VREFCNT(uppervp) : -99), - (uppervp ? vn_islocked(uppervp) : -99) - )); - - /* - * Disallow write attemps to the filesystem mounted read-only. - */ - if (uerror == EJUSTRETURN && - (dvp->v_mount->mnt_flag & MNT_RDONLY) && - (cnp->cn_nameiop == NAMEI_CREATE || cnp->cn_nameiop == NAMEI_RENAME)) { - error = EROFS; - goto out; - } - - /* - * Special case. If cn_consume != 0 skip out. The result - * of the lookup is transfered to our return variable. If - * an error occured we have to throw away the results. - */ - - if (cnp->cn_consume != 0) { - if ((error = uerror) == 0) { - *ap->a_vpp = uppervp; - uppervp = NULL; - } - goto out; - } - - /* - * Calculate whiteout, fall through - */ - - if (uerror == ENOENT || uerror == EJUSTRETURN) { - if (cnp->cn_flags & CNP_ISWHITEOUT) { - iswhiteout = 1; - } else if (lowerdvp != NULLVP) { - int terror; - - terror = VOP_GETATTR(upperdvp, &va); - if (terror == 0 && (va.va_flags & OPAQUE)) - iswhiteout = 1; - } - } - } - - /* - * in a similar way to the upper layer, do the lookup - * in the lower layer. this time, if there is some - * component magic going on, then vput whatever we got - * back from the upper layer and return the lower vnode - * instead. - */ - - if (lowerdvp != NULLVP && !iswhiteout) { - int nameiop; - - UDEBUG(("B %p\n", lowerdvp)); - - /* - * Force only LOOKUPs on the lower node, since - * we won't be making changes to it anyway. - */ - nameiop = cnp->cn_nameiop; - cnp->cn_nameiop = NAMEI_LOOKUP; - if (um->um_op == UNMNT_BELOW) { - saved_cred = cnp->cn_cred; - cnp->cn_cred = um->um_cred; - } - - /* - * We shouldn't have to worry about locking interactions - * between the lower layer and our union layer (w.r.t. - * `..' processing) because we don't futz with lowervp - * locks in the union-node instantiation code path. - * - * union_lookup1() requires lowervp to be locked on entry, - * and it will be unlocked on return. The ref count will - * not change. On return lowervp doesn't represent anything - * to us so we NULL it out. - */ - vref(lowerdvp); - vn_lock(lowerdvp, LK_EXCLUSIVE | LK_RETRY); - lerror = union_lookup1(um->um_lowervp, &lowerdvp, &lowervp, cnp); - if (lowerdvp == lowervp) - vrele(lowerdvp); - else - vput(lowerdvp); - lowerdvp = NULL; /* lowerdvp invalid after vput */ - - if (um->um_op == UNMNT_BELOW) - cnp->cn_cred = saved_cred; - cnp->cn_nameiop = nameiop; - - if (cnp->cn_consume != 0 || lerror == EACCES) { - if ((error = lerror) == 0) { - *ap->a_vpp = lowervp; - lowervp = NULL; - } - goto out; - } - } else { - UDEBUG(("C %p\n", lowerdvp)); - if ((cnp->cn_flags & CNP_ISDOTDOT) && dun->un_pvp != NULLVP) { - if ((lowervp = LOWERVP(dun->un_pvp)) != NULL) { - vref(lowervp); - vn_lock(lowervp, LK_EXCLUSIVE | LK_RETRY); - lerror = 0; - } - } - } - - /* - * Ok. Now we have uerror, uppervp, upperdvp, lerror, and lowervp. - * - * 1. If both layers returned an error, select the upper layer. - * - * 2. If the upper layer faile and the bottom layer succeeded, - * two subcases occur: - * - * a. The bottom vnode is not a directory, in which case - * just return a new union vnode referencing an - * empty top layer and the existing bottom layer. - * - * b. The button vnode is a directory, in which case - * create a new directory in the top layer and - * and fall through to case 3. - * - * 3. If the top layer succeeded then return a new union - * vnode referencing whatever the new top layer and - * whatever the bottom layer returned. - */ - - /* case 1. */ - if ((uerror != 0) && (lerror != 0)) { - error = uerror; - goto out; - } - - /* case 2. */ - if (uerror != 0 /* && (lerror == 0) */ ) { - if (lowervp->v_type == VDIR) { /* case 2b. */ - KASSERT(uppervp == NULL, ("uppervp unexpectedly non-NULL")); - /* - * oops, uppervp has a problem, we may have to shadow. - */ - uerror = union_mkshadow(um, upperdvp, cnp, &uppervp); - if (uerror) { - error = uerror; - goto out; - } - } - } - - /* - * Must call union_allocvp with both the upper and lower vnodes - * referenced and the upper vnode locked. ap->a_vpp is returned - * referenced and locked. lowervp, uppervp, and upperdvp are - * absorbed by union_allocvp() whether it succeeds or fails. - * - * upperdvp is the parent directory of uppervp which may be - * different, depending on the path, from dvp->un_uppervp. That's - * why it is a separate argument. Note that it must be unlocked. - * - * dvp must be locked on entry to the call and will be locked on - * return. - */ - - if (uppervp && uppervp != upperdvp) - vn_unlock(uppervp); - if (lowervp) - vn_unlock(lowervp); - if (upperdvp) - vn_unlock(upperdvp); - - error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp, - uppervp, lowervp, 1); - - UDEBUG(("Create %p = %p %p refs=%d\n", - *ap->a_vpp, uppervp, lowervp, - (*ap->a_vpp) ? (VREFCNT(*ap->a_vpp)) : -99)); - - uppervp = NULL; - upperdvp = NULL; - lowervp = NULL; - - /* - * Termination Code - * - * - put away any extra junk laying around. Note that lowervp - * (if not NULL) will never be the same as *ap->a_vp and - * neither will uppervp, because when we set that state we - * NULL-out lowervp or uppervp. On the otherhand, upperdvp - * may match uppervp or *ap->a_vpp. - * - * - relock/unlock dvp if appropriate. - */ - -out: - if (upperdvp) { - if (upperdvp == uppervp || upperdvp == *ap->a_vpp) - vrele(upperdvp); - else - vput(upperdvp); - } - - if (uppervp) - vput(uppervp); - - if (lowervp) - vput(lowervp); - - /* - * Restore LOCKPARENT state - */ - - if (!lockparent) - cnp->cn_flags &= ~CNP_LOCKPARENT; - - UDEBUG(("Out %d vpp %p/%d lower %p upper %p\n", error, *ap->a_vpp, - ((*ap->a_vpp) ? (*ap->a_vpp)->v_refcnt : -99), - lowervp, uppervp)); - - /* - * dvp lock state, determine whether to relock dvp. dvp is expected - * to be locked on return if: - * - * - there was an error (except not EJUSTRETURN), or - * - we hit the last component and lockparent is true - * - * dvp_is_locked is the current state of the dvp lock, not counting - * the possibility that *ap->a_vpp == dvp (in which case it is locked - * anyway). Note that *ap->a_vpp == dvp only if no error occured. - */ - - if (*ap->a_vpp != dvp) { - if ((error == 0 || error == EJUSTRETURN) && !lockparent) { - vn_unlock(dvp); - } - } - - /* - * Diagnostics - */ - -#ifdef DIAGNOSTIC - if (cnp->cn_namelen == 1 && - cnp->cn_nameptr[0] == '.' && - *ap->a_vpp != dvp) { - panic("union_lookup returning . (%p) not same as startdir (%p)", ap->a_vpp, dvp); - } -#endif - - return (error); -} - -/* - * union_create: - * - * a_dvp is locked on entry and remains locked on return. a_vpp is returned - * locked if no error occurs, otherwise it is garbage. - * - * union_create(struct vnode *a_dvp, struct vnode **a_vpp, - * struct componentname *a_cnp, struct vattr *a_vap) - */ -static int -union_create(struct vop_old_create_args *ap) -{ - struct union_node *dun = VTOUNION(ap->a_dvp); - struct componentname *cnp = ap->a_cnp; - struct thread *td = cnp->cn_td; - struct vnode *dvp; - int error = EROFS; - - if ((dvp = union_lock_upper(dun, td)) != NULL) { - struct vnode *vp; - struct mount *mp; - - error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap); - if (error == 0) { - mp = ap->a_dvp->v_mount; - vn_unlock(vp); - UDEBUG(("ALLOCVP-1 FROM %p REFS %d\n", - vp, vp->v_refcnt)); - error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, - cnp, vp, NULLVP, 1); - UDEBUG(("ALLOCVP-2B FROM %p REFS %d\n", - *ap->a_vpp, vp->v_refcnt)); - } - union_unlock_upper(dvp, td); - } - return (error); -} - -/* - * union_whiteout(struct vnode *a_dvp, struct componentname *a_cnp, - * int a_flags) - */ -static int -union_whiteout(struct vop_old_whiteout_args *ap) -{ - struct union_node *un = VTOUNION(ap->a_dvp); - struct componentname *cnp = ap->a_cnp; - struct vnode *uppervp; - int error = EOPNOTSUPP; - - if ((uppervp = union_lock_upper(un, cnp->cn_td)) != NULLVP) { - error = VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags); - union_unlock_upper(uppervp, cnp->cn_td); - } - return(error); -} - -/* - * union_mknod: - * - * a_dvp is locked on entry and should remain locked on return. - * a_vpp is garbagre whether an error occurs or not. - * - * union_mknod(struct vnode *a_dvp, struct vnode **a_vpp, - * struct componentname *a_cnp, struct vattr *a_vap) - */ -static int -union_mknod(struct vop_old_mknod_args *ap) -{ - struct union_node *dun = VTOUNION(ap->a_dvp); - struct componentname *cnp = ap->a_cnp; - struct vnode *dvp; - int error = EROFS; - - if ((dvp = union_lock_upper(dun, cnp->cn_td)) != NULL) { - error = VOP_MKNOD(dvp, ap->a_vpp, cnp, ap->a_vap); - union_unlock_upper(dvp, cnp->cn_td); - } - return (error); -} - -/* - * union_open: - * - * run open VOP. When opening the underlying vnode we have to mimic - * vn_open. What we *really* need to do to avoid screwups if the - * open semantics change is to call vn_open(). For example, ufs blows - * up if you open a file but do not vmio it prior to writing. - * - * union_open(struct vnode *a_vp, int a_mode, - * struct ucred *a_cred, struct thread *a_td) - */ -static int -union_open(struct vop_open_args *ap) -{ - struct union_node *un = VTOUNION(ap->a_vp); - struct vnode *tvp; - int mode = ap->a_mode; - struct ucred *cred = ap->a_cred; - struct thread *td = ap->a_td; - int error = 0; - int tvpisupper = 1; - - /* - * If there is an existing upper vp then simply open that. - * The upper vp takes precedence over the lower vp. When opening - * a lower vp for writing copy it to the uppervp and then open the - * uppervp. - * - * At the end of this section tvp will be left locked. - */ - if ((tvp = union_lock_upper(un, td)) == NULLVP) { - /* - * If the lower vnode is being opened for writing, then - * copy the file contents to the upper vnode and open that, - * otherwise can simply open the lower vnode. - */ - tvp = un->un_lowervp; - if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) { - int docopy = !(mode & O_TRUNC); - error = union_copyup(un, docopy, cred, td); - tvp = union_lock_upper(un, td); - } else { - un->un_openl++; - vref(tvp); - vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); - tvpisupper = 0; - } - } - - /* - * We are holding the correct vnode, open it. Note - * that in DragonFly, VOP_OPEN is responsible for associating - * a VM object with the vnode if the vnode is mappable or the - * underlying filesystem uses buffer cache calls on it. - */ - if (error == 0) - error = VOP_OPEN(tvp, mode, cred, NULL); - - /* - * Release any locks held - */ - if (tvpisupper) { - if (tvp) - union_unlock_upper(tvp, td); - } else { - vput(tvp); - } - return (error); -} - -/* - * union_close: - * - * It is unclear whether a_vp is passed locked or unlocked. Whatever - * the case we do not change it. - * - * union_close(struct vnode *a_vp, int a_fflag, struct ucred *a_cred, - * struct thread *a_td) - */ -static int -union_close(struct vop_close_args *ap) -{ - struct union_node *un = VTOUNION(ap->a_vp); - struct vnode *vp; - - vn_lock(vp, LK_UPGRADE | LK_RETRY); - if ((vp = un->un_uppervp) == NULLVP) { -#ifdef UNION_DIAGNOSTIC - if (un->un_openl <= 0) - panic("union: un_openl cnt"); -#endif - --un->un_openl; - vp = un->un_lowervp; - } - ap->a_head.a_ops = *vp->v_ops; - ap->a_vp = vp; - return(vop_close_ap(ap)); -} - -/* - * Check access permission on the union vnode. - * The access check being enforced is to check - * against both the underlying vnode, and any - * copied vnode. This ensures that no additional - * file permissions are given away simply because - * the user caused an implicit file copy. - * - * union_access(struct vnode *a_vp, int a_mode, - * struct ucred *a_cred, struct thread *a_td) - */ -static int -union_access(struct vop_access_args *ap) -{ - struct union_node *un = VTOUNION(ap->a_vp); - struct thread *td = ap->a_td; - int error = EACCES; - struct vnode *vp; - - /* - * Disallow write attempts on filesystems mounted read-only. - */ - if ((ap->a_mode & VWRITE) && - (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) { - switch (ap->a_vp->v_type) { - case VREG: - case VDIR: - case VLNK: - return (EROFS); - default: - break; - } - } - - if ((vp = union_lock_upper(un, td)) != NULLVP) { - ap->a_head.a_ops = *vp->v_ops; - ap->a_vp = vp; - error = vop_access_ap(ap); - union_unlock_upper(vp, td); - return(error); - } - - if ((vp = un->un_lowervp) != NULLVP) { - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - ap->a_head.a_ops = *vp->v_ops; - ap->a_vp = vp; - - /* - * Remove VWRITE from a_mode if our mount point is RW, because - * we want to allow writes and lowervp may be read-only. - */ - if ((un->un_vnode->v_mount->mnt_flag & MNT_RDONLY) == 0) - ap->a_mode &= ~VWRITE; - - error = vop_access_ap(ap); - if (error == 0) { - struct union_mount *um; - - um = MOUNTTOUNIONMOUNT(un->un_vnode->v_mount); - - if (um->um_op == UNMNT_BELOW) { - ap->a_cred = um->um_cred; - error = vop_access_ap(ap); - } - } - vn_unlock(vp); - } - return(error); -} - -/* - * We handle getattr only to change the fsid and - * track object sizes - * - * It's not clear whether VOP_GETATTR is to be - * called with the vnode locked or not. stat() calls - * it with (vp) locked, and fstat calls it with - * (vp) unlocked. - * - * Because of this we cannot use our normal locking functions - * if we do not intend to lock the main a_vp node. At the moment - * we are running without any specific locking at all, but beware - * to any programmer that care must be taken if locking is added - * to this function. - * - * union_getattr(struct vnode *a_vp, struct vattr *a_vap, - * struct ucred *a_cred, struct thread *a_td) - */ -static int -union_getattr(struct vop_getattr_args *ap) -{ - int error; - struct union_node *un = VTOUNION(ap->a_vp); - struct vnode *vp; - struct vattr *vap; - struct vattr va; - - /* - * Some programs walk the filesystem hierarchy by counting - * links to directories to avoid stat'ing all the time. - * This means the link count on directories needs to be "correct". - * The only way to do that is to call getattr on both layers - * and fix up the link count. The link count will not necessarily - * be accurate but will be large enough to defeat the tree walkers. - */ - - vap = ap->a_vap; - - if ((vp = un->un_uppervp) != NULLVP) { - error = VOP_GETATTR(vp, vap); - if (error) - return (error); - /* XXX isn't this dangerouso without a lock? */ - union_newsize(ap->a_vp, vap->va_size, VNOVAL); - } - - if (vp == NULLVP) { - vp = un->un_lowervp; - } else if (vp->v_type == VDIR && un->un_lowervp != NULLVP) { - vp = un->un_lowervp; - vap = &va; - } else { - vp = NULLVP; - } - - if (vp != NULLVP) { - error = VOP_GETATTR(vp, vap); - if (error) - return (error); - /* XXX isn't this dangerous without a lock? */ - union_newsize(ap->a_vp, VNOVAL, vap->va_size); - } - - if ((vap != ap->a_vap) && (vap->va_type == VDIR)) - ap->a_vap->va_nlink += vap->va_nlink; - return (0); -} - -/* - * union_setattr(struct vnode *a_vp, struct vattr *a_vap, - * struct ucred *a_cred, struct thread *a_td) - */ -static int -union_setattr(struct vop_setattr_args *ap) -{ - struct union_node *un = VTOUNION(ap->a_vp); - struct thread *td = ap->a_td; - struct vattr *vap = ap->a_vap; - struct vnode *uppervp; - int error; - - /* - * Disallow write attempts on filesystems mounted read-only. - */ - if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) && - (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || - vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || - vap->va_mtime.tv_sec != VNOVAL || - vap->va_mode != (mode_t)VNOVAL)) { - return (EROFS); - } - - /* - * Handle case of truncating lower object to zero size, - * by creating a zero length upper object. This is to - * handle the case of open with O_TRUNC and O_CREAT. - */ - if (un->un_uppervp == NULLVP && (un->un_lowervp->v_type == VREG)) { - error = union_copyup(un, (ap->a_vap->va_size != 0), - ap->a_cred, ap->a_td); - if (error) - return (error); - } - - /* - * Try to set attributes in upper layer, - * otherwise return read-only filesystem error. - */ - error = EROFS; - if ((uppervp = union_lock_upper(un, td)) != NULLVP) { - error = VOP_SETATTR(un->un_uppervp, ap->a_vap, ap->a_cred); - if ((error == 0) && (ap->a_vap->va_size != VNOVAL)) - union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL); - union_unlock_upper(uppervp, td); - } - return (error); -} - -/* - * union_getpages: - */ - -static int -union_getpages(struct vop_getpages_args *ap) -{ - int r; - - r = vnode_pager_generic_getpages(ap->a_vp, ap->a_m, - ap->a_count, ap->a_reqpage, - ap->a_seqaccess); - return(r); -} - -/* - * union_putpages: - */ - -static int -union_putpages(struct vop_putpages_args *ap) -{ - int r; - - r = vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count, - ap->a_sync, ap->a_rtvals); - return(r); -} - -/* - * union_read(struct vnode *a_vp, struct uio *a_uio, int a_ioflag, - * struct ucred *a_cred) - */ -static int -union_read(struct vop_read_args *ap) -{ - struct union_node *un = VTOUNION(ap->a_vp); - struct thread *td = ap->a_uio->uio_td; - struct vnode *uvp; - int error; - - uvp = union_lock_other(un, td); - KASSERT(uvp != NULL, ("union_read: backing vnode missing!")); - - if (ap->a_vp->v_flag & VOBJBUF) - union_vm_coherency(ap->a_vp, ap->a_uio, 0); - - error = VOP_READ(uvp, ap->a_uio, ap->a_ioflag, ap->a_cred); - union_unlock_other(uvp, td); - - /* - * XXX - * perhaps the size of the underlying object has changed under - * our feet. take advantage of the offset information present - * in the uio structure. - */ - if (error == 0) { - struct union_node *un = VTOUNION(ap->a_vp); - off_t cur = ap->a_uio->uio_offset; - - if (uvp == un->un_uppervp) { - if (cur > un->un_uppersz) - union_newsize(ap->a_vp, cur, VNOVAL); - } else { - if (cur > un->un_lowersz) - union_newsize(ap->a_vp, VNOVAL, cur); - } - } - return (error); -} - -/* - * union_write(struct vnode *a_vp, struct uio *a_uio, int a_ioflag, - * struct ucred *a_cred) - */ -static int -union_write(struct vop_read_args *ap) -{ - struct union_node *un = VTOUNION(ap->a_vp); - struct thread *td = ap->a_uio->uio_td; - struct vnode *uppervp; - int error; - - if ((uppervp = union_lock_upper(un, td)) == NULLVP) - panic("union: missing upper layer in write"); - - /* - * Since our VM pages are associated with our vnode rather then - * the real vnode, and since we do not run our reads and writes - * through our own VM cache, we have a VM/VFS coherency problem. - * We solve them by invalidating or flushing the associated VM - * pages prior to allowing a normal read or write to occur. - * - * VM-backed writes (UIO_NOCOPY) have to be converted to normal - * writes because we are not cache-coherent. Normal writes need - * to be made coherent with our VM-backing store, which we do by - * first flushing any dirty VM pages associated with the write - * range, and then destroying any clean VM pages associated with - * the write range. - */ - - if (ap->a_uio->uio_segflg == UIO_NOCOPY) { - ap->a_uio->uio_segflg = UIO_SYSSPACE; - } else if (ap->a_vp->v_flag & VOBJBUF) { - union_vm_coherency(ap->a_vp, ap->a_uio, 1); - } - - error = VOP_WRITE(uppervp, ap->a_uio, ap->a_ioflag, ap->a_cred); - - /* - * the size of the underlying object may be changed by the - * write. - */ - if (error == 0) { - off_t cur = ap->a_uio->uio_offset; - - if (cur > un->un_uppersz) - union_newsize(ap->a_vp, cur, VNOVAL); - } - union_unlock_upper(uppervp, td); - return (error); -} - -/* - * union_ioctl(struct vnode *a_vp, int a_command, caddr_t a_data, int a_fflag, - * struct ucred *a_cred, struct thread *a_td) - */ -static int -union_ioctl(struct vop_ioctl_args *ap) -{ - struct vnode *ovp = OTHERVP(ap->a_vp); - - ap->a_head.a_ops = *ovp->v_ops; - ap->a_vp = ovp; - return(vop_ioctl_ap(ap)); -} - -/* - * union_poll(struct vnode *a_vp, int a_events, struct ucred *a_cred, - * struct thread *a_td) - */ -static int -union_poll(struct vop_poll_args *ap) -{ - struct vnode *ovp = OTHERVP(ap->a_vp); - - ap->a_head.a_ops = *ovp->v_ops; - ap->a_vp = ovp; - return(vop_poll_ap(ap)); -} - -/* - * union_mmap(struct vnode *a_vp, int a_fflags, struct ucred *a_cred, - * struct thread *a_td) - */ -static int -union_mmap(struct vop_mmap_args *ap) -{ - struct vnode *ovp = OTHERVP(ap->a_vp); - - ap->a_head.a_ops = *ovp->v_ops; - ap->a_vp = ovp; - return (vop_mmap_ap(ap)); -} - -/* - * union_fsync(struct vnode *a_vp, struct ucred *a_cred, int a_waitfor, - * struct thread *a_td) - */ -static int -union_fsync(struct vop_fsync_args *ap) -{ - int error = 0; - struct thread *td = ap->a_td; - struct vnode *targetvp; - struct union_node *un = VTOUNION(ap->a_vp); - - if ((targetvp = union_lock_other(un, td)) != NULLVP) { - error = VOP_FSYNC(targetvp, ap->a_waitfor, 0); - union_unlock_other(targetvp, td); - } - - return (error); -} - -/* - * union_remove: - * - * Remove the specified cnp. The dvp and vp are passed to us locked - * and must remain locked on return. - * - * union_remove(struct vnode *a_dvp, struct vnode *a_vp, - * struct componentname *a_cnp) - */ -static int -union_remove(struct vop_old_remove_args *ap) -{ - struct union_node *dun = VTOUNION(ap->a_dvp); - struct union_node *un = VTOUNION(ap->a_vp); - struct componentname *cnp = ap->a_cnp; - struct thread *td = cnp->cn_td; - struct vnode *uppervp; - struct vnode *upperdvp; - int error; - - if ((upperdvp = union_lock_upper(dun, td)) == NULLVP) - panic("union remove: null upper vnode"); - - if ((uppervp = union_lock_upper(un, td)) != NULLVP) { - if (union_dowhiteout(un, cnp->cn_cred, td)) - cnp->cn_flags |= CNP_DOWHITEOUT; - error = VOP_REMOVE(upperdvp, uppervp, cnp); -#if 0 - /* XXX */ - if (!error) - union_removed_upper(un); -#endif - union_unlock_upper(uppervp, td); - } else { - error = union_mkwhiteout( - MOUNTTOUNIONMOUNT(ap->a_dvp->v_mount), - upperdvp, ap->a_cnp, un->un_path); - } - union_unlock_upper(upperdvp, td); - return (error); -} - -/* - * union_link: - * - * tdvp will be locked on entry, vp will not be locked on entry. - * tdvp should remain locked on return and vp should remain unlocked - * on return. - * - * union_link(struct vnode *a_tdvp, struct vnode *a_vp, - * struct componentname *a_cnp) - */ -static int -union_link(struct vop_old_link_args *ap) -{ - struct componentname *cnp = ap->a_cnp; - struct thread *td = cnp->cn_td; - struct union_node *dun = VTOUNION(ap->a_tdvp); - struct vnode *vp; - struct vnode *tdvp; - int error = 0; - - if (ap->a_tdvp->v_ops != ap->a_vp->v_ops) { - vp = ap->a_vp; - } else { - struct union_node *tun = VTOUNION(ap->a_vp); - - if (tun->un_uppervp == NULLVP) { - vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); -#if 0 - if (dun->un_uppervp == tun->un_dirvp) { - if (dun->un_flags & UN_ULOCK) { - dun->un_flags &= ~UN_ULOCK; - vn_unlock(dun->un_uppervp); - } - } -#endif - error = union_copyup(tun, 1, cnp->cn_cred, td); -#if 0 - if (dun->un_uppervp == tun->un_dirvp) { - vn_lock(dun->un_uppervp, - LK_EXCLUSIVE | LK_RETRY); - dun->un_flags |= UN_ULOCK; - } -#endif - vn_unlock(ap->a_vp); - } - vp = tun->un_uppervp; - } - - if (error) - return (error); - - /* - * Make sure upper is locked, then unlock the union directory we were - * called with to avoid a deadlock while we are calling VOP_LINK on - * the upper (with tdvp locked and vp not locked). Our ap->a_tdvp - * is expected to be locked on return. - */ - - if ((tdvp = union_lock_upper(dun, td)) == NULLVP) - return (EROFS); - - vn_unlock(ap->a_tdvp); /* unlock calling node */ - error = VOP_LINK(tdvp, vp, cnp); /* call link on upper */ - - /* - * We have to unlock tdvp prior to relocking our calling node in - * order to avoid a deadlock. - */ - union_unlock_upper(tdvp, td); - vn_lock(ap->a_tdvp, LK_EXCLUSIVE | LK_RETRY); - return (error); -} - -/* - * union_rename(struct vnode *a_fdvp, struct vnode *a_fvp, - * struct componentname *a_fcnp, struct vnode *a_tdvp, - * struct vnode *a_tvp, struct componentname *a_tcnp) - */ -static int -union_rename(struct vop_old_rename_args *ap) -{ - int error; - struct vnode *fdvp = ap->a_fdvp; - struct vnode *fvp = ap->a_fvp; - struct vnode *tdvp = ap->a_tdvp; - struct vnode *tvp = ap->a_tvp; - - /* - * Figure out what fdvp to pass to our upper or lower vnode. If we - * replace the fdvp, release the original one and ref the new one. - */ - - if (fdvp->v_tag == VT_UNION) { /* always true */ - struct union_node *un = VTOUNION(fdvp); - if (un->un_uppervp == NULLVP) { - /* - * this should never happen in normal - * operation but might if there was - * a problem creating the top-level shadow - * directory. - */ - error = EXDEV; - goto bad; - } - fdvp = un->un_uppervp; - vref(fdvp); - vrele(ap->a_fdvp); - } - - /* - * Figure out what fvp to pass to our upper or lower vnode. If we - * replace the fvp, release the original one and ref the new one. - */ - - if (fvp->v_tag == VT_UNION) { /* always true */ - struct union_node *un = VTOUNION(fvp); -#if 0 - struct union_mount *um = MOUNTTOUNIONMOUNT(fvp->v_mount); -#endif - - if (un->un_uppervp == NULLVP) { - switch(fvp->v_type) { - case VREG: - vn_lock(un->un_vnode, LK_EXCLUSIVE | LK_RETRY); - error = union_copyup(un, 1, ap->a_fcnp->cn_cred, ap->a_fcnp->cn_td); - vn_unlock(un->un_vnode); - if (error) - goto bad; - break; - case VDIR: - /* - * XXX not yet. - * - * There is only one way to rename a directory - * based in the lowervp, and that is to copy - * the entire directory hierarchy. Otherwise - * it would not last across a reboot. - */ -#if 0 - vrele(fvp); - fvp = NULL; - vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY); - error = union_mkshadow(um, fdvp, - ap->a_fcnp, &un->un_uppervp); - vn_unlock(fdvp); - if (un->un_uppervp) - vn_unlock(un->un_uppervp); - if (error) - goto bad; - break; -#endif - default: - error = EXDEV; - goto bad; - } - } - - if (un->un_lowervp != NULLVP) - ap->a_fcnp->cn_flags |= CNP_DOWHITEOUT; - fvp = un->un_uppervp; - vref(fvp); - vrele(ap->a_fvp); - } - - /* - * Figure out what tdvp (destination directory) to pass to the - * lower level. If we replace it with uppervp, we need to vput the - * old one. The exclusive lock is transfered to what we will pass - * down in the VOP_RENAME and we replace uppervp with a simple - * reference. - */ - - if (tdvp->v_tag == VT_UNION) { - struct union_node *un = VTOUNION(tdvp); - - if (un->un_uppervp == NULLVP) { - /* - * this should never happen in normal - * operation but might if there was - * a problem creating the top-level shadow - * directory. - */ - error = EXDEV; - goto bad; - } - - /* - * new tdvp is a lock and reference on uppervp, put away - * the old tdvp. - */ - tdvp = union_lock_upper(un, ap->a_tcnp->cn_td); - vput(ap->a_tdvp); - } - - /* - * Figure out what tvp (destination file) to pass to the - * lower level. - * - * If the uppervp file does not exist put away the (wrong) - * file and change tvp to NULL. - */ - - if (tvp != NULLVP && tvp->v_tag == VT_UNION) { - struct union_node *un = VTOUNION(tvp); - - tvp = union_lock_upper(un, ap->a_tcnp->cn_td); - vput(ap->a_tvp); - /* note: tvp may be NULL */ - } - - /* - * VOP_RENAME releases/vputs prior to returning, so we have no - * cleanup to do. - */ - - return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp)); - - /* - * Error. We still have to release / vput the various elements. - */ - -bad: - vrele(fdvp); - if (fvp) - vrele(fvp); - vput(tdvp); - if (tvp != NULLVP) { - if (tvp != tdvp) - vput(tvp); - else - vrele(tvp); - } - return (error); -} - -/* - * union_mkdir(struct vnode *a_dvp, struct vnode **a_vpp, - * struct componentname *a_cnp, struct vattr *a_vap) - */ -static int -union_mkdir(struct vop_old_mkdir_args *ap) -{ - struct union_node *dun = VTOUNION(ap->a_dvp); - struct componentname *cnp = ap->a_cnp; - struct thread *td = cnp->cn_td; - struct vnode *upperdvp; - int error = EROFS; - - if ((upperdvp = union_lock_upper(dun, td)) != NULLVP) { - struct vnode *vp; - - error = VOP_MKDIR(upperdvp, &vp, cnp, ap->a_vap); - union_unlock_upper(upperdvp, td); - - if (error == 0) { - vn_unlock(vp); - UDEBUG(("ALLOCVP-2 FROM %p REFS %d\n", - vp, vp->v_refcnt)); - error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount, - ap->a_dvp, NULLVP, cnp, vp, NULLVP, 1); - UDEBUG(("ALLOCVP-2B FROM %p REFS %d\n", - *ap->a_vpp, vp->v_refcnt)); - } - } - return (error); -} - -/* - * union_rmdir(struct vnode *a_dvp, struct vnode *a_vp, - * struct componentname *a_cnp) - */ -static int -union_rmdir(struct vop_old_rmdir_args *ap) -{ - struct union_node *dun = VTOUNION(ap->a_dvp); - struct union_node *un = VTOUNION(ap->a_vp); - struct componentname *cnp = ap->a_cnp; - struct thread *td = cnp->cn_td; - struct vnode *upperdvp; - struct vnode *uppervp; - int error; - - if ((upperdvp = union_lock_upper(dun, td)) == NULLVP) - panic("union rmdir: null upper vnode"); - - if ((uppervp = union_lock_upper(un, td)) != NULLVP) { - if (union_dowhiteout(un, cnp->cn_cred, td)) - cnp->cn_flags |= CNP_DOWHITEOUT; - error = VOP_RMDIR(upperdvp, uppervp, ap->a_cnp); - union_unlock_upper(uppervp, td); - } else { - error = union_mkwhiteout( - MOUNTTOUNIONMOUNT(ap->a_dvp->v_mount), - dun->un_uppervp, ap->a_cnp, un->un_path); - } - union_unlock_upper(upperdvp, td); - return (error); -} - -/* - * union_symlink: - * - * dvp is locked on entry and remains locked on return. a_vpp is garbage - * (unused). - * - * union_symlink(struct vnode *a_dvp, struct vnode **a_vpp, - * struct componentname *a_cnp, struct vattr *a_vap, - * char *a_target) - */ -static int -union_symlink(struct vop_old_symlink_args *ap) -{ - struct union_node *dun = VTOUNION(ap->a_dvp); - struct componentname *cnp = ap->a_cnp; - struct thread *td = cnp->cn_td; - struct vnode *dvp; - int error = EROFS; - - if ((dvp = union_lock_upper(dun, td)) != NULLVP) { - error = VOP_SYMLINK(dvp, ap->a_vpp, cnp, ap->a_vap, - ap->a_target); - union_unlock_upper(dvp, td); - } - return (error); -} - -/* - * union_readdir works in concert with getdirentries and - * readdir(3) to provide a list of entries in the unioned - * directories. getdirentries is responsible for walking - * down the union stack. readdir(3) is responsible for - * eliminating duplicate names from the returned data stream. - * - * union_readdir(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred, - * int *a_eofflag, off_t *a_cookies, int a_ncookies) - */ -static int -union_readdir(struct vop_readdir_args *ap) -{ - struct union_node *un = VTOUNION(ap->a_vp); - struct thread *td = ap->a_uio->uio_td; - struct vnode *uvp; - int error = 0; - - if ((uvp = union_ref_upper(un)) != NULLVP) { - ap->a_head.a_ops = *uvp->v_ops; - ap->a_vp = uvp; - error = vop_readdir_ap(ap); - vrele(uvp); - } - return(error); -} - -/* - * union_readlink(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred) - */ -static int -union_readlink(struct vop_readlink_args *ap) -{ - int error; - struct union_node *un = VTOUNION(ap->a_vp); - struct uio *uio = ap->a_uio; - struct thread *td = uio->uio_td; - struct vnode *vp; - - vp = union_lock_other(un, td); - KASSERT(vp != NULL, ("union_readlink: backing vnode missing!")); - - ap->a_head.a_ops = *vp->v_ops; - ap->a_vp = vp; - error = vop_readlink_ap(ap); - union_unlock_other(vp, td); - - return (error); -} - -/* - * union_inactive: - * - * Called with the vnode locked. We are expected to unlock the vnode. - * - * union_inactive(struct vnode *a_vp, struct thread *a_td) - */ -static int -union_inactive(struct vop_inactive_args *ap) -{ - struct vnode *vp = ap->a_vp; - /*struct thread *td = ap->a_td;*/ - struct union_node *un = VTOUNION(vp); - struct vnode **vpp; - - /* - * Do nothing (and _don't_ bypass). - * Wait to vrele lowervp until reclaim, - * so that until then our union_node is in the - * cache and reusable. - * - * NEEDSWORK: Someday, consider inactive'ing - * the lowervp and then trying to reactivate it - * with capabilities (v_id) - * like they do in the name lookup cache code. - * That's too much work for now. - */ - - if (un->un_dircache != 0) { - for (vpp = un->un_dircache; *vpp != NULLVP; vpp++) - vrele(*vpp); - kfree (un->un_dircache, M_TEMP); - un->un_dircache = 0; - } - -#if 0 - if ((un->un_flags & UN_ULOCK) && un->un_uppervp) { - un->un_flags &= ~UN_ULOCK; - vn_unlock(un->un_uppervp); - } -#endif - - if ((un->un_flags & UN_CACHED) == 0) - vgone_vxlocked(vp); - - return (0); -} - -/* - * union_reclaim(struct vnode *a_vp) - */ -static int -union_reclaim(struct vop_reclaim_args *ap) -{ - union_freevp(ap->a_vp); - - return (0); -} - -/* - * union_bmap: - * - * There isn't much we can do. We cannot push through to the real vnode - * to get to the underlying device because this will bypass data - * cached by the real vnode. - * - * For some reason we cannot return the 'real' vnode either, it seems - * to blow up memory maps. - * - * union_bmap(struct vnode *a_vp, off_t a_loffset, - * off_t *a_doffsetp, int *a_runp, int *a_runb) - */ -static int -union_bmap(struct vop_bmap_args *ap) -{ - return(EOPNOTSUPP); -} - -/* - * union_print(struct vnode *a_vp) - */ -static int -union_print(struct vop_print_args *ap) -{ - struct vnode *vp = ap->a_vp; - - kprintf("\ttag VT_UNION, vp=%p, uppervp=%p, lowervp=%p\n", - vp, UPPERVP(vp), LOWERVP(vp)); - if (UPPERVP(vp) != NULLVP) - vprint("union: upper", UPPERVP(vp)); - if (LOWERVP(vp) != NULLVP) - vprint("union: lower", LOWERVP(vp)); - - return (0); -} - -/* - * union_pathconf(struct vnode *a_vp, int a_name, int *a_retval) - */ -static int -union_pathconf(struct vop_pathconf_args *ap) -{ - int error; - struct thread *td = curthread; /* XXX */ - struct union_node *un = VTOUNION(ap->a_vp); - struct vnode *vp; - - vp = union_lock_other(un, td); - KASSERT(vp != NULL, ("union_pathconf: backing vnode missing!")); - - ap->a_head.a_ops = *vp->v_ops; - ap->a_vp = vp; - error = vop_pathconf_ap(ap); - union_unlock_other(vp, td); - - return (error); -} - -/* - * union_advlock(struct vnode *a_vp, caddr_t a_id, int a_op, - * struct flock *a_fl, int a_flags) - */ -static int -union_advlock(struct vop_advlock_args *ap) -{ - struct vnode *ovp = OTHERVP(ap->a_vp); - - ap->a_head.a_ops = *ovp->v_ops; - ap->a_vp = ovp; - return (vop_advlock_ap(ap)); -} - - -/* - * XXX - vop_strategy must be hand coded because it has no - * YYY - and it is not coherent with anything - * - * vnode in its arguments. - * This goes away with a merged VM/buffer cache. - * - * union_strategy(struct vnode *a_vp, struct bio *a_bio) - */ -static int -union_strategy(struct vop_strategy_args *ap) -{ - struct bio *bio = ap->a_bio; - struct buf *bp = bio->bio_buf; - struct vnode *othervp = OTHERVP(ap->a_vp); - -#ifdef DIAGNOSTIC - if (othervp == NULLVP) - panic("union_strategy: nil vp"); - if (bp->b_cmd != BUF_CMD_READ && (othervp == LOWERVP(ap->a_vp))) - panic("union_strategy: writing to lowervp"); -#endif - return (vn_strategy(othervp, bio)); -} - -/* - * Global vfs data structures - */ -struct vop_ops union_vnode_vops = { - .vop_default = vop_defaultop, - .vop_access = union_access, - .vop_advlock = union_advlock, - .vop_bmap = union_bmap, - .vop_close = union_close, - .vop_old_create = union_create, - .vop_fsync = union_fsync, - .vop_getpages = union_getpages, - .vop_putpages = union_putpages, - .vop_getattr = union_getattr, - .vop_inactive = union_inactive, - .vop_ioctl = union_ioctl, - .vop_old_link = union_link, - .vop_old_lookup = union_lookup, - .vop_old_mkdir = union_mkdir, - .vop_old_mknod = union_mknod, - .vop_mmap = union_mmap, - .vop_open = union_open, - .vop_pathconf = union_pathconf, - .vop_poll = union_poll, - .vop_print = union_print, - .vop_read = union_read, - .vop_readdir = union_readdir, - .vop_readlink = union_readlink, - .vop_reclaim = union_reclaim, - .vop_old_remove = union_remove, - .vop_old_rename = union_rename, - .vop_old_rmdir = union_rmdir, - .vop_setattr = union_setattr, - .vop_strategy = union_strategy, - .vop_old_symlink = union_symlink, - .vop_old_whiteout = union_whiteout, - .vop_write = union_write -}; - diff --git a/test/stress/stress2/misc/all.sh b/test/stress/stress2/misc/all.sh index dabb79249a..00c455db82 100755 --- a/test/stress/stress2/misc/all.sh +++ b/test/stress/stress2/misc/all.sh @@ -115,9 +115,6 @@ # umountf2.sh N Waiting for commit of fix # umountf3.sh N Deadlock. Waiting for commit of fix 20081212 # umountf4.sh Y Page fault in ufs/ufs/ufs_dirhash.c:204 20081003 -# unionfs.sh N Page fault 20070503 -# unionfs2.sh N Reported as cons224 20070504 -# unionfs3.sh N Page fault in vfs_statfs 20070504 # End of list diff --git a/test/stress/stress2/misc/union.sh b/test/stress/stress2/misc/union.sh deleted file mode 100755 index c02dac6e6a..0000000000 --- a/test/stress/stress2/misc/union.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 2009 Peter Holm -# 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$ -# - -# Simple union test scenario - -[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 - -. ../default.cfg - -u1=$mdstart -u2=$((u1 + 1)) -[ -d mp1 ] || mkdir mp1 - -mount | grep -q /dev/md${u2}$part && umount -f /dev/md${u2}$part -mount | grep -q /dev/md${u1}$part && umount -f /dev/md${u1}$part -mdconfig -l | grep -q md${u2} && mdconfig -d -u $u2 -mdconfig -l | grep -q md${u1} && mdconfig -d -u $u1 - -mdconfig -s 256m -u $u1 -bsdlabel -w md$u1 auto -newfs md${u1}${part} > /dev/null - -mdconfig -s 256m -u $u2 -bsdlabel -w md$u2 auto -newfs md${u2}${part} > /dev/null - -mount -o ro /dev/md${u1}$part mp1 -mount -o union /dev/md${u2}$part mp1 - -export RUNDIR=`pwd`/mp1/stressX -export runRUNTIME=10m -(cd ..; ./run.sh marcus.cfg) - -umount /dev/md${u2}$part -umount /dev/md${u1}$part - -mount | grep -q /dev/md${u2}$part && umount -f /dev/md${u2}$part -mount | grep -q /dev/md${u1}$part && umount -f /dev/md${u1}$part - -mdconfig -d -u $u2 -mdconfig -d -u $u1 - -rm -rf mp1 diff --git a/test/stress/stress2/misc/unionfs.sh b/test/stress/stress2/misc/unionfs.sh deleted file mode 100755 index 68f7c5ebde..0000000000 --- a/test/stress/stress2/misc/unionfs.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 2008 Peter Holm -# 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$ -# - -[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 - -# Causes this: panic: mutex Giant not owned at ../../../kern/vfs_subr.c:1968 -# with a kernel compiled with "options QUOTA" - -D=/usr/tmp/diskimage -truncate -s 256M $D - -mount | grep "/mnt" | grep md0c > /dev/null && umount /mnt -mdconfig -l | grep md0 > /dev/null && mdconfig -d -u 0 - -mdconfig -a -t vnode -f $D -u 0 -bsdlabel -w md0 auto -newfs -U md0c > /dev/null -mount /dev/md0c /mnt -mount -t unionfs -o noatime /mnt /tmp -export RUNDIR=/tmp/stressX -export runRUNTIME=10m # Run tests for 10 minutes -(cd /home/pho/stress2; ./run.sh disk.cfg) -mount | grep "/mnt" | grep md0c > /dev/null && umount /mnt -mount | grep "/mnt" | grep md0c > /dev/null && umount -f /mnt -mdconfig -d -u 0 -rm -f $D diff --git a/test/stress/stress2/misc/unionfs2.sh b/test/stress/stress2/misc/unionfs2.sh deleted file mode 100755 index 5960082d95..0000000000 --- a/test/stress/stress2/misc/unionfs2.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 2008 Peter Holm -# 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$ -# - -[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 - -saved=`sysctl vfs.lookup_shared | awk '{print $NF}'` -for i in 1 0; do - sysctl vfs.lookup_shared=$i - [ -d /var/tmp/unionfs ] || mkdir -p /var/tmp/unionfs - mount_unionfs /var/tmp/unionfs /tmp/stressX - - export RUNDIR=/var/tmp/unionfs/stressX - export runRUNTIME=10m # Run tests for 10 minutes - (cd /home/pho/stress2; ./run.sh disk.cfg) - false - while mount | grep -q /unionfs; do - umount /tmp/stressX > /dev/null 2>&1 - done - rm -rf /var/tmp/unionfs -done -sysctl vfs.lookup_shared=$saved diff --git a/test/stress/stress2/misc/unionfs3.sh b/test/stress/stress2/misc/unionfs3.sh deleted file mode 100755 index f3cd77b492..0000000000 --- a/test/stress/stress2/misc/unionfs3.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 2008 Peter Holm -# 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$ -# - -[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 - -# Test with interchanged arguments to mount_unionfs -# Causes page fault in vfs_mount.c:1975 - -D=/usr/tmp/diskimage -truncate -s 256M $D - -mount | grep "/mnt" | grep md0c > /dev/null && umount /mnt -mdconfig -l | grep md0 > /dev/null && mdconfig -d -u 0 - -mdconfig -a -t vnode -f $D -u 0 -bsdlabel -w md0 auto -newfs -U md0c > /dev/null -mount /dev/md0c /mnt -mount -t unionfs -o noatime /tmp /mnt -umount -f /tmp # panic -mount /tmp -mount | grep "/mnt" | grep md0c > /dev/null && umount /mnt -mount | grep "/mnt" | grep md0c > /dev/null && umount -f /mnt -mdconfig -d -u 0 -rm -f $D diff --git a/usr.sbin/pstat/pstat.c b/usr.sbin/pstat/pstat.c index 75500e1fe7..d1769e351e 100644 --- a/usr.sbin/pstat/pstat.c +++ b/usr.sbin/pstat/pstat.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -117,7 +116,6 @@ struct { { MNT_NOEXEC, "noexec" }, { MNT_NOSUID, "nosuid" }, { MNT_NODEV, "nodev" }, - { MNT_UNION, "union" }, { MNT_ASYNC, "async" }, { MNT_SUIDDIR, "suiddir" }, { MNT_SOFTDEP, "softdep" }, @@ -181,8 +179,6 @@ void ttyprt(struct tty *, int); void ttytype(struct tty *, const char *, int, int, int); void ufs_header(void); int ufs_print(struct vnode *); -void union_header(void); -int union_print(struct vnode *); static void usage(void); void vnode_header(void); void vnode_print(struct vnode *, struct vnode *); @@ -349,8 +345,6 @@ vnodemode(void) ufs_header(); else if (!strcmp(ST.f_fstypename, "nfs")) nfs_header(); - else if (!strcmp(ST.f_fstypename, "union")) - union_header(); printf("\n"); } vnode_print(evp->avnode, vp); @@ -359,8 +353,6 @@ vnodemode(void) ufs_print(vp); else if (!strcmp(ST.f_fstypename, "nfs")) nfs_print(vp); - else if (!strcmp(ST.f_fstypename, "union")) - union_print(vp); printf("\n"); } free(e_vnodebase); @@ -563,24 +555,6 @@ nfs_print(struct vnode *vp) return (0); } -void -union_header(void) -{ - printf(" UPPER LOWER"); -} - -int -union_print(struct vnode *vp) -{ - struct union_node unode, *up = &unode; - - KGETRET(VTOUNION(vp), &unode, sizeof(unode), "vnode's unode"); - - printf(" %8lx %8lx", (u_long)(void *)up->un_uppervp, - (u_long)(void *)up->un_lowervp); - return (0); -} - /* * Given a pointer to a mount structure in kernel space, * read it in and return a usable pointer to it.