PageRenderTime 109ms CodeModel.GetById 2ms app.highlight 92ms RepoModel.GetById 1ms app.codeStats 1ms

/sys/ufs/ufs/ufs_vnops.c

https://bitbucket.org/gthummalapalle/minix
C | 2989 lines | 1957 code | 220 blank | 812 comment | 477 complexity | 243686a49f381a6797c8d3dea722aed3 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*	$NetBSD: ufs_vnops.c,v 1.206 2011/11/18 21:18:52 christos Exp $	*/
   2
   3/*-
   4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
   5 * All rights reserved.
   6 *
   7 * This code is derived from software contributed to The NetBSD Foundation
   8 * by Wasabi Systems, Inc.
   9 *
  10 * Redistribution and use in source and binary forms, with or without
  11 * modification, are permitted provided that the following conditions
  12 * are met:
  13 * 1. Redistributions of source code must retain the above copyright
  14 *    notice, this list of conditions and the following disclaimer.
  15 * 2. Redistributions in binary form must reproduce the above copyright
  16 *    notice, this list of conditions and the following disclaimer in the
  17 *    documentation and/or other materials provided with the distribution.
  18 *
  19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  29 * POSSIBILITY OF SUCH DAMAGE.
  30 */
  31
  32/*
  33 * Copyright (c) 1982, 1986, 1989, 1993, 1995
  34 *	The Regents of the University of California.  All rights reserved.
  35 * (c) UNIX System Laboratories, Inc.
  36 * All or some portions of this file are derived from material licensed
  37 * to the University of California by American Telephone and Telegraph
  38 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
  39 * the permission of UNIX System Laboratories, Inc.
  40 *
  41 * Redistribution and use in source and binary forms, with or without
  42 * modification, are permitted provided that the following conditions
  43 * are met:
  44 * 1. Redistributions of source code must retain the above copyright
  45 *    notice, this list of conditions and the following disclaimer.
  46 * 2. Redistributions in binary form must reproduce the above copyright
  47 *    notice, this list of conditions and the following disclaimer in the
  48 *    documentation and/or other materials provided with the distribution.
  49 * 3. Neither the name of the University nor the names of its contributors
  50 *    may be used to endorse or promote products derived from this software
  51 *    without specific prior written permission.
  52 *
  53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  56 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  63 * SUCH DAMAGE.
  64 *
  65 *	@(#)ufs_vnops.c	8.28 (Berkeley) 7/31/95
  66 */
  67
  68#include <sys/cdefs.h>
  69__KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,v 1.206 2011/11/18 21:18:52 christos Exp $");
  70
  71#if defined(_KERNEL_OPT)
  72#include "opt_ffs.h"
  73#include "opt_quota.h"
  74#endif
  75
  76#include <sys/param.h>
  77#include <sys/systm.h>
  78#include <sys/namei.h>
  79#include <sys/resourcevar.h>
  80#include <sys/kernel.h>
  81#include <sys/file.h>
  82#include <sys/stat.h>
  83#include <sys/buf.h>
  84#include <sys/proc.h>
  85#include <sys/mount.h>
  86#include <sys/vnode.h>
  87#include <sys/malloc.h>
  88#include <sys/dirent.h>
  89#include <sys/lockf.h>
  90#include <sys/kauth.h>
  91#include <sys/wapbl.h>
  92#include <sys/fstrans.h>
  93
  94#include <miscfs/specfs/specdev.h>
  95#include <miscfs/fifofs/fifo.h>
  96#include <miscfs/genfs/genfs.h>
  97
  98#include <ufs/ufs/inode.h>
  99#include <ufs/ufs/dir.h>
 100#include <ufs/ufs/ufsmount.h>
 101#include <ufs/ufs/ufs_bswap.h>
 102#include <ufs/ufs/ufs_extern.h>
 103#include <ufs/ufs/ufs_wapbl.h>
 104#ifdef UFS_DIRHASH
 105#include <ufs/ufs/dirhash.h>
 106#endif
 107#include <ufs/ext2fs/ext2fs_extern.h>
 108#include <ufs/ext2fs/ext2fs_dir.h>
 109#include <ufs/ffs/ffs_extern.h>
 110#include <ufs/lfs/lfs_extern.h>
 111#include <ufs/lfs/lfs.h>
 112
 113#include <uvm/uvm.h>
 114
 115__CTASSERT(EXT2FS_MAXNAMLEN == FFS_MAXNAMLEN);
 116__CTASSERT(LFS_MAXNAMLEN == FFS_MAXNAMLEN);
 117
 118static int ufs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *);
 119static int ufs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
 120    struct lwp *);
 121
 122/*
 123 * A virgin directory (no blushing please).
 124 */
 125static const struct dirtemplate mastertemplate = {
 126	0,	12,		DT_DIR,	1,	".",
 127	0,	DIRBLKSIZ - 12,	DT_DIR,	2,	".."
 128};
 129
 130/*
 131 * Create a regular file
 132 */
 133int
 134ufs_create(void *v)
 135{
 136	struct vop_create_args /* {
 137		struct vnode		*a_dvp;
 138		struct vnode		**a_vpp;
 139		struct componentname	*a_cnp;
 140		struct vattr		*a_vap;
 141	} */ *ap = v;
 142	int	error;
 143	struct vnode *dvp = ap->a_dvp;
 144	struct ufs_lookup_results *ulr;
 145
 146	/* XXX should handle this material another way */
 147	ulr = &VTOI(dvp)->i_crap;
 148	UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
 149
 150	/*
 151	 * UFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful
 152	 * ufs_makeinode
 153	 */
 154	fstrans_start(dvp->v_mount, FSTRANS_SHARED);
 155	error =
 156	    ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
 157			  dvp, ulr, ap->a_vpp, ap->a_cnp);
 158	if (error) {
 159		fstrans_done(dvp->v_mount);
 160		return (error);
 161	}
 162	UFS_WAPBL_END1(dvp->v_mount, dvp);
 163	fstrans_done(dvp->v_mount);
 164	VN_KNOTE(dvp, NOTE_WRITE);
 165	return (0);
 166}
 167
 168/*
 169 * Mknod vnode call
 170 */
 171/* ARGSUSED */
 172int
 173ufs_mknod(void *v)
 174{
 175	struct vop_mknod_args /* {
 176		struct vnode		*a_dvp;
 177		struct vnode		**a_vpp;
 178		struct componentname	*a_cnp;
 179		struct vattr		*a_vap;
 180	} */ *ap = v;
 181	struct vattr	*vap;
 182	struct vnode	**vpp;
 183	struct inode	*ip;
 184	int		error;
 185	struct mount	*mp;
 186	ino_t		ino;
 187	struct ufs_lookup_results *ulr;
 188
 189	vap = ap->a_vap;
 190	vpp = ap->a_vpp;
 191
 192	/* XXX should handle this material another way */
 193	ulr = &VTOI(ap->a_dvp)->i_crap;
 194	UFS_CHECK_CRAPCOUNTER(VTOI(ap->a_dvp));
 195
 196	/*
 197	 * UFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful
 198	 * ufs_makeinode
 199	 */
 200	fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED);
 201	if ((error =
 202	    ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
 203	    ap->a_dvp, ulr, vpp, ap->a_cnp)) != 0)
 204		goto out;
 205	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
 206	ip = VTOI(*vpp);
 207	mp  = (*vpp)->v_mount;
 208	ino = ip->i_number;
 209	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
 210	if (vap->va_rdev != VNOVAL) {
 211		struct ufsmount *ump = ip->i_ump;
 212		/*
 213		 * Want to be able to use this to make badblock
 214		 * inodes, so don't truncate the dev number.
 215		 */
 216		if (ump->um_fstype == UFS1)
 217			ip->i_ffs1_rdev = ufs_rw32(vap->va_rdev,
 218			    UFS_MPNEEDSWAP(ump));
 219		else
 220			ip->i_ffs2_rdev = ufs_rw64(vap->va_rdev,
 221			    UFS_MPNEEDSWAP(ump));
 222	}
 223	UFS_WAPBL_UPDATE(*vpp, NULL, NULL, 0);
 224	UFS_WAPBL_END1(ap->a_dvp->v_mount, ap->a_dvp);
 225	/*
 226	 * Remove inode so that it will be reloaded by VFS_VGET and
 227	 * checked to see if it is an alias of an existing entry in
 228	 * the inode cache.
 229	 */
 230	(*vpp)->v_type = VNON;
 231	VOP_UNLOCK(*vpp);
 232	vgone(*vpp);
 233	error = VFS_VGET(mp, ino, vpp);
 234out:
 235	fstrans_done(ap->a_dvp->v_mount);
 236	if (error != 0) {
 237		*vpp = NULL;
 238		return (error);
 239	}
 240	return (0);
 241}
 242
 243/*
 244 * Open called.
 245 *
 246 * Nothing to do.
 247 */
 248/* ARGSUSED */
 249int
 250ufs_open(void *v)
 251{
 252	struct vop_open_args /* {
 253		struct vnode	*a_vp;
 254		int		a_mode;
 255		kauth_cred_t	a_cred;
 256	} */ *ap = v;
 257
 258	/*
 259	 * Files marked append-only must be opened for appending.
 260	 */
 261	if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
 262	    (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
 263		return (EPERM);
 264	return (0);
 265}
 266
 267/*
 268 * Close called.
 269 *
 270 * Update the times on the inode.
 271 */
 272/* ARGSUSED */
 273int
 274ufs_close(void *v)
 275{
 276	struct vop_close_args /* {
 277		struct vnode	*a_vp;
 278		int		a_fflag;
 279		kauth_cred_t	a_cred;
 280	} */ *ap = v;
 281	struct vnode	*vp;
 282	struct inode	*ip;
 283
 284	vp = ap->a_vp;
 285	ip = VTOI(vp);
 286	fstrans_start(vp->v_mount, FSTRANS_SHARED);
 287	if (vp->v_usecount > 1)
 288		UFS_ITIMES(vp, NULL, NULL, NULL);
 289	fstrans_done(vp->v_mount);
 290	return (0);
 291}
 292
 293static int
 294ufs_check_possible(struct vnode *vp, struct inode *ip, mode_t mode,
 295    kauth_cred_t cred)
 296{
 297#if defined(QUOTA) || defined(QUOTA2)
 298	int error;
 299#endif
 300
 301	/*
 302	 * Disallow write attempts on read-only file systems;
 303	 * unless the file is a socket, fifo, or a block or
 304	 * character device resident on the file system.
 305	 */
 306	if (mode & VWRITE) {
 307		switch (vp->v_type) {
 308		case VDIR:
 309		case VLNK:
 310		case VREG:
 311			if (vp->v_mount->mnt_flag & MNT_RDONLY)
 312				return (EROFS);
 313#if defined(QUOTA) || defined(QUOTA2)
 314			fstrans_start(vp->v_mount, FSTRANS_SHARED);
 315			error = chkdq(ip, 0, cred, 0);
 316			fstrans_done(vp->v_mount);
 317			if (error != 0)
 318				return error;
 319#endif
 320			break;
 321		case VBAD:
 322		case VBLK:
 323		case VCHR:
 324		case VSOCK:
 325		case VFIFO:
 326		case VNON:
 327		default:
 328			break;
 329		}
 330	}
 331
 332	/* If it is a snapshot, nobody gets access to it. */
 333	if ((ip->i_flags & SF_SNAPSHOT))
 334		return (EPERM);
 335	/* If immutable bit set, nobody gets to write it. */
 336	if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
 337		return (EPERM);
 338
 339	return 0;
 340}
 341
 342static int
 343ufs_check_permitted(struct vnode *vp, struct inode *ip, mode_t mode,
 344    kauth_cred_t cred)
 345{
 346
 347	return genfs_can_access(vp->v_type, ip->i_mode & ALLPERMS, ip->i_uid,
 348	    ip->i_gid, mode, cred);
 349}
 350
 351int
 352ufs_access(void *v)
 353{
 354	struct vop_access_args /* {
 355		struct vnode	*a_vp;
 356		int		a_mode;
 357		kauth_cred_t	a_cred;
 358	} */ *ap = v;
 359	struct vnode	*vp;
 360	struct inode	*ip;
 361	mode_t		mode;
 362	int		error;
 363
 364	vp = ap->a_vp;
 365	ip = VTOI(vp);
 366	mode = ap->a_mode;
 367
 368	error = ufs_check_possible(vp, ip, mode, ap->a_cred);
 369	if (error)
 370		return error;
 371
 372	error = ufs_check_permitted(vp, ip, mode, ap->a_cred);
 373
 374	return error;
 375}
 376
 377/* ARGSUSED */
 378int
 379ufs_getattr(void *v)
 380{
 381	struct vop_getattr_args /* {
 382		struct vnode	*a_vp;
 383		struct vattr	*a_vap;
 384		kauth_cred_t	a_cred;
 385	} */ *ap = v;
 386	struct vnode	*vp;
 387	struct inode	*ip;
 388	struct vattr	*vap;
 389
 390	vp = ap->a_vp;
 391	ip = VTOI(vp);
 392	vap = ap->a_vap;
 393	fstrans_start(vp->v_mount, FSTRANS_SHARED);
 394	UFS_ITIMES(vp, NULL, NULL, NULL);
 395
 396	/*
 397	 * Copy from inode table
 398	 */
 399	vap->va_fsid = ip->i_dev;
 400	vap->va_fileid = ip->i_number;
 401	vap->va_mode = ip->i_mode & ALLPERMS;
 402	vap->va_nlink = ip->i_nlink;
 403	vap->va_uid = ip->i_uid;
 404	vap->va_gid = ip->i_gid;
 405	vap->va_size = vp->v_size;
 406	if (ip->i_ump->um_fstype == UFS1) {
 407		vap->va_rdev = (dev_t)ufs_rw32(ip->i_ffs1_rdev,
 408		    UFS_MPNEEDSWAP(ip->i_ump));
 409		vap->va_atime.tv_sec = ip->i_ffs1_atime;
 410		vap->va_atime.tv_nsec = ip->i_ffs1_atimensec;
 411		vap->va_mtime.tv_sec = ip->i_ffs1_mtime;
 412		vap->va_mtime.tv_nsec = ip->i_ffs1_mtimensec;
 413		vap->va_ctime.tv_sec = ip->i_ffs1_ctime;
 414		vap->va_ctime.tv_nsec = ip->i_ffs1_ctimensec;
 415		vap->va_birthtime.tv_sec = 0;
 416		vap->va_birthtime.tv_nsec = 0;
 417		vap->va_bytes = dbtob((u_quad_t)ip->i_ffs1_blocks);
 418	} else {
 419		vap->va_rdev = (dev_t)ufs_rw64(ip->i_ffs2_rdev,
 420		    UFS_MPNEEDSWAP(ip->i_ump));
 421		vap->va_atime.tv_sec = ip->i_ffs2_atime;
 422		vap->va_atime.tv_nsec = ip->i_ffs2_atimensec;
 423		vap->va_mtime.tv_sec = ip->i_ffs2_mtime;
 424		vap->va_mtime.tv_nsec = ip->i_ffs2_mtimensec;
 425		vap->va_ctime.tv_sec = ip->i_ffs2_ctime;
 426		vap->va_ctime.tv_nsec = ip->i_ffs2_ctimensec;
 427		vap->va_birthtime.tv_sec = ip->i_ffs2_birthtime;
 428		vap->va_birthtime.tv_nsec = ip->i_ffs2_birthnsec;
 429		vap->va_bytes = dbtob(ip->i_ffs2_blocks);
 430	}
 431	vap->va_gen = ip->i_gen;
 432	vap->va_flags = ip->i_flags;
 433
 434	/* this doesn't belong here */
 435	if (vp->v_type == VBLK)
 436		vap->va_blocksize = BLKDEV_IOSIZE;
 437	else if (vp->v_type == VCHR)
 438		vap->va_blocksize = MAXBSIZE;
 439	else
 440		vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
 441	vap->va_type = vp->v_type;
 442	vap->va_filerev = ip->i_modrev;
 443	fstrans_done(vp->v_mount);
 444	return (0);
 445}
 446
 447/*
 448 * Set attribute vnode op. called from several syscalls
 449 */
 450int
 451ufs_setattr(void *v)
 452{
 453	struct vop_setattr_args /* {
 454		struct vnode	*a_vp;
 455		struct vattr	*a_vap;
 456		kauth_cred_t	a_cred;
 457	} */ *ap = v;
 458	struct vattr	*vap;
 459	struct vnode	*vp;
 460	struct inode	*ip;
 461	kauth_cred_t	cred;
 462	struct lwp	*l;
 463	int		error;
 464
 465	vap = ap->a_vap;
 466	vp = ap->a_vp;
 467	ip = VTOI(vp);
 468	cred = ap->a_cred;
 469	l = curlwp;
 470
 471	/*
 472	 * Check for unsettable attributes.
 473	 */
 474	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
 475	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
 476	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
 477	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
 478		return (EINVAL);
 479	}
 480
 481	fstrans_start(vp->v_mount, FSTRANS_SHARED);
 482
 483	if (vap->va_flags != VNOVAL) {
 484		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
 485			error = EROFS;
 486			goto out;
 487		}
 488		if (kauth_cred_geteuid(cred) != ip->i_uid &&
 489		    (error = kauth_authorize_generic(cred,
 490		    KAUTH_GENERIC_ISSUSER, NULL)))
 491			goto out;
 492		if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
 493		    NULL) == 0) {
 494			if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) &&
 495			    kauth_authorize_system(l->l_cred,
 496			     KAUTH_SYSTEM_CHSYSFLAGS, 0, NULL, NULL, NULL)) {
 497				error = EPERM;
 498				goto out;
 499			}
 500			/* Snapshot flag cannot be set or cleared */
 501			if ((vap->va_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) !=
 502			    (ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL))) {
 503				error = EPERM;
 504				goto out;
 505			}
 506			error = UFS_WAPBL_BEGIN(vp->v_mount);
 507			if (error)
 508				goto out;
 509			ip->i_flags = vap->va_flags;
 510			DIP_ASSIGN(ip, flags, ip->i_flags);
 511		} else {
 512			if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) ||
 513			    (vap->va_flags & UF_SETTABLE) != vap->va_flags) {
 514				error = EPERM;
 515				goto out;
 516			}
 517			if ((ip->i_flags & SF_SETTABLE) !=
 518			    (vap->va_flags & SF_SETTABLE)) {
 519				error = EPERM;
 520				goto out;
 521			}
 522			error = UFS_WAPBL_BEGIN(vp->v_mount);
 523			if (error)
 524				goto out;
 525			ip->i_flags &= SF_SETTABLE;
 526			ip->i_flags |= (vap->va_flags & UF_SETTABLE);
 527			DIP_ASSIGN(ip, flags, ip->i_flags);
 528		}
 529		ip->i_flag |= IN_CHANGE;
 530		UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
 531		UFS_WAPBL_END(vp->v_mount);
 532		if (vap->va_flags & (IMMUTABLE | APPEND)) {
 533			error = 0;
 534			goto out;
 535		}
 536	}
 537	if (ip->i_flags & (IMMUTABLE | APPEND)) {
 538		error = EPERM;
 539		goto out;
 540	}
 541	/*
 542	 * Go through the fields and update iff not VNOVAL.
 543	 */
 544	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
 545		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
 546			error = EROFS;
 547			goto out;
 548		}
 549		error = UFS_WAPBL_BEGIN(vp->v_mount);
 550		if (error)
 551			goto out;
 552		error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
 553		UFS_WAPBL_END(vp->v_mount);
 554		if (error)
 555			goto out;
 556	}
 557	if (vap->va_size != VNOVAL) {
 558		/*
 559		 * Disallow write attempts on read-only file systems;
 560		 * unless the file is a socket, fifo, or a block or
 561		 * character device resident on the file system.
 562		 */
 563		switch (vp->v_type) {
 564		case VDIR:
 565			error = EISDIR;
 566			goto out;
 567		case VCHR:
 568		case VBLK:
 569		case VFIFO:
 570			break;
 571		case VREG:
 572			if (vp->v_mount->mnt_flag & MNT_RDONLY) {
 573				error = EROFS;
 574				goto out;
 575			}
 576			if ((ip->i_flags & SF_SNAPSHOT) != 0) {
 577				error = EPERM;
 578				goto out;
 579			}
 580			error = UFS_WAPBL_BEGIN(vp->v_mount);
 581			if (error)
 582				goto out;
 583			/*
 584			 * When journaling, only truncate one indirect block
 585			 * at a time.
 586			 */
 587			if (vp->v_mount->mnt_wapbl) {
 588				uint64_t incr = MNINDIR(ip->i_ump) <<
 589				    vp->v_mount->mnt_fs_bshift; /* Power of 2 */
 590				uint64_t base = NDADDR <<
 591				    vp->v_mount->mnt_fs_bshift;
 592				while (!error && ip->i_size > base + incr &&
 593				    ip->i_size > vap->va_size + incr) {
 594					/*
 595					 * round down to next full indirect
 596					 * block boundary.
 597					 */
 598					uint64_t nsize = base +
 599					    ((ip->i_size - base - 1) &
 600					    ~(incr - 1));
 601					error = UFS_TRUNCATE(vp, nsize, 0,
 602					    cred);
 603					if (error == 0) {
 604						UFS_WAPBL_END(vp->v_mount);
 605						error =
 606						   UFS_WAPBL_BEGIN(vp->v_mount);
 607					}
 608				}
 609			}
 610			if (!error)
 611				error = UFS_TRUNCATE(vp, vap->va_size, 0, cred);
 612			UFS_WAPBL_END(vp->v_mount);
 613			if (error)
 614				goto out;
 615			break;
 616		default:
 617			error = EOPNOTSUPP;
 618			goto out;
 619		}
 620	}
 621	ip = VTOI(vp);
 622	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
 623	    vap->va_birthtime.tv_sec != VNOVAL) {
 624		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
 625			error = EROFS;
 626			goto out;
 627		}
 628		if ((ip->i_flags & SF_SNAPSHOT) != 0) {
 629			error = EPERM;
 630			goto out;
 631		}
 632		error = genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid, cred);
 633		if (error)
 634			goto out;
 635		error = UFS_WAPBL_BEGIN(vp->v_mount);
 636		if (error)
 637			goto out;
 638		if (vap->va_atime.tv_sec != VNOVAL)
 639			if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
 640				ip->i_flag |= IN_ACCESS;
 641		if (vap->va_mtime.tv_sec != VNOVAL) {
 642			ip->i_flag |= IN_CHANGE | IN_UPDATE;
 643			if (vp->v_mount->mnt_flag & MNT_RELATIME)
 644				ip->i_flag |= IN_ACCESS;
 645		}
 646		if (vap->va_birthtime.tv_sec != VNOVAL &&
 647		    ip->i_ump->um_fstype == UFS2) {
 648			ip->i_ffs2_birthtime = vap->va_birthtime.tv_sec;
 649			ip->i_ffs2_birthnsec = vap->va_birthtime.tv_nsec;
 650		}
 651		error = UFS_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 0);
 652		UFS_WAPBL_END(vp->v_mount);
 653		if (error)
 654			goto out;
 655	}
 656	error = 0;
 657	if (vap->va_mode != (mode_t)VNOVAL) {
 658		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
 659			error = EROFS;
 660			goto out;
 661		}
 662		if ((ip->i_flags & SF_SNAPSHOT) != 0 &&
 663		    (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP |
 664		     S_IXOTH | S_IWOTH))) {
 665			error = EPERM;
 666			goto out;
 667		}
 668		error = UFS_WAPBL_BEGIN(vp->v_mount);
 669		if (error)
 670			goto out;
 671		error = ufs_chmod(vp, (int)vap->va_mode, cred, l);
 672		UFS_WAPBL_END(vp->v_mount);
 673	}
 674	VN_KNOTE(vp, NOTE_ATTRIB);
 675out:
 676	fstrans_done(vp->v_mount);
 677	return (error);
 678}
 679
 680/*
 681 * Change the mode on a file.
 682 * Inode must be locked before calling.
 683 */
 684static int
 685ufs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l)
 686{
 687	struct inode	*ip;
 688	int		error;
 689
 690	UFS_WAPBL_JLOCK_ASSERT(vp->v_mount);
 691
 692	ip = VTOI(vp);
 693
 694	error = genfs_can_chmod(vp, cred, ip->i_uid, ip->i_gid, mode);
 695	if (error)
 696		return (error);
 697
 698	fstrans_start(vp->v_mount, FSTRANS_SHARED);
 699	ip->i_mode &= ~ALLPERMS;
 700	ip->i_mode |= (mode & ALLPERMS);
 701	ip->i_flag |= IN_CHANGE;
 702	DIP_ASSIGN(ip, mode, ip->i_mode);
 703	UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
 704	fstrans_done(vp->v_mount);
 705	return (0);
 706}
 707
 708/*
 709 * Perform chown operation on inode ip;
 710 * inode must be locked prior to call.
 711 */
 712static int
 713ufs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
 714    	struct lwp *l)
 715{
 716	struct inode	*ip;
 717	int		error = 0;
 718#if defined(QUOTA) || defined(QUOTA2)
 719	uid_t		ouid;
 720	gid_t		ogid;
 721	int64_t		change;
 722#endif
 723	ip = VTOI(vp);
 724	error = 0;
 725
 726	if (uid == (uid_t)VNOVAL)
 727		uid = ip->i_uid;
 728	if (gid == (gid_t)VNOVAL)
 729		gid = ip->i_gid;
 730
 731	error = genfs_can_chown(vp, cred, ip->i_uid, ip->i_gid, uid, gid);
 732	if (error)
 733		return (error);
 734
 735	fstrans_start(vp->v_mount, FSTRANS_SHARED);
 736#if defined(QUOTA) || defined(QUOTA2)
 737	ogid = ip->i_gid;
 738	ouid = ip->i_uid;
 739	change = DIP(ip, blocks);
 740	(void) chkdq(ip, -change, cred, 0);
 741	(void) chkiq(ip, -1, cred, 0);
 742#endif
 743	ip->i_gid = gid;
 744	DIP_ASSIGN(ip, gid, gid);
 745	ip->i_uid = uid;
 746	DIP_ASSIGN(ip, uid, uid);
 747#if defined(QUOTA) || defined(QUOTA2)
 748	if ((error = chkdq(ip, change, cred, 0)) == 0) {
 749		if ((error = chkiq(ip, 1, cred, 0)) == 0)
 750			goto good;
 751		else
 752			(void) chkdq(ip, -change, cred, FORCE);
 753	}
 754	ip->i_gid = ogid;
 755	DIP_ASSIGN(ip, gid, ogid);
 756	ip->i_uid = ouid;
 757	DIP_ASSIGN(ip, uid, ouid);
 758	(void) chkdq(ip, change, cred, FORCE);
 759	(void) chkiq(ip, 1, cred, FORCE);
 760	fstrans_done(vp->v_mount);
 761	return (error);
 762 good:
 763#endif /* QUOTA || QUOTA2 */
 764	ip->i_flag |= IN_CHANGE;
 765	UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
 766	fstrans_done(vp->v_mount);
 767	return (0);
 768}
 769
 770int
 771ufs_remove(void *v)
 772{
 773	struct vop_remove_args /* {
 774		struct vnode		*a_dvp;
 775		struct vnode		*a_vp;
 776		struct componentname	*a_cnp;
 777	} */ *ap = v;
 778	struct vnode	*vp, *dvp;
 779	struct inode	*ip;
 780	int		error;
 781	struct ufs_lookup_results *ulr;
 782
 783	vp = ap->a_vp;
 784	dvp = ap->a_dvp;
 785	ip = VTOI(vp);
 786
 787	/* XXX should handle this material another way */
 788	ulr = &VTOI(dvp)->i_crap;
 789	UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
 790
 791	fstrans_start(dvp->v_mount, FSTRANS_SHARED);
 792	if (vp->v_type == VDIR || (ip->i_flags & (IMMUTABLE | APPEND)) ||
 793	    (VTOI(dvp)->i_flags & APPEND))
 794		error = EPERM;
 795	else {
 796		error = UFS_WAPBL_BEGIN(dvp->v_mount);
 797		if (error == 0) {
 798			error = ufs_dirremove(dvp, ulr,
 799					      ip, ap->a_cnp->cn_flags, 0);
 800			UFS_WAPBL_END(dvp->v_mount);
 801		}
 802	}
 803	VN_KNOTE(vp, NOTE_DELETE);
 804	VN_KNOTE(dvp, NOTE_WRITE);
 805	if (dvp == vp)
 806		vrele(vp);
 807	else
 808		vput(vp);
 809	vput(dvp);
 810	fstrans_done(dvp->v_mount);
 811	return (error);
 812}
 813
 814/*
 815 * ufs_link: create hard link.
 816 */
 817int
 818ufs_link(void *v)
 819{
 820	struct vop_link_args /* {
 821		struct vnode *a_dvp;
 822		struct vnode *a_vp;
 823		struct componentname *a_cnp;
 824	} */ *ap = v;
 825	struct vnode *dvp = ap->a_dvp;
 826	struct vnode *vp = ap->a_vp;
 827	struct componentname *cnp = ap->a_cnp;
 828	struct inode *ip;
 829	struct direct *newdir;
 830	int error;
 831	struct ufs_lookup_results *ulr;
 832
 833	KASSERT(dvp != vp);
 834	KASSERT(vp->v_type != VDIR);
 835	KASSERT(dvp->v_mount == vp->v_mount);
 836
 837	/* XXX should handle this material another way */
 838	ulr = &VTOI(dvp)->i_crap;
 839	UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
 840
 841	fstrans_start(dvp->v_mount, FSTRANS_SHARED);
 842	error = vn_lock(vp, LK_EXCLUSIVE);
 843	if (error) {
 844		VOP_ABORTOP(dvp, cnp);
 845		goto out2;
 846	}
 847	ip = VTOI(vp);
 848	if ((nlink_t)ip->i_nlink >= LINK_MAX) {
 849		VOP_ABORTOP(dvp, cnp);
 850		error = EMLINK;
 851		goto out1;
 852	}
 853	if (ip->i_flags & (IMMUTABLE | APPEND)) {
 854		VOP_ABORTOP(dvp, cnp);
 855		error = EPERM;
 856		goto out1;
 857	}
 858	error = UFS_WAPBL_BEGIN(vp->v_mount);
 859	if (error) {
 860		VOP_ABORTOP(dvp, cnp);
 861		goto out1;
 862	}
 863	ip->i_nlink++;
 864	DIP_ASSIGN(ip, nlink, ip->i_nlink);
 865	ip->i_flag |= IN_CHANGE;
 866	error = UFS_UPDATE(vp, NULL, NULL, UPDATE_DIROP);
 867	if (!error) {
 868		newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK);
 869		ufs_makedirentry(ip, cnp, newdir);
 870		error = ufs_direnter(dvp, ulr, vp, newdir, cnp, NULL);
 871		pool_cache_put(ufs_direct_cache, newdir);
 872	}
 873	if (error) {
 874		ip->i_nlink--;
 875		DIP_ASSIGN(ip, nlink, ip->i_nlink);
 876		ip->i_flag |= IN_CHANGE;
 877		UFS_WAPBL_UPDATE(vp, NULL, NULL, UPDATE_DIROP);
 878	}
 879	UFS_WAPBL_END(vp->v_mount);
 880 out1:
 881	VOP_UNLOCK(vp);
 882 out2:
 883	VN_KNOTE(vp, NOTE_LINK);
 884	VN_KNOTE(dvp, NOTE_WRITE);
 885	vput(dvp);
 886	fstrans_done(dvp->v_mount);
 887	return (error);
 888}
 889
 890/*
 891 * whiteout vnode call
 892 */
 893int
 894ufs_whiteout(void *v)
 895{
 896	struct vop_whiteout_args /* {
 897		struct vnode		*a_dvp;
 898		struct componentname	*a_cnp;
 899		int			a_flags;
 900	} */ *ap = v;
 901	struct vnode		*dvp = ap->a_dvp;
 902	struct componentname	*cnp = ap->a_cnp;
 903	struct direct		*newdir;
 904	int			error;
 905	struct ufsmount		*ump = VFSTOUFS(dvp->v_mount);
 906	struct ufs_lookup_results *ulr;
 907
 908	/* XXX should handle this material another way */
 909	ulr = &VTOI(dvp)->i_crap;
 910	UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
 911
 912	error = 0;
 913	switch (ap->a_flags) {
 914	case LOOKUP:
 915		/* 4.4 format directories support whiteout operations */
 916		if (ump->um_maxsymlinklen > 0)
 917			return (0);
 918		return (EOPNOTSUPP);
 919
 920	case CREATE:
 921		/* create a new directory whiteout */
 922		fstrans_start(dvp->v_mount, FSTRANS_SHARED);
 923		error = UFS_WAPBL_BEGIN(dvp->v_mount);
 924		if (error)
 925			break;
 926#ifdef DIAGNOSTIC
 927		if (ump->um_maxsymlinklen <= 0)
 928			panic("ufs_whiteout: old format filesystem");
 929#endif
 930
 931		newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK);
 932		newdir->d_ino = WINO;
 933		newdir->d_namlen = cnp->cn_namelen;
 934		memcpy(newdir->d_name, cnp->cn_nameptr,
 935		    (size_t)cnp->cn_namelen);
 936		newdir->d_name[cnp->cn_namelen] = '\0';
 937		newdir->d_type = DT_WHT;
 938		error = ufs_direnter(dvp, ulr, NULL, newdir, cnp, NULL);
 939		pool_cache_put(ufs_direct_cache, newdir);
 940		break;
 941
 942	case DELETE:
 943		/* remove an existing directory whiteout */
 944		fstrans_start(dvp->v_mount, FSTRANS_SHARED);
 945		error = UFS_WAPBL_BEGIN(dvp->v_mount);
 946		if (error)
 947			break;
 948#ifdef DIAGNOSTIC
 949		if (ump->um_maxsymlinklen <= 0)
 950			panic("ufs_whiteout: old format filesystem");
 951#endif
 952
 953		cnp->cn_flags &= ~DOWHITEOUT;
 954		error = ufs_dirremove(dvp, ulr, NULL, cnp->cn_flags, 0);
 955		break;
 956	default:
 957		panic("ufs_whiteout: unknown op");
 958		/* NOTREACHED */
 959	}
 960	UFS_WAPBL_END(dvp->v_mount);
 961	fstrans_done(dvp->v_mount);
 962	return (error);
 963}
 964
 965
 966/*
 967 * Rename vnode operation
 968 * 	rename("foo", "bar");
 969 * is essentially
 970 *	unlink("bar");
 971 *	link("foo", "bar");
 972 *	unlink("foo");
 973 * but ``atomically''.  Can't do full commit without saving state in the
 974 * inode on disk which isn't feasible at this time.  Best we can do is
 975 * always guarantee the target exists.
 976 *
 977 * Basic algorithm is:
 978 *
 979 * 1) Bump link count on source while we're linking it to the
 980 *    target.  This also ensure the inode won't be deleted out
 981 *    from underneath us while we work (it may be truncated by
 982 *    a concurrent `trunc' or `open' for creation).
 983 * 2) Link source to destination.  If destination already exists,
 984 *    delete it first.
 985 * 3) Unlink source reference to inode if still around. If a
 986 *    directory was moved and the parent of the destination
 987 *    is different from the source, patch the ".." entry in the
 988 *    directory.
 989 */
 990
 991/*
 992 * Notes on rename locking:
 993 *
 994 * We lock parent vnodes before child vnodes. This means in particular
 995 * that if A is above B in the directory tree then A must be locked
 996 * before B. (This is true regardless of how many steps appear in
 997 * between, because an arbitrary number of other processes could lock
 998 * parent/child in between and establish a lock cycle and deadlock.)
 999 *
1000 * Therefore, if tdvp is above fdvp we must lock tdvp first; if fdvp
1001 * is above tdvp we must lock fdvp first; and if they're
1002 * incommensurate it doesn't matter. (But, we rely on the fact that
1003 * there's a whole-volume rename lock to prevent deadlock among groups
1004 * of renames upon overlapping sets of incommensurate vnodes.)
1005 *
1006 * In addition to establishing lock ordering the parent check also
1007 * serves to rule out cases where someone tries to move a directory
1008 * underneath itself, e.g. rename("a/b", "a/b/c"). If allowed to
1009 * proceed such renames would detach portions of the directory tree
1010 * and make fsck very unhappy.
1011 *
1012 * Note that it is an error for *fvp* to be above tdvp; however,
1013 * *fdvp* can be above tdvp, as in rename("a/b", "a/c/d").
1014 *
1015 * The parent check searches up the tree from tdvp until it either
1016 * finds fdvp or the root of the volume. It also returns the vnode it
1017 * saw immediately before fdvp, if any. Later on (after looking up
1018 * fvp) we will check to see if this *is* fvp and if so fail.
1019 *
1020 * If the parent check finds fdvp, it means fdvp is above tdvp, so we
1021 * lock fdvp first and then tdvp. Otherwise, either tdvp is above fdvp
1022 * or they're incommensurate and we lock tdvp first.
1023 *
1024 * In either case each of the child vnodes has to be looked up and
1025 * locked immediately after its parent. The cases
1026 *
1027 *       fdvp/fvp/[.../]tdvp/tvp
1028 *       tdvp/tvp/[.../]fdvp/fvp
1029 *
1030 * can cause deadlock otherwise. Note that both of these are error
1031 * cases; the first fails the parent check and the second fails
1032 * because tvp isn't empty. The parent check case is handled before
1033 * we start locking; however, the nonempty case requires locking tvp
1034 * to find out safely that it's nonempty.
1035 *
1036 * Therefore the procedure is either
1037 *
1038 *   lock fdvp
1039 *   lookup fvp
1040 *   lock fvp
1041 *   lock tdvp
1042 *   lookup tvp
1043 *   lock tvp
1044 *
1045 * or
1046 *
1047 *   lock tdvp
1048 *   lookup tvp
1049 *   lock tvp
1050 *   lock fdvp
1051 *   lookup fvp
1052 *   lock fvp
1053 *
1054 * This could in principle be simplified by always looking up fvp
1055 * last; because of the parent check we know by the time we start
1056 * locking that fvp cannot be directly above tdvp, so (given the
1057 * whole-volume rename lock and other assumptions) it's safe to lock
1058 * tdvp before fvp. This would allow the following scheme:
1059 *
1060 *   lock fdvp
1061 *   lock tdvp
1062 * or
1063 *   lock tdvp
1064 *   lock fdvp
1065 *
1066 * then
1067 *   lookup tvp
1068 *   lock tvp
1069 *   lookup fvp
1070 *   check if fvp is above of tdvp, fail if so
1071 *   lock fvp
1072 *
1073 * which is much, much simpler.
1074 *
1075 * However, current levels of vfs namei/lookup sanity do not permit
1076 * this. It is impossible currently to look up fvp without locking it.
1077 * (It gets locked regardless of whether LOCKLEAF is set; without
1078 * LOCKLEAF it just gets unlocked again, which doesn't help.)
1079 *
1080 * Therefore, because we must look up fvp to know if it's above tdvp,
1081 * which locks fvp, we must, at least in the case where fdvp is above
1082 * tdvp, do that before locking tdvp. The longer scheme does that; the
1083 * simpler scheme is not safe.
1084 *
1085 * Note that for now we aren't doing lookup() but relookup(); however,
1086 * the differences are minor.
1087 *
1088 * On top of all the above, just to make everything more
1089 * exciting, any two of the vnodes might end up being the same.
1090 *
1091 * FROMPARENT == FROMCHILD	mv a/. foo	is an error.
1092 * FROMPARENT == TOPARENT	mv a/b a/c	is ok.
1093 * FROMPARENT == TOCHILD	mv a/b/c a/b	will give ENOTEMPTY.
1094 * FROMCHILD == TOPARENT	mv a/b a/b/c	fails the parent check.
1095 * FROMCHILD == TOCHILD		mv a/b a/b	is ok.
1096 * TOPARENT == TOCHILD		mv foo a/.	is an error.
1097 *
1098 * This introduces more cases in the locking, because each distinct
1099 * vnode must be locked exactly once.
1100 *
1101 * When FROMPARENT == TOPARENT and FROMCHILD != TOCHILD we assume it
1102 * doesn't matter what order the children are locked in, because the
1103 * per-volume rename lock excludes other renames and no other
1104 * operation locks two files in the same directory at once. (Note: if
1105 * it turns out that link() does, link() is wrong.)
1106 *
1107 * Until such time as we can do lookups without the namei and lookup
1108 * machinery "helpfully" locking the result vnode for us, we can't
1109 * avoid tripping on cases where FROMCHILD == TOCHILD. Currently for
1110 * non-directories we unlock the first one we lock while looking up
1111 * the second, then relock it if necessary. This is more or less
1112 * harmless since not much of interest can happen to the objects in
1113 * that window while we have the containing directory locked; but it's
1114 * not desirable and should be cleaned up when that becomes possible.
1115 * The right way to do it is to check after looking the second one up
1116 * and only lock it if it's different. (Note: for directories we don't
1117 * do this dance because the same directory can't appear more than
1118 * once.)
1119 */
1120
1121/* XXX following lifted from ufs_lookup.c */
1122#define	FSFMT(vp)	(((vp)->v_mount->mnt_iflag & IMNT_DTYPE) == 0)
1123
1124/*
1125 * Check if either entry referred to by FROM_ULR is within the range
1126 * of entries named by TO_ULR.
1127 */
1128static int
1129ulr_overlap(const struct ufs_lookup_results *from_ulr,
1130	    const struct ufs_lookup_results *to_ulr)
1131{
1132	doff_t from_start, from_prevstart;
1133	doff_t to_start, to_end;
1134
1135	/*
1136	 * FROM is a DELETE result; offset points to the entry to
1137	 * remove and subtracting count gives the previous entry.
1138	 */
1139	from_start = from_ulr->ulr_offset - from_ulr->ulr_count;
1140	from_prevstart = from_ulr->ulr_offset;
1141
1142	/*
1143	 * TO is a RENAME (thus non-DELETE) result; offset points
1144	 * to the beginning of a region to write in, and adding
1145	 * count gives the end of the region.
1146	 */
1147	to_start = to_ulr->ulr_offset;
1148	to_end = to_ulr->ulr_offset + to_ulr->ulr_count;
1149
1150	if (from_prevstart >= to_start && from_prevstart < to_end) {
1151		return 1;
1152	}
1153	if (from_start >= to_start && from_start < to_end) {
1154		return 1;
1155	}
1156	return 0;
1157}
1158
1159/*
1160 * Wrapper for relookup that also updates the supplemental results.
1161 */
1162static int
1163do_relookup(struct vnode *dvp, struct ufs_lookup_results *ulr,
1164	    struct vnode **vp, struct componentname *cnp)
1165{
1166	int error;
1167
1168	error = relookup(dvp, vp, cnp, 0);
1169	if (error) {
1170		return error;
1171	}
1172	/* update the supplemental reasults */
1173	*ulr = VTOI(dvp)->i_crap;
1174	UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
1175	return 0;
1176}
1177
1178/*
1179 * Lock and relookup a sequence of two directories and two children.
1180 *
1181 */
1182static int
1183lock_vnode_sequence(struct vnode *d1, struct ufs_lookup_results *ulr1,
1184		    struct vnode **v1_ret, struct componentname *cn1, 
1185		    int v1_missing_ok,
1186		    int overlap_error,
1187		    struct vnode *d2, struct ufs_lookup_results *ulr2,
1188		    struct vnode **v2_ret, struct componentname *cn2, 
1189		    int v2_missing_ok)
1190{
1191	struct vnode *v1, *v2;
1192	int error;
1193
1194	KASSERT(d1 != d2);
1195
1196	vn_lock(d1, LK_EXCLUSIVE | LK_RETRY);
1197	if (VTOI(d1)->i_size == 0) {
1198		/* d1 has been rmdir'd */
1199		VOP_UNLOCK(d1);
1200		return ENOENT;
1201	}
1202	error = do_relookup(d1, ulr1, &v1, cn1);
1203	if (v1_missing_ok) {
1204		if (error == ENOENT) {
1205			/*
1206			 * Note: currently if the name doesn't exist,
1207			 * relookup succeeds (it intercepts the
1208			 * EJUSTRETURN from VOP_LOOKUP) and sets tvp
1209			 * to NULL. Therefore, we will never get
1210			 * ENOENT and this branch is not needed.
1211			 * However, in a saner future the EJUSTRETURN
1212			 * garbage will go away, so let's DTRT.
1213			 */
1214			v1 = NULL;
1215			error = 0;
1216		}
1217	} else {
1218		if (error == 0 && v1 == NULL) {
1219			/* This is what relookup sets if v1 disappeared. */
1220			error = ENOENT;
1221		}
1222	}
1223	if (error) {
1224		VOP_UNLOCK(d1);
1225		return error;
1226	}
1227	if (v1 && v1 == d2) {
1228		VOP_UNLOCK(d1);
1229		VOP_UNLOCK(v1);
1230		vrele(v1);
1231		return overlap_error;
1232	}
1233
1234	/*
1235	 * The right way to do this is to do lookups without locking
1236	 * the results, and lock the results afterwards; then at the
1237	 * end we can avoid trying to lock v2 if v2 == v1.
1238	 *
1239	 * However, for the reasons described in the fdvp == tdvp case
1240	 * in rename below, we can't do that safely. So, in the case
1241	 * where v1 is not a directory, unlock it and lock it again
1242	 * afterwards. This is safe in locking order because a
1243	 * non-directory can't be above anything else in the tree. If
1244	 * v1 *is* a directory, that's not true, but then because d1
1245	 * != d2, v1 != v2.
1246	 */
1247	if (v1 && v1->v_type != VDIR) {
1248		VOP_UNLOCK(v1);
1249	}
1250	vn_lock(d2, LK_EXCLUSIVE | LK_RETRY);
1251	if (VTOI(d2)->i_size == 0) {
1252		/* d2 has been rmdir'd */
1253		VOP_UNLOCK(d2);
1254		if (v1 && v1->v_type == VDIR) {
1255			VOP_UNLOCK(v1);
1256		}
1257		VOP_UNLOCK(d1);
1258		if (v1) {
1259			vrele(v1);
1260		}
1261		return ENOENT;
1262	}
1263	error = do_relookup(d2, ulr2, &v2, cn2);
1264	if (v2_missing_ok) {
1265		if (error == ENOENT) {
1266			/* as above */
1267			v2 = NULL;
1268			error = 0;
1269		}
1270	} else {
1271		if (error == 0 && v2 == NULL) {
1272			/* This is what relookup sets if v2 disappeared. */
1273			error = ENOENT;
1274		}
1275	}
1276	if (error) {
1277		VOP_UNLOCK(d2);
1278		if (v1 && v1->v_type == VDIR) {
1279			VOP_UNLOCK(v1);
1280		}
1281		VOP_UNLOCK(d1);
1282		if (v1) {
1283			vrele(v1);
1284		}
1285		return error;
1286	}
1287	if (v1 && v1->v_type != VDIR && v1 != v2) {
1288		vn_lock(v1, LK_EXCLUSIVE | LK_RETRY);
1289	}
1290	*v1_ret = v1;
1291	*v2_ret = v2;
1292	return 0;
1293}
1294
1295/*
1296 * Rename vnode operation
1297 * 	rename("foo", "bar");
1298 * is essentially
1299 *	unlink("bar");
1300 *	link("foo", "bar");
1301 *	unlink("foo");
1302 * but ``atomically''.  Can't do full commit without saving state in the
1303 * inode on disk which isn't feasible at this time.  Best we can do is
1304 * always guarantee the target exists.
1305 *
1306 * Basic algorithm is:
1307 *
1308 * 1) Bump link count on source while we're linking it to the
1309 *    target.  This also ensure the inode won't be deleted out
1310 *    from underneath us while we work (it may be truncated by
1311 *    a concurrent `trunc' or `open' for creation).
1312 * 2) Link source to destination.  If destination already exists,
1313 *    delete it first.
1314 * 3) Unlink source reference to inode if still around. If a
1315 *    directory was moved and the parent of the destination
1316 *    is different from the source, patch the ".." entry in the
1317 *    directory.
1318 */
1319int
1320ufs_rename(void *v)
1321{
1322	struct vop_rename_args  /* {
1323		struct vnode		*a_fdvp;
1324		struct vnode		*a_fvp;
1325		struct componentname	*a_fcnp;
1326		struct vnode		*a_tdvp;
1327		struct vnode		*a_tvp;
1328		struct componentname	*a_tcnp;
1329	} */ *ap = v;
1330	struct vnode		*tvp, *tdvp, *fvp, *fdvp;
1331	struct componentname	*tcnp, *fcnp;
1332	struct inode		*ip, *txp, *fxp, *tdp, *fdp;
1333	struct mount		*mp;
1334	struct direct		*newdir;
1335	int			doingdirectory, error;
1336	ino_t			oldparent, newparent;
1337
1338	struct ufs_lookup_results from_ulr, to_ulr;
1339
1340	tvp = ap->a_tvp;
1341	tdvp = ap->a_tdvp;
1342	fvp = ap->a_fvp;
1343	fdvp = ap->a_fdvp;
1344	tcnp = ap->a_tcnp;
1345	fcnp = ap->a_fcnp;
1346	doingdirectory = error = 0;
1347	oldparent = newparent = 0;
1348
1349	/* save the supplemental lookup results as they currently exist */
1350	from_ulr = VTOI(fdvp)->i_crap;
1351	to_ulr = VTOI(tdvp)->i_crap;
1352	UFS_CHECK_CRAPCOUNTER(VTOI(fdvp));
1353	UFS_CHECK_CRAPCOUNTER(VTOI(tdvp));
1354
1355	/*
1356	 * Owing to VFS oddities we are currently called with tdvp/tvp
1357	 * locked and not fdvp/fvp. In a sane world we'd be passed
1358	 * tdvp and fdvp only, unlocked, and two name strings. Pretend
1359	 * we have a sane world and unlock tdvp and tvp.
1360	 */
1361	VOP_UNLOCK(tdvp);
1362	if (tvp && tvp != tdvp) {
1363		VOP_UNLOCK(tvp);
1364	}
1365
1366	/* Also pretend we have a sane world and vrele fvp/tvp. */
1367	vrele(fvp);
1368	fvp = NULL;
1369	if (tvp) {
1370		vrele(tvp);
1371		tvp = NULL;
1372	}
1373
1374	/*
1375	 * Check for cross-device rename.
1376	 */
1377	if (fdvp->v_mount != tdvp->v_mount) {
1378		error = EXDEV;
1379		goto abort;
1380	}
1381
1382	/*
1383	 * Reject "." and ".."
1384	 */
1385	if ((fcnp->cn_flags & ISDOTDOT) || (tcnp->cn_flags & ISDOTDOT) ||
1386	    (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
1387	    (tcnp->cn_namelen == 1 && tcnp->cn_nameptr[0] == '.')) {
1388		error = EINVAL;
1389		goto abort;
1390	}
1391	    
1392	/*
1393	 * Get locks.
1394	 */
1395
1396	/* paranoia */
1397	fcnp->cn_flags |= LOCKPARENT|LOCKLEAF;
1398	tcnp->cn_flags |= LOCKPARENT|LOCKLEAF;
1399
1400	if (fdvp == tdvp) {
1401		/* One directory. Lock it and relookup both children. */
1402		vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
1403
1404		if (VTOI(fdvp)->i_size == 0) {
1405			/* directory has been rmdir'd */
1406			VOP_UNLOCK(fdvp);
1407			error = ENOENT;
1408			goto abort;
1409		}
1410
1411		error = do_relookup(fdvp, &from_ulr, &fvp, fcnp);
1412		if (error == 0 && fvp == NULL) {
1413			/* relookup may produce this if fvp disappears */
1414			error = ENOENT;
1415		}
1416		if (error) {
1417			VOP_UNLOCK(fdvp);
1418			goto abort;
1419		}
1420
1421		/*
1422		 * The right way to do this is to look up both children
1423		 * without locking either, and then lock both unless they
1424		 * turn out to be the same. However, due to deep-seated
1425		 * VFS-level issues all lookups lock the child regardless
1426		 * of whether LOCKLEAF is set (if LOCKLEAF is not set,
1427		 * the child is locked during lookup and then unlocked)
1428		 * so it is not safe to look up tvp while fvp is locked.
1429		 *
1430		 * Unlocking fvp here temporarily is more or less safe,
1431		 * because with the directory locked there's not much
1432		 * that can happen to it. However, ideally it wouldn't
1433		 * be necessary. XXX.
1434		 */
1435		VOP_UNLOCK(fvp);
1436		/* remember fdvp == tdvp so tdvp is locked */
1437		error = do_relookup(tdvp, &to_ulr, &tvp, tcnp);
1438		if (error && error != ENOENT) {
1439			VOP_UNLOCK(fdvp);
1440			goto abort;
1441		}
1442		if (error == ENOENT) {
1443			/*
1444			 * Note: currently if the name doesn't exist,
1445			 * relookup succeeds (it intercepts the
1446			 * EJUSTRETURN from VOP_LOOKUP) and sets tvp
1447			 * to NULL. Therefore, we will never get
1448			 * ENOENT and this branch is not needed.
1449			 * However, in a saner future the EJUSTRETURN
1450			 * garbage will go away, so let's DTRT.
1451			 */
1452			tvp = NULL;
1453		}
1454
1455		/* tvp is locked; lock fvp if necessary */
1456		if (!tvp || tvp != fvp) {
1457			vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
1458		}
1459	} else {
1460		int found_fdvp;
1461		struct vnode *illegal_fvp;
1462
1463		/*
1464		 * The source must not be above the destination. (If
1465		 * it were, the rename would detach a section of the
1466		 * tree.)
1467		 *
1468		 * Look up the tree from tdvp to see if we find fdvp,
1469		 * and if so, return the immediate child of fdvp we're
1470		 * under; that must not turn out to be the same as
1471		 * fvp.
1472		 *
1473		 * The per-volume rename lock guarantees that the
1474		 * result of this check remains true until we finish
1475		 * looking up and locking.
1476		 */
1477		error = ufs_parentcheck(fdvp, tdvp, fcnp->cn_cred,
1478					&found_fdvp, &illegal_fvp);
1479		if (error) {
1480			goto abort;
1481		}
1482
1483		/* Must lock in tree order. */
1484
1485		if (found_fdvp) {
1486			/* fdvp -> fvp -> tdvp -> tvp */
1487			error = lock_vnode_sequence(fdvp, &from_ulr,
1488						    &fvp, fcnp, 0,
1489						    EINVAL,
1490						    tdvp, &to_ulr,
1491						    &tvp, tcnp, 1);
1492		} else {
1493			/* tdvp -> tvp -> fdvp -> fvp */
1494			error = lock_vnode_sequence(tdvp, &to_ulr,
1495						    &tvp, tcnp, 1,
1496						    ENOTEMPTY,
1497						    fdvp, &from_ulr,
1498						    &fvp, fcnp, 0);
1499		}
1500		if (error) {
1501			if (illegal_fvp) {
1502				vrele(illegal_fvp);
1503			}
1504			goto abort;
1505		}
1506		KASSERT(fvp != NULL);
1507
1508		if (illegal_fvp && fvp == illegal_fvp) {
1509			vrele(illegal_fvp);
1510			error = EINVAL;
1511			goto abort_withlocks;
1512		}
1513
1514		if (illegal_fvp) {
1515			vrele(illegal_fvp);
1516		}
1517	}
1518
1519	KASSERT(fdvp && VOP_ISLOCKED(fdvp));
1520	KASSERT(fvp && VOP_ISLOCKED(fvp));
1521	KASSERT(tdvp && VOP_ISLOCKED(tdvp));
1522	KASSERT(tvp == NULL || VOP_ISLOCKED(tvp));
1523
1524	/* --- everything is now locked --- */
1525
1526	if (tvp && ((VTOI(tvp)->i_flags & (IMMUTABLE | APPEND)) ||
1527	    (VTOI(tdvp)->i_flags & APPEND))) {
1528		error = EPERM;
1529		goto abort_withlocks;
1530	}
1531
1532	/*
1533	 * Check if just deleting a link name.
1534	 */
1535	if (fvp == tvp) {
1536		if (fvp->v_type == VDIR) {
1537			error = EINVAL;
1538			goto abort_withlocks;
1539		}
1540
1541		/* Release destination completely. Leave fdvp locked. */
1542		VOP_ABORTOP(tdvp, tcnp);
1543		if (fdvp != tdvp) {
1544			VOP_UNLOCK(tdvp);
1545		}
1546		VOP_UNLOCK(tvp);
1547		vrele(tdvp);
1548		vrele(tvp);
1549
1550		/* Delete source. */
1551		/* XXX: do we really need to relookup again? */
1552
1553		/*
1554		 * fdvp is still locked, but we just unlocked fvp
1555		 * (because fvp == tvp) so just decref fvp
1556		 */
1557		vrele(fvp);
1558		fcnp->cn_flags &= ~(MODMASK);
1559		fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1560		fcnp->cn_nameiop = DELETE;
1561		if ((error = relookup(fdvp, &fvp, fcnp, 0))) {
1562			vput(fdvp);
1563			return (error);
1564		}
1565		return (VOP_REMOVE(fdvp, fvp, fcnp));
1566	}
1567	fdp = VTOI(fdvp);
1568	ip = VTOI(fvp);
1569	if ((nlink_t) ip->i_nlink >= LINK_MAX) {
1570		error = EMLINK;
1571		goto abort_withlocks;
1572	}
1573	if ((ip->i_flags & (IMMUTABLE | APPEND)) ||
1574		(fdp->i_flags & APPEND)) {
1575		error = EPERM;
1576		goto abort_withlocks;
1577	}
1578	if ((ip->i_mode & IFMT) == IFDIR) {
1579		/*
1580		 * Avoid ".", "..", and aliases of "." for obvious reasons.
1581		 */
1582		if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
1583		    fdp == ip ||
1584		    (fcnp->cn_flags & ISDOTDOT) ||
1585		    (tcnp->cn_flags & ISDOTDOT) ||
1586		    (ip->i_flag & IN_RENAME)) {
1587			error = EINVAL;
1588			goto abort_withlocks;
1589		}
1590		ip->i_flag |= IN_RENAME;
1591		doingdirectory = 1;
1592	}
1593	oldparent = fdp->i_number;
1594	VN_KNOTE(fdvp, NOTE_WRITE);		/* XXXLUKEM/XXX: right place? */
1595
1596	/*
1597	 * Both the directory
1598	 * and target vnodes are locked.
1599	 */
1600	tdp = VTOI(tdvp);
1601	txp = NULL;
1602	if (tvp)
1603		txp = VTOI(tvp);
1604
1605	mp = fdvp->v_mount;
1606	fstrans_start(mp, FSTRANS_SHARED);
1607
1608	if (oldparent != tdp->i_number)
1609		newparent = tdp->i_number;
1610
1611	/*
1612	 * If ".." must be changed (ie the directory gets a new
1613	 * parent) the user must have write permission in the source
1614	 * so as to be able to change "..".
1615	 */
1616	if (doingdirectory && newparent) {
1617		error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred);
1618		if (error)
1619			goto out;
1620	}
1621
1622	KASSERT(fdvp != tvp);
1623
1624	if (newparent) {
1625		/* Check for the rename("foo/foo", "foo") case. */
1626		if (fdvp == tvp) {
1627			error = doingdirectory ? ENOTEMPTY : EISDIR;
1628			goto out;
1629		}
1630	}
1631
1632	fxp = VTOI(fvp);
1633	fdp = VTOI(fdvp);
1634
1635	error = UFS_WAPBL_BEGIN(fdvp->v_mount);
1636	if (error)
1637		goto out2;
1638
1639	/*
1640	 * 1) Bump link count while we're moving stuff
1641	 *    around.  If we crash somewhere before
1642	 *    completing our work, the link count
1643	 *    may be wrong, but correctable.
1644	 */
1645	ip->i_nlink++;
1646	DIP_ASSIGN(ip, nlink, ip->i_nlink);
1647	ip->i_flag |= IN_CHANGE;
1648	if ((error = UFS_UPDATE(fvp, NULL, NULL, UPDATE_DIROP)) != 0) {
1649		goto bad;
1650	}
1651
1652	/*
1653	 * 2) If target doesn't exist, link the target
1654	 *    to the source and unlink the source.
1655	 *    Otherwise, rewrite the target directory
1656	 *    entry to reference the source inode and
1657	 *    expunge the original entry's existence.
1658	 */
1659	if (txp == NULL) {
1660		if (tdp->i_dev != ip->i_dev)
1661			panic("rename: EXDEV");
1662		/*
1663		 * Account for ".." in new directory.
1664		 * When source and destination have the same
1665		 * parent we don't fool with the link count.
1666		 */
1667		if (doingdirectory && newparent) {
1668			if ((nlink_t)tdp->i_nlink >= LINK_MAX) {
1669				error = EMLINK;
1670				goto bad;
1671			}
1672			tdp->i_nlink++;
1673			DIP_ASSIGN(tdp, nlink, tdp->i_nlink);
1674			tdp->i_flag |= IN_CHANGE;
1675			if ((error = UFS_UPDATE(tdvp, NULL, NULL,
1676			    UPDATE_DIROP)) != 0) {
1677				tdp->i_nlink--;
1678				DIP_ASSIGN(tdp, nlink, tdp->i_nlink);
1679				tdp->i_flag |= IN_CHANGE;
1680				goto bad;
1681			}
1682		}
1683		newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK);
1684		ufs_makedirentry(ip, tcnp, newdir);
1685		error = ufs_direnter(tdvp, &to_ulr,
1686				     NULL, newdir, tcnp, NULL);
1687		pool_cache_put(ufs_direct_cache, newdir);
1688		if (error != 0) {
1689			if (doingdirectory && newparent) {
1690				tdp->i_nlink--;
1691				DIP_ASSIGN(tdp, nlink, tdp->i_nlink);
1692				tdp->i_flag |= IN_CHANGE;
1693				(void)UFS_UPDATE(tdvp, NULL, NULL,
1694						 UPDATE_WAIT | UPDATE_DIROP);
1695			}
1696			goto bad;
1697		}
1698		VN_KNOTE(tdvp, NOTE_WRITE);
1699	} else {
1700		if (txp->i_dev != tdp->i_dev || txp->i_dev != ip->i_dev)
1701			panic("rename: EXDEV");
1702		/*
1703		 * Short circuit rename(foo, foo).
1704		 */
1705		if (txp->i_number == ip->i_number)
1706			panic("rename: same file");
1707		/*
1708		 * If the parent directory is "sticky", then the user must
1709		 * own the parent directory, or the destination of the rename,
1710		 * otherwise the destination may not be changed (except by
1711		 * root). This implements append-only directories.
1712		 */
1713		if ((tdp->i_mode & S_ISTXT) &&
1714		    kauth_authorize_generic(tcnp->cn_cred,
1715		     KAUTH_GENERIC_ISSUSER, NULL) != 0 &&
1716		    kauth_cred_geteuid(tcnp->cn_cred) != tdp->i_uid &&
1717		    txp->i_uid != kauth_cred_geteuid(tcnp->cn_cred)) {
1718			error = EPERM;
1719			goto bad;
1720		}
1721		/*
1722		 * Target must be empty if a directory and have no links
1723		 * to it. Also, ensure source and target are compatible
1724		 * (both directories, or both not directories).
1725		 */
1726		if ((txp->i_mode & IFMT) == IFDIR) {
1727			if (txp->i_nlink > 2 ||
1728			    !ufs_dirempty(txp, tdp->i_number, tcnp->cn_cred)) {
1729				error = ENOTEMPTY;
1730				goto bad;
1731			}
1732			if (!doingdirectory) {
1733				error = ENOTDIR;
1734				goto bad;
1735			}
1736			cache_purge(tdvp);
1737		} else if (doingdirectory) {
1738			error = EISDIR;
1739			goto bad;
1740		}
1741		if ((error = ufs_dirrewrite(tdp, to_ulr.ulr_offset,
1742		    txp, ip->i_number,
1743		    IFTODT(ip->i_mode), doingdirectory && newparent ?
1744		    newparent : doingdirectory, IN_CHANGE | IN_UPDATE)) != 0)
1745			goto bad;
1746		if (doingdirectory) {
1747			/*
1748			 * Truncate inode. The only stuff left in the directory
1749			 * is "." and "..". The "." reference is inconsequential
1750			 * since we are quashing it. We have removed the "."
1751			 * reference and the reference in the parent directory,
1752			 * but there may be other hard links.
1753			 */
1754			if (!newparent) {
1755				tdp->i_nlink--;
1756				DIP_ASSIGN(tdp, nlink, tdp->i_nlink);
1757				tdp->i_flag |= IN_CHANGE;
1758				UFS_WAPBL_UPDATE(tdvp, NULL, NULL, 0);
1759			}
1760			txp->i_nlink--;
1761			DIP_ASSIGN(txp, nlink, txp->i_nlink);
1762			txp->i_flag |= IN_CHANGE;
1763			if ((error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC,
1764			    tcnp->cn_cred)))
1765				goto bad;
1766		}
1767		VN_KNOTE(tdvp, NOTE_WRITE);
1768		VN_KNOTE(tvp, NOTE_DELETE);
1769	}
1770
1771	/*
1772	 * Handle case where the directory entry we need to remove,
1773	 * which is/was at from_ulr.ulr_offset, or the one before it,
1774	 * which is/was at from_ulr.ulr_offset - from_ulr.ulr_count,
1775	 * may have been moved when the directory insertion above
1776	 * performed compaction.
1777	 */
1778	if (tdp->i_number == fdp->i_number &&
1779	    ulr_overlap(&from_ulr, &to_ulr)) {
1780
1781		struct buf *bp;
1782		struct direct *ep;
1783		struct ufsmount *ump = fdp->i_ump;
1784		doff_t curpos;
1785		doff_t endsearch;	/* offset to end directory search */
1786		uint32_t prev_reclen;
1787		int dirblksiz = ump->um_dirblksiz;
1788		const int needswap = UFS_MPNEEDSWAP(ump);
1789		u_long bmask;
1790		int namlen, entryoffsetinblock;
1791		char *dirbuf;
1792
1793		bmask = fdvp->v_mount->mnt_stat.f_iosize - 1;
1794
1795		/*
1796		 * The fcnp entry will be somewhere between the start of
1797		 * compaction (to_ulr.ulr_offset) and the original location
1798		 * (from_ulr.ulr_offset).
1799		 */
1800		curpos = to_ulr.ulr_offset;
1801		endsearch = from_ulr.ulr_offset + from_ulr.ulr_reclen;
1802		entryoffsetinblock = 0;
1803
1804		/*
1805		 * Get the directory block containing the start of
1806		 * compaction.
1807		 */
1808		error = ufs_blkatoff(fdvp, (off_t)to_ulr.ulr_offset, &dirbuf,
1809		    &bp, false);
1810		if (error)
1811			goto bad;
1812
1813		/*
1814		 * Keep existing ulr_count (length of previous record)
1815		 * for the case where compaction did not include the
1816		 * previous entry but started at the from-entry.
1817		 */
1818		prev_reclen = from_ulr.ulr_count;
1819
1820		while (curpos < endsearch) {
1821			uint32_t reclen;
1822
1823			/*
1824			 * If necessary, get the next directory block.
1825			 *
1826			 * dholland 7/13/11 to the best of my understanding
1827			 * this should never happen; compaction occurs only
1828			 * within single blocks. I think.
1829			 */
1830			if ((curpos & bmask) == 0) {
1831				if (bp != NULL)
1832					brelse(bp, 0);
1833				error = ufs_blkatoff(fdvp, (off_t)curpos,
1834				    &dirbuf, &bp, false);
1835				if (error)
1836					goto bad;
1837				entryoffsetinblock = 0;
1838			}
1839
1840			KASSERT(bp != NULL);
1841			ep = (struct direct *)(dirbuf + entryoffsetinblock);
1842			reclen = ufs_rw16(ep->d_reclen, needswap);
1843
1844#if (BYTE_ORDER == LITTLE_ENDIAN)
1845			if (FSFMT(fdvp) && needswap == 0)
1846				namlen = ep->d_type;
1847			else
1848				namlen = ep->d_namlen;
1849#else
1850			if (FSFMT(fdvp) && needswap != 0)
1851				namlen = ep->d_type;
1852			else
1853				namlen = ep->d_namlen;
1854#endif
1855			if ((ep->d_ino != 0) &&
1856			    (ufs_rw32(ep->d_ino, needswap) != WINO) &&
1857			    (namlen == fcnp->cn_namelen) &&
1858			    memcmp(ep->d_name, fcnp->cn_nameptr, namlen) == 0) {
1859				from_ulr.ulr_reclen = reclen;
1860				break;
1861			}
1862			curpos += reclen;
1863			entryoffsetinblock += reclen;
1864			prev_reclen = reclen;
1865		}
1866
1867		from_ulr.ulr_offset = curpos;
1868		from_ulr.ulr_count = prev_reclen;
1869
1870		KASSERT(curpos <= endsearch);
1871
1872		/*
1873		 * If ulr_offset points to start of a directory block,
1874		 * clear ulr_count so ufs_dirremove() doesn't try to
1875		 * merge free space over a directory block boundary.
1876		 */
1877		if ((from_ulr.ulr_offset & (dirblksiz - 1)) == 0)
1878			from_ulr.ulr_count = 0;
1879
1880		brelse(bp, 0);
1881	}
1882
1883	/*
1884	 * 3) Unlink the source.
1885	 */
1886
1887#if 0
1888	/*
1889	 * Ensure that the directory entry still exists and has not
1890	 * changed while the new name has been entered. If the source is
1891	 * a file then

Large files files are truncated, but you can click here to view the full file