xref: /minix3/sys/ufs/ext2fs/ext2fs_readwrite.c (revision d65f6f70097893d1dfe5e389f081f247bf3df183)
1*d65f6f70SBen Gras /*	$NetBSD: ext2fs_readwrite.c,v 1.58 2011/11/18 21:18:51 christos Exp $	*/
2*d65f6f70SBen Gras 
3*d65f6f70SBen Gras /*-
4*d65f6f70SBen Gras  * Copyright (c) 1993
5*d65f6f70SBen Gras  *	The Regents of the University of California.  All rights reserved.
6*d65f6f70SBen Gras  *
7*d65f6f70SBen Gras  * Redistribution and use in source and binary forms, with or without
8*d65f6f70SBen Gras  * modification, are permitted provided that the following conditions
9*d65f6f70SBen Gras  * are met:
10*d65f6f70SBen Gras  * 1. Redistributions of source code must retain the above copyright
11*d65f6f70SBen Gras  *    notice, this list of conditions and the following disclaimer.
12*d65f6f70SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
13*d65f6f70SBen Gras  *    notice, this list of conditions and the following disclaimer in the
14*d65f6f70SBen Gras  *    documentation and/or other materials provided with the distribution.
15*d65f6f70SBen Gras  * 3. Neither the name of the University nor the names of its contributors
16*d65f6f70SBen Gras  *    may be used to endorse or promote products derived from this software
17*d65f6f70SBen Gras  *    without specific prior written permission.
18*d65f6f70SBen Gras  *
19*d65f6f70SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*d65f6f70SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*d65f6f70SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*d65f6f70SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*d65f6f70SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*d65f6f70SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*d65f6f70SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*d65f6f70SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*d65f6f70SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*d65f6f70SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*d65f6f70SBen Gras  * SUCH DAMAGE.
30*d65f6f70SBen Gras  *
31*d65f6f70SBen Gras  *	@(#)ufs_readwrite.c	8.8 (Berkeley) 8/4/94
32*d65f6f70SBen Gras  * Modified for ext2fs by Manuel Bouyer.
33*d65f6f70SBen Gras  */
34*d65f6f70SBen Gras 
35*d65f6f70SBen Gras /*-
36*d65f6f70SBen Gras  * Copyright (c) 1997 Manuel Bouyer.
37*d65f6f70SBen Gras  *
38*d65f6f70SBen Gras  * Redistribution and use in source and binary forms, with or without
39*d65f6f70SBen Gras  * modification, are permitted provided that the following conditions
40*d65f6f70SBen Gras  * are met:
41*d65f6f70SBen Gras  * 1. Redistributions of source code must retain the above copyright
42*d65f6f70SBen Gras  *    notice, this list of conditions and the following disclaimer.
43*d65f6f70SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
44*d65f6f70SBen Gras  *    notice, this list of conditions and the following disclaimer in the
45*d65f6f70SBen Gras  *    documentation and/or other materials provided with the distribution.
46*d65f6f70SBen Gras  *
47*d65f6f70SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48*d65f6f70SBen Gras  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49*d65f6f70SBen Gras  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50*d65f6f70SBen Gras  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51*d65f6f70SBen Gras  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52*d65f6f70SBen Gras  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53*d65f6f70SBen Gras  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54*d65f6f70SBen Gras  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55*d65f6f70SBen Gras  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
56*d65f6f70SBen Gras  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57*d65f6f70SBen Gras  *
58*d65f6f70SBen Gras  *	@(#)ufs_readwrite.c	8.8 (Berkeley) 8/4/94
59*d65f6f70SBen Gras  * Modified for ext2fs by Manuel Bouyer.
60*d65f6f70SBen Gras  */
61*d65f6f70SBen Gras 
62*d65f6f70SBen Gras #include <sys/cdefs.h>
63*d65f6f70SBen Gras __KERNEL_RCSID(0, "$NetBSD: ext2fs_readwrite.c,v 1.58 2011/11/18 21:18:51 christos Exp $");
64*d65f6f70SBen Gras 
65*d65f6f70SBen Gras #include <sys/param.h>
66*d65f6f70SBen Gras #include <sys/systm.h>
67*d65f6f70SBen Gras #include <sys/resourcevar.h>
68*d65f6f70SBen Gras #include <sys/kernel.h>
69*d65f6f70SBen Gras #include <sys/file.h>
70*d65f6f70SBen Gras #include <sys/stat.h>
71*d65f6f70SBen Gras #include <sys/buf.h>
72*d65f6f70SBen Gras #include <sys/proc.h>
73*d65f6f70SBen Gras #include <sys/mount.h>
74*d65f6f70SBen Gras #include <sys/vnode.h>
75*d65f6f70SBen Gras #include <sys/malloc.h>
76*d65f6f70SBen Gras #include <sys/signalvar.h>
77*d65f6f70SBen Gras #include <sys/kauth.h>
78*d65f6f70SBen Gras 
79*d65f6f70SBen Gras #include <ufs/ufs/inode.h>
80*d65f6f70SBen Gras #include <ufs/ufs/ufsmount.h>
81*d65f6f70SBen Gras #include <ufs/ufs/ufs_extern.h>
82*d65f6f70SBen Gras #include <ufs/ext2fs/ext2fs.h>
83*d65f6f70SBen Gras #include <ufs/ext2fs/ext2fs_extern.h>
84*d65f6f70SBen Gras 
85*d65f6f70SBen Gras 
86*d65f6f70SBen Gras #define doclusterread 0 /* XXX underway */
87*d65f6f70SBen Gras #define doclusterwrite 0
88*d65f6f70SBen Gras 
89*d65f6f70SBen Gras /*
90*d65f6f70SBen Gras  * Vnode op for reading.
91*d65f6f70SBen Gras  */
92*d65f6f70SBen Gras /* ARGSUSED */
93*d65f6f70SBen Gras int
94*d65f6f70SBen Gras ext2fs_read(void *v)
95*d65f6f70SBen Gras {
96*d65f6f70SBen Gras 	struct vop_read_args /* {
97*d65f6f70SBen Gras 		struct vnode *a_vp;
98*d65f6f70SBen Gras 		struct uio *a_uio;
99*d65f6f70SBen Gras 		int a_ioflag;
100*d65f6f70SBen Gras 		kauth_cred_t a_cred;
101*d65f6f70SBen Gras 	} */ *ap = v;
102*d65f6f70SBen Gras 	struct vnode *vp;
103*d65f6f70SBen Gras 	struct inode *ip;
104*d65f6f70SBen Gras 	struct uio *uio;
105*d65f6f70SBen Gras 	struct m_ext2fs *fs;
106*d65f6f70SBen Gras 	struct buf *bp;
107*d65f6f70SBen Gras 	struct ufsmount *ump;
108*d65f6f70SBen Gras 	vsize_t bytelen;
109*d65f6f70SBen Gras 	daddr_t lbn, nextlbn;
110*d65f6f70SBen Gras 	off_t bytesinfile;
111*d65f6f70SBen Gras 	long size, xfersize, blkoffset;
112*d65f6f70SBen Gras 	int error;
113*d65f6f70SBen Gras 
114*d65f6f70SBen Gras 	vp = ap->a_vp;
115*d65f6f70SBen Gras 	ip = VTOI(vp);
116*d65f6f70SBen Gras 	ump = ip->i_ump;
117*d65f6f70SBen Gras 	uio = ap->a_uio;
118*d65f6f70SBen Gras 	error = 0;
119*d65f6f70SBen Gras 
120*d65f6f70SBen Gras #ifdef DIAGNOSTIC
121*d65f6f70SBen Gras 	if (uio->uio_rw != UIO_READ)
122*d65f6f70SBen Gras 		panic("%s: mode", "ext2fs_read");
123*d65f6f70SBen Gras 
124*d65f6f70SBen Gras 	if (vp->v_type == VLNK) {
125*d65f6f70SBen Gras 		if (ext2fs_size(ip) < ump->um_maxsymlinklen ||
126*d65f6f70SBen Gras 		    (ump->um_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0))
127*d65f6f70SBen Gras 			panic("%s: short symlink", "ext2fs_read");
128*d65f6f70SBen Gras 	} else if (vp->v_type != VREG && vp->v_type != VDIR)
129*d65f6f70SBen Gras 		panic("%s: type %d", "ext2fs_read", vp->v_type);
130*d65f6f70SBen Gras #endif
131*d65f6f70SBen Gras 	fs = ip->i_e2fs;
132*d65f6f70SBen Gras 	if ((uint64_t)uio->uio_offset > ump->um_maxfilesize)
133*d65f6f70SBen Gras 		return (EFBIG);
134*d65f6f70SBen Gras 	if (uio->uio_resid == 0)
135*d65f6f70SBen Gras 		return (0);
136*d65f6f70SBen Gras 	if (uio->uio_offset >= ext2fs_size(ip))
137*d65f6f70SBen Gras 		goto out;
138*d65f6f70SBen Gras 
139*d65f6f70SBen Gras 	if (vp->v_type == VREG) {
140*d65f6f70SBen Gras 		const int advice = IO_ADV_DECODE(ap->a_ioflag);
141*d65f6f70SBen Gras 
142*d65f6f70SBen Gras 		while (uio->uio_resid > 0) {
143*d65f6f70SBen Gras 			bytelen = MIN(ext2fs_size(ip) - uio->uio_offset,
144*d65f6f70SBen Gras 			    uio->uio_resid);
145*d65f6f70SBen Gras 			if (bytelen == 0)
146*d65f6f70SBen Gras 				break;
147*d65f6f70SBen Gras 
148*d65f6f70SBen Gras 			error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
149*d65f6f70SBen Gras 			    UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
150*d65f6f70SBen Gras 			if (error)
151*d65f6f70SBen Gras 				break;
152*d65f6f70SBen Gras 		}
153*d65f6f70SBen Gras 		goto out;
154*d65f6f70SBen Gras 	}
155*d65f6f70SBen Gras 
156*d65f6f70SBen Gras 	for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
157*d65f6f70SBen Gras 		bytesinfile = ext2fs_size(ip) - uio->uio_offset;
158*d65f6f70SBen Gras 		if (bytesinfile <= 0)
159*d65f6f70SBen Gras 			break;
160*d65f6f70SBen Gras 		lbn = lblkno(fs, uio->uio_offset);
161*d65f6f70SBen Gras 		nextlbn = lbn + 1;
162*d65f6f70SBen Gras 		size = fs->e2fs_bsize;
163*d65f6f70SBen Gras 		blkoffset = blkoff(fs, uio->uio_offset);
164*d65f6f70SBen Gras 		xfersize = fs->e2fs_bsize - blkoffset;
165*d65f6f70SBen Gras 		if (uio->uio_resid < xfersize)
166*d65f6f70SBen Gras 			xfersize = uio->uio_resid;
167*d65f6f70SBen Gras 		if (bytesinfile < xfersize)
168*d65f6f70SBen Gras 			xfersize = bytesinfile;
169*d65f6f70SBen Gras 
170*d65f6f70SBen Gras 		if (lblktosize(fs, nextlbn) >= ext2fs_size(ip))
171*d65f6f70SBen Gras 			error = bread(vp, lbn, size, NOCRED, 0, &bp);
172*d65f6f70SBen Gras 		else {
173*d65f6f70SBen Gras 			int nextsize = fs->e2fs_bsize;
174*d65f6f70SBen Gras 			error = breadn(vp, lbn,
175*d65f6f70SBen Gras 				size, &nextlbn, &nextsize, 1, NOCRED, 0, &bp);
176*d65f6f70SBen Gras 		}
177*d65f6f70SBen Gras 		if (error)
178*d65f6f70SBen Gras 			break;
179*d65f6f70SBen Gras 
180*d65f6f70SBen Gras 		/*
181*d65f6f70SBen Gras 		 * We should only get non-zero b_resid when an I/O error
182*d65f6f70SBen Gras 		 * has occurred, which should cause us to break above.
183*d65f6f70SBen Gras 		 * However, if the short read did not cause an error,
184*d65f6f70SBen Gras 		 * then we want to ensure that we do not uiomove bad
185*d65f6f70SBen Gras 		 * or uninitialized data.
186*d65f6f70SBen Gras 		 */
187*d65f6f70SBen Gras 		size -= bp->b_resid;
188*d65f6f70SBen Gras 		if (size < xfersize) {
189*d65f6f70SBen Gras 			if (size == 0)
190*d65f6f70SBen Gras 				break;
191*d65f6f70SBen Gras 			xfersize = size;
192*d65f6f70SBen Gras 		}
193*d65f6f70SBen Gras 		error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
194*d65f6f70SBen Gras 		if (error)
195*d65f6f70SBen Gras 			break;
196*d65f6f70SBen Gras 		brelse(bp, 0);
197*d65f6f70SBen Gras 	}
198*d65f6f70SBen Gras 	if (bp != NULL)
199*d65f6f70SBen Gras 		brelse(bp, 0);
200*d65f6f70SBen Gras 
201*d65f6f70SBen Gras out:
202*d65f6f70SBen Gras 	if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
203*d65f6f70SBen Gras 		ip->i_flag |= IN_ACCESS;
204*d65f6f70SBen Gras 		if ((ap->a_ioflag & IO_SYNC) == IO_SYNC)
205*d65f6f70SBen Gras 			error = ext2fs_update(vp, NULL, NULL, UPDATE_WAIT);
206*d65f6f70SBen Gras 	}
207*d65f6f70SBen Gras 	return (error);
208*d65f6f70SBen Gras }
209*d65f6f70SBen Gras 
210*d65f6f70SBen Gras /*
211*d65f6f70SBen Gras  * Vnode op for writing.
212*d65f6f70SBen Gras  */
213*d65f6f70SBen Gras int
214*d65f6f70SBen Gras ext2fs_write(void *v)
215*d65f6f70SBen Gras {
216*d65f6f70SBen Gras 	struct vop_write_args /* {
217*d65f6f70SBen Gras 		struct vnode *a_vp;
218*d65f6f70SBen Gras 		struct uio *a_uio;
219*d65f6f70SBen Gras 		int a_ioflag;
220*d65f6f70SBen Gras 		kauth_cred_t a_cred;
221*d65f6f70SBen Gras 	} */ *ap = v;
222*d65f6f70SBen Gras 	struct vnode *vp;
223*d65f6f70SBen Gras 	struct uio *uio;
224*d65f6f70SBen Gras 	struct inode *ip;
225*d65f6f70SBen Gras 	struct m_ext2fs *fs;
226*d65f6f70SBen Gras 	struct buf *bp;
227*d65f6f70SBen Gras 	struct ufsmount *ump;
228*d65f6f70SBen Gras 	daddr_t lbn;
229*d65f6f70SBen Gras 	off_t osize;
230*d65f6f70SBen Gras 	int blkoffset, error, flags, ioflag, resid, xfersize;
231*d65f6f70SBen Gras 	vsize_t bytelen;
232*d65f6f70SBen Gras 	off_t oldoff = 0;					/* XXX */
233*d65f6f70SBen Gras 	bool async;
234*d65f6f70SBen Gras 	int extended = 0;
235*d65f6f70SBen Gras 	int advice;
236*d65f6f70SBen Gras 
237*d65f6f70SBen Gras 	ioflag = ap->a_ioflag;
238*d65f6f70SBen Gras 	advice = IO_ADV_DECODE(ioflag);
239*d65f6f70SBen Gras 	uio = ap->a_uio;
240*d65f6f70SBen Gras 	vp = ap->a_vp;
241*d65f6f70SBen Gras 	ip = VTOI(vp);
242*d65f6f70SBen Gras 	ump = ip->i_ump;
243*d65f6f70SBen Gras 	error = 0;
244*d65f6f70SBen Gras 
245*d65f6f70SBen Gras #ifdef DIAGNOSTIC
246*d65f6f70SBen Gras 	if (uio->uio_rw != UIO_WRITE)
247*d65f6f70SBen Gras 		panic("%s: mode", "ext2fs_write");
248*d65f6f70SBen Gras #endif
249*d65f6f70SBen Gras 
250*d65f6f70SBen Gras 	switch (vp->v_type) {
251*d65f6f70SBen Gras 	case VREG:
252*d65f6f70SBen Gras 		if (ioflag & IO_APPEND)
253*d65f6f70SBen Gras 			uio->uio_offset = ext2fs_size(ip);
254*d65f6f70SBen Gras 		if ((ip->i_e2fs_flags & EXT2_APPEND) &&
255*d65f6f70SBen Gras 		    uio->uio_offset != ext2fs_size(ip))
256*d65f6f70SBen Gras 			return (EPERM);
257*d65f6f70SBen Gras 		/* FALLTHROUGH */
258*d65f6f70SBen Gras 	case VLNK:
259*d65f6f70SBen Gras 		break;
260*d65f6f70SBen Gras 	case VDIR:
261*d65f6f70SBen Gras 		if ((ioflag & IO_SYNC) == 0)
262*d65f6f70SBen Gras 			panic("%s: nonsync dir write", "ext2fs_write");
263*d65f6f70SBen Gras 		break;
264*d65f6f70SBen Gras 	default:
265*d65f6f70SBen Gras 		panic("%s: type", "ext2fs_write");
266*d65f6f70SBen Gras 	}
267*d65f6f70SBen Gras 
268*d65f6f70SBen Gras 	fs = ip->i_e2fs;
269*d65f6f70SBen Gras 	if (uio->uio_offset < 0 ||
270*d65f6f70SBen Gras 	    (uint64_t)uio->uio_offset + uio->uio_resid > ump->um_maxfilesize)
271*d65f6f70SBen Gras 		return (EFBIG);
272*d65f6f70SBen Gras 	if (uio->uio_resid == 0)
273*d65f6f70SBen Gras 		return (0);
274*d65f6f70SBen Gras 
275*d65f6f70SBen Gras 	async = vp->v_mount->mnt_flag & MNT_ASYNC;
276*d65f6f70SBen Gras 	resid = uio->uio_resid;
277*d65f6f70SBen Gras 	osize = ext2fs_size(ip);
278*d65f6f70SBen Gras 
279*d65f6f70SBen Gras 	if (vp->v_type == VREG) {
280*d65f6f70SBen Gras 		while (uio->uio_resid > 0) {
281*d65f6f70SBen Gras 			oldoff = uio->uio_offset;
282*d65f6f70SBen Gras 			blkoffset = blkoff(fs, uio->uio_offset);
283*d65f6f70SBen Gras 			bytelen = MIN(fs->e2fs_bsize - blkoffset,
284*d65f6f70SBen Gras 			    uio->uio_resid);
285*d65f6f70SBen Gras 
286*d65f6f70SBen Gras 			if (vp->v_size < oldoff + bytelen) {
287*d65f6f70SBen Gras 				uvm_vnp_setwritesize(vp, oldoff + bytelen);
288*d65f6f70SBen Gras 			}
289*d65f6f70SBen Gras 			error = ufs_balloc_range(vp, uio->uio_offset,
290*d65f6f70SBen Gras 			    bytelen, ap->a_cred, 0);
291*d65f6f70SBen Gras 			if (error)
292*d65f6f70SBen Gras 				break;
293*d65f6f70SBen Gras 			error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
294*d65f6f70SBen Gras 			    UBC_WRITE | UBC_UNMAP_FLAG(vp));
295*d65f6f70SBen Gras 			if (error)
296*d65f6f70SBen Gras 				break;
297*d65f6f70SBen Gras 
298*d65f6f70SBen Gras 			/*
299*d65f6f70SBen Gras 			 * update UVM's notion of the size now that we've
300*d65f6f70SBen Gras 			 * copied the data into the vnode's pages.
301*d65f6f70SBen Gras 			 */
302*d65f6f70SBen Gras 
303*d65f6f70SBen Gras 			if (vp->v_size < uio->uio_offset) {
304*d65f6f70SBen Gras 				uvm_vnp_setsize(vp, uio->uio_offset);
305*d65f6f70SBen Gras 				extended = 1;
306*d65f6f70SBen Gras 			}
307*d65f6f70SBen Gras 
308*d65f6f70SBen Gras 			/*
309*d65f6f70SBen Gras 			 * flush what we just wrote if necessary.
310*d65f6f70SBen Gras 			 * XXXUBC simplistic async flushing.
311*d65f6f70SBen Gras 			 */
312*d65f6f70SBen Gras 
313*d65f6f70SBen Gras 			if (!async && oldoff >> 16 != uio->uio_offset >> 16) {
314*d65f6f70SBen Gras 				mutex_enter(vp->v_interlock);
315*d65f6f70SBen Gras 				error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16,
316*d65f6f70SBen Gras 				    (uio->uio_offset >> 16) << 16, PGO_CLEANIT);
317*d65f6f70SBen Gras 			}
318*d65f6f70SBen Gras 		}
319*d65f6f70SBen Gras 		if (error == 0 && ioflag & IO_SYNC) {
320*d65f6f70SBen Gras 			mutex_enter(vp->v_interlock);
321*d65f6f70SBen Gras 			error = VOP_PUTPAGES(vp, trunc_page(oldoff),
322*d65f6f70SBen Gras 			    round_page(blkroundup(fs, uio->uio_offset)),
323*d65f6f70SBen Gras 			    PGO_CLEANIT | PGO_SYNCIO);
324*d65f6f70SBen Gras 		}
325*d65f6f70SBen Gras 
326*d65f6f70SBen Gras 		goto out;
327*d65f6f70SBen Gras 	}
328*d65f6f70SBen Gras 
329*d65f6f70SBen Gras 	flags = ioflag & IO_SYNC ? B_SYNC : 0;
330*d65f6f70SBen Gras 	for (error = 0; uio->uio_resid > 0;) {
331*d65f6f70SBen Gras 		lbn = lblkno(fs, uio->uio_offset);
332*d65f6f70SBen Gras 		blkoffset = blkoff(fs, uio->uio_offset);
333*d65f6f70SBen Gras 		xfersize = MIN(fs->e2fs_bsize - blkoffset, uio->uio_resid);
334*d65f6f70SBen Gras 		if (xfersize < fs->e2fs_bsize)
335*d65f6f70SBen Gras 			flags |= B_CLRBUF;
336*d65f6f70SBen Gras 		else
337*d65f6f70SBen Gras 			flags &= ~B_CLRBUF;
338*d65f6f70SBen Gras 		error = ext2fs_balloc(ip,
339*d65f6f70SBen Gras 		    lbn, blkoffset + xfersize, ap->a_cred, &bp, flags);
340*d65f6f70SBen Gras 		if (error)
341*d65f6f70SBen Gras 			break;
342*d65f6f70SBen Gras 		if (ext2fs_size(ip) < uio->uio_offset + xfersize) {
343*d65f6f70SBen Gras 			error = ext2fs_setsize(ip, uio->uio_offset + xfersize);
344*d65f6f70SBen Gras 			if (error)
345*d65f6f70SBen Gras 				break;
346*d65f6f70SBen Gras 		}
347*d65f6f70SBen Gras 		error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
348*d65f6f70SBen Gras 
349*d65f6f70SBen Gras 		/*
350*d65f6f70SBen Gras 		 * update UVM's notion of the size now that we've
351*d65f6f70SBen Gras 		 * copied the data into the vnode's pages.
352*d65f6f70SBen Gras 		 */
353*d65f6f70SBen Gras 
354*d65f6f70SBen Gras 		if (vp->v_size < uio->uio_offset) {
355*d65f6f70SBen Gras 			uvm_vnp_setsize(vp, uio->uio_offset);
356*d65f6f70SBen Gras 			extended = 1;
357*d65f6f70SBen Gras 		}
358*d65f6f70SBen Gras 
359*d65f6f70SBen Gras 		if (ioflag & IO_SYNC)
360*d65f6f70SBen Gras 			(void)bwrite(bp);
361*d65f6f70SBen Gras 		else if (xfersize + blkoffset == fs->e2fs_bsize)
362*d65f6f70SBen Gras 			bawrite(bp);
363*d65f6f70SBen Gras 		else
364*d65f6f70SBen Gras 			bdwrite(bp);
365*d65f6f70SBen Gras 		if (error || xfersize == 0)
366*d65f6f70SBen Gras 			break;
367*d65f6f70SBen Gras 	}
368*d65f6f70SBen Gras 
369*d65f6f70SBen Gras 	/*
370*d65f6f70SBen Gras 	 * If we successfully wrote any data, and we are not the superuser
371*d65f6f70SBen Gras 	 * we clear the setuid and setgid bits as a precaution against
372*d65f6f70SBen Gras 	 * tampering.
373*d65f6f70SBen Gras 	 */
374*d65f6f70SBen Gras 
375*d65f6f70SBen Gras out:
376*d65f6f70SBen Gras 	ip->i_flag |= IN_CHANGE | IN_UPDATE;
377*d65f6f70SBen Gras 	if (vp->v_mount->mnt_flag & MNT_RELATIME)
378*d65f6f70SBen Gras 		ip->i_flag |= IN_ACCESS;
379*d65f6f70SBen Gras 	if (resid > uio->uio_resid && ap->a_cred &&
380*d65f6f70SBen Gras 	    kauth_authorize_generic(ap->a_cred, KAUTH_GENERIC_ISSUSER, NULL))
381*d65f6f70SBen Gras 		ip->i_e2fs_mode &= ~(ISUID | ISGID);
382*d65f6f70SBen Gras 	if (resid > uio->uio_resid)
383*d65f6f70SBen Gras 		VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
384*d65f6f70SBen Gras 	if (error) {
385*d65f6f70SBen Gras 		(void) ext2fs_truncate(vp, osize, ioflag & IO_SYNC, ap->a_cred);
386*d65f6f70SBen Gras 		uio->uio_offset -= resid - uio->uio_resid;
387*d65f6f70SBen Gras 		uio->uio_resid = resid;
388*d65f6f70SBen Gras 	} else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC)
389*d65f6f70SBen Gras 		error = ext2fs_update(vp, NULL, NULL, UPDATE_WAIT);
390*d65f6f70SBen Gras 	KASSERT(vp->v_size == ext2fs_size(ip));
391*d65f6f70SBen Gras 	return (error);
392*d65f6f70SBen Gras }
393