File:  [DragonFly] / src / sys / vfs / gnu / ext2fs / ext2_vnops.c
Revision 1.11: download - view: text, annotated - select for diffs
Thu Apr 8 20:57:52 2004 UTC (10 years, 6 months ago) by cpressey
Branches: MAIN
CVS tags: HEAD
Style(9) cleanup to src/sys/vfs, stage 5/21: ext2fs.

- Convert K&R-style function definitions to ANSI style.

Submitted-by: Andre Nathan <andre@digirati.com.br>
Additional-reformatting-by: cpressey

    1: /*
    2:  *  modified for EXT2FS support in Lites 1.1
    3:  *
    4:  *  Aug 1995, Godmar Back (gback@cs.utah.edu)
    5:  *  University of Utah, Department of Computer Science
    6:  */
    7: /*
    8:  * Copyright (c) 1982, 1986, 1989, 1993
    9:  *	The Regents of the University of California.  All rights reserved.
   10:  * (c) UNIX System Laboratories, Inc.
   11:  * All or some portions of this file are derived from material licensed
   12:  * to the University of California by American Telephone and Telegraph
   13:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   14:  * the permission of UNIX System Laboratories, Inc.
   15:  *
   16:  * Redistribution and use in source and binary forms, with or without
   17:  * modification, are permitted provided that the following conditions
   18:  * are met:
   19:  * 1. Redistributions of source code must retain the above copyright
   20:  *    notice, this list of conditions and the following disclaimer.
   21:  * 2. Redistributions in binary form must reproduce the above copyright
   22:  *    notice, this list of conditions and the following disclaimer in the
   23:  *    documentation and/or other materials provided with the distribution.
   24:  * 3. All advertising materials mentioning features or use of this software
   25:  *    must display the following acknowledgement:
   26:  *	This product includes software developed by the University of
   27:  *	California, Berkeley and its contributors.
   28:  * 4. Neither the name of the University nor the names of its contributors
   29:  *    may be used to endorse or promote products derived from this software
   30:  *    without specific prior written permission.
   31:  *
   32:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   33:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   34:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   35:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   36:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   37:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   38:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   39:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   40:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   41:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   42:  * SUCH DAMAGE.
   43:  *
   44:  *	@(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95
   45:  *	@(#)ext2_vnops.c	8.7 (Berkeley) 2/3/94
   46:  * $FreeBSD: src/sys/gnu/ext2fs/ext2_vnops.c,v 1.51.2.2 2003/01/02 17:26:18 bde Exp $
   47:  * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_vnops.c,v 1.11 2004/04/08 20:57:52 cpressey Exp $
   48:  */
   49: 
   50: #include "opt_quota.h"
   51: #include "opt_suiddir.h"
   52: 
   53: #include <sys/param.h>
   54: #include <sys/systm.h>
   55: #include <sys/resourcevar.h>
   56: #include <sys/kernel.h>
   57: #include <sys/stat.h>
   58: #include <sys/buf.h>
   59: #include <sys/proc.h>
   60: #include <sys/mount.h>
   61: #include <sys/time.h>
   62: #include <sys/vnode.h>
   63: #include <sys/namei.h>
   64: 
   65: #include <vm/vm.h>
   66: #include <vm/vm_extern.h>
   67: #include <vm/vm_zone.h>
   68: #include <vm/vnode_pager.h>
   69: #include <sys/buf2.h>
   70: 
   71: #include <sys/signalvar.h>
   72: #include <vfs/ufs/dir.h>
   73: #include <vfs/ufs/quota.h>
   74: #include <vfs/ufs/inode.h>
   75: #include <vfs/ufs/ufsmount.h>
   76: #include <vfs/ufs/ufs_extern.h>
   77: 
   78: #include "ext2_fs_sb.h"
   79: #include "fs.h"
   80: #include "ext2_extern.h"
   81: #include "ext2_fs.h"
   82: 
   83: static int ext2_makeinode (int mode, struct vnode *, struct vnode **, struct componentname *);
   84: 
   85: static int ext2_fsync (struct vop_fsync_args *);
   86: static int ext2_read (struct vop_read_args *);
   87: static int ext2_write (struct vop_write_args *);
   88: static int ext2_remove (struct vop_remove_args *);
   89: static int ext2_link (struct vop_link_args *);
   90: static int ext2_rename (struct vop_rename_args *);
   91: static int ext2_mkdir (struct vop_mkdir_args *);
   92: static int ext2_rmdir (struct vop_rmdir_args *);
   93: static int ext2_create (struct vop_create_args *);
   94: static int ext2_mknod (struct vop_mknod_args *);
   95: static int ext2_symlink (struct vop_symlink_args *);
   96: static int ext2_getpages (struct vop_getpages_args *);
   97: static int ext2_putpages (struct vop_putpages_args *);
   98: 
   99: /* Global vfs data structures for ufs. */
  100: vop_t **ext2_vnodeop_p;
  101: static struct vnodeopv_entry_desc ext2_vnodeop_entries[] = {
  102: 	{ &vop_default_desc,		(vop_t *) ufs_vnoperate },
  103: 	{ &vop_cachedlookup_desc,	(vop_t *) ext2_lookup },
  104: 	{ &vop_fsync_desc,		(vop_t *) ext2_fsync },
  105: 	{ &vop_inactive_desc,		(vop_t *) ext2_inactive },
  106: 	{ &vop_lookup_desc,		(vop_t *) vfs_cache_lookup },
  107: 	{ &vop_read_desc,		(vop_t *) ext2_read },
  108: 	{ &vop_readdir_desc,		(vop_t *) ext2_readdir },
  109: 	{ &vop_reallocblks_desc,	(vop_t *) ext2_reallocblks },
  110: 	{ &vop_write_desc,		(vop_t *) ext2_write },
  111: 	{ &vop_remove_desc,		(vop_t *) ext2_remove },
  112: 	{ &vop_link_desc,		(vop_t *) ext2_link },
  113: 	{ &vop_rename_desc,		(vop_t *) ext2_rename },
  114: 	{ &vop_mkdir_desc,		(vop_t *) ext2_mkdir },
  115: 	{ &vop_rmdir_desc,		(vop_t *) ext2_rmdir },
  116: 	{ &vop_create_desc,		(vop_t *) ext2_create },
  117: 	{ &vop_mknod_desc,		(vop_t *) ext2_mknod },
  118: 	{ &vop_symlink_desc,		(vop_t *) ext2_symlink },
  119: 	{ &vop_getpages_desc,		(vop_t *) ext2_getpages },
  120: 	{ &vop_putpages_desc,		(vop_t *) ext2_putpages },
  121: 	{ NULL, NULL }
  122: };
  123: static struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
  124: 	{ &ext2_vnodeop_p, ext2_vnodeop_entries };
  125: 
  126: vop_t **ext2_specop_p;
  127: static struct vnodeopv_entry_desc ext2_specop_entries[] = {
  128: 	{ &vop_default_desc,		(vop_t *) ufs_vnoperatespec },
  129: 	{ &vop_fsync_desc,		(vop_t *) ext2_fsync },
  130: 	{ &vop_inactive_desc,		(vop_t *) ext2_inactive },
  131: 	{ NULL, NULL }
  132: };
  133: static struct vnodeopv_desc ext2fs_specop_opv_desc =
  134: 	{ &ext2_specop_p, ext2_specop_entries };
  135: 
  136: vop_t **ext2_fifoop_p;
  137: static struct vnodeopv_entry_desc ext2_fifoop_entries[] = {
  138: 	{ &vop_default_desc,		(vop_t *) ufs_vnoperatefifo },
  139: 	{ &vop_fsync_desc,		(vop_t *) ext2_fsync },
  140: 	{ &vop_inactive_desc,		(vop_t *) ext2_inactive },
  141: 	{ NULL, NULL }
  142: };
  143: static struct vnodeopv_desc ext2fs_fifoop_opv_desc =
  144: 	{ &ext2_fifoop_p, ext2_fifoop_entries };
  145: 
  146: 	VNODEOP_SET(ext2fs_vnodeop_opv_desc);
  147: 	VNODEOP_SET(ext2fs_specop_opv_desc);
  148: 	VNODEOP_SET(ext2fs_fifoop_opv_desc);
  149: 
  150: #include "ext2_readwrite.c"
  151: 
  152: /*
  153:  * A virgin directory (no blushing please).
  154:  * Note that the type and namlen fields are reversed relative to ufs.
  155:  * Also, we don't use `struct odirtemplate', since it would just cause
  156:  * endianness problems.
  157:  */
  158: static struct dirtemplate mastertemplate = {
  159: 	0, 12, 1, EXT2_FT_DIR, ".",
  160: 	0, DIRBLKSIZ - 12, 2, EXT2_FT_DIR, ".."
  161: };
  162: static struct dirtemplate omastertemplate = {
  163: 	0, 12, 1, EXT2_FT_UNKNOWN, ".",
  164: 	0, DIRBLKSIZ - 12, 2, EXT2_FT_UNKNOWN, ".."
  165: };
  166: 
  167: /*
  168:  * Create a regular file
  169:  *
  170:  * ext2_create(struct vnode *a_dvp, struct vnode **a_vpp,
  171:  *	       struct componentname *a_cnp, struct vattr *a_vap)
  172:  */
  173: static int
  174: ext2_create(struct vop_create_args *ap)
  175: {
  176: 	int error;
  177: 
  178: 	error =
  179: 	    ext2_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
  180: 	    ap->a_dvp, ap->a_vpp, ap->a_cnp);
  181: 	if (error)
  182: 		return (error);
  183: 	return (0);
  184: }
  185: 
  186: /*
  187:  * Synch an open file.
  188:  *
  189:  * ext2_fsync(struct vnode *a_vp, struct ucred *a_cred, int a_waitfor,
  190:  *	      struct proc *a_p)
  191:  */
  192: /* ARGSUSED */
  193: static int
  194: ext2_fsync(struct vop_fsync_args *ap)
  195: {
  196: 	struct vnode *vp = ap->a_vp;
  197: 	struct buf *bp;
  198: 	struct buf *nbp;
  199: 	int s;
  200: 
  201: 	/* 
  202: 	 * XXX why is all this fs specific?
  203: 	 */
  204: 
  205: 	/*
  206: 	 * Flush all dirty buffers associated with a vnode.
  207: 	 */
  208: 	ext2_discard_prealloc(VTOI(vp));
  209: 
  210: loop:
  211: 	s = splbio();
  212: 	for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
  213: 		nbp = TAILQ_NEXT(bp, b_vnbufs);
  214: 		if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT))
  215: 			continue;
  216: 		if ((bp->b_flags & B_DELWRI) == 0)
  217: 			panic("ext2_fsync: not dirty");
  218: 		bremfree(bp);
  219: 		splx(s);
  220: 		/*
  221: 		 * Wait for I/O associated with indirect blocks to complete,
  222: 		 * since there is no way to quickly wait for them below.
  223: 		 */
  224: 		if (bp->b_vp == vp || ap->a_waitfor == MNT_NOWAIT)
  225: 			(void) bawrite(bp);
  226: 		else
  227: 			(void) bwrite(bp);
  228: 		goto loop;
  229: 	}
  230: 	if (ap->a_waitfor == MNT_WAIT) {
  231: 		while (vp->v_numoutput) {
  232: 			vp->v_flag |= VBWAIT;
  233: 			tsleep(&vp->v_numoutput, 0, "e2fsyn", 0);
  234: 		}
  235: #if DIAGNOSTIC
  236: 		if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) {
  237: 			vprint("ext2_fsync: dirty", vp);
  238: 			goto loop;
  239: 		}
  240: #endif
  241: 	}
  242: 	splx(s);
  243: 	return (UFS_UPDATE(ap->a_vp, ap->a_waitfor == MNT_WAIT));
  244: }
  245: 
  246: /*
  247:  * Mknod vnode call
  248:  *
  249:  * ext2_mknod(struct vnode *a_dvp, struct vnode **a_vpp,
  250:  *	      struct componentname *a_cnp, struct vattr *a_vap)
  251:  */
  252: /* ARGSUSED */
  253: static int
  254: ext2_mknod(struct vop_mknod_args *ap)
  255: {
  256: 	struct vattr *vap = ap->a_vap;
  257: 	struct vnode **vpp = ap->a_vpp;
  258: 	struct inode *ip;
  259: 	ino_t ino;
  260: 	int error;
  261: 
  262: 	error = ext2_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
  263: 	    ap->a_dvp, vpp, ap->a_cnp);
  264: 	if (error)
  265: 		return (error);
  266: 	ip = VTOI(*vpp);
  267: 	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
  268: 	if (vap->va_rdev != VNOVAL) {
  269: 		/*
  270: 		 * Want to be able to use this to make badblock
  271: 		 * inodes, so don't truncate the dev number.
  272: 		 */
  273: 		ip->i_rdev = vap->va_rdev;
  274: 	}
  275: 	/*
  276: 	 * Remove inode, then reload it through VFS_VGET so it is
  277: 	 * checked to see if it is an alias of an existing entry in
  278: 	 * the inode cache.
  279: 	 */
  280: 	vput(*vpp);
  281: 	(*vpp)->v_type = VNON;
  282: 	ino = ip->i_number;	/* Save this before vgone() invalidates ip. */
  283: 	vgone(*vpp);
  284: 	error = VFS_VGET(ap->a_dvp->v_mount, ino, vpp);
  285: 	if (error) {
  286: 		*vpp = NULL;
  287: 		return (error);
  288: 	}
  289: 	return (0);
  290: }
  291: 
  292: /*
  293:  * ext2_remove(struct vnode *a_dvp, struct vnode *a_vp,
  294:  *	       struct componentname *a_cnp)
  295:  */
  296: static int
  297: ext2_remove(struct vop_remove_args *ap)
  298: {
  299: 	struct inode *ip;
  300: 	struct vnode *vp = ap->a_vp;
  301: 	struct vnode *dvp = ap->a_dvp;
  302: 	int error;
  303: 
  304: 	ip = VTOI(vp);
  305: 	if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
  306: 	    (VTOI(dvp)->i_flags & APPEND)) {
  307: 		error = EPERM;
  308: 		goto out;
  309: 	}
  310: 	error = ext2_dirremove(dvp, ap->a_cnp);
  311: 	if (error == 0) {
  312: 		ip->i_nlink--;
  313: 		ip->i_flag |= IN_CHANGE;
  314: 	}
  315: out:
  316: 	return (error);
  317: }
  318: 
  319: /*
  320:  * link vnode call
  321:  *
  322:  * ext2_link(struct vnode *a_tdvp, struct vnode *a_vp,
  323:  *	     struct componentname *a_cnp)
  324:  */
  325: static int
  326: ext2_link(struct vop_link_args *ap)
  327: {
  328: 	struct vnode *vp = ap->a_vp;
  329: 	struct vnode *tdvp = ap->a_tdvp;
  330: 	struct componentname *cnp = ap->a_cnp;
  331: 	struct thread *td = cnp->cn_td;
  332: 	struct inode *ip;
  333: 	int error;
  334: 
  335: #ifdef DIAGNOSTIC
  336: 	if ((cnp->cn_flags & CNP_HASBUF) == 0)
  337: 		panic("ufs_link: no name");
  338: #endif
  339: 	if (tdvp->v_mount != vp->v_mount) {
  340: 		error = EXDEV;
  341: 		goto out2;
  342: 	}
  343: 	if (tdvp != vp && (error = vn_lock(vp, NULL, LK_EXCLUSIVE, td))) {
  344: 		goto out2;
  345: 	}
  346: 	ip = VTOI(vp);
  347: 	if ((nlink_t)ip->i_nlink >= LINK_MAX) {
  348: 		error = EMLINK;
  349: 		goto out1;
  350: 	}
  351: 	if (ip->i_flags & (IMMUTABLE | APPEND)) {
  352: 		error = EPERM;
  353: 		goto out1;
  354: 	}
  355: 	ip->i_nlink++;
  356: 	ip->i_flag |= IN_CHANGE;
  357: 	error = UFS_UPDATE(vp, 1);
  358: 	if (!error)
  359: 		error = ext2_direnter(ip, tdvp, cnp);
  360: 	if (error) {
  361: 		ip->i_nlink--;
  362: 		ip->i_flag |= IN_CHANGE;
  363: 	}
  364: out1:
  365: 	if (tdvp != vp)
  366: 		VOP_UNLOCK(vp, NULL, 0, td);
  367: out2:
  368: 	return (error);
  369: }
  370: 
  371: /*
  372:  * Rename system call.
  373:  *   See comments in sys/ufs/ufs/ufs_vnops.c
  374:  *
  375:  * ext2_rename(struct vnode *a_fdvp, struct vnode *a_fvp,
  376:  *		struct componentname *a_fcnp, struct vnode *a_tdvp,
  377:  *		struct vnode *a_tvp, struct componentname *a_tcnp)
  378:  */
  379: static int
  380: ext2_rename(struct vop_rename_args *ap)
  381: {
  382: 	struct vnode *tvp = ap->a_tvp;
  383: 	struct vnode *tdvp = ap->a_tdvp;
  384: 	struct vnode *fvp = ap->a_fvp;
  385: 	struct vnode *fdvp = ap->a_fdvp;
  386: 	struct componentname *tcnp = ap->a_tcnp;
  387: 	struct componentname *fcnp = ap->a_fcnp;
  388: 	struct thread *td = fcnp->cn_td;
  389: 	struct inode *ip, *xp, *dp;
  390: 	struct dirtemplate dirbuf;
  391: 	int doingdirectory = 0, oldparent = 0, newparent = 0;
  392: 	int error = 0;
  393: 	u_char namlen;
  394: 
  395: #ifdef DIAGNOSTIC
  396: 	if ((tcnp->cn_flags & CNP_HASBUF) == 0 ||
  397: 	    (fcnp->cn_flags & CNP_HASBUF) == 0)
  398: 		panic("ufs_rename: no name");
  399: #endif
  400: 	/*
  401: 	 * Check for cross-device rename.
  402: 	 */
  403: 	if ((fvp->v_mount != tdvp->v_mount) ||
  404: 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
  405: 		error = EXDEV;
  406: abortit:
  407: 		if (tdvp == tvp)
  408: 			vrele(tdvp);
  409: 		else
  410: 			vput(tdvp);
  411: 		if (tvp)
  412: 			vput(tvp);
  413: 		vrele(fdvp);
  414: 		vrele(fvp);
  415: 		return (error);
  416: 	}
  417: 
  418: 	if (tvp && ((VTOI(tvp)->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
  419: 	    (VTOI(tdvp)->i_flags & APPEND))) {
  420: 		error = EPERM;
  421: 		goto abortit;
  422: 	}
  423: 
  424: 	/*
  425: 	 * Renaming a file to itself has no effect.  The upper layers should
  426: 	 * not call us in that case.  Temporarily just warn if they do.
  427: 	 */
  428: 	if (fvp == tvp) {
  429: 		printf("ext2_rename: fvp == tvp (can't happen)\n");
  430: 		error = 0;
  431: 		goto abortit;
  432: 	}
  433: 
  434: 	if ((error = vn_lock(fvp, NULL, LK_EXCLUSIVE, td)) != 0)
  435: 		goto abortit;
  436: 	dp = VTOI(fdvp);
  437: 	ip = VTOI(fvp);
  438:  	if (ip->i_nlink >= LINK_MAX) {
  439:  		VOP_UNLOCK(fvp, NULL, 0, td);
  440:  		error = EMLINK;
  441:  		goto abortit;
  442:  	}
  443: 	if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))
  444: 	    || (dp->i_flags & APPEND)) {
  445: 		VOP_UNLOCK(fvp, NULL, 0, td);
  446: 		error = EPERM;
  447: 		goto abortit;
  448: 	}
  449: 	if ((ip->i_mode & IFMT) == IFDIR) {
  450: 		/*
  451: 		 * Avoid ".", "..", and aliases of "." for obvious reasons.
  452: 		 */
  453: 		if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
  454: 		    dp == ip || (fcnp->cn_flags | tcnp->cn_flags) & CNP_ISDOTDOT ||
  455: 		    (ip->i_flag & IN_RENAME)) {
  456: 			VOP_UNLOCK(fvp, NULL, 0, td);
  457: 			error = EINVAL;
  458: 			goto abortit;
  459: 		}
  460: 		ip->i_flag |= IN_RENAME;
  461: 		oldparent = dp->i_number;
  462: 		doingdirectory++;
  463: 	}
  464: 	vrele(fdvp);
  465: 
  466: 	/*
  467: 	 * When the target exists, both the directory
  468: 	 * and target vnodes are returned locked.
  469: 	 */
  470: 	dp = VTOI(tdvp);
  471: 	xp = NULL;
  472: 	if (tvp)
  473: 		xp = VTOI(tvp);
  474: 
  475: 	/*
  476: 	 * 1) Bump link count while we're moving stuff
  477: 	 *    around.  If we crash somewhere before
  478: 	 *    completing our work, the link count
  479: 	 *    may be wrong, but correctable.
  480: 	 */
  481: 	ip->i_nlink++;
  482: 	ip->i_flag |= IN_CHANGE;
  483: 	if ((error = UFS_UPDATE(fvp, 1)) != 0) {
  484: 		VOP_UNLOCK(fvp, NULL, 0, td);
  485: 		goto bad;
  486: 	}
  487: 
  488: 	/*
  489: 	 * If ".." must be changed (ie the directory gets a new
  490: 	 * parent) then the source directory must not be in the
  491: 	 * directory heirarchy above the target, as this would
  492: 	 * orphan everything below the source directory. Also
  493: 	 * the user must have write permission in the source so
  494: 	 * as to be able to change "..". We must repeat the call
  495: 	 * to namei, as the parent directory is unlocked by the
  496: 	 * call to checkpath().
  497: 	 */
  498: 	error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_td);
  499: 	VOP_UNLOCK(fvp, NULL, 0, td);
  500: 	if (oldparent != dp->i_number)
  501: 		newparent = dp->i_number;
  502: 	if (doingdirectory && newparent) {
  503: 		if (error)	/* write access check above */
  504: 			goto bad;
  505: 		if (xp != NULL)
  506: 			vput(tvp);
  507: 		error = ext2_checkpath(ip, dp, tcnp->cn_cred);
  508: 		if (error)
  509: 			goto out;
  510: 		VREF(tdvp);
  511: 		error = relookup(tdvp, &tvp, tcnp);
  512: 		if (error)
  513: 			goto out;
  514: 		vrele(tdvp);
  515: 		dp = VTOI(tdvp);
  516: 		xp = NULL;
  517: 		if (tvp)
  518: 			xp = VTOI(tvp);
  519: 	}
  520: 	/*
  521: 	 * 2) If target doesn't exist, link the target
  522: 	 *    to the source and unlink the source.
  523: 	 *    Otherwise, rewrite the target directory
  524: 	 *    entry to reference the source inode and
  525: 	 *    expunge the original entry's existence.
  526: 	 */
  527: 	if (xp == NULL) {
  528: 		if (dp->i_dev != ip->i_dev)
  529: 			panic("ufs_rename: EXDEV");
  530: 		/*
  531: 		 * Account for ".." in new directory.
  532: 		 * When source and destination have the same
  533: 		 * parent we don't fool with the link count.
  534: 		 */
  535: 		if (doingdirectory && newparent) {
  536: 			if ((nlink_t)dp->i_nlink >= LINK_MAX) {
  537: 				error = EMLINK;
  538: 				goto bad;
  539: 			}
  540: 			dp->i_nlink++;
  541: 			dp->i_flag |= IN_CHANGE;
  542: 			error = UFS_UPDATE(tdvp, 1);
  543: 			if (error)
  544: 				goto bad;
  545: 		}
  546: 		error = ext2_direnter(ip, tdvp, tcnp);
  547: 		if (error) {
  548: 			if (doingdirectory && newparent) {
  549: 				dp->i_nlink--;
  550: 				dp->i_flag |= IN_CHANGE;
  551: 				(void)UFS_UPDATE(tdvp, 1);
  552: 			}
  553: 			goto bad;
  554: 		}
  555: 		vput(tdvp);
  556: 	} else {
  557: 		if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
  558: 			panic("ufs_rename: EXDEV");
  559: 		/*
  560: 		 * Short circuit rename(foo, foo).
  561: 		 */
  562: 		if (xp->i_number == ip->i_number)
  563: 			panic("ufs_rename: same file");
  564: 		/*
  565: 		 * If the parent directory is "sticky", then the user must
  566: 		 * own the parent directory, or the destination of the rename,
  567: 		 * otherwise the destination may not be changed (except by
  568: 		 * root). This implements append-only directories.
  569: 		 */
  570: 		if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
  571: 		    tcnp->cn_cred->cr_uid != dp->i_uid &&
  572: 		    xp->i_uid != tcnp->cn_cred->cr_uid) {
  573: 			error = EPERM;
  574: 			goto bad;
  575: 		}
  576: 		/*
  577: 		 * Target must be empty if a directory and have no links
  578: 		 * to it. Also, ensure source and target are compatible
  579: 		 * (both directories, or both not directories).
  580: 		 */
  581: 		if ((xp->i_mode&IFMT) == IFDIR) {
  582: 			if (! ext2_dirempty(xp, dp->i_number, tcnp->cn_cred) || 
  583: 			    xp->i_nlink > 2) {
  584: 				error = ENOTEMPTY;
  585: 				goto bad;
  586: 			}
  587: 			if (!doingdirectory) {
  588: 				error = ENOTDIR;
  589: 				goto bad;
  590: 			}
  591: 			cache_purge(tdvp);
  592: 		} else if (doingdirectory) {
  593: 			error = EISDIR;
  594: 			goto bad;
  595: 		}
  596: 		error = ext2_dirrewrite(dp, ip, tcnp);
  597: 		if (error)
  598: 			goto bad;
  599: 		/*
  600: 		 * If the target directory is in the same
  601: 		 * directory as the source directory,
  602: 		 * decrement the link count on the parent
  603: 		 * of the target directory.
  604: 		 */
  605: 		 if (doingdirectory && !newparent) {
  606: 			dp->i_nlink--;
  607: 			dp->i_flag |= IN_CHANGE;
  608: 		}
  609: 		vput(tdvp);
  610: 		/*
  611: 		 * Adjust the link count of the target to
  612: 		 * reflect the dirrewrite above.  If this is
  613: 		 * a directory it is empty and there are
  614: 		 * no links to it, so we can squash the inode and
  615: 		 * any space associated with it.  We disallowed
  616: 		 * renaming over top of a directory with links to
  617: 		 * it above, as the remaining link would point to
  618: 		 * a directory without "." or ".." entries.
  619: 		 */
  620: 		xp->i_nlink--;
  621: 		if (doingdirectory) {
  622: 			if (--xp->i_nlink != 0)
  623: 				panic("ufs_rename: linked directory");
  624: 			error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC,
  625: 			    tcnp->cn_cred, tcnp->cn_td);
  626: 		}
  627: 		xp->i_flag |= IN_CHANGE;
  628: 		vput(tvp);
  629: 		xp = NULL;
  630: 	}
  631: 
  632: 	/*
  633: 	 * 3) Unlink the source.
  634: 	 */
  635: 	fcnp->cn_flags &= ~CNP_MODMASK;
  636: 	fcnp->cn_flags |= CNP_LOCKPARENT | CNP_LOCKLEAF;
  637: 	VREF(fdvp);
  638: 	error = relookup(fdvp, &fvp, fcnp);
  639: 	if (error == 0)
  640: 		vrele(fdvp);
  641: 	if (fvp != NULL) {
  642: 		xp = VTOI(fvp);
  643: 		dp = VTOI(fdvp);
  644: 	} else {
  645: 		/*
  646: 		 * From name has disappeared.
  647: 		 */
  648: 		if (doingdirectory)
  649: 			panic("ufs_rename: lost dir entry");
  650: 		vrele(ap->a_fvp);
  651: 		return (0);
  652: 	}
  653: 	/*
  654: 	 * Ensure that the directory entry still exists and has not
  655: 	 * changed while the new name has been entered. If the source is
  656: 	 * a file then the entry may have been unlinked or renamed. In
  657: 	 * either case there is no further work to be done. If the source
  658: 	 * is a directory then it cannot have been rmdir'ed; its link
  659: 	 * count of three would cause a rmdir to fail with ENOTEMPTY.
  660: 	 * The IN_RENAME flag ensures that it cannot be moved by another
  661: 	 * rename.
  662: 	 */
  663: 	if (xp != ip) {
  664: 		if (doingdirectory)
  665: 			panic("ufs_rename: lost dir entry");
  666: 	} else {
  667: 		/*
  668: 		 * If the source is a directory with a
  669: 		 * new parent, the link count of the old
  670: 		 * parent directory must be decremented
  671: 		 * and ".." set to point to the new parent.
  672: 		 */
  673: 		if (doingdirectory && newparent) {
  674: 			dp->i_nlink--;
  675: 			dp->i_flag |= IN_CHANGE;
  676: 			error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
  677: 				sizeof (struct dirtemplate), (off_t)0,
  678: 				UIO_SYSSPACE, IO_NODELOCKED,
  679: 				tcnp->cn_cred, (int *)0, NULL);
  680: 			if (error == 0) {
  681: 				/* Like ufs little-endian: */
  682: 				namlen = dirbuf.dotdot_type;
  683: 				if (namlen != 2 ||
  684: 				    dirbuf.dotdot_name[0] != '.' ||
  685: 				    dirbuf.dotdot_name[1] != '.') {
  686: 					ufs_dirbad(xp, (doff_t)12,
  687: 					    "rename: mangled dir");
  688: 				} else {
  689: 					dirbuf.dotdot_ino = newparent;
  690: 					(void) vn_rdwr(UIO_WRITE, fvp,
  691: 					    (caddr_t)&dirbuf,
  692: 					    sizeof (struct dirtemplate),
  693: 					    (off_t)0, UIO_SYSSPACE,
  694: 					    IO_NODELOCKED|IO_SYNC,
  695: 					    tcnp->cn_cred, (int *)0,
  696: 					    NULL);
  697: 					cache_purge(fdvp);
  698: 				}
  699: 			}
  700: 		}
  701: 		error = ext2_dirremove(fdvp, fcnp);
  702: 		if (!error) {
  703: 			xp->i_nlink--;
  704: 			xp->i_flag |= IN_CHANGE;
  705: 		}
  706: 		xp->i_flag &= ~IN_RENAME;
  707: 	}
  708: 	if (dp)
  709: 		vput(fdvp);
  710: 	if (xp)
  711: 		vput(fvp);
  712: 	vrele(ap->a_fvp);
  713: 	return (error);
  714: 
  715: bad:
  716: 	if (xp)
  717: 		vput(ITOV(xp));
  718: 	vput(ITOV(dp));
  719: out:
  720: 	if (doingdirectory)
  721: 		ip->i_flag &= ~IN_RENAME;
  722: 	if (vn_lock(fvp, NULL, LK_EXCLUSIVE, td) == 0) {
  723: 		ip->i_nlink--;
  724: 		ip->i_flag |= IN_CHANGE;
  725: 		ip->i_flag &= ~IN_RENAME;
  726: 		vput(fvp);
  727: 	} else
  728: 		vrele(fvp);
  729: 	return (error);
  730: }
  731: 
  732: /*
  733:  * Mkdir system call
  734:  *
  735:  * ext2_mkdir(struct vnode *a_dvp, struct vnode **a_vpp,
  736:  *	      struct componentname *a_cnp, struct vattr *a_vap)
  737:  */
  738: static int
  739: ext2_mkdir(struct vop_mkdir_args *ap)
  740: {
  741: 	struct vnode *dvp = ap->a_dvp;
  742: 	struct vattr *vap = ap->a_vap;
  743: 	struct componentname *cnp = ap->a_cnp;
  744: 	struct inode *ip, *dp;
  745: 	struct vnode *tvp;
  746: 	struct dirtemplate dirtemplate, *dtp;
  747: 	int error, dmode;
  748: 
  749: #ifdef DIAGNOSTIC
  750: 	if ((cnp->cn_flags & CNP_HASBUF) == 0)
  751: 		panic("ufs_mkdir: no name");
  752: #endif
  753: 	dp = VTOI(dvp);
  754: 	if ((nlink_t)dp->i_nlink >= LINK_MAX) {
  755: 		error = EMLINK;
  756: 		goto out;
  757: 	}
  758: 	dmode = vap->va_mode & 0777;
  759: 	dmode |= IFDIR;
  760: 	/*
  761: 	 * Must simulate part of ext2_makeinode here to acquire the inode,
  762: 	 * but not have it entered in the parent directory. The entry is
  763: 	 * made later after writing "." and ".." entries.
  764: 	 */
  765: 	error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp);
  766: 	if (error)
  767: 		goto out;
  768: 	ip = VTOI(tvp);
  769: 	ip->i_gid = dp->i_gid;
  770: #ifdef SUIDDIR
  771: 	{
  772: #ifdef QUOTA
  773: 		struct ucred ucred, *ucp;
  774: 		ucp = cnp->cn_cred;
  775: #endif			I
  776: 		/*
  777: 		 * if we are hacking owners here, (only do this where told to)
  778: 		 * and we are not giving it TOO root, (would subvert quotas)
  779: 		 * then go ahead and give it to the other user.
  780: 		 * The new directory also inherits the SUID bit. 
  781: 		 * If user's UID and dir UID are the same,
  782: 		 * 'give it away' so that the SUID is still forced on.
  783: 		 */
  784: 		if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
  785: 		   (dp->i_mode & ISUID) && dp->i_uid) {
  786: 			dmode |= ISUID;
  787: 			ip->i_uid = dp->i_uid;
  788: #ifdef QUOTA
  789: 			if (dp->i_uid != cnp->cn_cred->cr_uid) {
  790: 				/*
  791: 				 * make sure the correct user gets charged
  792: 				 * for the space.
  793: 				 * Make a dummy credential for the victim.
  794: 				 * XXX This seems to never be accessed out of
  795: 				 * our context so a stack variable is ok.
  796: 				 */
  797: 				ucred.cr_ref = 1;
  798: 				ucred.cr_uid = ip->i_uid;
  799: 				ucred.cr_ngroups = 1;
  800: 				ucred.cr_groups[0] = dp->i_gid;
  801: 				ucp = &ucred;
  802: 			}
  803: #endif			I
  804: 		} else {
  805: 			ip->i_uid = cnp->cn_cred->cr_uid;
  806: 		}
  807: #ifdef QUOTA
  808: 		if ((error = getinoquota(ip)) ||
  809: 	    	(error = chkiq(ip, 1, ucp, 0))) {
  810: 			UFS_VFREE(tvp, ip->i_number, dmode);
  811: 			vput(tvp);
  812: 			return (error);
  813: 		}
  814: #endif
  815: 	}
  816: #else
  817: 	ip->i_uid = cnp->cn_cred->cr_uid;
  818: #ifdef QUOTA
  819: 	if ((error = getinoquota(ip)) ||
  820: 	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
  821: 		UFS_VFREE(tvp, ip->i_number, dmode);
  822: 		vput(tvp);
  823: 		return (error);
  824: 	}
  825: #endif
  826: #endif
  827: 	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
  828: 	ip->i_mode = dmode;
  829: 	tvp->v_type = VDIR;	/* Rest init'd in getnewvnode(). */
  830: 	ip->i_nlink = 2;
  831: 	if (cnp->cn_flags & CNP_ISWHITEOUT)
  832: 		ip->i_flags |= UF_OPAQUE;
  833: 	error = UFS_UPDATE(tvp, 1);
  834: 
  835: 	/*
  836: 	 * Bump link count in parent directory
  837: 	 * to reflect work done below.  Should
  838: 	 * be done before reference is created
  839: 	 * so reparation is possible if we crash.
  840: 	 */
  841: 	dp->i_nlink++;
  842: 	dp->i_flag |= IN_CHANGE;
  843: 	error = UFS_UPDATE(dvp, 1);
  844: 	if (error)
  845: 		goto bad;
  846: 
  847: 	/* Initialize directory with "." and ".." from static template. */
  848: 	if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
  849: 	    EXT2_FEATURE_INCOMPAT_FILETYPE))
  850: 		dtp = &mastertemplate;
  851: 	else
  852: 		dtp = &omastertemplate;
  853: 	dirtemplate = *dtp;
  854: 	dirtemplate.dot_ino = ip->i_number;
  855: 	dirtemplate.dotdot_ino = dp->i_number;
  856: 	/* note that in ext2 DIRBLKSIZ == blocksize, not DEV_BSIZE 
  857: 	 * so let's just redefine it - for this function only
  858: 	 */
  859: #undef  DIRBLKSIZ 
  860: #define DIRBLKSIZ  VTOI(dvp)->i_e2fs->s_blocksize
  861: 	dirtemplate.dotdot_reclen = DIRBLKSIZ - 12;
  862: 	error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
  863: 	    sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
  864: 	    IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, NULL);
  865: 	if (error) {
  866: 		dp->i_nlink--;
  867: 		dp->i_flag |= IN_CHANGE;
  868: 		goto bad;
  869: 	}
  870: 	if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
  871: 		panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
  872: 	else {
  873: 		ip->i_size = DIRBLKSIZ;
  874: 		ip->i_flag |= IN_CHANGE;
  875: 	}
  876: 
  877: 	/* Directory set up, now install its entry in the parent directory. */
  878: 	error = ext2_direnter(ip, dvp, cnp);
  879: 	if (error) {
  880: 		dp->i_nlink--;
  881: 		dp->i_flag |= IN_CHANGE;
  882: 	}
  883: bad:
  884: 	/*
  885: 	 * No need to do an explicit VOP_TRUNCATE here, vrele will do this
  886: 	 * for us because we set the link count to 0.
  887: 	 */
  888: 	if (error) {
  889: 		ip->i_nlink = 0;
  890: 		ip->i_flag |= IN_CHANGE;
  891: 		vput(tvp);
  892: 	} else
  893: 		*ap->a_vpp = tvp;
  894: out:
  895: 	return (error);
  896: #undef  DIRBLKSIZ
  897: #define DIRBLKSIZ  DEV_BSIZE
  898: }
  899: 
  900: /*
  901:  * Rmdir system call.
  902:  *
  903:  * ext2_rmdir(struct vnode *a_dvp, struct vnode *a_vp,
  904:  *	      struct componentname *a_cnp)
  905:  */
  906: static int
  907: ext2_rmdir(struct vop_rmdir_args *ap)
  908: {
  909: 	struct vnode *vp = ap->a_vp;
  910: 	struct vnode *dvp = ap->a_dvp;
  911: 	struct componentname *cnp = ap->a_cnp;
  912: 	struct thread *td = cnp->cn_td;
  913: 	struct inode *ip, *dp;
  914: 	int error;
  915: 
  916: 	ip = VTOI(vp);
  917: 	dp = VTOI(dvp);
  918: 
  919: 	/*
  920: 	 * Verify the directory is empty (and valid).
  921: 	 * (Rmdir ".." won't be valid since
  922: 	 *  ".." will contain a reference to
  923: 	 *  the current directory and thus be
  924: 	 *  non-empty.)
  925: 	 */
  926: 	error = 0;
  927: 	if (ip->i_nlink != 2 || !ext2_dirempty(ip, dp->i_number, cnp->cn_cred)) {
  928: 		error = ENOTEMPTY;
  929: 		goto out;
  930: 	}
  931: 	if ((dp->i_flags & APPEND)
  932: 	    || (ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
  933: 		error = EPERM;
  934: 		goto out;
  935: 	}
  936: 	/*
  937: 	 * Delete reference to directory before purging
  938: 	 * inode.  If we crash in between, the directory
  939: 	 * will be reattached to lost+found,
  940: 	 */
  941: 	error = ext2_dirremove(dvp, cnp);
  942: 	if (error)
  943: 		goto out;
  944: 	dp->i_nlink--;
  945: 	dp->i_flag |= IN_CHANGE;
  946: 	cache_purge(dvp);
  947: 	VOP_UNLOCK(dvp, NULL, 0, td);
  948: 	/*
  949: 	 * Truncate inode.  The only stuff left
  950: 	 * in the directory is "." and "..".  The
  951: 	 * "." reference is inconsequential since
  952: 	 * we're quashing it.  The ".." reference
  953: 	 * has already been adjusted above.  We've
  954: 	 * removed the "." reference and the reference
  955: 	 * in the parent directory, but there may be
  956: 	 * other hard links so decrement by 2 and
  957: 	 * worry about them later.
  958: 	 */
  959: 	ip->i_nlink -= 2;
  960: 	error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, td);
  961: 	cache_purge(ITOV(ip));
  962: 	vn_lock(dvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
  963: out:
  964: 	return (error);
  965: }
  966: 
  967: /*
  968:  * symlink -- make a symbolic link
  969:  *
  970:  * ext2_symlink(struct vnode *a_dvp, struct vnode **a_vpp,
  971:  *		struct componentname *a_cnp, struct vattr *a_vap,
  972:  *		char *a_target)
  973:  */
  974: static int
  975: ext2_symlink(struct vop_symlink_args *ap)
  976: {
  977: 	struct vnode *vp, **vpp = ap->a_vpp;
  978: 	struct inode *ip;
  979: 	int len, error;
  980: 
  981: 	error = ext2_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
  982: 	    vpp, ap->a_cnp);
  983: 	if (error)
  984: 		return (error);
  985: 	vp = *vpp;
  986: 	len = strlen(ap->a_target);
  987: 	if (len < vp->v_mount->mnt_maxsymlinklen) {
  988: 		ip = VTOI(vp);
  989: 		bcopy(ap->a_target, (char *)ip->i_shortlink, len);
  990: 		ip->i_size = len;
  991: 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
  992: 	} else
  993: 		error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
  994: 		    UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
  995: 		    NULL);
  996: 	if (error)
  997: 		vput(vp);
  998: 	return (error);
  999: }
 1000: 
 1001: /*
 1002:  * Allocate a new inode.
 1003:  */
 1004: static int
 1005: ext2_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
 1006: 	       struct componentname *cnp)
 1007: {
 1008: 	struct inode *ip, *pdir;
 1009: 	struct vnode *tvp;
 1010: 	int error;
 1011: 
 1012: 	pdir = VTOI(dvp);
 1013: #ifdef DIAGNOSTIC
 1014: 	if ((cnp->cn_flags & CNP_HASBUF) == 0)
 1015: 		panic("ext2_makeinode: no name");
 1016: #endif
 1017: 	*vpp = NULL;
 1018: 	if ((mode & IFMT) == 0)
 1019: 		mode |= IFREG;
 1020: 
 1021: 	error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp);
 1022: 	if (error) {
 1023: 		return (error);
 1024: 	}
 1025: 	ip = VTOI(tvp);
 1026: 	ip->i_gid = pdir->i_gid;
 1027: #ifdef SUIDDIR
 1028: 	{
 1029: #ifdef QUOTA
 1030: 		struct ucred ucred, *ucp;
 1031: 		ucp = cnp->cn_cred;
 1032: #endif			I
 1033: 		/*
 1034: 		 * if we are
 1035: 		 * not the owner of the directory,
 1036: 		 * and we are hacking owners here, (only do this where told to)
 1037: 		 * and we are not giving it TOO root, (would subvert quotas)
 1038: 		 * then go ahead and give it to the other user.
 1039: 		 * Note that this drops off the execute bits for security.
 1040: 		 */
 1041: 		if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
 1042: 		     (pdir->i_mode & ISUID) &&
 1043: 		     (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) {
 1044: 			ip->i_uid = pdir->i_uid;
 1045: 			mode &= ~07111;
 1046: #ifdef QUOTA
 1047: 			/*
 1048: 			 * make sure the correct user gets charged
 1049: 			 * for the space.
 1050: 			 * Quickly knock up a dummy credential for the victim.
 1051: 			 * XXX This seems to never be accessed out of our
 1052: 			 * context so a stack variable is ok.
 1053: 			 */
 1054: 			ucred.cr_ref = 1;
 1055: 			ucred.cr_uid = ip->i_uid;
 1056: 			ucred.cr_ngroups = 1;
 1057: 			ucred.cr_groups[0] = pdir->i_gid;
 1058: 			ucp = &ucred;
 1059: #endif			I
 1060: 		} else {
 1061: 			ip->i_uid = cnp->cn_cred->cr_uid;
 1062: 		}
 1063: 	
 1064: #ifdef QUOTA
 1065: 		if ((error = getinoquota(ip)) ||
 1066: 	    	(error = chkiq(ip, 1, ucp, 0))) {
 1067: 			UFS_VFREE(tvp, ip->i_number, mode);
 1068: 			vput(tvp);
 1069: 			return (error);
 1070: 		}
 1071: #endif
 1072: 	}
 1073: #else
 1074: 	ip->i_uid = cnp->cn_cred->cr_uid;
 1075: #ifdef QUOTA
 1076: 	if ((error = getinoquota(ip)) ||
 1077: 	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
 1078: 		UFS_VFREE(tvp, ip->i_number, mode);
 1079: 		vput(tvp);
 1080: 		return (error);
 1081: 	}
 1082: #endif
 1083: #endif
 1084: 	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
 1085: 	ip->i_mode = mode;
 1086: 	tvp->v_type = IFTOVT(mode);	/* Rest init'd in getnewvnode(). */
 1087: 	ip->i_nlink = 1;
 1088: 	if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
 1089: 	    suser_cred(cnp->cn_cred, PRISON_ROOT))
 1090: 		ip->i_mode &= ~ISGID;
 1091: 
 1092: 	if (cnp->cn_flags & CNP_ISWHITEOUT)
 1093: 		ip->i_flags |= UF_OPAQUE;
 1094: 
 1095: 	/*
 1096: 	 * Make sure inode goes to disk before directory entry.
 1097: 	 */
 1098: 	error = UFS_UPDATE(tvp, 1);
 1099: 	if (error)
 1100: 		goto bad;
 1101: 	error = ext2_direnter(ip, dvp, cnp);
 1102: 	if (error)
 1103: 		goto bad;
 1104: 
 1105: 	*vpp = tvp;
 1106: 	return (0);
 1107: 
 1108: bad:
 1109: 	/*
 1110: 	 * Write error occurred trying to update the inode
 1111: 	 * or the directory so must deallocate the inode.
 1112: 	 */
 1113: 	ip->i_nlink = 0;
 1114: 	ip->i_flag |= IN_CHANGE;
 1115: 	vput(tvp);
 1116: 	return (error);
 1117: }
 1118: 
 1119: /*
 1120:  * get page routine
 1121:  *
 1122:  * XXX By default, wimp out... note that a_offset is ignored (and always
 1123:  * XXX has been).
 1124:  */
 1125: static int
 1126: ext2_getpages(struct vop_getpages_args *ap)
 1127: {
 1128: 	return (vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
 1129: 		ap->a_reqpage));
 1130: }
 1131: 
 1132: /*
 1133:  * put page routine
 1134:  *
 1135:  * XXX By default, wimp out... note that a_offset is ignored (and always
 1136:  * XXX has been).
 1137:  */
 1138: static int
 1139: ext2_putpages(struct vop_putpages_args *ap)
 1140: {
 1141: 	return (vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
 1142: 		ap->a_sync, ap->a_rtvals));
 1143: }