1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1994 The Regents of the University of California. 3df8bae1dSRodney W. Grimes * Copyright (c) 1994 Jan-Simon Pendry. 4df8bae1dSRodney W. Grimes * All rights reserved. 5df8bae1dSRodney W. Grimes * 6df8bae1dSRodney W. Grimes * This code is derived from software donated to Berkeley by 7df8bae1dSRodney W. Grimes * Jan-Simon Pendry. 8df8bae1dSRodney W. Grimes * 9df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 10df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 11df8bae1dSRodney W. Grimes * are met: 12df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 13df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 14df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 15df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 16df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 17df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 18df8bae1dSRodney W. Grimes * must display the following acknowledgement: 19df8bae1dSRodney W. Grimes * This product includes software developed by the University of 20df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 21df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 22df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 23df8bae1dSRodney W. Grimes * without specific prior written permission. 24df8bae1dSRodney W. Grimes * 25df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35df8bae1dSRodney W. Grimes * SUCH DAMAGE. 36df8bae1dSRodney W. Grimes * 37df8bae1dSRodney W. Grimes * @(#)union_vfsops.c 8.7 (Berkeley) 3/5/94 38c9b1d604SGarrett Wollman * $Id: union_vfsops.c,v 1.4 1994/09/21 03:47:13 wollman Exp $ 39df8bae1dSRodney W. Grimes */ 40df8bae1dSRodney W. Grimes 41df8bae1dSRodney W. Grimes /* 42df8bae1dSRodney W. Grimes * Union Layer 43df8bae1dSRodney W. Grimes */ 44df8bae1dSRodney W. Grimes 45df8bae1dSRodney W. Grimes #include <sys/param.h> 46df8bae1dSRodney W. Grimes #include <sys/systm.h> 47c9b1d604SGarrett Wollman #include <sys/kernel.h> 48df8bae1dSRodney W. Grimes #include <sys/time.h> 49df8bae1dSRodney W. Grimes #include <sys/types.h> 50df8bae1dSRodney W. Grimes #include <sys/proc.h> 51df8bae1dSRodney W. Grimes #include <sys/vnode.h> 52df8bae1dSRodney W. Grimes #include <sys/mount.h> 53df8bae1dSRodney W. Grimes #include <sys/namei.h> 54df8bae1dSRodney W. Grimes #include <sys/malloc.h> 55df8bae1dSRodney W. Grimes #include <sys/filedesc.h> 56df8bae1dSRodney W. Grimes #include <sys/queue.h> 57df8bae1dSRodney W. Grimes #include <miscfs/union/union.h> 58df8bae1dSRodney W. Grimes 59df8bae1dSRodney W. Grimes /* 60df8bae1dSRodney W. Grimes * Mount union filesystem 61df8bae1dSRodney W. Grimes */ 62df8bae1dSRodney W. Grimes int 63df8bae1dSRodney W. Grimes union_mount(mp, path, data, ndp, p) 64df8bae1dSRodney W. Grimes struct mount *mp; 65df8bae1dSRodney W. Grimes char *path; 66df8bae1dSRodney W. Grimes caddr_t data; 67df8bae1dSRodney W. Grimes struct nameidata *ndp; 68df8bae1dSRodney W. Grimes struct proc *p; 69df8bae1dSRodney W. Grimes { 70df8bae1dSRodney W. Grimes int error = 0; 71df8bae1dSRodney W. Grimes struct union_args args; 72df8bae1dSRodney W. Grimes struct vnode *lowerrootvp = NULLVP; 73df8bae1dSRodney W. Grimes struct vnode *upperrootvp = NULLVP; 74df8bae1dSRodney W. Grimes struct union_mount *um; 75df8bae1dSRodney W. Grimes struct ucred *cred = 0; 76df8bae1dSRodney W. Grimes struct ucred *scred; 77df8bae1dSRodney W. Grimes struct vattr va; 7826f9a767SRodney W. Grimes char *cp = 0; 79df8bae1dSRodney W. Grimes int len; 80df8bae1dSRodney W. Grimes u_int size; 81df8bae1dSRodney W. Grimes 82df8bae1dSRodney W. Grimes #ifdef UNION_DIAGNOSTIC 83df8bae1dSRodney W. Grimes printf("union_mount(mp = %x)\n", mp); 84df8bae1dSRodney W. Grimes #endif 85df8bae1dSRodney W. Grimes 86df8bae1dSRodney W. Grimes /* 87df8bae1dSRodney W. Grimes * Update is a no-op 88df8bae1dSRodney W. Grimes */ 89df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_UPDATE) { 90df8bae1dSRodney W. Grimes /* 91df8bae1dSRodney W. Grimes * Need to provide. 92df8bae1dSRodney W. Grimes * 1. a way to convert between rdonly and rdwr mounts. 93df8bae1dSRodney W. Grimes * 2. support for nfs exports. 94df8bae1dSRodney W. Grimes */ 95df8bae1dSRodney W. Grimes error = EOPNOTSUPP; 96df8bae1dSRodney W. Grimes goto bad; 97df8bae1dSRodney W. Grimes } 98df8bae1dSRodney W. Grimes 99df8bae1dSRodney W. Grimes /* 100df8bae1dSRodney W. Grimes * Take a copy of the process's credentials. This isn't 101df8bae1dSRodney W. Grimes * quite right since the euid will always be zero and we 102df8bae1dSRodney W. Grimes * want to get the "real" users credentials. So fix up 103df8bae1dSRodney W. Grimes * the uid field after taking the copy. 104df8bae1dSRodney W. Grimes */ 105df8bae1dSRodney W. Grimes cred = crdup(p->p_ucred); 106df8bae1dSRodney W. Grimes cred->cr_uid = p->p_cred->p_ruid; 107df8bae1dSRodney W. Grimes 108df8bae1dSRodney W. Grimes /* 109df8bae1dSRodney W. Grimes * Ensure the *real* user has write permission on the 110df8bae1dSRodney W. Grimes * mounted-on directory. This allows the mount_union 111df8bae1dSRodney W. Grimes * command to be made setuid root so allowing anyone 112df8bae1dSRodney W. Grimes * to do union mounts onto any directory on which they 113df8bae1dSRodney W. Grimes * have write permission and which they also own. 114df8bae1dSRodney W. Grimes */ 115df8bae1dSRodney W. Grimes error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p); 116df8bae1dSRodney W. Grimes if (error) 117df8bae1dSRodney W. Grimes goto bad; 118df8bae1dSRodney W. Grimes if ((va.va_uid != cred->cr_uid) && 119df8bae1dSRodney W. Grimes (cred->cr_uid != 0)) { 120df8bae1dSRodney W. Grimes error = EACCES; 121df8bae1dSRodney W. Grimes goto bad; 122df8bae1dSRodney W. Grimes } 123df8bae1dSRodney W. Grimes error = VOP_ACCESS(mp->mnt_vnodecovered, VWRITE, cred, p); 124df8bae1dSRodney W. Grimes if (error) 125df8bae1dSRodney W. Grimes goto bad; 126df8bae1dSRodney W. Grimes 127df8bae1dSRodney W. Grimes /* 128df8bae1dSRodney W. Grimes * Get argument 129df8bae1dSRodney W. Grimes */ 130df8bae1dSRodney W. Grimes if (error = copyin(data, (caddr_t)&args, sizeof(struct union_args))) 131df8bae1dSRodney W. Grimes goto bad; 132df8bae1dSRodney W. Grimes 133df8bae1dSRodney W. Grimes lowerrootvp = mp->mnt_vnodecovered; 134df8bae1dSRodney W. Grimes VREF(lowerrootvp); 135df8bae1dSRodney W. Grimes 136df8bae1dSRodney W. Grimes /* 137df8bae1dSRodney W. Grimes * Find upper node. Use the real process credentials, 138df8bae1dSRodney W. Grimes * not the effective ones since this will have come 139df8bae1dSRodney W. Grimes * through a setuid process (mount_union). All this 140df8bae1dSRodney W. Grimes * messing around with permissions is entirely bogus 141df8bae1dSRodney W. Grimes * and should be removed by allowing any user straight 142df8bae1dSRodney W. Grimes * past the mount system call. 143df8bae1dSRodney W. Grimes */ 144df8bae1dSRodney W. Grimes scred = p->p_ucred; 145df8bae1dSRodney W. Grimes p->p_ucred = cred; 146df8bae1dSRodney W. Grimes NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT, 147df8bae1dSRodney W. Grimes UIO_USERSPACE, args.target, p); 148df8bae1dSRodney W. Grimes p->p_ucred = scred; 149df8bae1dSRodney W. Grimes 150df8bae1dSRodney W. Grimes if (error = namei(ndp)) 151df8bae1dSRodney W. Grimes goto bad; 152df8bae1dSRodney W. Grimes 153df8bae1dSRodney W. Grimes upperrootvp = ndp->ni_vp; 154df8bae1dSRodney W. Grimes vrele(ndp->ni_dvp); 155df8bae1dSRodney W. Grimes ndp->ni_dvp = NULL; 156df8bae1dSRodney W. Grimes 157df8bae1dSRodney W. Grimes if (upperrootvp->v_type != VDIR) { 158df8bae1dSRodney W. Grimes error = EINVAL; 159df8bae1dSRodney W. Grimes goto bad; 160df8bae1dSRodney W. Grimes } 161df8bae1dSRodney W. Grimes 162df8bae1dSRodney W. Grimes um = (struct union_mount *) malloc(sizeof(struct union_mount), 163df8bae1dSRodney W. Grimes M_UFSMNT, M_WAITOK); /* XXX */ 164df8bae1dSRodney W. Grimes 165df8bae1dSRodney W. Grimes /* 166df8bae1dSRodney W. Grimes * Keep a held reference to the target vnodes. 167df8bae1dSRodney W. Grimes * They are vrele'd in union_unmount. 168df8bae1dSRodney W. Grimes * 169df8bae1dSRodney W. Grimes * Depending on the _BELOW flag, the filesystems are 170df8bae1dSRodney W. Grimes * viewed in a different order. In effect, this is the 171df8bae1dSRodney W. Grimes * same as providing a mount under option to the mount syscall. 172df8bae1dSRodney W. Grimes */ 173df8bae1dSRodney W. Grimes 174df8bae1dSRodney W. Grimes um->um_op = args.mntflags & UNMNT_OPMASK; 175df8bae1dSRodney W. Grimes switch (um->um_op) { 176df8bae1dSRodney W. Grimes case UNMNT_ABOVE: 177df8bae1dSRodney W. Grimes um->um_lowervp = lowerrootvp; 178df8bae1dSRodney W. Grimes um->um_uppervp = upperrootvp; 179df8bae1dSRodney W. Grimes break; 180df8bae1dSRodney W. Grimes 181df8bae1dSRodney W. Grimes case UNMNT_BELOW: 182df8bae1dSRodney W. Grimes um->um_lowervp = upperrootvp; 183df8bae1dSRodney W. Grimes um->um_uppervp = lowerrootvp; 184df8bae1dSRodney W. Grimes break; 185df8bae1dSRodney W. Grimes 186df8bae1dSRodney W. Grimes case UNMNT_REPLACE: 187df8bae1dSRodney W. Grimes vrele(lowerrootvp); 188df8bae1dSRodney W. Grimes lowerrootvp = NULLVP; 189df8bae1dSRodney W. Grimes um->um_uppervp = upperrootvp; 190df8bae1dSRodney W. Grimes um->um_lowervp = lowerrootvp; 191df8bae1dSRodney W. Grimes break; 192df8bae1dSRodney W. Grimes 193df8bae1dSRodney W. Grimes default: 194df8bae1dSRodney W. Grimes error = EINVAL; 195df8bae1dSRodney W. Grimes goto bad; 196df8bae1dSRodney W. Grimes } 197df8bae1dSRodney W. Grimes 198df8bae1dSRodney W. Grimes um->um_cred = cred; 199df8bae1dSRodney W. Grimes um->um_cmode = UN_DIRMODE &~ p->p_fd->fd_cmask; 200df8bae1dSRodney W. Grimes 201df8bae1dSRodney W. Grimes /* 202df8bae1dSRodney W. Grimes * Depending on what you think the MNT_LOCAL flag might mean, 203df8bae1dSRodney W. Grimes * you may want the && to be || on the conditional below. 204df8bae1dSRodney W. Grimes * At the moment it has been defined that the filesystem is 205df8bae1dSRodney W. Grimes * only local if it is all local, ie the MNT_LOCAL flag implies 206df8bae1dSRodney W. Grimes * that the entire namespace is local. If you think the MNT_LOCAL 207df8bae1dSRodney W. Grimes * flag implies that some of the files might be stored locally 208df8bae1dSRodney W. Grimes * then you will want to change the conditional. 209df8bae1dSRodney W. Grimes */ 210df8bae1dSRodney W. Grimes if (um->um_op == UNMNT_ABOVE) { 211df8bae1dSRodney W. Grimes if (((um->um_lowervp == NULLVP) || 212df8bae1dSRodney W. Grimes (um->um_lowervp->v_mount->mnt_flag & MNT_LOCAL)) && 213df8bae1dSRodney W. Grimes (um->um_uppervp->v_mount->mnt_flag & MNT_LOCAL)) 214df8bae1dSRodney W. Grimes mp->mnt_flag |= MNT_LOCAL; 215df8bae1dSRodney W. Grimes } 216df8bae1dSRodney W. Grimes 217df8bae1dSRodney W. Grimes /* 218df8bae1dSRodney W. Grimes * Copy in the upper layer's RDONLY flag. This is for the benefit 219df8bae1dSRodney W. Grimes * of lookup() which explicitly checks the flag, rather than asking 220df8bae1dSRodney W. Grimes * the filesystem for it's own opinion. This means, that an update 221df8bae1dSRodney W. Grimes * mount of the underlying filesystem to go from rdonly to rdwr 222df8bae1dSRodney W. Grimes * will leave the unioned view as read-only. 223df8bae1dSRodney W. Grimes */ 224df8bae1dSRodney W. Grimes mp->mnt_flag |= (um->um_uppervp->v_mount->mnt_flag & MNT_RDONLY); 225df8bae1dSRodney W. Grimes 226df8bae1dSRodney W. Grimes /* 227df8bae1dSRodney W. Grimes * This is a user mount. Privilege check for unmount 228df8bae1dSRodney W. Grimes * will be done in union_unmount. 229df8bae1dSRodney W. Grimes */ 230df8bae1dSRodney W. Grimes mp->mnt_flag |= MNT_USER; 231df8bae1dSRodney W. Grimes 232df8bae1dSRodney W. Grimes mp->mnt_data = (qaddr_t) um; 233df8bae1dSRodney W. Grimes getnewfsid(mp, MOUNT_UNION); 234df8bae1dSRodney W. Grimes 235df8bae1dSRodney W. Grimes (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 236df8bae1dSRodney W. Grimes bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 237df8bae1dSRodney W. Grimes 238df8bae1dSRodney W. Grimes switch (um->um_op) { 239df8bae1dSRodney W. Grimes case UNMNT_ABOVE: 240df8bae1dSRodney W. Grimes cp = "<above>"; 241df8bae1dSRodney W. Grimes break; 242df8bae1dSRodney W. Grimes case UNMNT_BELOW: 243df8bae1dSRodney W. Grimes cp = "<below>"; 244df8bae1dSRodney W. Grimes break; 245df8bae1dSRodney W. Grimes case UNMNT_REPLACE: 246df8bae1dSRodney W. Grimes cp = ""; 247df8bae1dSRodney W. Grimes break; 248df8bae1dSRodney W. Grimes } 249df8bae1dSRodney W. Grimes len = strlen(cp); 250df8bae1dSRodney W. Grimes bcopy(cp, mp->mnt_stat.f_mntfromname, len); 251df8bae1dSRodney W. Grimes 252df8bae1dSRodney W. Grimes cp = mp->mnt_stat.f_mntfromname + len; 253df8bae1dSRodney W. Grimes len = MNAMELEN - len; 254df8bae1dSRodney W. Grimes 255df8bae1dSRodney W. Grimes (void) copyinstr(args.target, cp, len - 1, &size); 256df8bae1dSRodney W. Grimes bzero(cp + size, len - size); 257df8bae1dSRodney W. Grimes 258df8bae1dSRodney W. Grimes #ifdef UNION_DIAGNOSTIC 259df8bae1dSRodney W. Grimes printf("union_mount: from %s, on %s\n", 260df8bae1dSRodney W. Grimes mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 261df8bae1dSRodney W. Grimes #endif 262df8bae1dSRodney W. Grimes return (0); 263df8bae1dSRodney W. Grimes 264df8bae1dSRodney W. Grimes bad: 265df8bae1dSRodney W. Grimes if (cred) 266df8bae1dSRodney W. Grimes crfree(cred); 267df8bae1dSRodney W. Grimes if (upperrootvp) 268df8bae1dSRodney W. Grimes vrele(upperrootvp); 269df8bae1dSRodney W. Grimes if (lowerrootvp) 270df8bae1dSRodney W. Grimes vrele(lowerrootvp); 271df8bae1dSRodney W. Grimes return (error); 272df8bae1dSRodney W. Grimes } 273df8bae1dSRodney W. Grimes 274df8bae1dSRodney W. Grimes /* 275df8bae1dSRodney W. Grimes * VFS start. Nothing needed here - the start routine 276df8bae1dSRodney W. Grimes * on the underlying filesystem(s) will have been called 277df8bae1dSRodney W. Grimes * when that filesystem was mounted. 278df8bae1dSRodney W. Grimes */ 279df8bae1dSRodney W. Grimes int 280df8bae1dSRodney W. Grimes union_start(mp, flags, p) 281df8bae1dSRodney W. Grimes struct mount *mp; 282df8bae1dSRodney W. Grimes int flags; 283df8bae1dSRodney W. Grimes struct proc *p; 284df8bae1dSRodney W. Grimes { 285df8bae1dSRodney W. Grimes 286df8bae1dSRodney W. Grimes return (0); 287df8bae1dSRodney W. Grimes } 288df8bae1dSRodney W. Grimes 289df8bae1dSRodney W. Grimes /* 290df8bae1dSRodney W. Grimes * Free reference to union layer 291df8bae1dSRodney W. Grimes */ 292df8bae1dSRodney W. Grimes int 293df8bae1dSRodney W. Grimes union_unmount(mp, mntflags, p) 294df8bae1dSRodney W. Grimes struct mount *mp; 295df8bae1dSRodney W. Grimes int mntflags; 296df8bae1dSRodney W. Grimes struct proc *p; 297df8bae1dSRodney W. Grimes { 298df8bae1dSRodney W. Grimes struct union_mount *um = MOUNTTOUNIONMOUNT(mp); 299df8bae1dSRodney W. Grimes struct vnode *um_rootvp; 300df8bae1dSRodney W. Grimes int error; 301df8bae1dSRodney W. Grimes int flags = 0; 302df8bae1dSRodney W. Grimes extern int doforce; 303df8bae1dSRodney W. Grimes 304df8bae1dSRodney W. Grimes #ifdef UNION_DIAGNOSTIC 305df8bae1dSRodney W. Grimes printf("union_unmount(mp = %x)\n", mp); 306df8bae1dSRodney W. Grimes #endif 307df8bae1dSRodney W. Grimes 308df8bae1dSRodney W. Grimes /* only the mounter, or superuser can unmount */ 309df8bae1dSRodney W. Grimes if ((p->p_cred->p_ruid != um->um_cred->cr_uid) && 310df8bae1dSRodney W. Grimes (error = suser(p->p_ucred, &p->p_acflag))) 311df8bae1dSRodney W. Grimes return (error); 312df8bae1dSRodney W. Grimes 313df8bae1dSRodney W. Grimes if (mntflags & MNT_FORCE) { 314df8bae1dSRodney W. Grimes /* union can never be rootfs so don't check for it */ 315df8bae1dSRodney W. Grimes if (!doforce) 316df8bae1dSRodney W. Grimes return (EINVAL); 317df8bae1dSRodney W. Grimes flags |= FORCECLOSE; 318df8bae1dSRodney W. Grimes } 319df8bae1dSRodney W. Grimes 320df8bae1dSRodney W. Grimes if (error = union_root(mp, &um_rootvp)) 321df8bae1dSRodney W. Grimes return (error); 322df8bae1dSRodney W. Grimes if (um_rootvp->v_usecount > 1) { 323df8bae1dSRodney W. Grimes vput(um_rootvp); 324df8bae1dSRodney W. Grimes return (EBUSY); 325df8bae1dSRodney W. Grimes } 326df8bae1dSRodney W. Grimes if (error = vflush(mp, um_rootvp, flags)) { 327df8bae1dSRodney W. Grimes vput(um_rootvp); 328df8bae1dSRodney W. Grimes return (error); 329df8bae1dSRodney W. Grimes } 330df8bae1dSRodney W. Grimes 331df8bae1dSRodney W. Grimes #ifdef UNION_DIAGNOSTIC 332df8bae1dSRodney W. Grimes vprint("alias root of lower", um_rootvp); 333df8bae1dSRodney W. Grimes #endif 334df8bae1dSRodney W. Grimes /* 335df8bae1dSRodney W. Grimes * Discard references to upper and lower target vnodes. 336df8bae1dSRodney W. Grimes */ 337df8bae1dSRodney W. Grimes if (um->um_lowervp) 338df8bae1dSRodney W. Grimes vrele(um->um_lowervp); 339df8bae1dSRodney W. Grimes vrele(um->um_uppervp); 340df8bae1dSRodney W. Grimes crfree(um->um_cred); 341df8bae1dSRodney W. Grimes /* 342df8bae1dSRodney W. Grimes * Release reference on underlying root vnode 343df8bae1dSRodney W. Grimes */ 344df8bae1dSRodney W. Grimes vput(um_rootvp); 345df8bae1dSRodney W. Grimes /* 346df8bae1dSRodney W. Grimes * And blow it away for future re-use 347df8bae1dSRodney W. Grimes */ 348df8bae1dSRodney W. Grimes vgone(um_rootvp); 349df8bae1dSRodney W. Grimes /* 350df8bae1dSRodney W. Grimes * Finally, throw away the union_mount structure 351df8bae1dSRodney W. Grimes */ 352df8bae1dSRodney W. Grimes free(mp->mnt_data, M_UFSMNT); /* XXX */ 353df8bae1dSRodney W. Grimes mp->mnt_data = 0; 354df8bae1dSRodney W. Grimes return (0); 355df8bae1dSRodney W. Grimes } 356df8bae1dSRodney W. Grimes 357df8bae1dSRodney W. Grimes int 358df8bae1dSRodney W. Grimes union_root(mp, vpp) 359df8bae1dSRodney W. Grimes struct mount *mp; 360df8bae1dSRodney W. Grimes struct vnode **vpp; 361df8bae1dSRodney W. Grimes { 362df8bae1dSRodney W. Grimes struct union_mount *um = MOUNTTOUNIONMOUNT(mp); 363df8bae1dSRodney W. Grimes int error; 364df8bae1dSRodney W. Grimes int loselock; 365df8bae1dSRodney W. Grimes 366df8bae1dSRodney W. Grimes #ifdef UNION_DIAGNOSTIC 367df8bae1dSRodney W. Grimes printf("union_root(mp = %x, lvp = %x, uvp = %x)\n", mp, 368df8bae1dSRodney W. Grimes um->um_lowervp, 369df8bae1dSRodney W. Grimes um->um_uppervp); 370df8bae1dSRodney W. Grimes #endif 371df8bae1dSRodney W. Grimes 372df8bae1dSRodney W. Grimes /* 373df8bae1dSRodney W. Grimes * Return locked reference to root. 374df8bae1dSRodney W. Grimes */ 375df8bae1dSRodney W. Grimes VREF(um->um_uppervp); 376df8bae1dSRodney W. Grimes if ((um->um_op == UNMNT_BELOW) && 377df8bae1dSRodney W. Grimes VOP_ISLOCKED(um->um_uppervp)) { 378df8bae1dSRodney W. Grimes loselock = 1; 379df8bae1dSRodney W. Grimes } else { 380df8bae1dSRodney W. Grimes VOP_LOCK(um->um_uppervp); 381df8bae1dSRodney W. Grimes loselock = 0; 382df8bae1dSRodney W. Grimes } 383df8bae1dSRodney W. Grimes if (um->um_lowervp) 384df8bae1dSRodney W. Grimes VREF(um->um_lowervp); 385df8bae1dSRodney W. Grimes error = union_allocvp(vpp, mp, 386df8bae1dSRodney W. Grimes (struct vnode *) 0, 387df8bae1dSRodney W. Grimes (struct vnode *) 0, 388df8bae1dSRodney W. Grimes (struct componentname *) 0, 389df8bae1dSRodney W. Grimes um->um_uppervp, 390df8bae1dSRodney W. Grimes um->um_lowervp); 391df8bae1dSRodney W. Grimes 392df8bae1dSRodney W. Grimes if (error) { 393df8bae1dSRodney W. Grimes if (!loselock) 394df8bae1dSRodney W. Grimes VOP_UNLOCK(um->um_uppervp); 395df8bae1dSRodney W. Grimes vrele(um->um_uppervp); 396df8bae1dSRodney W. Grimes if (um->um_lowervp) 397df8bae1dSRodney W. Grimes vrele(um->um_lowervp); 398df8bae1dSRodney W. Grimes } else { 399df8bae1dSRodney W. Grimes (*vpp)->v_flag |= VROOT; 400df8bae1dSRodney W. Grimes if (loselock) 401df8bae1dSRodney W. Grimes VTOUNION(*vpp)->un_flags &= ~UN_ULOCK; 402df8bae1dSRodney W. Grimes } 403df8bae1dSRodney W. Grimes 404df8bae1dSRodney W. Grimes return (error); 405df8bae1dSRodney W. Grimes } 406df8bae1dSRodney W. Grimes 407df8bae1dSRodney W. Grimes int 408df8bae1dSRodney W. Grimes union_quotactl(mp, cmd, uid, arg, p) 409df8bae1dSRodney W. Grimes struct mount *mp; 410df8bae1dSRodney W. Grimes int cmd; 411df8bae1dSRodney W. Grimes uid_t uid; 412df8bae1dSRodney W. Grimes caddr_t arg; 413df8bae1dSRodney W. Grimes struct proc *p; 414df8bae1dSRodney W. Grimes { 415df8bae1dSRodney W. Grimes 416df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 417df8bae1dSRodney W. Grimes } 418df8bae1dSRodney W. Grimes 419df8bae1dSRodney W. Grimes int 420df8bae1dSRodney W. Grimes union_statfs(mp, sbp, p) 421df8bae1dSRodney W. Grimes struct mount *mp; 422df8bae1dSRodney W. Grimes struct statfs *sbp; 423df8bae1dSRodney W. Grimes struct proc *p; 424df8bae1dSRodney W. Grimes { 425df8bae1dSRodney W. Grimes int error; 426df8bae1dSRodney W. Grimes struct union_mount *um = MOUNTTOUNIONMOUNT(mp); 427df8bae1dSRodney W. Grimes struct statfs mstat; 428df8bae1dSRodney W. Grimes int lbsize; 429df8bae1dSRodney W. Grimes 430df8bae1dSRodney W. Grimes #ifdef UNION_DIAGNOSTIC 431df8bae1dSRodney W. Grimes printf("union_statfs(mp = %x, lvp = %x, uvp = %x)\n", mp, 432df8bae1dSRodney W. Grimes um->um_lowervp, 433df8bae1dSRodney W. Grimes um->um_uppervp); 434df8bae1dSRodney W. Grimes #endif 435df8bae1dSRodney W. Grimes 436df8bae1dSRodney W. Grimes bzero(&mstat, sizeof(mstat)); 437df8bae1dSRodney W. Grimes 438df8bae1dSRodney W. Grimes if (um->um_lowervp) { 439df8bae1dSRodney W. Grimes error = VFS_STATFS(um->um_lowervp->v_mount, &mstat, p); 440df8bae1dSRodney W. Grimes if (error) 441df8bae1dSRodney W. Grimes return (error); 442df8bae1dSRodney W. Grimes } 443df8bae1dSRodney W. Grimes 444df8bae1dSRodney W. Grimes /* now copy across the "interesting" information and fake the rest */ 445df8bae1dSRodney W. Grimes #if 0 446df8bae1dSRodney W. Grimes sbp->f_type = mstat.f_type; 447df8bae1dSRodney W. Grimes sbp->f_flags = mstat.f_flags; 448df8bae1dSRodney W. Grimes sbp->f_bsize = mstat.f_bsize; 449df8bae1dSRodney W. Grimes sbp->f_iosize = mstat.f_iosize; 450df8bae1dSRodney W. Grimes #endif 451df8bae1dSRodney W. Grimes lbsize = mstat.f_bsize; 452df8bae1dSRodney W. Grimes sbp->f_blocks = mstat.f_blocks; 453df8bae1dSRodney W. Grimes sbp->f_bfree = mstat.f_bfree; 454df8bae1dSRodney W. Grimes sbp->f_bavail = mstat.f_bavail; 455df8bae1dSRodney W. Grimes sbp->f_files = mstat.f_files; 456df8bae1dSRodney W. Grimes sbp->f_ffree = mstat.f_ffree; 457df8bae1dSRodney W. Grimes 458df8bae1dSRodney W. Grimes error = VFS_STATFS(um->um_uppervp->v_mount, &mstat, p); 459df8bae1dSRodney W. Grimes if (error) 460df8bae1dSRodney W. Grimes return (error); 461df8bae1dSRodney W. Grimes 462df8bae1dSRodney W. Grimes sbp->f_type = MOUNT_UNION; 463df8bae1dSRodney W. Grimes sbp->f_flags = mstat.f_flags; 464df8bae1dSRodney W. Grimes sbp->f_bsize = mstat.f_bsize; 465df8bae1dSRodney W. Grimes sbp->f_iosize = mstat.f_iosize; 466df8bae1dSRodney W. Grimes 467df8bae1dSRodney W. Grimes /* 468df8bae1dSRodney W. Grimes * if the lower and upper blocksizes differ, then frig the 469df8bae1dSRodney W. Grimes * block counts so that the sizes reported by df make some 470df8bae1dSRodney W. Grimes * kind of sense. none of this makes sense though. 471df8bae1dSRodney W. Grimes */ 472df8bae1dSRodney W. Grimes 473df8bae1dSRodney W. Grimes if (mstat.f_bsize != lbsize) { 474df8bae1dSRodney W. Grimes sbp->f_blocks = sbp->f_blocks * lbsize / mstat.f_bsize; 475df8bae1dSRodney W. Grimes sbp->f_bfree = sbp->f_bfree * lbsize / mstat.f_bsize; 476df8bae1dSRodney W. Grimes sbp->f_bavail = sbp->f_bavail * lbsize / mstat.f_bsize; 477df8bae1dSRodney W. Grimes } 478df8bae1dSRodney W. Grimes sbp->f_blocks += mstat.f_blocks; 479df8bae1dSRodney W. Grimes sbp->f_bfree += mstat.f_bfree; 480df8bae1dSRodney W. Grimes sbp->f_bavail += mstat.f_bavail; 481df8bae1dSRodney W. Grimes sbp->f_files += mstat.f_files; 482df8bae1dSRodney W. Grimes sbp->f_ffree += mstat.f_ffree; 483df8bae1dSRodney W. Grimes 484df8bae1dSRodney W. Grimes if (sbp != &mp->mnt_stat) { 485df8bae1dSRodney W. Grimes bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 486df8bae1dSRodney W. Grimes bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 487df8bae1dSRodney W. Grimes bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 488df8bae1dSRodney W. Grimes } 489df8bae1dSRodney W. Grimes return (0); 490df8bae1dSRodney W. Grimes } 491df8bae1dSRodney W. Grimes 492df8bae1dSRodney W. Grimes int 493df8bae1dSRodney W. Grimes union_sync(mp, waitfor, cred, p) 494df8bae1dSRodney W. Grimes struct mount *mp; 495df8bae1dSRodney W. Grimes int waitfor; 496df8bae1dSRodney W. Grimes struct ucred *cred; 497df8bae1dSRodney W. Grimes struct proc *p; 498df8bae1dSRodney W. Grimes { 499df8bae1dSRodney W. Grimes 500df8bae1dSRodney W. Grimes /* 501df8bae1dSRodney W. Grimes * XXX - Assumes no data cached at union layer. 502df8bae1dSRodney W. Grimes */ 503df8bae1dSRodney W. Grimes return (0); 504df8bae1dSRodney W. Grimes } 505df8bae1dSRodney W. Grimes 506df8bae1dSRodney W. Grimes int 507df8bae1dSRodney W. Grimes union_vget(mp, ino, vpp) 508df8bae1dSRodney W. Grimes struct mount *mp; 509df8bae1dSRodney W. Grimes ino_t ino; 510df8bae1dSRodney W. Grimes struct vnode **vpp; 511df8bae1dSRodney W. Grimes { 512df8bae1dSRodney W. Grimes 513df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 514df8bae1dSRodney W. Grimes } 515df8bae1dSRodney W. Grimes 516df8bae1dSRodney W. Grimes int 517df8bae1dSRodney W. Grimes union_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp) 518df8bae1dSRodney W. Grimes struct mount *mp; 519df8bae1dSRodney W. Grimes struct fid *fidp; 520df8bae1dSRodney W. Grimes struct mbuf *nam; 521df8bae1dSRodney W. Grimes struct vnode **vpp; 522df8bae1dSRodney W. Grimes int *exflagsp; 523df8bae1dSRodney W. Grimes struct ucred **credanonp; 524df8bae1dSRodney W. Grimes { 525df8bae1dSRodney W. Grimes 526df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 527df8bae1dSRodney W. Grimes } 528df8bae1dSRodney W. Grimes 529df8bae1dSRodney W. Grimes int 530df8bae1dSRodney W. Grimes union_vptofh(vp, fhp) 531df8bae1dSRodney W. Grimes struct vnode *vp; 532df8bae1dSRodney W. Grimes struct fid *fhp; 533df8bae1dSRodney W. Grimes { 534df8bae1dSRodney W. Grimes 535df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 536df8bae1dSRodney W. Grimes } 537df8bae1dSRodney W. Grimes 538df8bae1dSRodney W. Grimes int union_init __P((void)); 539df8bae1dSRodney W. Grimes 540df8bae1dSRodney W. Grimes struct vfsops union_vfsops = { 541df8bae1dSRodney W. Grimes union_mount, 542df8bae1dSRodney W. Grimes union_start, 543df8bae1dSRodney W. Grimes union_unmount, 544df8bae1dSRodney W. Grimes union_root, 545df8bae1dSRodney W. Grimes union_quotactl, 546df8bae1dSRodney W. Grimes union_statfs, 547df8bae1dSRodney W. Grimes union_sync, 548df8bae1dSRodney W. Grimes union_vget, 549df8bae1dSRodney W. Grimes union_fhtovp, 550df8bae1dSRodney W. Grimes union_vptofh, 551df8bae1dSRodney W. Grimes union_init, 552df8bae1dSRodney W. Grimes }; 553c901836cSGarrett Wollman 554c901836cSGarrett Wollman VFS_SET(union_vfsops, union, MOUNT_UNION, 0); 555