ulfs_readwrite.c revision 1.4.2.2 1 1.4.2.2 tls /* $NetBSD: ulfs_readwrite.c,v 1.4.2.2 2013/06/23 06:18:39 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.2 2013/06/23 06:18:39 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 ulfsmount *ump;
73 1.4.2.2 tls struct buf *bp;
74 1.4.2.2 tls FS *fs;
75 1.4.2.2 tls vsize_t bytelen;
76 1.4.2.2 tls daddr_t lbn, nextlbn;
77 1.4.2.2 tls off_t bytesinfile;
78 1.4.2.2 tls long size, xfersize, blkoffset;
79 1.4.2.2 tls int error, ioflag;
80 1.4.2.2 tls bool usepc = false;
81 1.4.2.2 tls
82 1.4.2.2 tls vp = ap->a_vp;
83 1.4.2.2 tls ip = VTOI(vp);
84 1.4.2.2 tls ump = ip->i_ump;
85 1.4.2.2 tls uio = ap->a_uio;
86 1.4.2.2 tls ioflag = ap->a_ioflag;
87 1.4.2.2 tls error = 0;
88 1.4.2.2 tls
89 1.4.2.2 tls #ifdef DIAGNOSTIC
90 1.4.2.2 tls if (uio->uio_rw != UIO_READ)
91 1.4.2.2 tls panic("%s: mode", READ_S);
92 1.4.2.2 tls
93 1.4.2.2 tls if (vp->v_type == VLNK) {
94 1.4.2.2 tls if (ip->i_size < ump->um_maxsymlinklen ||
95 1.4.2.2 tls (ump->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0))
96 1.4.2.2 tls panic("%s: short symlink", READ_S);
97 1.4.2.2 tls } else if (vp->v_type != VREG && vp->v_type != VDIR)
98 1.4.2.2 tls panic("%s: type %d", READ_S, vp->v_type);
99 1.4.2.2 tls #endif
100 1.4.2.2 tls fs = ip->I_FS;
101 1.4.2.2 tls if ((u_int64_t)uio->uio_offset > ump->um_maxfilesize)
102 1.4.2.2 tls return (EFBIG);
103 1.4.2.2 tls if (uio->uio_resid == 0)
104 1.4.2.2 tls return (0);
105 1.4.2.2 tls
106 1.4.2.2 tls #ifndef LFS_READWRITE
107 1.4.2.2 tls if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) == SF_SNAPSHOT)
108 1.4.2.2 tls return ffs_snapshot_read(vp, uio, ioflag);
109 1.4.2.2 tls #endif /* !LFS_READWRITE */
110 1.4.2.2 tls
111 1.4.2.2 tls fstrans_start(vp->v_mount, FSTRANS_SHARED);
112 1.4.2.2 tls
113 1.4.2.2 tls if (uio->uio_offset >= ip->i_size)
114 1.4.2.2 tls goto out;
115 1.4.2.2 tls
116 1.4.2.2 tls #ifdef LFS_READWRITE
117 1.4.2.2 tls usepc = (vp->v_type == VREG && ip->i_number != LFS_IFILE_INUM);
118 1.4.2.2 tls #else /* !LFS_READWRITE */
119 1.4.2.2 tls usepc = vp->v_type == VREG;
120 1.4.2.2 tls #endif /* !LFS_READWRITE */
121 1.4.2.2 tls if (usepc) {
122 1.4.2.2 tls const int advice = IO_ADV_DECODE(ap->a_ioflag);
123 1.4.2.2 tls
124 1.4.2.2 tls while (uio->uio_resid > 0) {
125 1.4.2.2 tls if (ioflag & IO_DIRECT) {
126 1.4.2.2 tls genfs_directio(vp, uio, ioflag);
127 1.4.2.2 tls }
128 1.4.2.2 tls bytelen = MIN(ip->i_size - uio->uio_offset,
129 1.4.2.2 tls uio->uio_resid);
130 1.4.2.2 tls if (bytelen == 0)
131 1.4.2.2 tls break;
132 1.4.2.2 tls error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
133 1.4.2.2 tls UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
134 1.4.2.2 tls if (error)
135 1.4.2.2 tls break;
136 1.4.2.2 tls }
137 1.4.2.2 tls goto out;
138 1.4.2.2 tls }
139 1.4.2.2 tls
140 1.4.2.2 tls for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
141 1.4.2.2 tls bytesinfile = ip->i_size - uio->uio_offset;
142 1.4.2.2 tls if (bytesinfile <= 0)
143 1.4.2.2 tls break;
144 1.4.2.2 tls lbn = lfs_lblkno(fs, uio->uio_offset);
145 1.4.2.2 tls nextlbn = lbn + 1;
146 1.4.2.2 tls size = lfs_blksize(fs, ip, lbn);
147 1.4.2.2 tls blkoffset = lfs_blkoff(fs, uio->uio_offset);
148 1.4.2.2 tls xfersize = MIN(MIN(fs->fs_bsize - blkoffset, uio->uio_resid),
149 1.4.2.2 tls bytesinfile);
150 1.4.2.2 tls
151 1.4.2.2 tls if (lfs_lblktosize(fs, nextlbn) >= ip->i_size)
152 1.4.2.2 tls error = bread(vp, lbn, size, NOCRED, 0, &bp);
153 1.4.2.2 tls else {
154 1.4.2.2 tls int nextsize = lfs_blksize(fs, ip, nextlbn);
155 1.4.2.2 tls error = breadn(vp, lbn,
156 1.4.2.2 tls size, &nextlbn, &nextsize, 1, NOCRED, 0, &bp);
157 1.4.2.2 tls }
158 1.4.2.2 tls if (error)
159 1.4.2.2 tls break;
160 1.4.2.2 tls
161 1.4.2.2 tls /*
162 1.4.2.2 tls * We should only get non-zero b_resid when an I/O error
163 1.4.2.2 tls * has occurred, which should cause us to break above.
164 1.4.2.2 tls * However, if the short read did not cause an error,
165 1.4.2.2 tls * then we want to ensure that we do not uiomove bad
166 1.4.2.2 tls * or uninitialized data.
167 1.4.2.2 tls */
168 1.4.2.2 tls size -= bp->b_resid;
169 1.4.2.2 tls if (size < xfersize) {
170 1.4.2.2 tls if (size == 0)
171 1.4.2.2 tls break;
172 1.4.2.2 tls xfersize = size;
173 1.4.2.2 tls }
174 1.4.2.2 tls error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
175 1.4.2.2 tls if (error)
176 1.4.2.2 tls break;
177 1.4.2.2 tls brelse(bp, 0);
178 1.4.2.2 tls }
179 1.4.2.2 tls if (bp != NULL)
180 1.4.2.2 tls brelse(bp, 0);
181 1.4.2.2 tls
182 1.4.2.2 tls out:
183 1.4.2.2 tls if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
184 1.4.2.2 tls ip->i_flag |= IN_ACCESS;
185 1.4.2.2 tls if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) {
186 1.4.2.2 tls error = ULFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
187 1.4.2.2 tls }
188 1.4.2.2 tls }
189 1.4.2.2 tls
190 1.4.2.2 tls fstrans_done(vp->v_mount);
191 1.4.2.2 tls return (error);
192 1.4.2.2 tls }
193 1.4.2.2 tls
194 1.4.2.2 tls /*
195 1.4.2.2 tls * Vnode op for writing.
196 1.4.2.2 tls */
197 1.4.2.2 tls int
198 1.4.2.2 tls WRITE(void *v)
199 1.4.2.2 tls {
200 1.4.2.2 tls struct vop_write_args /* {
201 1.4.2.2 tls struct vnode *a_vp;
202 1.4.2.2 tls struct uio *a_uio;
203 1.4.2.2 tls int a_ioflag;
204 1.4.2.2 tls kauth_cred_t a_cred;
205 1.4.2.2 tls } */ *ap = v;
206 1.4.2.2 tls struct vnode *vp;
207 1.4.2.2 tls struct uio *uio;
208 1.4.2.2 tls struct inode *ip;
209 1.4.2.2 tls FS *fs;
210 1.4.2.2 tls struct buf *bp;
211 1.4.2.2 tls kauth_cred_t cred;
212 1.4.2.2 tls daddr_t lbn;
213 1.4.2.2 tls off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize;
214 1.4.2.2 tls int blkoffset, error, flags, ioflag, resid, size, xfersize;
215 1.4.2.2 tls int aflag;
216 1.4.2.2 tls int extended=0;
217 1.4.2.2 tls vsize_t bytelen;
218 1.4.2.2 tls bool async;
219 1.4.2.2 tls bool usepc = false;
220 1.4.2.2 tls #ifdef LFS_READWRITE
221 1.4.2.2 tls bool need_unreserve = false;
222 1.4.2.2 tls #endif
223 1.4.2.2 tls struct ulfsmount *ump;
224 1.4.2.2 tls
225 1.4.2.2 tls cred = ap->a_cred;
226 1.4.2.2 tls ioflag = ap->a_ioflag;
227 1.4.2.2 tls uio = ap->a_uio;
228 1.4.2.2 tls vp = ap->a_vp;
229 1.4.2.2 tls ip = VTOI(vp);
230 1.4.2.2 tls ump = ip->i_ump;
231 1.4.2.2 tls
232 1.4.2.2 tls KASSERT(vp->v_size == ip->i_size);
233 1.4.2.2 tls #ifdef DIAGNOSTIC
234 1.4.2.2 tls if (uio->uio_rw != UIO_WRITE)
235 1.4.2.2 tls panic("%s: mode", WRITE_S);
236 1.4.2.2 tls #endif
237 1.4.2.2 tls
238 1.4.2.2 tls switch (vp->v_type) {
239 1.4.2.2 tls case VREG:
240 1.4.2.2 tls if (ioflag & IO_APPEND)
241 1.4.2.2 tls uio->uio_offset = ip->i_size;
242 1.4.2.2 tls if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
243 1.4.2.2 tls return (EPERM);
244 1.4.2.2 tls /* FALLTHROUGH */
245 1.4.2.2 tls case VLNK:
246 1.4.2.2 tls break;
247 1.4.2.2 tls case VDIR:
248 1.4.2.2 tls if ((ioflag & IO_SYNC) == 0)
249 1.4.2.2 tls panic("%s: nonsync dir write", WRITE_S);
250 1.4.2.2 tls break;
251 1.4.2.2 tls default:
252 1.4.2.2 tls panic("%s: type", WRITE_S);
253 1.4.2.2 tls }
254 1.4.2.2 tls
255 1.4.2.2 tls fs = ip->I_FS;
256 1.4.2.2 tls if (uio->uio_offset < 0 ||
257 1.4.2.2 tls (u_int64_t)uio->uio_offset + uio->uio_resid > ump->um_maxfilesize)
258 1.4.2.2 tls return (EFBIG);
259 1.4.2.2 tls #ifdef LFS_READWRITE
260 1.4.2.2 tls /* Disallow writes to the Ifile, even if noschg flag is removed */
261 1.4.2.2 tls /* XXX can this go away when the Ifile is no longer in the namespace? */
262 1.4.2.2 tls if (vp == fs->lfs_ivnode)
263 1.4.2.2 tls return (EPERM);
264 1.4.2.2 tls #endif
265 1.4.2.2 tls if (uio->uio_resid == 0)
266 1.4.2.2 tls return (0);
267 1.4.2.2 tls
268 1.4.2.2 tls fstrans_start(vp->v_mount, FSTRANS_SHARED);
269 1.4.2.2 tls
270 1.4.2.2 tls flags = ioflag & IO_SYNC ? B_SYNC : 0;
271 1.4.2.2 tls async = vp->v_mount->mnt_flag & MNT_ASYNC;
272 1.4.2.2 tls origoff = uio->uio_offset;
273 1.4.2.2 tls resid = uio->uio_resid;
274 1.4.2.2 tls osize = ip->i_size;
275 1.4.2.2 tls error = 0;
276 1.4.2.2 tls
277 1.4.2.2 tls usepc = vp->v_type == VREG;
278 1.4.2.2 tls
279 1.4.2.2 tls #ifdef LFS_READWRITE
280 1.4.2.2 tls async = true;
281 1.4.2.2 tls lfs_availwait(fs, lfs_btofsb(fs, uio->uio_resid));
282 1.4.2.2 tls lfs_check(vp, LFS_UNUSED_LBN, 0);
283 1.4.2.2 tls #endif /* !LFS_READWRITE */
284 1.4.2.2 tls if (!usepc)
285 1.4.2.2 tls goto bcache;
286 1.4.2.2 tls
287 1.4.2.2 tls preallocoff = round_page(lfs_blkroundup(fs, MAX(osize, uio->uio_offset)));
288 1.4.2.2 tls aflag = ioflag & IO_SYNC ? B_SYNC : 0;
289 1.4.2.2 tls nsize = MAX(osize, uio->uio_offset + uio->uio_resid);
290 1.4.2.2 tls endallocoff = nsize - lfs_blkoff(fs, nsize);
291 1.4.2.2 tls
292 1.4.2.2 tls /*
293 1.4.2.2 tls * if we're increasing the file size, deal with expanding
294 1.4.2.2 tls * the fragment if there is one.
295 1.4.2.2 tls */
296 1.4.2.2 tls
297 1.4.2.2 tls if (nsize > osize && lfs_lblkno(fs, osize) < ULFS_NDADDR &&
298 1.4.2.2 tls lfs_lblkno(fs, osize) != lfs_lblkno(fs, nsize) &&
299 1.4.2.2 tls lfs_blkroundup(fs, osize) != osize) {
300 1.4.2.2 tls off_t eob;
301 1.4.2.2 tls
302 1.4.2.2 tls eob = lfs_blkroundup(fs, osize);
303 1.4.2.2 tls uvm_vnp_setwritesize(vp, eob);
304 1.4.2.2 tls error = ulfs_balloc_range(vp, osize, eob - osize, cred, aflag);
305 1.4.2.2 tls if (error)
306 1.4.2.2 tls goto out;
307 1.4.2.2 tls if (flags & B_SYNC) {
308 1.4.2.2 tls mutex_enter(vp->v_interlock);
309 1.4.2.2 tls VOP_PUTPAGES(vp, trunc_page(osize & fs->fs_bmask),
310 1.4.2.2 tls round_page(eob),
311 1.4.2.2 tls PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
312 1.4.2.2 tls }
313 1.4.2.2 tls }
314 1.4.2.2 tls
315 1.4.2.2 tls while (uio->uio_resid > 0) {
316 1.4.2.2 tls int ubc_flags = UBC_WRITE;
317 1.4.2.2 tls bool overwrite; /* if we're overwrite a whole block */
318 1.4.2.2 tls off_t newoff;
319 1.4.2.2 tls
320 1.4.2.2 tls if (ioflag & IO_DIRECT) {
321 1.4.2.2 tls genfs_directio(vp, uio, ioflag | IO_JOURNALLOCKED);
322 1.4.2.2 tls }
323 1.4.2.2 tls
324 1.4.2.2 tls oldoff = uio->uio_offset;
325 1.4.2.2 tls blkoffset = lfs_blkoff(fs, uio->uio_offset);
326 1.4.2.2 tls bytelen = MIN(fs->fs_bsize - blkoffset, uio->uio_resid);
327 1.4.2.2 tls if (bytelen == 0) {
328 1.4.2.2 tls break;
329 1.4.2.2 tls }
330 1.4.2.2 tls
331 1.4.2.2 tls /*
332 1.4.2.2 tls * if we're filling in a hole, allocate the blocks now and
333 1.4.2.2 tls * initialize the pages first. if we're extending the file,
334 1.4.2.2 tls * we can safely allocate blocks without initializing pages
335 1.4.2.2 tls * since the new blocks will be inaccessible until the write
336 1.4.2.2 tls * is complete.
337 1.4.2.2 tls */
338 1.4.2.2 tls overwrite = uio->uio_offset >= preallocoff &&
339 1.4.2.2 tls uio->uio_offset < endallocoff;
340 1.4.2.2 tls if (!overwrite && (vp->v_vflag & VV_MAPPED) == 0 &&
341 1.4.2.2 tls lfs_blkoff(fs, uio->uio_offset) == 0 &&
342 1.4.2.2 tls (uio->uio_offset & PAGE_MASK) == 0) {
343 1.4.2.2 tls vsize_t len;
344 1.4.2.2 tls
345 1.4.2.2 tls len = trunc_page(bytelen);
346 1.4.2.2 tls len -= lfs_blkoff(fs, len);
347 1.4.2.2 tls if (len > 0) {
348 1.4.2.2 tls overwrite = true;
349 1.4.2.2 tls bytelen = len;
350 1.4.2.2 tls }
351 1.4.2.2 tls }
352 1.4.2.2 tls
353 1.4.2.2 tls newoff = oldoff + bytelen;
354 1.4.2.2 tls if (vp->v_size < newoff) {
355 1.4.2.2 tls uvm_vnp_setwritesize(vp, newoff);
356 1.4.2.2 tls }
357 1.4.2.2 tls
358 1.4.2.2 tls if (!overwrite) {
359 1.4.2.2 tls error = ulfs_balloc_range(vp, uio->uio_offset, bytelen,
360 1.4.2.2 tls cred, aflag);
361 1.4.2.2 tls if (error)
362 1.4.2.2 tls break;
363 1.4.2.2 tls } else {
364 1.4.2.2 tls genfs_node_wrlock(vp);
365 1.4.2.2 tls error = GOP_ALLOC(vp, uio->uio_offset, bytelen,
366 1.4.2.2 tls aflag, cred);
367 1.4.2.2 tls genfs_node_unlock(vp);
368 1.4.2.2 tls if (error)
369 1.4.2.2 tls break;
370 1.4.2.2 tls ubc_flags |= UBC_FAULTBUSY;
371 1.4.2.2 tls }
372 1.4.2.2 tls
373 1.4.2.2 tls /*
374 1.4.2.2 tls * copy the data.
375 1.4.2.2 tls */
376 1.4.2.2 tls
377 1.4.2.2 tls error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
378 1.4.2.2 tls IO_ADV_DECODE(ioflag), ubc_flags | UBC_UNMAP_FLAG(vp));
379 1.4.2.2 tls
380 1.4.2.2 tls /*
381 1.4.2.2 tls * update UVM's notion of the size now that we've
382 1.4.2.2 tls * copied the data into the vnode's pages.
383 1.4.2.2 tls *
384 1.4.2.2 tls * we should update the size even when uiomove failed.
385 1.4.2.2 tls */
386 1.4.2.2 tls
387 1.4.2.2 tls if (vp->v_size < newoff) {
388 1.4.2.2 tls uvm_vnp_setsize(vp, newoff);
389 1.4.2.2 tls extended = 1;
390 1.4.2.2 tls }
391 1.4.2.2 tls
392 1.4.2.2 tls if (error)
393 1.4.2.2 tls break;
394 1.4.2.2 tls
395 1.4.2.2 tls /*
396 1.4.2.2 tls * flush what we just wrote if necessary.
397 1.4.2.2 tls * XXXUBC simplistic async flushing.
398 1.4.2.2 tls */
399 1.4.2.2 tls
400 1.4.2.2 tls #ifndef LFS_READWRITE
401 1.4.2.2 tls if (!async && oldoff >> 16 != uio->uio_offset >> 16) {
402 1.4.2.2 tls mutex_enter(vp->v_interlock);
403 1.4.2.2 tls error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16,
404 1.4.2.2 tls (uio->uio_offset >> 16) << 16,
405 1.4.2.2 tls PGO_CLEANIT | PGO_JOURNALLOCKED | PGO_LAZY);
406 1.4.2.2 tls if (error)
407 1.4.2.2 tls break;
408 1.4.2.2 tls }
409 1.4.2.2 tls #endif
410 1.4.2.2 tls }
411 1.4.2.2 tls if (error == 0 && ioflag & IO_SYNC) {
412 1.4.2.2 tls mutex_enter(vp->v_interlock);
413 1.4.2.2 tls error = VOP_PUTPAGES(vp, trunc_page(origoff & fs->fs_bmask),
414 1.4.2.2 tls round_page(lfs_blkroundup(fs, uio->uio_offset)),
415 1.4.2.2 tls PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
416 1.4.2.2 tls }
417 1.4.2.2 tls goto out;
418 1.4.2.2 tls
419 1.4.2.2 tls bcache:
420 1.4.2.2 tls mutex_enter(vp->v_interlock);
421 1.4.2.2 tls VOP_PUTPAGES(vp, trunc_page(origoff), round_page(origoff + resid),
422 1.4.2.2 tls PGO_CLEANIT | PGO_FREE | PGO_SYNCIO | PGO_JOURNALLOCKED);
423 1.4.2.2 tls while (uio->uio_resid > 0) {
424 1.4.2.2 tls lbn = lfs_lblkno(fs, uio->uio_offset);
425 1.4.2.2 tls blkoffset = lfs_blkoff(fs, uio->uio_offset);
426 1.4.2.2 tls xfersize = MIN(fs->fs_bsize - blkoffset, uio->uio_resid);
427 1.4.2.2 tls if (fs->fs_bsize > xfersize)
428 1.4.2.2 tls flags |= B_CLRBUF;
429 1.4.2.2 tls else
430 1.4.2.2 tls flags &= ~B_CLRBUF;
431 1.4.2.2 tls
432 1.4.2.2 tls #ifdef LFS_READWRITE
433 1.4.2.2 tls error = lfs_reserve(fs, vp, NULL,
434 1.4.2.2 tls lfs_btofsb(fs, (ULFS_NIADDR + 1) << fs->lfs_bshift));
435 1.4.2.2 tls if (error)
436 1.4.2.2 tls break;
437 1.4.2.2 tls need_unreserve = true;
438 1.4.2.2 tls #endif
439 1.4.2.2 tls error = ULFS_BALLOC(vp, uio->uio_offset, xfersize,
440 1.4.2.2 tls ap->a_cred, flags, &bp);
441 1.4.2.2 tls
442 1.4.2.2 tls if (error)
443 1.4.2.2 tls break;
444 1.4.2.2 tls if (uio->uio_offset + xfersize > ip->i_size) {
445 1.4.2.2 tls ip->i_size = uio->uio_offset + xfersize;
446 1.4.2.2 tls DIP_ASSIGN(ip, size, ip->i_size);
447 1.4.2.2 tls uvm_vnp_setsize(vp, ip->i_size);
448 1.4.2.2 tls extended = 1;
449 1.4.2.2 tls }
450 1.4.2.2 tls size = lfs_blksize(fs, ip, lbn) - bp->b_resid;
451 1.4.2.2 tls if (xfersize > size)
452 1.4.2.2 tls xfersize = size;
453 1.4.2.2 tls
454 1.4.2.2 tls error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
455 1.4.2.2 tls
456 1.4.2.2 tls /*
457 1.4.2.2 tls * if we didn't clear the block and the uiomove failed,
458 1.4.2.2 tls * the buf will now contain part of some other file,
459 1.4.2.2 tls * so we need to invalidate it.
460 1.4.2.2 tls */
461 1.4.2.2 tls if (error && (flags & B_CLRBUF) == 0) {
462 1.4.2.2 tls brelse(bp, BC_INVAL);
463 1.4.2.2 tls break;
464 1.4.2.2 tls }
465 1.4.2.2 tls #ifdef LFS_READWRITE
466 1.4.2.2 tls (void)VOP_BWRITE(bp->b_vp, bp);
467 1.4.2.2 tls lfs_reserve(fs, vp, NULL,
468 1.4.2.2 tls -lfs_btofsb(fs, (ULFS_NIADDR + 1) << fs->lfs_bshift));
469 1.4.2.2 tls need_unreserve = false;
470 1.4.2.2 tls #else
471 1.4.2.2 tls if (ioflag & IO_SYNC)
472 1.4.2.2 tls (void)bwrite(bp);
473 1.4.2.2 tls else if (xfersize + blkoffset == fs->fs_bsize)
474 1.4.2.2 tls bawrite(bp);
475 1.4.2.2 tls else
476 1.4.2.2 tls bdwrite(bp);
477 1.4.2.2 tls #endif
478 1.4.2.2 tls if (error || xfersize == 0)
479 1.4.2.2 tls break;
480 1.4.2.2 tls }
481 1.4.2.2 tls #ifdef LFS_READWRITE
482 1.4.2.2 tls if (need_unreserve) {
483 1.4.2.2 tls lfs_reserve(fs, vp, NULL,
484 1.4.2.2 tls -lfs_btofsb(fs, (ULFS_NIADDR + 1) << fs->lfs_bshift));
485 1.4.2.2 tls }
486 1.4.2.2 tls #endif
487 1.4.2.2 tls
488 1.4.2.2 tls /*
489 1.4.2.2 tls * If we successfully wrote any data, and we are not the superuser
490 1.4.2.2 tls * we clear the setuid and setgid bits as a precaution against
491 1.4.2.2 tls * tampering.
492 1.4.2.2 tls */
493 1.4.2.2 tls out:
494 1.4.2.2 tls ip->i_flag |= IN_CHANGE | IN_UPDATE;
495 1.4.2.2 tls if (vp->v_mount->mnt_flag & MNT_RELATIME)
496 1.4.2.2 tls ip->i_flag |= IN_ACCESS;
497 1.4.2.2 tls if (resid > uio->uio_resid && ap->a_cred) {
498 1.4.2.2 tls if (ip->i_mode & ISUID) {
499 1.4.2.2 tls if (kauth_authorize_vnode(ap->a_cred,
500 1.4.2.2 tls KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0) {
501 1.4.2.2 tls ip->i_mode &= ~ISUID;
502 1.4.2.2 tls DIP_ASSIGN(ip, mode, ip->i_mode);
503 1.4.2.2 tls }
504 1.4.2.2 tls }
505 1.4.2.2 tls
506 1.4.2.2 tls if (ip->i_mode & ISGID) {
507 1.4.2.2 tls if (kauth_authorize_vnode(ap->a_cred,
508 1.4.2.2 tls KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0) {
509 1.4.2.2 tls ip->i_mode &= ~ISGID;
510 1.4.2.2 tls DIP_ASSIGN(ip, mode, ip->i_mode);
511 1.4.2.2 tls }
512 1.4.2.2 tls }
513 1.4.2.2 tls }
514 1.4.2.2 tls if (resid > uio->uio_resid)
515 1.4.2.2 tls VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
516 1.4.2.2 tls if (error) {
517 1.4.2.2 tls (void) ULFS_TRUNCATE(vp, osize, ioflag & IO_SYNC, ap->a_cred);
518 1.4.2.2 tls uio->uio_offset -= resid - uio->uio_resid;
519 1.4.2.2 tls uio->uio_resid = resid;
520 1.4.2.2 tls } else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC) {
521 1.4.2.2 tls error = ULFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
522 1.4.2.2 tls } else {
523 1.4.2.2 tls /* nothing */
524 1.4.2.2 tls }
525 1.4.2.2 tls KASSERT(vp->v_size == ip->i_size);
526 1.4.2.2 tls fstrans_done(vp->v_mount);
527 1.4.2.2 tls
528 1.4.2.2 tls return (error);
529 1.4.2.2 tls }
530