ulfs_readwrite.c revision 1.4.2.3 1 1.4.2.2 tls /* $NetBSD: ulfs_readwrite.c,v 1.4.2.3 2014/08/20 00:04:45 tls Exp $ */
2 1.4.2.2 tls /* from NetBSD: ufs_readwrite.c,v 1.105 2013/01/22 09:39:18 dholland Exp */
3 1.4.2.2 tls
4 1.4.2.2 tls /*-
5 1.4.2.2 tls * Copyright (c) 1993
6 1.4.2.2 tls * The Regents of the University of California. All rights reserved.
7 1.4.2.2 tls *
8 1.4.2.2 tls * Redistribution and use in source and binary forms, with or without
9 1.4.2.2 tls * modification, are permitted provided that the following conditions
10 1.4.2.2 tls * are met:
11 1.4.2.2 tls * 1. Redistributions of source code must retain the above copyright
12 1.4.2.2 tls * notice, this list of conditions and the following disclaimer.
13 1.4.2.2 tls * 2. Redistributions in binary form must reproduce the above copyright
14 1.4.2.2 tls * notice, this list of conditions and the following disclaimer in the
15 1.4.2.2 tls * documentation and/or other materials provided with the distribution.
16 1.4.2.2 tls * 3. Neither the name of the University nor the names of its contributors
17 1.4.2.2 tls * may be used to endorse or promote products derived from this software
18 1.4.2.2 tls * without specific prior written permission.
19 1.4.2.2 tls *
20 1.4.2.2 tls * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 1.4.2.2 tls * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 1.4.2.2 tls * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 1.4.2.2 tls * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 1.4.2.2 tls * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 1.4.2.2 tls * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 1.4.2.2 tls * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 1.4.2.2 tls * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 1.4.2.2 tls * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 1.4.2.2 tls * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 1.4.2.2 tls * SUCH DAMAGE.
31 1.4.2.2 tls *
32 1.4.2.2 tls * @(#)ufs_readwrite.c 8.11 (Berkeley) 5/8/95
33 1.4.2.2 tls */
34 1.4.2.2 tls
35 1.4.2.2 tls #include <sys/cdefs.h>
36 1.4.2.2 tls __KERNEL_RCSID(1, "$NetBSD: ulfs_readwrite.c,v 1.4.2.3 2014/08/20 00:04:45 tls Exp $");
37 1.4.2.2 tls
38 1.4.2.2 tls #ifdef LFS_READWRITE
39 1.4.2.2 tls #define FS struct lfs
40 1.4.2.2 tls #define I_FS i_lfs
41 1.4.2.2 tls #define READ lfs_read
42 1.4.2.2 tls #define READ_S "lfs_read"
43 1.4.2.2 tls #define WRITE lfs_write
44 1.4.2.2 tls #define WRITE_S "lfs_write"
45 1.4.2.2 tls #define fs_bsize lfs_bsize
46 1.4.2.2 tls #define fs_bmask lfs_bmask
47 1.4.2.2 tls #else
48 1.4.2.2 tls #define FS struct fs
49 1.4.2.2 tls #define I_FS i_fs
50 1.4.2.2 tls #define READ ffs_read
51 1.4.2.2 tls #define READ_S "ffs_read"
52 1.4.2.2 tls #define WRITE ffs_write
53 1.4.2.2 tls #define WRITE_S "ffs_write"
54 1.4.2.2 tls #endif
55 1.4.2.2 tls
56 1.4.2.2 tls /*
57 1.4.2.2 tls * Vnode op for reading.
58 1.4.2.2 tls */
59 1.4.2.2 tls /* ARGSUSED */
60 1.4.2.2 tls int
61 1.4.2.2 tls READ(void *v)
62 1.4.2.2 tls {
63 1.4.2.2 tls struct vop_read_args /* {
64 1.4.2.2 tls struct vnode *a_vp;
65 1.4.2.2 tls struct uio *a_uio;
66 1.4.2.2 tls int a_ioflag;
67 1.4.2.2 tls kauth_cred_t a_cred;
68 1.4.2.2 tls } */ *ap = v;
69 1.4.2.2 tls struct vnode *vp;
70 1.4.2.2 tls struct inode *ip;
71 1.4.2.2 tls struct uio *uio;
72 1.4.2.2 tls struct buf *bp;
73 1.4.2.2 tls FS *fs;
74 1.4.2.2 tls vsize_t bytelen;
75 1.4.2.2 tls daddr_t lbn, nextlbn;
76 1.4.2.2 tls off_t bytesinfile;
77 1.4.2.2 tls long size, xfersize, blkoffset;
78 1.4.2.2 tls int error, ioflag;
79 1.4.2.2 tls bool usepc = false;
80 1.4.2.2 tls
81 1.4.2.2 tls vp = ap->a_vp;
82 1.4.2.2 tls ip = VTOI(vp);
83 1.4.2.3 tls fs = ip->I_FS;
84 1.4.2.2 tls uio = ap->a_uio;
85 1.4.2.2 tls ioflag = ap->a_ioflag;
86 1.4.2.2 tls error = 0;
87 1.4.2.2 tls
88 1.4.2.2 tls #ifdef DIAGNOSTIC
89 1.4.2.2 tls if (uio->uio_rw != UIO_READ)
90 1.4.2.2 tls panic("%s: mode", READ_S);
91 1.4.2.2 tls
92 1.4.2.2 tls if (vp->v_type == VLNK) {
93 1.4.2.3 tls if (ip->i_size < fs->um_maxsymlinklen ||
94 1.4.2.3 tls (fs->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0))
95 1.4.2.2 tls panic("%s: short symlink", READ_S);
96 1.4.2.2 tls } else if (vp->v_type != VREG && vp->v_type != VDIR)
97 1.4.2.2 tls panic("%s: type %d", READ_S, vp->v_type);
98 1.4.2.2 tls #endif
99 1.4.2.3 tls if ((u_int64_t)uio->uio_offset > fs->um_maxfilesize)
100 1.4.2.2 tls return (EFBIG);
101 1.4.2.2 tls if (uio->uio_resid == 0)
102 1.4.2.2 tls return (0);
103 1.4.2.2 tls
104 1.4.2.2 tls #ifndef LFS_READWRITE
105 1.4.2.2 tls if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) == SF_SNAPSHOT)
106 1.4.2.2 tls return ffs_snapshot_read(vp, uio, ioflag);
107 1.4.2.2 tls #endif /* !LFS_READWRITE */
108 1.4.2.2 tls
109 1.4.2.2 tls fstrans_start(vp->v_mount, FSTRANS_SHARED);
110 1.4.2.2 tls
111 1.4.2.2 tls if (uio->uio_offset >= ip->i_size)
112 1.4.2.2 tls goto out;
113 1.4.2.2 tls
114 1.4.2.2 tls #ifdef LFS_READWRITE
115 1.4.2.2 tls usepc = (vp->v_type == VREG && ip->i_number != LFS_IFILE_INUM);
116 1.4.2.2 tls #else /* !LFS_READWRITE */
117 1.4.2.2 tls usepc = vp->v_type == VREG;
118 1.4.2.2 tls #endif /* !LFS_READWRITE */
119 1.4.2.2 tls if (usepc) {
120 1.4.2.2 tls const int advice = IO_ADV_DECODE(ap->a_ioflag);
121 1.4.2.2 tls
122 1.4.2.2 tls while (uio->uio_resid > 0) {
123 1.4.2.2 tls if (ioflag & IO_DIRECT) {
124 1.4.2.2 tls genfs_directio(vp, uio, ioflag);
125 1.4.2.2 tls }
126 1.4.2.2 tls bytelen = MIN(ip->i_size - uio->uio_offset,
127 1.4.2.2 tls uio->uio_resid);
128 1.4.2.2 tls if (bytelen == 0)
129 1.4.2.2 tls break;
130 1.4.2.2 tls error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
131 1.4.2.2 tls UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
132 1.4.2.2 tls if (error)
133 1.4.2.2 tls break;
134 1.4.2.2 tls }
135 1.4.2.2 tls goto out;
136 1.4.2.2 tls }
137 1.4.2.2 tls
138 1.4.2.2 tls for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
139 1.4.2.2 tls bytesinfile = ip->i_size - uio->uio_offset;
140 1.4.2.2 tls if (bytesinfile <= 0)
141 1.4.2.2 tls break;
142 1.4.2.2 tls lbn = lfs_lblkno(fs, uio->uio_offset);
143 1.4.2.2 tls nextlbn = lbn + 1;
144 1.4.2.2 tls size = lfs_blksize(fs, ip, lbn);
145 1.4.2.2 tls blkoffset = lfs_blkoff(fs, uio->uio_offset);
146 1.4.2.2 tls xfersize = MIN(MIN(fs->fs_bsize - blkoffset, uio->uio_resid),
147 1.4.2.2 tls bytesinfile);
148 1.4.2.2 tls
149 1.4.2.2 tls if (lfs_lblktosize(fs, nextlbn) >= ip->i_size)
150 1.4.2.2 tls error = bread(vp, lbn, size, NOCRED, 0, &bp);
151 1.4.2.2 tls else {
152 1.4.2.2 tls int nextsize = lfs_blksize(fs, ip, nextlbn);
153 1.4.2.2 tls error = breadn(vp, lbn,
154 1.4.2.2 tls size, &nextlbn, &nextsize, 1, NOCRED, 0, &bp);
155 1.4.2.2 tls }
156 1.4.2.2 tls if (error)
157 1.4.2.2 tls break;
158 1.4.2.2 tls
159 1.4.2.2 tls /*
160 1.4.2.2 tls * We should only get non-zero b_resid when an I/O error
161 1.4.2.2 tls * has occurred, which should cause us to break above.
162 1.4.2.2 tls * However, if the short read did not cause an error,
163 1.4.2.2 tls * then we want to ensure that we do not uiomove bad
164 1.4.2.2 tls * or uninitialized data.
165 1.4.2.2 tls */
166 1.4.2.2 tls size -= bp->b_resid;
167 1.4.2.2 tls if (size < xfersize) {
168 1.4.2.2 tls if (size == 0)
169 1.4.2.2 tls break;
170 1.4.2.2 tls xfersize = size;
171 1.4.2.2 tls }
172 1.4.2.2 tls error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
173 1.4.2.2 tls if (error)
174 1.4.2.2 tls break;
175 1.4.2.2 tls brelse(bp, 0);
176 1.4.2.2 tls }
177 1.4.2.2 tls if (bp != NULL)
178 1.4.2.2 tls brelse(bp, 0);
179 1.4.2.2 tls
180 1.4.2.2 tls out:
181 1.4.2.2 tls if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
182 1.4.2.2 tls ip->i_flag |= IN_ACCESS;
183 1.4.2.2 tls if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) {
184 1.4.2.3 tls error = lfs_update(vp, NULL, NULL, UPDATE_WAIT);
185 1.4.2.2 tls }
186 1.4.2.2 tls }
187 1.4.2.2 tls
188 1.4.2.2 tls fstrans_done(vp->v_mount);
189 1.4.2.2 tls return (error);
190 1.4.2.2 tls }
191 1.4.2.2 tls
192 1.4.2.2 tls /*
193 1.4.2.2 tls * Vnode op for writing.
194 1.4.2.2 tls */
195 1.4.2.2 tls int
196 1.4.2.2 tls WRITE(void *v)
197 1.4.2.2 tls {
198 1.4.2.2 tls struct vop_write_args /* {
199 1.4.2.2 tls struct vnode *a_vp;
200 1.4.2.2 tls struct uio *a_uio;
201 1.4.2.2 tls int a_ioflag;
202 1.4.2.2 tls kauth_cred_t a_cred;
203 1.4.2.2 tls } */ *ap = v;
204 1.4.2.2 tls struct vnode *vp;
205 1.4.2.2 tls struct uio *uio;
206 1.4.2.2 tls struct inode *ip;
207 1.4.2.2 tls FS *fs;
208 1.4.2.2 tls struct buf *bp;
209 1.4.2.2 tls kauth_cred_t cred;
210 1.4.2.2 tls daddr_t lbn;
211 1.4.2.2 tls off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize;
212 1.4.2.2 tls int blkoffset, error, flags, ioflag, resid, size, xfersize;
213 1.4.2.2 tls int aflag;
214 1.4.2.2 tls int extended=0;
215 1.4.2.2 tls vsize_t bytelen;
216 1.4.2.2 tls bool async;
217 1.4.2.2 tls bool usepc = false;
218 1.4.2.2 tls #ifdef LFS_READWRITE
219 1.4.2.2 tls bool need_unreserve = false;
220 1.4.2.2 tls #endif
221 1.4.2.2 tls
222 1.4.2.2 tls cred = ap->a_cred;
223 1.4.2.2 tls ioflag = ap->a_ioflag;
224 1.4.2.2 tls uio = ap->a_uio;
225 1.4.2.2 tls vp = ap->a_vp;
226 1.4.2.2 tls ip = VTOI(vp);
227 1.4.2.2 tls
228 1.4.2.2 tls KASSERT(vp->v_size == ip->i_size);
229 1.4.2.2 tls #ifdef DIAGNOSTIC
230 1.4.2.2 tls if (uio->uio_rw != UIO_WRITE)
231 1.4.2.2 tls panic("%s: mode", WRITE_S);
232 1.4.2.2 tls #endif
233 1.4.2.2 tls
234 1.4.2.2 tls switch (vp->v_type) {
235 1.4.2.2 tls case VREG:
236 1.4.2.2 tls if (ioflag & IO_APPEND)
237 1.4.2.2 tls uio->uio_offset = ip->i_size;
238 1.4.2.2 tls if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
239 1.4.2.2 tls return (EPERM);
240 1.4.2.2 tls /* FALLTHROUGH */
241 1.4.2.2 tls case VLNK:
242 1.4.2.2 tls break;
243 1.4.2.2 tls case VDIR:
244 1.4.2.2 tls if ((ioflag & IO_SYNC) == 0)
245 1.4.2.2 tls panic("%s: nonsync dir write", WRITE_S);
246 1.4.2.2 tls break;
247 1.4.2.2 tls default:
248 1.4.2.2 tls panic("%s: type", WRITE_S);
249 1.4.2.2 tls }
250 1.4.2.2 tls
251 1.4.2.2 tls fs = ip->I_FS;
252 1.4.2.2 tls if (uio->uio_offset < 0 ||
253 1.4.2.3 tls (u_int64_t)uio->uio_offset + uio->uio_resid > fs->um_maxfilesize)
254 1.4.2.2 tls return (EFBIG);
255 1.4.2.2 tls #ifdef LFS_READWRITE
256 1.4.2.2 tls /* Disallow writes to the Ifile, even if noschg flag is removed */
257 1.4.2.2 tls /* XXX can this go away when the Ifile is no longer in the namespace? */
258 1.4.2.2 tls if (vp == fs->lfs_ivnode)
259 1.4.2.2 tls return (EPERM);
260 1.4.2.2 tls #endif
261 1.4.2.2 tls if (uio->uio_resid == 0)
262 1.4.2.2 tls return (0);
263 1.4.2.2 tls
264 1.4.2.2 tls fstrans_start(vp->v_mount, FSTRANS_SHARED);
265 1.4.2.2 tls
266 1.4.2.2 tls flags = ioflag & IO_SYNC ? B_SYNC : 0;
267 1.4.2.2 tls async = vp->v_mount->mnt_flag & MNT_ASYNC;
268 1.4.2.2 tls origoff = uio->uio_offset;
269 1.4.2.2 tls resid = uio->uio_resid;
270 1.4.2.2 tls osize = ip->i_size;
271 1.4.2.2 tls error = 0;
272 1.4.2.2 tls
273 1.4.2.2 tls usepc = vp->v_type == VREG;
274 1.4.2.2 tls
275 1.4.2.2 tls #ifdef LFS_READWRITE
276 1.4.2.2 tls async = true;
277 1.4.2.2 tls lfs_availwait(fs, lfs_btofsb(fs, uio->uio_resid));
278 1.4.2.2 tls lfs_check(vp, LFS_UNUSED_LBN, 0);
279 1.4.2.2 tls #endif /* !LFS_READWRITE */
280 1.4.2.2 tls if (!usepc)
281 1.4.2.2 tls goto bcache;
282 1.4.2.2 tls
283 1.4.2.2 tls preallocoff = round_page(lfs_blkroundup(fs, MAX(osize, uio->uio_offset)));
284 1.4.2.2 tls aflag = ioflag & IO_SYNC ? B_SYNC : 0;
285 1.4.2.2 tls nsize = MAX(osize, uio->uio_offset + uio->uio_resid);
286 1.4.2.2 tls endallocoff = nsize - lfs_blkoff(fs, nsize);
287 1.4.2.2 tls
288 1.4.2.2 tls /*
289 1.4.2.2 tls * if we're increasing the file size, deal with expanding
290 1.4.2.2 tls * the fragment if there is one.
291 1.4.2.2 tls */
292 1.4.2.2 tls
293 1.4.2.2 tls if (nsize > osize && lfs_lblkno(fs, osize) < ULFS_NDADDR &&
294 1.4.2.2 tls lfs_lblkno(fs, osize) != lfs_lblkno(fs, nsize) &&
295 1.4.2.2 tls lfs_blkroundup(fs, osize) != osize) {
296 1.4.2.2 tls off_t eob;
297 1.4.2.2 tls
298 1.4.2.2 tls eob = lfs_blkroundup(fs, osize);
299 1.4.2.2 tls uvm_vnp_setwritesize(vp, eob);
300 1.4.2.2 tls error = ulfs_balloc_range(vp, osize, eob - osize, cred, aflag);
301 1.4.2.2 tls if (error)
302 1.4.2.2 tls goto out;
303 1.4.2.2 tls if (flags & B_SYNC) {
304 1.4.2.2 tls mutex_enter(vp->v_interlock);
305 1.4.2.2 tls VOP_PUTPAGES(vp, trunc_page(osize & fs->fs_bmask),
306 1.4.2.2 tls round_page(eob),
307 1.4.2.2 tls PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
308 1.4.2.2 tls }
309 1.4.2.2 tls }
310 1.4.2.2 tls
311 1.4.2.2 tls while (uio->uio_resid > 0) {
312 1.4.2.2 tls int ubc_flags = UBC_WRITE;
313 1.4.2.2 tls bool overwrite; /* if we're overwrite a whole block */
314 1.4.2.2 tls off_t newoff;
315 1.4.2.2 tls
316 1.4.2.2 tls if (ioflag & IO_DIRECT) {
317 1.4.2.2 tls genfs_directio(vp, uio, ioflag | IO_JOURNALLOCKED);
318 1.4.2.2 tls }
319 1.4.2.2 tls
320 1.4.2.2 tls oldoff = uio->uio_offset;
321 1.4.2.2 tls blkoffset = lfs_blkoff(fs, uio->uio_offset);
322 1.4.2.2 tls bytelen = MIN(fs->fs_bsize - blkoffset, uio->uio_resid);
323 1.4.2.2 tls if (bytelen == 0) {
324 1.4.2.2 tls break;
325 1.4.2.2 tls }
326 1.4.2.2 tls
327 1.4.2.2 tls /*
328 1.4.2.2 tls * if we're filling in a hole, allocate the blocks now and
329 1.4.2.2 tls * initialize the pages first. if we're extending the file,
330 1.4.2.2 tls * we can safely allocate blocks without initializing pages
331 1.4.2.2 tls * since the new blocks will be inaccessible until the write
332 1.4.2.2 tls * is complete.
333 1.4.2.2 tls */
334 1.4.2.2 tls overwrite = uio->uio_offset >= preallocoff &&
335 1.4.2.2 tls uio->uio_offset < endallocoff;
336 1.4.2.2 tls if (!overwrite && (vp->v_vflag & VV_MAPPED) == 0 &&
337 1.4.2.2 tls lfs_blkoff(fs, uio->uio_offset) == 0 &&
338 1.4.2.2 tls (uio->uio_offset & PAGE_MASK) == 0) {
339 1.4.2.2 tls vsize_t len;
340 1.4.2.2 tls
341 1.4.2.2 tls len = trunc_page(bytelen);
342 1.4.2.2 tls len -= lfs_blkoff(fs, len);
343 1.4.2.2 tls if (len > 0) {
344 1.4.2.2 tls overwrite = true;
345 1.4.2.2 tls bytelen = len;
346 1.4.2.2 tls }
347 1.4.2.2 tls }
348 1.4.2.2 tls
349 1.4.2.2 tls newoff = oldoff + bytelen;
350 1.4.2.2 tls if (vp->v_size < newoff) {
351 1.4.2.2 tls uvm_vnp_setwritesize(vp, newoff);
352 1.4.2.2 tls }
353 1.4.2.2 tls
354 1.4.2.2 tls if (!overwrite) {
355 1.4.2.2 tls error = ulfs_balloc_range(vp, uio->uio_offset, bytelen,
356 1.4.2.2 tls cred, aflag);
357 1.4.2.2 tls if (error)
358 1.4.2.2 tls break;
359 1.4.2.2 tls } else {
360 1.4.2.2 tls genfs_node_wrlock(vp);
361 1.4.2.2 tls error = GOP_ALLOC(vp, uio->uio_offset, bytelen,
362 1.4.2.2 tls aflag, cred);
363 1.4.2.2 tls genfs_node_unlock(vp);
364 1.4.2.2 tls if (error)
365 1.4.2.2 tls break;
366 1.4.2.2 tls ubc_flags |= UBC_FAULTBUSY;
367 1.4.2.2 tls }
368 1.4.2.2 tls
369 1.4.2.2 tls /*
370 1.4.2.2 tls * copy the data.
371 1.4.2.2 tls */
372 1.4.2.2 tls
373 1.4.2.2 tls error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
374 1.4.2.2 tls IO_ADV_DECODE(ioflag), ubc_flags | UBC_UNMAP_FLAG(vp));
375 1.4.2.2 tls
376 1.4.2.2 tls /*
377 1.4.2.2 tls * update UVM's notion of the size now that we've
378 1.4.2.2 tls * copied the data into the vnode's pages.
379 1.4.2.2 tls *
380 1.4.2.2 tls * we should update the size even when uiomove failed.
381 1.4.2.2 tls */
382 1.4.2.2 tls
383 1.4.2.2 tls if (vp->v_size < newoff) {
384 1.4.2.2 tls uvm_vnp_setsize(vp, newoff);
385 1.4.2.2 tls extended = 1;
386 1.4.2.2 tls }
387 1.4.2.2 tls
388 1.4.2.2 tls if (error)
389 1.4.2.2 tls break;
390 1.4.2.2 tls
391 1.4.2.2 tls /*
392 1.4.2.2 tls * flush what we just wrote if necessary.
393 1.4.2.2 tls * XXXUBC simplistic async flushing.
394 1.4.2.2 tls */
395 1.4.2.2 tls
396 1.4.2.2 tls #ifndef LFS_READWRITE
397 1.4.2.2 tls if (!async && oldoff >> 16 != uio->uio_offset >> 16) {
398 1.4.2.2 tls mutex_enter(vp->v_interlock);
399 1.4.2.2 tls error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16,
400 1.4.2.2 tls (uio->uio_offset >> 16) << 16,
401 1.4.2.2 tls PGO_CLEANIT | PGO_JOURNALLOCKED | PGO_LAZY);
402 1.4.2.2 tls if (error)
403 1.4.2.2 tls break;
404 1.4.2.2 tls }
405 1.4.2.3 tls #else
406 1.4.2.3 tls __USE(async);
407 1.4.2.2 tls #endif
408 1.4.2.2 tls }
409 1.4.2.2 tls if (error == 0 && ioflag & IO_SYNC) {
410 1.4.2.2 tls mutex_enter(vp->v_interlock);
411 1.4.2.2 tls error = VOP_PUTPAGES(vp, trunc_page(origoff & fs->fs_bmask),
412 1.4.2.2 tls round_page(lfs_blkroundup(fs, uio->uio_offset)),
413 1.4.2.2 tls PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
414 1.4.2.2 tls }
415 1.4.2.2 tls goto out;
416 1.4.2.2 tls
417 1.4.2.2 tls bcache:
418 1.4.2.2 tls mutex_enter(vp->v_interlock);
419 1.4.2.2 tls VOP_PUTPAGES(vp, trunc_page(origoff), round_page(origoff + resid),
420 1.4.2.2 tls PGO_CLEANIT | PGO_FREE | PGO_SYNCIO | PGO_JOURNALLOCKED);
421 1.4.2.2 tls while (uio->uio_resid > 0) {
422 1.4.2.2 tls lbn = lfs_lblkno(fs, uio->uio_offset);
423 1.4.2.2 tls blkoffset = lfs_blkoff(fs, uio->uio_offset);
424 1.4.2.2 tls xfersize = MIN(fs->fs_bsize - blkoffset, uio->uio_resid);
425 1.4.2.2 tls if (fs->fs_bsize > xfersize)
426 1.4.2.2 tls flags |= B_CLRBUF;
427 1.4.2.2 tls else
428 1.4.2.2 tls flags &= ~B_CLRBUF;
429 1.4.2.2 tls
430 1.4.2.2 tls #ifdef LFS_READWRITE
431 1.4.2.2 tls error = lfs_reserve(fs, vp, NULL,
432 1.4.2.2 tls lfs_btofsb(fs, (ULFS_NIADDR + 1) << fs->lfs_bshift));
433 1.4.2.2 tls if (error)
434 1.4.2.2 tls break;
435 1.4.2.2 tls need_unreserve = true;
436 1.4.2.2 tls #endif
437 1.4.2.3 tls error = lfs_balloc(vp, uio->uio_offset, xfersize,
438 1.4.2.2 tls ap->a_cred, flags, &bp);
439 1.4.2.2 tls
440 1.4.2.2 tls if (error)
441 1.4.2.2 tls break;
442 1.4.2.2 tls if (uio->uio_offset + xfersize > ip->i_size) {
443 1.4.2.2 tls ip->i_size = uio->uio_offset + xfersize;
444 1.4.2.2 tls DIP_ASSIGN(ip, size, ip->i_size);
445 1.4.2.2 tls uvm_vnp_setsize(vp, ip->i_size);
446 1.4.2.2 tls extended = 1;
447 1.4.2.2 tls }
448 1.4.2.2 tls size = lfs_blksize(fs, ip, lbn) - bp->b_resid;
449 1.4.2.2 tls if (xfersize > size)
450 1.4.2.2 tls xfersize = size;
451 1.4.2.2 tls
452 1.4.2.2 tls error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
453 1.4.2.2 tls
454 1.4.2.2 tls /*
455 1.4.2.2 tls * if we didn't clear the block and the uiomove failed,
456 1.4.2.2 tls * the buf will now contain part of some other file,
457 1.4.2.2 tls * so we need to invalidate it.
458 1.4.2.2 tls */
459 1.4.2.2 tls if (error && (flags & B_CLRBUF) == 0) {
460 1.4.2.2 tls brelse(bp, BC_INVAL);
461 1.4.2.2 tls break;
462 1.4.2.2 tls }
463 1.4.2.2 tls #ifdef LFS_READWRITE
464 1.4.2.2 tls (void)VOP_BWRITE(bp->b_vp, bp);
465 1.4.2.2 tls lfs_reserve(fs, vp, NULL,
466 1.4.2.2 tls -lfs_btofsb(fs, (ULFS_NIADDR + 1) << fs->lfs_bshift));
467 1.4.2.2 tls need_unreserve = false;
468 1.4.2.2 tls #else
469 1.4.2.2 tls if (ioflag & IO_SYNC)
470 1.4.2.2 tls (void)bwrite(bp);
471 1.4.2.2 tls else if (xfersize + blkoffset == fs->fs_bsize)
472 1.4.2.2 tls bawrite(bp);
473 1.4.2.2 tls else
474 1.4.2.2 tls bdwrite(bp);
475 1.4.2.2 tls #endif
476 1.4.2.2 tls if (error || xfersize == 0)
477 1.4.2.2 tls break;
478 1.4.2.2 tls }
479 1.4.2.2 tls #ifdef LFS_READWRITE
480 1.4.2.2 tls if (need_unreserve) {
481 1.4.2.2 tls lfs_reserve(fs, vp, NULL,
482 1.4.2.2 tls -lfs_btofsb(fs, (ULFS_NIADDR + 1) << fs->lfs_bshift));
483 1.4.2.2 tls }
484 1.4.2.2 tls #endif
485 1.4.2.2 tls
486 1.4.2.2 tls /*
487 1.4.2.2 tls * If we successfully wrote any data, and we are not the superuser
488 1.4.2.2 tls * we clear the setuid and setgid bits as a precaution against
489 1.4.2.2 tls * tampering.
490 1.4.2.2 tls */
491 1.4.2.2 tls out:
492 1.4.2.2 tls ip->i_flag |= IN_CHANGE | IN_UPDATE;
493 1.4.2.2 tls if (vp->v_mount->mnt_flag & MNT_RELATIME)
494 1.4.2.2 tls ip->i_flag |= IN_ACCESS;
495 1.4.2.2 tls if (resid > uio->uio_resid && ap->a_cred) {
496 1.4.2.2 tls if (ip->i_mode & ISUID) {
497 1.4.2.2 tls if (kauth_authorize_vnode(ap->a_cred,
498 1.4.2.2 tls KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0) {
499 1.4.2.2 tls ip->i_mode &= ~ISUID;
500 1.4.2.2 tls DIP_ASSIGN(ip, mode, ip->i_mode);
501 1.4.2.2 tls }
502 1.4.2.2 tls }
503 1.4.2.2 tls
504 1.4.2.2 tls if (ip->i_mode & ISGID) {
505 1.4.2.2 tls if (kauth_authorize_vnode(ap->a_cred,
506 1.4.2.2 tls KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0) {
507 1.4.2.2 tls ip->i_mode &= ~ISGID;
508 1.4.2.2 tls DIP_ASSIGN(ip, mode, ip->i_mode);
509 1.4.2.2 tls }
510 1.4.2.2 tls }
511 1.4.2.2 tls }
512 1.4.2.2 tls if (resid > uio->uio_resid)
513 1.4.2.2 tls VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
514 1.4.2.2 tls if (error) {
515 1.4.2.3 tls (void) lfs_truncate(vp, osize, ioflag & IO_SYNC, ap->a_cred);
516 1.4.2.2 tls uio->uio_offset -= resid - uio->uio_resid;
517 1.4.2.2 tls uio->uio_resid = resid;
518 1.4.2.2 tls } else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC) {
519 1.4.2.3 tls error = lfs_update(vp, NULL, NULL, UPDATE_WAIT);
520 1.4.2.2 tls } else {
521 1.4.2.2 tls /* nothing */
522 1.4.2.2 tls }
523 1.4.2.2 tls KASSERT(vp->v_size == ip->i_size);
524 1.4.2.2 tls fstrans_done(vp->v_mount);
525 1.4.2.2 tls
526 1.4.2.2 tls return (error);
527 1.4.2.2 tls }
528