X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0c530ab8987f0ae6a1a3d9284f40182b88852816..2d21ac55c334faf3a56e5634905ed6987fc787d4:/bsd/miscfs/union/union_vnops.c diff --git a/bsd/miscfs/union/union_vnops.c b/bsd/miscfs/union/union_vnops.c index 4b1ca8ef1..240ab9f40 100644 --- a/bsd/miscfs/union/union_vnops.c +++ b/bsd/miscfs/union/union_vnops.c @@ -1,23 +1,29 @@ /* * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ /* @@ -77,23 +83,10 @@ #include <miscfs/union/union.h> #include <vfs/vfs_support.h> #include <sys/ubc.h> +#include <sys/kdebug.h> #include <sys/uio_internal.h> -#define FIXUP(un, p) { \ - if (((un)->un_flags & UN_ULOCK) == 0) { \ - union_fixup(un, p); \ - } \ -} - -static void -union_fixup(un, p) - struct union_node *un; - struct proc *p; -{ - - un->un_flags |= UN_ULOCK; -} - +/* called with no union lock held */ static int union_lookup1(struct vnode *udvp, struct vnode **dvpp, struct vnode **vpp, struct componentname *cnp) @@ -158,30 +151,35 @@ union_lookup1(struct vnode *udvp, struct vnode **dvpp, struct vnode **vpp, return (0); } -int -union_lookup( - struct vnop_lookup_args /* { +static int +union_lookup(struct vnop_lookup_args *ap) +/* + struct vnop_lookup_args { struct vnodeop_desc *a_desc; struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; vfs_context_t a_context; - } */ *ap) + } *ap) +*/ { int error; - int uerror, lerror; + int uerror = 0; + int lerror = 0; struct vnode *uppervp, *lowervp; struct vnode *upperdvp, *lowerdvp; struct vnode *dvp = ap->a_dvp; - struct union_node *dun = VTOUNION(dvp); + struct union_node *dun; struct componentname *cnp = ap->a_cnp; vfs_context_t ctx = cnp->cn_context; - struct proc *p = vfs_context_proc(ctx); int lockparent = cnp->cn_flags & LOCKPARENT; - struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount); + struct union_mount *um; kauth_cred_t saved_cred; int iswhiteout; struct vnode_attr va; + int isfaultfs = 0; + int upperlookup = 0; + int retry_count = 0; #ifdef notyet if (cnp->cn_namelen == 3 && @@ -197,14 +195,26 @@ union_lookup( } #endif - cnp->cn_flags |= LOCKPARENT; + +retry: + union_lock(); + um = MOUNTTOUNIONMOUNT(dvp->v_mount); + dun = VTOUNION(dvp); upperdvp = dun->un_uppervp; lowerdvp = dun->un_lowervp; uppervp = NULLVP; lowervp = NULLVP; iswhiteout = 0; + union_unlock(); + + if(UNION_FAULTIN(um)) + isfaultfs = 1; + + if (isfaultfs == 0) + cnp->cn_flags |= LOCKPARENT; + /* * do the lookup in the upper level. * if that level comsumes additional pathnames, @@ -212,16 +222,18 @@ union_lookup( * on and just return that vnode. */ if (upperdvp != NULLVP) { - FIXUP(dun, p); + if (lockparent != 0) + cnp->cn_flags &= ~LOCKPARENT; uerror = union_lookup1(um->um_uppervp, &upperdvp, &uppervp, cnp); - /*if (uppervp == upperdvp) - dun->un_flags |= UN_KLOCK;*/ + upperlookup = 1; if (cnp->cn_consume != 0) { *ap->a_vpp = uppervp; if (!lockparent) cnp->cn_flags &= ~LOCKPARENT; + else + cnp->cn_flags |= LOCKPARENT; return (uerror); } if (uerror == ENOENT || uerror == EJUSTRETURN) { @@ -239,6 +251,15 @@ union_lookup( uerror = ENOENT; } + /* + * faultingfs: If upper layer lookup is succesful + * we will return that vp if it is regular file. + * So so skip lower level lookup + */ + + if ((isfaultfs == 1) && (upperlookup == 1) && (uerror == 0) && ((vnode_isreg(uppervp) != 0))) + goto donelowerlookup; + /* * in a similar way to the upper layer, do the lookup * in the lower layer. this time, if there is some @@ -259,10 +280,14 @@ union_lookup( /* XXX BOGUS */ saved_cred = cnp->cn_context->vc_ucred; cnp->cn_context->vc_ucred = um->um_cred; + if (lockparent != 0) + cnp->cn_flags &= ~LOCKPARENT; lerror = union_lookup1(um->um_lowervp, &lowerdvp, &lowervp, cnp); cnp->cn_context->vc_ucred = saved_cred; } else { + if (lockparent != 0) + cnp->cn_flags &= ~LOCKPARENT; lerror = union_lookup1(um->um_lowervp, &lowerdvp, &lowervp, cnp); } @@ -276,6 +301,8 @@ union_lookup( *ap->a_vpp = lowervp; if (!lockparent) cnp->cn_flags &= ~LOCKPARENT; + else + cnp->cn_flags |= LOCKPARENT; return (lerror); } } else { @@ -283,12 +310,13 @@ union_lookup( if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) { lowervp = LOWERVP(dun->un_pvp); if (lowervp != NULLVP) { - vnode_get(lowervp); lerror = 0; } } } +donelowerlookup: + if (!lockparent) cnp->cn_flags &= ~LOCKPARENT; @@ -320,27 +348,72 @@ union_lookup( /* case 1. */ if ((uerror != 0) && (lerror != 0)) { + if (!lockparent) + cnp->cn_flags &= ~LOCKPARENT; + else + cnp->cn_flags |= LOCKPARENT; return (uerror); } /* case 2. */ if (uerror != 0 /* && (lerror == 0) */ ) { if (lowervp->v_type == VDIR) { /* case 2b. */ - dun->un_flags &= ~UN_ULOCK; + /* No need to lock the union here */ + /* if the vnode exists it returns it even if it marks error */ + + uppervp = NULLVP; + uerror = union_mkshadow(um, upperdvp, cnp, &uppervp); - dun->un_flags |= UN_ULOCK; + if ((uerror == EEXIST)){ + if (uppervp == NULLVP) { + retry_count++; + if (retry_count <= 2) { + if (lowervp != NULLVP) + vnode_put(lowervp); + goto retry; + } + } + uerror = 0; + } + if (uerror) { + if (uppervp != NULLVP) { + vnode_put(uppervp); + } if (lowervp != NULLVP) { vnode_put(lowervp); - lowervp = NULLVP; } + if (!lockparent) + cnp->cn_flags &= ~LOCKPARENT; + else + cnp->cn_flags |= LOCKPARENT; return (uerror); } + } else if ((lowervp->v_type == VREG) && (isfaultfs == 1)) { + error = union_faultin_copyup(&uppervp, upperdvp, lowervp, cnp, ctx); + uerror = 0; } } + + + /* if this is faulting filesystem and upper vp exisits skip allocation of union node */ + if ((isfaultfs == 1) && (uerror == 0) && (uppervp != NULLVP) && ((vnode_isreg(uppervp) != 0)|| (vnode_islnk(uppervp) != 0))) { + vn_checkunionwait(uppervp); + *ap->a_vpp = uppervp; + if (lowervp != NULLVP) + vnode_put(lowervp); + if (!lockparent) + cnp->cn_flags &= ~LOCKPARENT; + else + cnp->cn_flags |= LOCKPARENT; + return(0); + } + + union_lock(); error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp, uppervp, lowervp, 1); + union_unlock(); if (error) { if (uppervp != NULLVP) @@ -349,33 +422,35 @@ union_lookup( vnode_put(lowervp); } + if (!lockparent) + cnp->cn_flags &= ~LOCKPARENT; + else + cnp->cn_flags |= LOCKPARENT; return (error); } -int -union_create( - struct vnop_create_args /* { +static int +union_create(struct vnop_create_args *ap) +/* + struct vnop_create_args { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vnode_attr *a_vap; vfs_context_t a_context; - } */ *ap) + } *ap; +*/ { struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; struct componentname *cnp = ap->a_cnp; - vfs_context_t ctx = cnp->cn_context; - struct proc *p = vfs_context_proc(ctx); if (dvp != NULLVP) { int error; struct vnode *vp; struct mount *mp; - FIXUP(un, p); - un->un_flags |= UN_KLOCK; mp = ap->a_dvp->v_mount; /* note that this is a direct passthrough to the filesystem */ @@ -383,60 +458,71 @@ union_create( if (error) return (error); + /* if this is faulting filesystem and is a reg file, skip allocation of union node */ + if (UNNODE_FAULTIN(un) && (vp != NULLVP) && ((vnode_isreg(vp) != 0)|| (vnode_islnk(vp) != 0))) { + *ap->a_vpp = vp; + return(0); + } + + + union_lock(); error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, cnp, vp, NULLVP, 1); + union_unlock(); if (error) vnode_put(vp); return (error); } + return (EROFS); } -int -union_whiteout( - struct vnop_whiteout_args /* { +static int +union_whiteout(struct vnop_whiteout_args *ap) +/* + struct vnop_whiteout_args { struct vnode *a_dvp; struct componentname *a_cnp; int a_flags; vfs_context_t a_context; - } */ *ap) + } *ap; +*/ { struct union_node *un = VTOUNION(ap->a_dvp); struct componentname *cnp = ap->a_cnp; - vfs_context_t ctx = cnp->cn_context; - struct proc *p = vfs_context_proc(ctx); + int error; - if (un->un_uppervp == NULLVP) + if (un->un_uppervp == NULLVP) { return (ENOTSUP); + } - FIXUP(un, p); - return (VNOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags, ap->a_context)); + error = (VNOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags, ap->a_context)); + return(error); } -int -union_mknod( - struct vnop_mknod_args /* { +/* mknod can do fifos, chr, blk or whiteout entries */ +static int +union_mknod(struct vnop_mknod_args *ap) +/* + struct vnop_mknod_args { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vnode_attr *a_vap; vfs_context_t a_context; - } */ *ap) + } *ap; +*/ { struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; struct componentname *cnp = ap->a_cnp; - vfs_context_t ctx = cnp->cn_context; - struct proc *p = vfs_context_proc(ctx); if (dvp != NULLVP) { int error; struct vnode *vp; struct mount *mp; - FIXUP(un, p); - un->un_flags |= UN_KLOCK; mp = ap->a_dvp->v_mount; /* note that this is a direct passthrough to the filesystem */ @@ -445,8 +531,10 @@ union_mknod( return (error); if (vp != NULLVP) { + union_lock(); error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, cnp, vp, NULLVP, 1); + union_unlock(); if (error) vnode_put(vp); } @@ -455,27 +543,29 @@ union_mknod( return (EROFS); } -int -union_open( - struct vnop_open_args /* { +static int +union_open(struct vnop_open_args *ap) +/* + struct vnop_open_args { struct vnodeop_desc *a_desc; struct vnode *a_vp; int a_mode; vfs_context_t a_context; - } */ *ap) + } *ap; +*/ { struct union_node *un = VTOUNION(ap->a_vp); struct vnode *tvp; int mode = ap->a_mode; - kauth_cred_t cred = vfs_context_ucred(ap->a_context); - struct proc *p = vfs_context_proc(ap->a_context); int error; /* * If there is an existing upper vp then simply open that. */ + tvp = un->un_uppervp; if (tvp == NULLVP) { + /* * If the lower vnode is being opened for writing, then * copy the file contents to the upper vnode and open that, @@ -483,7 +573,19 @@ union_open( */ tvp = un->un_lowervp; if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) { - error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p); + /* For above below mounts we need draining.. */ + /* This path is not taken for faultin mode */ + /* LOCK the union node as well **/ + union_lock(); + un->un_flags |= UN_LOCKED; + + error = union_copyup(un, (mode&O_TRUNC) == 0, ap->a_context); + un->un_flags &= ~UN_LOCKED; + if ((un->un_flags & UN_WANT) == UN_WANT) { + un->un_flags &= ~UN_WANT; + wakeup(&un->un_flags); + } + union_unlock(); if (error == 0) error = VNOP_OPEN(un->un_uppervp, mode, ap->a_context); return (error); @@ -499,23 +601,24 @@ union_open( return (error); } - FIXUP(un, p); - error = VNOP_OPEN(tvp, mode, ap->a_context); return (error); } -int -union_close(ap) - struct vnop_close_args /* { +static int +union_close(struct vnop_close_args *ap) +/* + struct vnop_close_args { struct vnode *a_vp; int a_fflag; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { struct union_node *un = VTOUNION(ap->a_vp); struct vnode *vp; + int error = 0; if ((vp = un->un_uppervp) == NULLVP) { #ifdef UNION_DIAGNOSTIC @@ -527,7 +630,8 @@ union_close(ap) } ap->a_vp = vp; - return (VCALL(vp, VOFFSET(vnop_close), ap)); + error = (VCALL(vp, VOFFSET(vnop_close), ap)); + return(error); } /* @@ -538,22 +642,22 @@ union_close(ap) * file permissions are given away simply because * the user caused an implicit file copy. */ -int -union_access( - struct vnop_access_args /* { +static int +union_access(struct vnop_access_args *ap) +/* + struct vnop_access_args { struct vnodeop_desc *a_desc; struct vnode *a_vp; int a_action; vfs_context_t a_context; - } */ *ap) + } *ap; +*/ { struct union_node *un = VTOUNION(ap->a_vp); - struct proc *p = vfs_context_proc(ap->a_context); int error = EACCES; struct vnode *vp; if ((vp = un->un_uppervp) != NULLVP) { - FIXUP(un, p); ap->a_vp = vp; return (VCALL(vp, VOFFSET(vnop_access), ap)); } @@ -565,8 +669,6 @@ union_access( struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount); if (um->um_op == UNMNT_BELOW) { - /* XXX fix me */ - // ap->a_cred = um->um_cred; error = VCALL(vp, VOFFSET(vnop_access), ap); } } @@ -581,18 +683,19 @@ union_access( * We handle getattr only to change the fsid and * track object sizes */ -int -union_getattr(ap) - struct vnop_getattr_args /* { +static int +union_getattr(struct vnop_getattr_args *ap) +/* + struct vnop_getattr_args { struct vnode *a_vp; struct vnode_attr *a_vap; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { - int error; + int error=0; struct union_node *un = VTOUNION(ap->a_vp); struct vnode *vp = un->un_uppervp; - struct proc *p = vfs_context_proc(ap->a_context); struct vnode_attr *vap; struct vnode_attr va; @@ -618,13 +721,14 @@ union_getattr(ap) * In the mean time, compensate here by checking * the union_node's lock flag. */ - if (un->un_flags & UN_LOCKED) - FIXUP(un, p); error = vnode_getattr(vp, vap, ap->a_context); - if (error) + if (error) { return (error); + } + union_lock(); union_newsize(ap->a_vp, vap->va_data_size, VNOVAL); + union_unlock(); } if (vp == NULLVP) { @@ -641,9 +745,12 @@ union_getattr(ap) if (vp != NULLVP) { error = vnode_getattr(vp, vap, ap->a_context); - if (error) + if (error) { return (error); + } + union_lock(); union_newsize(ap->a_vp, VNOVAL, vap->va_data_size); + union_unlock(); } if ((vap != ap->a_vap) && (vap->va_type == VDIR)) @@ -653,17 +760,17 @@ union_getattr(ap) return (0); } -int -union_setattr(ap) - struct vnop_setattr_args /* { +static int +union_setattr(struct vnop_setattr_args *ap) +/* + struct vnop_setattr_args { struct vnode *a_vp; struct vnode_attr *a_vap; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { struct union_node *un = VTOUNION(ap->a_vp); - struct proc *p = vfs_context_proc(ap->a_context); - kauth_cred_t cred = vfs_context_ucred(ap->a_context); int error; /* @@ -675,9 +782,12 @@ union_setattr(ap) (un->un_uppervp == NULLVP) && /* assert(un->un_lowervp != NULLVP) */ (un->un_lowervp->v_type == VREG)) { - error = union_copyup(un, (ap->a_vap->va_data_size != 0), cred, p); - if (error) + union_lock(); + error = union_copyup(un, (ap->a_vap->va_data_size != 0), ap->a_context); + union_unlock(); + if (error) { return (error); + } } /* @@ -685,10 +795,12 @@ union_setattr(ap) * otherwise return read-only filesystem error. */ if (un->un_uppervp != NULLVP) { - FIXUP(un, p); error = vnode_setattr(un->un_uppervp, ap->a_vap, ap->a_context); - if ((error == 0) && VATTR_IS_ACTIVE(ap->a_vap, va_data_size)) + if ((error == 0) && VATTR_IS_ACTIVE(ap->a_vap, va_data_size)) { + union_lock(); union_newsize(ap->a_vp, ap->a_vap->va_data_size, VNOVAL); + union_unlock(); + } } else { error = EROFS; } @@ -696,22 +808,20 @@ union_setattr(ap) return (error); } -int -union_read(ap) - struct vnop_read_args /* { +static int +union_read(struct vnop_read_args *ap) +/* + struct vnop_read_args { struct vnode *a_vp; struct uio *a_uio; int a_ioflag; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { int error; - struct proc *p = vfs_context_proc(ap->a_context); struct vnode *vp = OTHERVP(ap->a_vp); - int dolock = (vp == LOWERVP(ap->a_vp)); - if (!dolock) - FIXUP(VTOUNION(ap->a_vp), p); error = VNOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_context); /* @@ -725,36 +835,42 @@ union_read(ap) off_t cur = ap->a_uio->uio_offset; if (vp == un->un_uppervp) { - if (cur > un->un_uppersz) + if (cur > un->un_uppersz) { + union_lock(); union_newsize(ap->a_vp, cur, VNOVAL); + union_unlock(); + } } else { - if (cur > un->un_lowersz) + if (cur > un->un_lowersz) { + union_lock(); union_newsize(ap->a_vp, VNOVAL, cur); + union_unlock(); + } } } return (error); } -int -union_write(ap) - struct vnop_read_args /* { +static int +union_write(struct vnop_write_args *ap) +/* + struct vnop_write_args { struct vnode *a_vp; struct uio *a_uio; int a_ioflag; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { int error; struct vnode *vp; struct union_node *un = VTOUNION(ap->a_vp); - struct proc *p = vfs_context_proc(ap->a_context); vp = UPPERVP(ap->a_vp); if (vp == NULLVP) panic("union: missing upper layer in write"); - FIXUP(un, p); error = VNOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_context); /* @@ -764,23 +880,28 @@ union_write(ap) if (error == 0) { off_t cur = ap->a_uio->uio_offset; - if (cur > un->un_uppersz) + if (cur > un->un_uppersz) { + union_lock(); union_newsize(ap->a_vp, cur, VNOVAL); + union_unlock(); + } } return (error); } -int -union_ioctl(ap) - struct vnop_ioctl_args /* { +static int +union_ioctl(struct vnop_ioctl_args *ap) +/* + struct vnop_ioctl_args { struct vnode *a_vp; int a_command; caddr_t a_data; int a_fflag; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { register struct vnode *ovp = OTHERVP(ap->a_vp); @@ -788,15 +909,17 @@ union_ioctl(ap) return (VCALL(ovp, VOFFSET(vnop_ioctl), ap)); } -int -union_select(ap) - struct vnop_select_args /* { +static int +union_select(struct vnop_select_args *ap) +/* + struct vnop_select_args { struct vnode *a_vp; int a_which; int a_fflags; void * a_wql; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { register struct vnode *ovp = OTHERVP(ap->a_vp); @@ -804,13 +927,15 @@ union_select(ap) return (VCALL(ovp, VOFFSET(vnop_select), ap)); } -int -union_revoke(ap) - struct vnop_revoke_args /* { +static int +union_revoke(struct vnop_revoke_args *ap) +/* + struct vnop_revoke_args { struct vnode *a_vp; int a_flags; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { struct vnode *vp = ap->a_vp; @@ -819,16 +944,20 @@ union_revoke(ap) if (LOWERVP(vp)) VNOP_REVOKE(LOWERVP(vp), ap->a_flags, ap->a_context); vnode_reclaim(vp); + + return (0); } -int -union_mmap(ap) - struct vnop_mmap_args /* { +static int +union_mmap(struct vnop_mmap_args *ap) +/* + struct vnop_mmap_args { struct vnode *a_vp; int a_fflags; kauth_cred_t a_cred; struct proc *a_p; - } */ *ap; + } *ap; +*/ { register struct vnode *ovp = OTHERVP(ap->a_vp); @@ -836,64 +965,102 @@ union_mmap(ap) return (VCALL(ovp, VOFFSET(vnop_mmap), ap)); } -int -union_fsync( - struct vnop_fsync_args /* { +static int +union_mnomap(struct vnop_mnomap_args *ap) +/* + struct vnop_mnomap_args { + struct vnode *a_vp; + int a_fflags; + kauth_cred_t a_cred; + struct proc *a_p; + } *ap; +*/ +{ + register struct vnode *ovp = OTHERVP(ap->a_vp); + + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vnop_mnomap), ap)); +} + +static int +union_fsync(struct vnop_fsync_args *ap) +/* + struct vnop_fsync_args { struct vnode *a_vp; int a_waitfor; vfs_context_t a_context; - } */ *ap) + } *ap; +*/ { int error = 0; - struct proc *p = vfs_context_proc(ap->a_context); struct vnode *targetvp = OTHERVP(ap->a_vp); if (targetvp != NULLVP) { - int dolock = (targetvp == LOWERVP(ap->a_vp)); - if (!dolock) - FIXUP(VTOUNION(ap->a_vp), p); error = VNOP_FSYNC(targetvp, ap->a_waitfor, ap->a_context); } return (error); } -int -union_remove( - struct vnop_remove_args /* { +static int +union_remove(struct vnop_remove_args *ap) +/* + struct vnop_remove_args { struct vnode *a_dvp; struct vnode *a_vp; struct componentname *a_cnp; vfs_context_t a_context; - } */ *ap) + } *ap; +*/ { - int error; + int error, flags; struct union_node *dun = VTOUNION(ap->a_dvp); struct union_node *un = VTOUNION(ap->a_vp); struct componentname *cnp = ap->a_cnp; - vfs_context_t ctx = cnp->cn_context; - struct proc *p = vfs_context_proc(ctx); + int busydel = 0; if (dun->un_uppervp == NULLVP) panic("union remove: null upper vnode"); + if (UNNODE_FAULTIN(dun) && ((ap->a_vp != NULLVP) && + ((vnode_isreg(ap->a_vp) != 0) || (vnode_islnk(ap->a_vp) != 0)))) { + return(VNOP_REMOVE(dun->un_uppervp, ap->a_vp, ap->a_cnp, ap->a_flags, ap->a_context)); + } + if (un->un_uppervp != NULLVP) { struct vnode *dvp = dun->un_uppervp; struct vnode *vp = un->un_uppervp; - FIXUP(dun, p); - dun->un_flags |= UN_KLOCK; - FIXUP(un, p); - un->un_flags |= UN_KLOCK; - + flags = ap->a_flags; + if (vnode_isinuse(ap->a_vp, 0)) + busydel = 1; + if ((flags & VNODE_REMOVE_NODELETEBUSY) && (busydel != 0)) { + return(EBUSY); + } if (union_dowhiteout(un, cnp->cn_context)) cnp->cn_flags |= DOWHITEOUT; + + if (busydel != 0) { + union_lock(); + un->un_flags |= UN_DELETED; + if (un->un_flags & UN_CACHED) { + un->un_flags &= ~UN_CACHED; + LIST_REMOVE(un, un_cache); + } + union_unlock(); + vnode_ref(vp); + } error = VNOP_REMOVE(dvp, vp, cnp, 0, ap->a_context); - if (!error) - union_removed_upper(un); + if (!error) { + union_lock(); + if (busydel == 0) + union_removed_upper(un); + union_unlock(); + } } else { - FIXUP(dun, p); + if (UNNODE_FAULTIN(un)) + panic("faultfs: No uppervp"); error = union_mkwhiteout( MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount), dun->un_uppervp, ap->a_cnp, un->un_path); @@ -902,19 +1069,19 @@ union_remove( return (error); } -int -union_link( - struct vnop_link_args /* { +static int +union_link(struct vnop_link_args *ap) +/* + struct vnop_link_args { struct vnode *a_vp; struct vnode *a_tdvp; struct componentname *a_cnp; vfs_context_t a_context; - } */ *ap) + } *ap; +*/ { int error = 0; struct componentname *cnp = ap->a_cnp; - vfs_context_t ctx = cnp->cn_context; - struct proc *p = vfs_context_proc(ctx); struct union_node *un; struct vnode *vp; struct vnode *tdvp; @@ -926,13 +1093,20 @@ union_link( } else { struct union_node *tun = VTOUNION(ap->a_vp); if (tun->un_uppervp == NULLVP) { + if (UNNODE_FAULTIN(tun)) + panic("faultfs: No uppervp"); if (un->un_uppervp == tun->un_dirvp) { - un->un_flags &= ~UN_ULOCK; } - error = union_copyup(tun, 1, vfs_context_ucred(ctx), p); - if (un->un_uppervp == tun->un_dirvp) { - un->un_flags |= UN_ULOCK; + union_lock(); + /* Would need to drain for above,below mount and faulin does not enter this path */ + un->un_flags |= UN_LOCKED; + error = union_copyup(tun, 1, ap->a_context); + un->un_flags &= ~UN_LOCKED; + if ((un->un_flags & UN_WANT) == UN_WANT) { + un->un_flags &= ~UN_WANT; + wakeup(&un->un_flags); } + union_unlock(); } vp = tun->un_uppervp; } @@ -944,16 +1118,15 @@ union_link( return (error); } - FIXUP(un, p); - vnode_get(tdvp); - un->un_flags |= UN_KLOCK; - return (VNOP_LINK(vp, tdvp, cnp, ap->a_context)); + error = (VNOP_LINK(vp, tdvp, cnp, ap->a_context)); + return(error); } -int -union_rename(ap) - struct vnop_rename_args /* { +static int +union_rename(struct vnop_rename_args *ap) +/* + struct vnop_rename_args { struct vnode *a_fdvp; struct vnode *a_fvp; struct componentname *a_fcnp; @@ -961,7 +1134,8 @@ union_rename(ap) struct vnode *a_tvp; struct componentname *a_tcnp; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { int error; @@ -970,9 +1144,12 @@ union_rename(ap) struct vnode *tdvp = ap->a_tdvp; struct vnode *tvp = ap->a_tvp; + if (fdvp->v_op == union_vnodeop_p) { /* always true */ struct union_node *un = VTOUNION(fdvp); if (un->un_uppervp == NULLVP) { + if (UNNODE_FAULTIN(un)) + panic("faultfs rename: No uppervp"); /* * this should never happen in normal * operation but might if there was @@ -984,12 +1161,13 @@ union_rename(ap) } fdvp = un->un_uppervp; - vnode_get(fdvp); } if (fvp->v_op == union_vnodeop_p) { /* always true */ struct union_node *un = VTOUNION(fvp); if (un->un_uppervp == NULLVP) { + if (UNNODE_FAULTIN(un)) + panic("faultfs rename: No uppervp"); /* XXX: should do a copyup */ error = EXDEV; goto bad; @@ -999,7 +1177,6 @@ union_rename(ap) ap->a_fcnp->cn_flags |= DOWHITEOUT; fvp = un->un_uppervp; - vnode_get(fvp); } if (tdvp->v_op == union_vnodeop_p) { @@ -1011,23 +1188,19 @@ union_rename(ap) * a problem creating the top-level shadow * directory. */ + if (UNNODE_FAULTIN(un)) + panic("faultfs rename: No uppervp"); error = EXDEV; goto bad; } tdvp = un->un_uppervp; - vnode_get(tdvp); - un->un_flags |= UN_KLOCK; } if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) { struct union_node *un = VTOUNION(tvp); tvp = un->un_uppervp; - if (tvp != NULLVP) { - vnode_get(tvp); - un->un_flags |= UN_KLOCK; - } } return (VNOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp, ap->a_context)); @@ -1036,36 +1209,36 @@ bad: return (error); } -int -union_mkdir( - struct vnop_mkdir_args /* { +static int +union_mkdir(struct vnop_mkdir_args *ap) +/* + struct vnop_mkdir_args { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vnode_attr *a_vap; vfs_context_t a_context; - } */ *ap) + } *ap; +*/ { struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; struct componentname *cnp = ap->a_cnp; - vfs_context_t ctx = cnp->cn_context; - struct proc *p = vfs_context_proc(ctx); if (dvp != NULLVP) { int error; struct vnode *vp; - FIXUP(un, p); - un->un_flags |= UN_KLOCK; /* note that this is a direct fallthrough to the filesystem */ error = VNOP_MKDIR(dvp, &vp, cnp, ap->a_vap, ap->a_context); if (error) return (error); + union_lock(); error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount, ap->a_dvp, NULLVP, cnp, vp, NULLVP, 1); + union_unlock(); if (error) vnode_put(vp); return (error); @@ -1073,22 +1246,24 @@ union_mkdir( return (EROFS); } -int -union_rmdir( - struct vnop_rmdir_args /* { +static int +union_rmdir(struct vnop_rmdir_args *ap) +/* + struct vnop_rmdir_args { struct vnode *a_dvp; struct vnode *a_vp; struct componentname *a_cnp; vfs_context_t a_context; - } */ *ap) + } *ap; +*/ { int error; struct union_node *dun = VTOUNION(ap->a_dvp); struct union_node *un = VTOUNION(ap->a_vp); struct componentname *cnp = ap->a_cnp; - vfs_context_t ctx = cnp->cn_context; - struct proc *p = vfs_context_proc(ctx); + int busydel = 0; + /******* NODE HAS TO BE LOCKED ******/ if (dun->un_uppervp == NULLVP) panic("union rmdir: null upper vnode"); @@ -1096,20 +1271,31 @@ union_rmdir( struct vnode *dvp = dun->un_uppervp; struct vnode *vp = un->un_uppervp; - FIXUP(dun, p); - vnode_get(dvp); - dun->un_flags |= UN_KLOCK; - FIXUP(un, p); - vnode_get(vp); - un->un_flags |= UN_KLOCK; + if (vnode_isinuse(ap->a_vp, 0)) { + busydel = 1; + union_lock(); + un->un_flags |= UN_DELETED; + if (un->un_flags & UN_CACHED) { + un->un_flags &= ~UN_CACHED; + LIST_REMOVE(un, un_cache); + } + union_unlock(); + vnode_ref(vp); + } + if (union_dowhiteout(un, cnp->cn_context)) cnp->cn_flags |= DOWHITEOUT; error = VNOP_RMDIR(dvp, vp, ap->a_cnp, ap->a_context); - if (!error) - union_removed_upper(un); + if (!error) { + union_lock(); + if (busydel == 0) + union_removed_upper(un); + union_unlock(); + } } else { - FIXUP(dun, p); + if (UNNODE_FAULTIN(un)) + panic("faultfs: No uppervp"); error = union_mkwhiteout( MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount), dun->un_uppervp, ap->a_cnp, un->un_path); @@ -1117,32 +1303,29 @@ union_rmdir( return (error); } -int -union_symlink( - struct vnop_symlink_args /* { +static int +union_symlink(struct vnop_symlink_args *ap) +/* + struct vnop_symlink_args { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vnode_attr *a_vap; char *a_target; vfs_context_t a_context; - } */ *ap) + } *ap; +*/ { struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; struct componentname *cnp = ap->a_cnp; - vfs_context_t ctx = cnp->cn_context; - struct proc *p = vfs_context_proc(ctx); if (dvp != NULLVP) { int error; struct vnode *vp; - FIXUP(un, p); - un->un_flags |= UN_KLOCK; - error = VNOP_SYMLINK(dvp, &vp, cnp, ap->a_vap, ap->a_target, ap->a_context); - *ap->a_vpp = NULLVP; + *ap->a_vpp = vp; return (error); } return (EROFS); @@ -1155,9 +1338,10 @@ union_symlink( * down the union stack. readdir(3) is responsible for * eliminating duplicate names from the returned data stream. */ -int -union_readdir(ap) - struct vnop_readdir_args /* { +static int +union_readdir(struct vnop_readdir_args *ap) +/* + struct vnop_readdir_args { struct vnodeop_desc *a_desc; struct vnode *a_vp; struct uio *a_uio; @@ -1165,11 +1349,11 @@ union_readdir(ap) int *a_eofflag; int *a_numdirent; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { struct union_node *un = VTOUNION(ap->a_vp); struct vnode *uvp = un->un_uppervp; - struct proc *p = vfs_context_proc(ap->a_context); if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF)) return (EINVAL); @@ -1177,43 +1361,40 @@ union_readdir(ap) if (uvp == NULLVP) return (0); - FIXUP(un, p); ap->a_vp = uvp; return (VCALL(uvp, VOFFSET(vnop_readdir), ap)); } -int -union_readlink(ap) - struct vnop_readlink_args /* { +static int +union_readlink(struct vnop_readlink_args *ap) +/* + struct vnop_readlink_args { struct vnode *a_vp; struct uio *a_uio; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { int error; - struct uio *uio = ap->a_uio; - struct proc *p = vfs_context_proc(ap->a_context); struct vnode *vp = OTHERVP(ap->a_vp); - int dolock = (vp == LOWERVP(ap->a_vp)); - if (!dolock) - FIXUP(VTOUNION(ap->a_vp), p); ap->a_vp = vp; error = VCALL(vp, VOFFSET(vnop_readlink), ap); return (error); } -int -union_inactive( - struct vnop_inactive_args /* { +static int +union_inactive(struct vnop_inactive_args *ap) +/* + struct vnop_inactive_args { struct vnode *a_vp; vfs_context_t a_context; - } */ *ap) + } *ap; +*/ { struct vnode *vp = ap->a_vp; struct union_node *un = VTOUNION(vp); - struct vnode **vpp; /* * Do nothing (and _don't_ bypass). @@ -1228,35 +1409,47 @@ union_inactive( * That's too much work for now. */ - if (un->un_dircache != 0) { - for (vpp = un->un_dircache; *vpp != NULLVP; vpp++) - vnode_put(*vpp); - _FREE(un->un_dircache, M_TEMP); - un->un_dircache = 0; + union_lock(); + if (un->un_flags & UN_DELETED) { + if(un->un_uppervp != NULLVP) { + vnode_rele(un->un_uppervp); + } + union_removed_upper(un); } - if ((un->un_flags & UN_CACHED) == 0) + if (un->un_dircache != 0) { + union_dircache_free(un); + } + if (un->un_flags & UN_DIRENVN) { vnode_recycle(vp); + } + + union_unlock(); return (0); } -int -union_reclaim(ap) - struct vnop_reclaim_args /* { +static int +union_reclaim(struct vnop_reclaim_args *ap) +/* + struct vnop_reclaim_args { struct vnode *a_vp; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { + union_lock(); union_freevp(ap->a_vp); + union_unlock(); return (0); } -int -union_blockmap(ap) - struct vnop_blockmap_args /* { +static int +union_blockmap(struct vnop_blockmap_args *ap) +/* + struct vnop_blockmap_args { struct vnode *a_vp; off_t a_offset; size_t a_size; @@ -1264,53 +1457,50 @@ union_blockmap(ap) size_t *a_run; void *a_poff; int a_flags; - } */ *ap; + } *ap; +*/ { int error; - struct proc *p = current_proc(); /* XXX */ struct vnode *vp = OTHERVP(ap->a_vp); - int dolock = (vp == LOWERVP(ap->a_vp)); - if (!dolock) - FIXUP(VTOUNION(ap->a_vp), p); ap->a_vp = vp; error = VCALL(vp, VOFFSET(vnop_blockmap), ap); return (error); } -int -union_pathconf(ap) - struct vnop_pathconf_args /* { +static int +union_pathconf(struct vnop_pathconf_args *ap) +/* + struct vnop_pathconf_args { struct vnode *a_vp; int a_name; int *a_retval; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { int error; - struct proc *p = current_proc(); /* XXX */ struct vnode *vp = OTHERVP(ap->a_vp); - int dolock = (vp == LOWERVP(ap->a_vp)); - if (!dolock) - FIXUP(VTOUNION(ap->a_vp), p); ap->a_vp = vp; error = VCALL(vp, VOFFSET(vnop_pathconf), ap); return (error); } -int -union_advlock(ap) - struct vnop_advlock_args /* { +static int +union_advlock(struct vnop_advlock_args *ap) +/* + struct vnop_advlock_args { struct vnode *a_vp; caddr_t a_id; int a_op; struct flock *a_fl; int a_flags; vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { register struct vnode *ovp = OTHERVP(ap->a_vp); @@ -1324,11 +1514,13 @@ union_advlock(ap) * vnode in its arguments. * This goes away with a merged VM/buffer cache. */ -int -union_strategy(ap) - struct vnop_strategy_args /* { +static int +union_strategy(struct vnop_strategy_args *ap) +/* + struct vnop_strategy_args { struct buf *a_bp; - } */ *ap; + } *ap; +*/ { struct buf *bp = ap->a_bp; int error; @@ -1352,9 +1544,10 @@ union_strategy(ap) } /* Pagein */ -int -union_pagein(ap) - struct vnop_pagein_args /* { +static int +union_pagein(struct vnop_pagein_args *ap) +/* + struct vnop_pagein_args { struct vnode *a_vp, upl_t a_pl, vm_offset_t a_pl_offset, @@ -1362,7 +1555,8 @@ union_pagein(ap) size_t a_size, int a_flags vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { int error; struct vnode *vp = OTHERVP(ap->a_vp); @@ -1381,11 +1575,17 @@ union_pagein(ap) off_t cur = ap->a_f_offset + (off_t)ap->a_pl_offset; if (vp == un->un_uppervp) { - if (cur > un->un_uppersz) + if (cur > un->un_uppersz) { + union_lock(); union_newsize(ap->a_vp, cur, VNOVAL); + union_unlock(); + } } else { - if (cur > un->un_lowersz) + if (cur > un->un_lowersz) { + union_lock(); union_newsize(ap->a_vp, VNOVAL, cur); + union_unlock(); + } } } @@ -1393,9 +1593,10 @@ union_pagein(ap) } /* Pageout */ -int -union_pageout(ap) - struct vnop_pageout_args /* { +static int +union_pageout(struct vnop_pageout_args *ap) +/* + struct vnop_pageout_args { struct vnode *a_vp, upl_t a_pl, vm_offset_t a_pl_offset, @@ -1403,7 +1604,8 @@ union_pageout(ap) size_t a_size, int a_flags vfs_context_t a_context; - } */ *ap; + } *ap; +*/ { int error; struct vnode *vp; @@ -1423,21 +1625,26 @@ union_pageout(ap) if (error == 0) { off_t cur = ap->a_f_offset + (off_t)ap->a_pl_offset; - if (cur > un->un_uppersz) + if (cur > un->un_uppersz) { + union_lock(); union_newsize(ap->a_vp, cur, VNOVAL); + union_unlock(); + } } return (error); } /* Blktooff derives file offset for the given logical block number */ -int -union_blktooff(ap) - struct vnop_blktooff_args /* { +static int +union_blktooff(struct vnop_blktooff_args *ap) +/* + struct vnop_blktooff_args { struct vnode *a_vp; daddr64_t a_lblkno; off_t *a_offset; - } */ *ap; + } *ap; +*/ { int error; struct vnode *vp = OTHERVP(ap->a_vp); @@ -1448,13 +1655,15 @@ union_blktooff(ap) } /* offtoblk derives file offset for the given logical block number */ -int -union_offtoblk(ap) - struct vnop_offtoblk_args /* { +static int +union_offtoblk(struct vnop_offtoblk_args *ap) +/* + struct vnop_offtoblk_args { struct vnode *a_vp; off_t a_offset; daddr64_t *a_lblkno; - } */ *ap; + } *ap; +*/ { int error; struct vnode *vp = OTHERVP(ap->a_vp); @@ -1487,6 +1696,7 @@ struct vnodeopv_entry_desc union_vnodeop_entries[] = { { &vnop_select_desc, (VOPFUNC)union_select }, /* select */ { &vnop_revoke_desc, (VOPFUNC)union_revoke }, /* revoke */ { &vnop_mmap_desc, (VOPFUNC)union_mmap }, /* mmap */ + { &vnop_mnomap_desc, (VOPFUNC)union_mnomap }, /* mnomap */ { &vnop_fsync_desc, (VOPFUNC)union_fsync }, /* fsync */ { &vnop_remove_desc, (VOPFUNC)union_remove }, /* remove */ { &vnop_link_desc, (VOPFUNC)union_link }, /* link */