Home | History | Annotate | Line # | Download | only in ufs
      1 /*	$NetBSD: ufs_readwrite.c,v 1.131 2026/07/22 14:44:49 hannken Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  *
     31  *	@(#)ufs_readwrite.c	8.11 (Berkeley) 5/8/95
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(1, "$NetBSD: ufs_readwrite.c,v 1.131 2026/07/22 14:44:49 hannken Exp $");
     36 
     37 #include <sys/bitops.h>
     38 #include <sys/sdt.h>
     39 
     40 #define	FS			struct fs
     41 #define	I_FS			i_fs
     42 #define	READ			ffs_read
     43 #define	READ_S			"ffs_read"
     44 #define	WRITE			ffs_write
     45 #define	WRITE_S			"ffs_write"
     46 #define	BUFRD			ffs_bufrd
     47 #define	BUFWR			ffs_bufwr
     48 #define ufs_blkoff		ffs_blkoff
     49 #define ufs_blksize		ffs_blksize
     50 #define ufs_lblkno		ffs_lblkno
     51 #define ufs_lblktosize		ffs_lblktosize
     52 #define ufs_blkroundup		ffs_blkroundup
     53 
     54 static int	ufs_post_read_update(struct vnode *, int, int);
     55 static int	ufs_post_write_update(struct vnode *, struct uio *, int,
     56 		    kauth_cred_t, off_t, int, int);
     57 
     58 /*
     59  * Vnode op for reading.
     60  */
     61 /* ARGSUSED */
     62 int
     63 READ(void *v)
     64 {
     65 	struct vop_read_args /* {
     66 		struct vnode *a_vp;
     67 		struct uio *a_uio;
     68 		int a_ioflag;
     69 		kauth_cred_t a_cred;
     70 	} */ *ap = v;
     71 	struct vnode *vp;
     72 	struct inode *ip;
     73 	struct uio *uio;
     74 	struct ufsmount *ump;
     75 	vsize_t bytelen;
     76 	int error, ioflag, advice;
     77 
     78 	vp = ap->a_vp;
     79 	ip = VTOI(vp);
     80 	ump = ip->i_ump;
     81 	uio = ap->a_uio;
     82 	ioflag = ap->a_ioflag;
     83 	error = 0;
     84 
     85 	KASSERT(uio->uio_rw == UIO_READ);
     86 	KASSERT(vp->v_type == VREG || vp->v_type == VDIR);
     87 
     88 	/* XXX Eliminate me by refusing directory reads from userland.  */
     89 	if (vp->v_type == VDIR)
     90 		return BUFRD(vp, uio, ioflag, ap->a_cred);
     91 	if ((u_int64_t)uio->uio_offset > ump->um_maxfilesize)
     92 		return SET_ERROR(EFBIG);
     93 	if (uio->uio_resid == 0)
     94 		return 0;
     95 
     96 	if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) == SF_SNAPSHOT)
     97 #ifndef FFS_NO_SNAPSHOT
     98 		return ffs_snapshot_read(vp, uio, ioflag);
     99 #else
    100 		panic("%s: unexpected snapshot", __func__);
    101 #endif
    102 
    103 	if (uio->uio_offset >= ip->i_size)
    104 		goto out;
    105 
    106 	KASSERT(vp->v_type == VREG);
    107 	advice = IO_ADV_DECODE(ap->a_ioflag);
    108 	while (uio->uio_resid > 0) {
    109 		if (ioflag & IO_DIRECT) {
    110 			genfs_directio(vp, uio, ioflag);
    111 		}
    112 		bytelen = MIN(ip->i_size - uio->uio_offset, uio->uio_resid);
    113 		if (bytelen == 0)
    114 			break;
    115 		error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
    116 		    UBC_READ | UBC_PARTIALOK | UBC_VNODE_FLAGS(vp));
    117 		if (error)
    118 			break;
    119 	}
    120 
    121  out:
    122 	error = ufs_post_read_update(vp, ap->a_ioflag, error);
    123 	return error;
    124 }
    125 
    126 /*
    127  * UFS op for reading via the buffer cache
    128  */
    129 int
    130 BUFRD(struct vnode *vp, struct uio *uio, int ioflag, kauth_cred_t cred)
    131 {
    132 	struct inode *ip;
    133 	struct ufsmount *ump;
    134 	FS *fs;
    135 	struct buf *bp;
    136 	daddr_t lbn, nextlbn;
    137 	off_t bytesinfile;
    138 	long size, xfersize, blkoffset;
    139 	int error;
    140 
    141 	KASSERT(VOP_ISLOCKED(vp));
    142 	KASSERT(vp->v_type == VDIR || vp->v_type == VLNK);
    143 	KASSERT(uio->uio_rw == UIO_READ);
    144 
    145 	ip = VTOI(vp);
    146 	ump = ip->i_ump;
    147 	fs = ip->I_FS;
    148 	error = 0;
    149 
    150 	KASSERT(vp->v_type != VLNK || ip->i_size >= ump->um_maxsymlinklen);
    151 	KASSERT(vp->v_type != VLNK || ump->um_maxsymlinklen != 0 ||
    152 	    DIP(ip, blocks) != 0);
    153 
    154 	if (uio->uio_offset > ump->um_maxfilesize)
    155 		return SET_ERROR(EFBIG);
    156 	if (uio->uio_resid == 0)
    157 		return 0;
    158 
    159 	KASSERT(!ISSET(ip->i_flags, (SF_SNAPSHOT | SF_SNAPINVAL)));
    160 
    161 	if (uio->uio_offset >= ip->i_size)
    162 		goto out;
    163 
    164 	for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
    165 		bytesinfile = ip->i_size - uio->uio_offset;
    166 		if (bytesinfile <= 0)
    167 			break;
    168 		lbn = ufs_lblkno(fs, uio->uio_offset);
    169 		nextlbn = lbn + 1;
    170 		size = ufs_blksize(fs, ip, lbn);
    171 		blkoffset = ufs_blkoff(fs, uio->uio_offset);
    172 		xfersize = MIN(MIN(fs->fs_bsize - blkoffset, uio->uio_resid),
    173 		    bytesinfile);
    174 
    175 		if (ufs_lblktosize(fs, nextlbn) >= ip->i_size)
    176 			error = bread(vp, lbn, size, 0, &bp);
    177 		else {
    178 			int nextsize = ufs_blksize(fs, ip, nextlbn);
    179 			error = breadn(vp, lbn,
    180 			    size, &nextlbn, &nextsize, 1, 0, &bp);
    181 		}
    182 		if (error)
    183 			break;
    184 
    185 		/*
    186 		 * We should only get non-zero b_resid when an I/O error
    187 		 * has occurred, which should cause us to break above.
    188 		 * However, if the short read did not cause an error,
    189 		 * then we want to ensure that we do not uiomove bad
    190 		 * or uninitialized data.
    191 		 */
    192 		size -= bp->b_resid;
    193 		if (size < xfersize) {
    194 			if (size == 0)
    195 				break;
    196 			xfersize = size;
    197 		}
    198 		error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
    199 		if (error)
    200 			break;
    201 		brelse(bp, 0);
    202 	}
    203 	if (bp != NULL)
    204 		brelse(bp, 0);
    205 
    206  out:
    207 	error = ufs_post_read_update(vp, ioflag, error);
    208 	return error;
    209 }
    210 
    211 static int
    212 ufs_post_read_update(struct vnode *vp, int ioflag, int oerror)
    213 {
    214 	struct inode *ip = VTOI(vp);
    215 	int error = oerror;
    216 
    217 	if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
    218 		ip->i_flag |= IN_ACCESS;
    219 		if ((ioflag & IO_SYNC) == IO_SYNC) {
    220 			error = UFS_WAPBL_BEGIN(vp->v_mount);
    221 			if (error)
    222 				goto out;
    223 			error = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
    224 			UFS_WAPBL_END(vp->v_mount);
    225 		}
    226 	}
    227 
    228 out:
    229 	/* Read error overrides any inode update error.  */
    230 	if (oerror)
    231 		error = oerror;
    232 	return error;
    233 }
    234 
    235 /*
    236  * Vnode op for writing.
    237  */
    238 int
    239 WRITE(void *v)
    240 {
    241 	struct vop_write_args /* {
    242 		struct vnode *a_vp;
    243 		struct uio *a_uio;
    244 		int a_ioflag;
    245 		kauth_cred_t a_cred;
    246 	} */ *ap = v;
    247 	struct vnode *vp;
    248 	struct uio *uio;
    249 	struct inode *ip;
    250 	FS *fs;
    251 	kauth_cred_t cred;
    252 	off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize;
    253 	int blkoffset, error, flags, ioflag, resid;
    254 	int aflag;
    255 	vsize_t bytelen;
    256 	bool async;
    257 	struct ufsmount *ump;
    258 	const unsigned int fshift = ilog2(MAXPHYS);
    259 
    260 	cred = ap->a_cred;
    261 	ioflag = ap->a_ioflag;
    262 	uio = ap->a_uio;
    263 	vp = ap->a_vp;
    264 	ip = VTOI(vp);
    265 	ump = ip->i_ump;
    266 
    267 	KASSERT(vp->v_size == ip->i_size);
    268 	KASSERT(uio->uio_rw == UIO_WRITE);
    269 	KASSERT(vp->v_type == VREG);
    270 	KASSERT(!ISSET(ioflag, IO_JOURNALLOCKED));
    271 	UFS_WAPBL_JUNLOCK_ASSERT(vp->v_mount);
    272 
    273 	if (ioflag & IO_APPEND)
    274 		uio->uio_offset = ip->i_size;
    275 	if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
    276 		return SET_ERROR(EPERM);
    277 
    278 	fs = ip->I_FS;
    279 	if (uio->uio_offset < 0 ||
    280 	    (u_int64_t)uio->uio_offset + uio->uio_resid > ump->um_maxfilesize)
    281 		return SET_ERROR(EFBIG);
    282 	if (uio->uio_resid == 0)
    283 		return 0;
    284 
    285 	flags = ioflag & IO_SYNC ? B_SYNC : 0;
    286 	async = vp->v_mount->mnt_flag & MNT_ASYNC;
    287 	origoff = uio->uio_offset;
    288 	resid = uio->uio_resid;
    289 	osize = ip->i_size;
    290 	error = 0;
    291 
    292 	KASSERT(vp->v_type == VREG);
    293 
    294 	/*
    295 	 * XXX The entire write operation must occur in a single WAPBL
    296 	 * transaction because it may allocate disk blocks, if
    297 	 * appending or filling holes, which is allowed to happen only
    298 	 * if the write fully succeeds.
    299 	 *
    300 	 * If ubc_uiomove fails in the middle with EFAULT, we can clean
    301 	 * up at the end with UFS_TRUNCATE.  But if the power fails in
    302 	 * the middle, there would be nobody to deallocate the blocks,
    303 	 * without an fsck to globally analyze the file system.
    304 	 *
    305 	 * If the increasingly inaccurately named WAPBL were augmented
    306 	 * with rollback records for block allocations, then we could
    307 	 * split this into multiple transactions and commit the
    308 	 * allocations in the last one.
    309 	 *
    310 	 * But WAPBL doesn't have that notion now, so we'll have to
    311 	 * live with gigantic transactions and WAPBL tentacles in
    312 	 * genfs_getpages/putpages to cope with the possibility that
    313 	 * the transaction may or may not be locked on entry to the
    314 	 * page cache.
    315 	 *
    316 	 * And even if we added that notion to WAPBL, it wouldn't help
    317 	 * us get rid of the tentacles in genfs_getpages/putpages
    318 	 * because we'd have to interoperate with old implementations
    319 	 * that assume they can replay the log without fsck.
    320 	 */
    321 	error = UFS_WAPBL_BEGIN(vp->v_mount);
    322 	if (error) {
    323 		return error;
    324 	}
    325 
    326 
    327 	preallocoff = round_page(ufs_blkroundup(fs, MAX(osize, uio->uio_offset)));
    328 	aflag = ioflag & IO_SYNC ? B_SYNC : 0;
    329 	nsize = MAX(osize, uio->uio_offset + uio->uio_resid);
    330 	endallocoff = nsize - ufs_blkoff(fs, nsize);
    331 
    332 	/*
    333 	 * if we're increasing the file size, deal with expanding
    334 	 * the fragment if there is one.
    335 	 */
    336 
    337 	if (nsize > osize && ufs_lblkno(fs, osize) < UFS_NDADDR &&
    338 	    ufs_lblkno(fs, osize) != ufs_lblkno(fs, nsize) &&
    339 	    ufs_blkroundup(fs, osize) != osize) {
    340 		off_t eob;
    341 
    342 		eob = ufs_blkroundup(fs, osize);
    343 		uvm_vnp_setwritesize(vp, eob);
    344 		error = ufs_balloc_range(vp, osize, eob - osize, cred, aflag);
    345 		if (error)
    346 			goto out;
    347 		if (flags & B_SYNC) {
    348 			rw_enter(vp->v_uobj.vmobjlock, RW_WRITER);
    349 			VOP_PUTPAGES(vp, trunc_page(osize & fs->fs_bmask),
    350 			    round_page(eob),
    351 			    PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
    352 		}
    353 	}
    354 
    355 	while (uio->uio_resid > 0) {
    356 		int ubc_flags = UBC_WRITE;
    357 		bool overwrite; /* if we're overwrite a whole block */
    358 		off_t newoff;
    359 
    360 		if (ioflag & IO_DIRECT) {
    361 			genfs_directio(vp, uio, ioflag | IO_JOURNALLOCKED);
    362 		}
    363 
    364 		oldoff = uio->uio_offset;
    365 		blkoffset = ufs_blkoff(fs, uio->uio_offset);
    366 		bytelen = MIN(fs->fs_bsize - blkoffset, uio->uio_resid);
    367 		if (bytelen == 0) {
    368 			break;
    369 		}
    370 
    371 		/*
    372 		 * if we're filling in a hole, allocate the blocks now and
    373 		 * initialize the pages first.  if we're extending the file,
    374 		 * we can safely allocate blocks without initializing pages
    375 		 * since the new blocks will be inaccessible until the write
    376 		 * is complete.
    377 		 */
    378 		overwrite = uio->uio_offset >= preallocoff &&
    379 		    uio->uio_offset < endallocoff;
    380 		if (!overwrite && (vp->v_vflag & VV_MAPPED) == 0 &&
    381 		    ufs_blkoff(fs, uio->uio_offset) == 0 &&
    382 		    (uio->uio_offset & PAGE_MASK) == 0) {
    383 			vsize_t len;
    384 
    385 			len = trunc_page(bytelen);
    386 			len -= ufs_blkoff(fs, len);
    387 			if (len > 0) {
    388 				overwrite = true;
    389 				bytelen = len;
    390 			}
    391 		}
    392 
    393 		newoff = oldoff + bytelen;
    394 		if (vp->v_size < newoff) {
    395 			uvm_vnp_setwritesize(vp, newoff);
    396 		}
    397 
    398 		if (!overwrite) {
    399 			error = ufs_balloc_range(vp, uio->uio_offset, bytelen,
    400 			    cred, aflag);
    401 			if (error)
    402 				break;
    403 		} else {
    404 			genfs_node_wrlock(vp);
    405 			error = GOP_ALLOC(vp, uio->uio_offset, bytelen,
    406 			    aflag, cred);
    407 			genfs_node_unlock(vp);
    408 			if (error)
    409 				break;
    410 			ubc_flags |= UBC_FAULTBUSY;
    411 		}
    412 
    413 		/*
    414 		 * copy the data.
    415 		 */
    416 
    417 		error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
    418 		    IO_ADV_DECODE(ioflag), ubc_flags | UBC_VNODE_FLAGS(vp));
    419 
    420 		/*
    421 		 * update UVM's notion of the size now that we've
    422 		 * copied the data into the vnode's pages.
    423 		 *
    424 		 * we should update the size even when uiomove failed.
    425 		 */
    426 
    427 		if (vp->v_size < newoff) {
    428 			uvm_vnp_setsize(vp, newoff);
    429 		}
    430 
    431 		if (error)
    432 			break;
    433 
    434 		/*
    435 		 * flush what we just wrote if necessary.
    436 		 * XXXUBC simplistic async flushing.
    437 		 */
    438 
    439 		if (!async && oldoff >> fshift != uio->uio_offset >> fshift) {
    440 			rw_enter(vp->v_uobj.vmobjlock, RW_WRITER);
    441 			error = VOP_PUTPAGES(vp, (oldoff >> fshift) << fshift,
    442 			    (uio->uio_offset >> fshift) << fshift,
    443 			    PGO_CLEANIT | PGO_JOURNALLOCKED | PGO_LAZY);
    444 			if (error)
    445 				break;
    446 		}
    447 	}
    448 	if (error == 0 && ioflag & IO_SYNC) {
    449 		rw_enter(vp->v_uobj.vmobjlock, RW_WRITER);
    450 		error = VOP_PUTPAGES(vp, trunc_page(origoff & fs->fs_bmask),
    451 		    round_page(ufs_blkroundup(fs, uio->uio_offset)),
    452 		    PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
    453 	}
    454 
    455 out:
    456 	error = ufs_post_write_update(vp, uio, ioflag, cred, osize, resid,
    457 	    error);
    458 	UFS_WAPBL_END(vp->v_mount);
    459 
    460 	return error;
    461 }
    462 
    463 /*
    464  * UFS op for writing via the buffer cache
    465  */
    466 int
    467 BUFWR(struct vnode *vp, struct uio *uio, int ioflag, kauth_cred_t cred)
    468 {
    469 	struct inode *ip;
    470 	struct ufsmount *ump;
    471 	FS *fs;
    472 	int flags;
    473 	struct buf *bp;
    474 	off_t osize;
    475 	int resid, xfersize, size, blkoffset;
    476 	daddr_t lbn;
    477 	int error;
    478 
    479 	KASSERT(ISSET(ioflag, IO_NODELOCKED));
    480 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
    481 	KASSERT(vp->v_type == VDIR || vp->v_type == VLNK);
    482 	KASSERT(vp->v_type != VDIR || ISSET(ioflag, IO_SYNC));
    483 	KASSERT(uio->uio_rw == UIO_WRITE);
    484 	KASSERT(ISSET(ioflag, IO_JOURNALLOCKED));
    485 	UFS_WAPBL_JLOCK_ASSERT(vp->v_mount);
    486 
    487 	ip = VTOI(vp);
    488 	ump = ip->i_ump;
    489 	fs = ip->I_FS;
    490 
    491 	KASSERT(vp->v_size == ip->i_size);
    492 
    493 	if (uio->uio_offset < 0 ||
    494 	    uio->uio_resid > ump->um_maxfilesize ||
    495 	    uio->uio_offset > (ump->um_maxfilesize - uio->uio_resid))
    496 		return SET_ERROR(EFBIG);
    497 	if (uio->uio_resid == 0)
    498 		return 0;
    499 
    500 	flags = ioflag & IO_SYNC ? B_SYNC : 0;
    501 	resid = uio->uio_resid;
    502 	osize = ip->i_size;
    503 	error = 0;
    504 
    505 	KASSERT(vp->v_type != VREG);
    506 
    507 
    508 	/* XXX Should never have pages cached here.  */
    509 	KASSERT(vp->v_uobj.uo_npages == 0);
    510 	while (uio->uio_resid > 0) {
    511 		lbn = ufs_lblkno(fs, uio->uio_offset);
    512 		blkoffset = ufs_blkoff(fs, uio->uio_offset);
    513 		xfersize = MIN(fs->fs_bsize - blkoffset, uio->uio_resid);
    514 		if (fs->fs_bsize > xfersize)
    515 			flags |= B_CLRBUF;
    516 		else
    517 			flags &= ~B_CLRBUF;
    518 
    519 		error = UFS_BALLOC(vp, uio->uio_offset, xfersize, cred, flags,
    520 		    &bp);
    521 
    522 		if (error)
    523 			break;
    524 		if (uio->uio_offset + xfersize > ip->i_size) {
    525 			ip->i_size = uio->uio_offset + xfersize;
    526 			DIP_ASSIGN(ip, size, ip->i_size);
    527 			uvm_vnp_setsize(vp, ip->i_size);
    528 		}
    529 		size = ufs_blksize(fs, ip, lbn) - bp->b_resid;
    530 		if (xfersize > size)
    531 			xfersize = size;
    532 
    533 		error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
    534 
    535 		/*
    536 		 * if we didn't clear the block and the uiomove failed,
    537 		 * the buf will now contain part of some other file,
    538 		 * so we need to invalidate it.
    539 		 */
    540 		if (error && (flags & B_CLRBUF) == 0) {
    541 			brelse(bp, BC_INVAL);
    542 			break;
    543 		}
    544 		if (ioflag & IO_SYNC)
    545 			(void)bwrite(bp);
    546 		else if (xfersize + blkoffset == fs->fs_bsize)
    547 			bawrite(bp);
    548 		else
    549 			bdwrite(bp);
    550 		if (error || xfersize == 0)
    551 			break;
    552 	}
    553 
    554 	error = ufs_post_write_update(vp, uio, ioflag, cred, osize, resid,
    555 	    error);
    556 
    557 	return error;
    558 }
    559 
    560 static int
    561 ufs_post_write_update(struct vnode *vp, struct uio *uio, int ioflag,
    562     kauth_cred_t cred, off_t osize, int resid, int oerror)
    563 {
    564 	struct inode *ip = VTOI(vp);
    565 	int error = oerror;
    566 
    567 	/* Trigger ctime and mtime updates, and atime if MNT_RELATIME.  */
    568 	ip->i_flag |= IN_CHANGE | IN_UPDATE;
    569 	if (vp->v_mount->mnt_flag & MNT_RELATIME)
    570 		ip->i_flag |= IN_ACCESS;
    571 
    572 	/*
    573 	 * If we successfully wrote any data and we are not the superuser,
    574 	 * we clear the setuid and setgid bits as a precaution against
    575 	 * tampering.
    576 	 */
    577 	if (resid > uio->uio_resid && cred) {
    578 		if (ip->i_mode & ISUID) {
    579 			if (kauth_authorize_vnode(cred,
    580 			    KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0) {
    581 				ip->i_mode &= ~ISUID;
    582 				DIP_ASSIGN(ip, mode, ip->i_mode);
    583 			}
    584 		}
    585 
    586 		if (ip->i_mode & ISGID) {
    587 			if (kauth_authorize_vnode(cred,
    588 			    KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0) {
    589 				ip->i_mode &= ~ISGID;
    590 				DIP_ASSIGN(ip, mode, ip->i_mode);
    591 			}
    592 		}
    593 	}
    594 
    595 	/*
    596 	 * Update the size on disk: truncate back to original size on
    597 	 * error, or reflect the new size on success.
    598 	 */
    599 	if (error) {
    600 		(void) UFS_TRUNCATE(vp, osize, ioflag & IO_SYNC, cred);
    601 		uio->uio_offset -= resid - uio->uio_resid;
    602 		uio->uio_resid = resid;
    603 	} else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC)
    604 		error = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
    605 	else
    606 		UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
    607 
    608 	/* Make sure the vnode uvm size matches the inode file size.  */
    609 	KASSERT(vp->v_size == ip->i_size);
    610 
    611 	/* Write error overrides any inode update error.  */
    612 	if (oerror)
    613 		error = oerror;
    614 	return error;
    615 }
    616