nfs_bio.c revision 1.11 1 1.1 cgd /*
2 1.1 cgd * Copyright (c) 1989 The Regents of the University of California.
3 1.1 cgd * All rights reserved.
4 1.1 cgd *
5 1.1 cgd * This code is derived from software contributed to Berkeley by
6 1.1 cgd * Rick Macklem at The University of Guelph.
7 1.1 cgd *
8 1.1 cgd * Redistribution and use in source and binary forms, with or without
9 1.1 cgd * modification, are permitted provided that the following conditions
10 1.1 cgd * are met:
11 1.1 cgd * 1. Redistributions of source code must retain the above copyright
12 1.1 cgd * notice, this list of conditions and the following disclaimer.
13 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer in the
15 1.1 cgd * documentation and/or other materials provided with the distribution.
16 1.1 cgd * 3. All advertising materials mentioning features or use of this software
17 1.1 cgd * must display the following acknowledgement:
18 1.1 cgd * This product includes software developed by the University of
19 1.1 cgd * California, Berkeley and its contributors.
20 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
21 1.1 cgd * may be used to endorse or promote products derived from this software
22 1.1 cgd * without specific prior written permission.
23 1.1 cgd *
24 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 1.1 cgd * SUCH DAMAGE.
35 1.1 cgd *
36 1.2 cgd * from: @(#)nfs_bio.c 7.19 (Berkeley) 4/16/91
37 1.11 cgd * $Id: nfs_bio.c,v 1.11 1994/05/24 02:33:34 cgd Exp $
38 1.1 cgd */
39 1.1 cgd
40 1.8 mycroft #include <sys/param.h>
41 1.8 mycroft #include <sys/systm.h>
42 1.8 mycroft #include <sys/proc.h>
43 1.8 mycroft #include <sys/buf.h>
44 1.8 mycroft #include <sys/uio.h>
45 1.8 mycroft #include <sys/namei.h>
46 1.8 mycroft #include <sys/vnode.h>
47 1.8 mycroft #include <sys/trace.h>
48 1.8 mycroft #include <sys/mount.h>
49 1.8 mycroft #include <sys/resourcevar.h>
50 1.1 cgd
51 1.8 mycroft #include <nfs/nfsnode.h>
52 1.8 mycroft #include <nfs/nfsv2.h>
53 1.8 mycroft #include <nfs/nfs.h>
54 1.8 mycroft #include <nfs/nfsiom.h>
55 1.8 mycroft #include <nfs/nfsmount.h>
56 1.1 cgd
57 1.1 cgd /* True and false, how exciting */
58 1.1 cgd #define TRUE 1
59 1.1 cgd #define FALSE 0
60 1.1 cgd
61 1.1 cgd /*
62 1.1 cgd * Vnode op for read using bio
63 1.1 cgd * Any similarity to readip() is purely coincidental
64 1.1 cgd */
65 1.1 cgd nfs_bioread(vp, uio, ioflag, cred)
66 1.1 cgd register struct vnode *vp;
67 1.1 cgd register struct uio *uio;
68 1.1 cgd int ioflag;
69 1.1 cgd struct ucred *cred;
70 1.1 cgd {
71 1.1 cgd register struct nfsnode *np = VTONFS(vp);
72 1.1 cgd register int biosize;
73 1.1 cgd struct buf *bp;
74 1.1 cgd struct vattr vattr;
75 1.1 cgd daddr_t lbn, bn, rablock;
76 1.1 cgd int diff, error = 0;
77 1.1 cgd long n, on;
78 1.1 cgd
79 1.1 cgd #ifdef lint
80 1.1 cgd ioflag = ioflag;
81 1.1 cgd #endif /* lint */
82 1.1 cgd #ifdef DIAGNOSTIC
83 1.1 cgd if (uio->uio_rw != UIO_READ)
84 1.1 cgd panic("nfs_read mode");
85 1.1 cgd #endif
86 1.1 cgd if (uio->uio_resid == 0)
87 1.1 cgd return (0);
88 1.1 cgd if (uio->uio_offset < 0 && vp->v_type != VDIR)
89 1.1 cgd return (EINVAL);
90 1.1 cgd biosize = VFSTONFS(vp->v_mount)->nm_rsize;
91 1.1 cgd /*
92 1.1 cgd * If the file's modify time on the server has changed since the
93 1.1 cgd * last read rpc or you have written to the file,
94 1.1 cgd * you may have lost data cache consistency with the
95 1.1 cgd * server, so flush all of the file's data out of the cache.
96 1.1 cgd * Then force a getattr rpc to ensure that you have up to date
97 1.1 cgd * attributes.
98 1.1 cgd * NB: This implies that cache data can be read when up to
99 1.1 cgd * NFS_ATTRTIMEO seconds out of date. If you find that you need current
100 1.1 cgd * attributes this could be forced by setting n_attrstamp to 0 before
101 1.1 cgd * the nfs_dogetattr() call.
102 1.1 cgd */
103 1.1 cgd if (vp->v_type != VLNK) {
104 1.1 cgd if (np->n_flag & NMODIFIED) {
105 1.1 cgd np->n_flag &= ~NMODIFIED;
106 1.1 cgd vinvalbuf(vp, TRUE);
107 1.1 cgd np->n_attrstamp = 0;
108 1.1 cgd np->n_direofoffset = 0;
109 1.1 cgd if (error = nfs_dogetattr(vp, &vattr, cred, 1,
110 1.1 cgd uio->uio_procp))
111 1.1 cgd return (error);
112 1.10 cgd np->n_mtime = vattr.va_mtime.ts_sec;
113 1.1 cgd } else {
114 1.1 cgd if (error = nfs_dogetattr(vp, &vattr, cred, 1,
115 1.1 cgd uio->uio_procp))
116 1.1 cgd return (error);
117 1.10 cgd if (np->n_mtime != vattr.va_mtime.ts_sec) {
118 1.1 cgd np->n_direofoffset = 0;
119 1.1 cgd vinvalbuf(vp, TRUE);
120 1.10 cgd np->n_mtime = vattr.va_mtime.ts_sec;
121 1.1 cgd }
122 1.1 cgd }
123 1.1 cgd }
124 1.1 cgd do {
125 1.1 cgd switch (vp->v_type) {
126 1.1 cgd case VREG:
127 1.1 cgd nfsstats.biocache_reads++;
128 1.1 cgd lbn = uio->uio_offset / biosize;
129 1.1 cgd on = uio->uio_offset & (biosize-1);
130 1.11 cgd n = min((unsigned)(biosize - on), uio->uio_resid);
131 1.1 cgd diff = np->n_size - uio->uio_offset;
132 1.1 cgd if (diff <= 0)
133 1.1 cgd return (error);
134 1.1 cgd if (diff < n)
135 1.1 cgd n = diff;
136 1.1 cgd bn = lbn*(biosize/DEV_BSIZE);
137 1.1 cgd rablock = (lbn+1)*(biosize/DEV_BSIZE);
138 1.1 cgd if (vp->v_lastr + 1 == lbn &&
139 1.1 cgd np->n_size > (rablock * DEV_BSIZE))
140 1.1 cgd error = breada(vp, bn, biosize, rablock, biosize,
141 1.1 cgd cred, &bp);
142 1.1 cgd else
143 1.1 cgd error = bread(vp, bn, biosize, cred, &bp);
144 1.1 cgd vp->v_lastr = lbn;
145 1.1 cgd if (bp->b_resid) {
146 1.1 cgd diff = (on >= (biosize-bp->b_resid)) ? 0 :
147 1.1 cgd (biosize-bp->b_resid-on);
148 1.11 cgd n = min(n, diff);
149 1.1 cgd }
150 1.1 cgd break;
151 1.1 cgd case VLNK:
152 1.1 cgd nfsstats.biocache_readlinks++;
153 1.1 cgd on = 0;
154 1.1 cgd error = bread(vp, (daddr_t)0, NFS_MAXPATHLEN, cred, &bp);
155 1.11 cgd n = min(uio->uio_resid, NFS_MAXPATHLEN - bp->b_resid);
156 1.1 cgd break;
157 1.1 cgd case VDIR:
158 1.1 cgd nfsstats.biocache_readdirs++;
159 1.1 cgd on = 0;
160 1.1 cgd error = bread(vp, uio->uio_offset, NFS_DIRBLKSIZ, cred, &bp);
161 1.11 cgd n = min(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid);
162 1.1 cgd break;
163 1.1 cgd };
164 1.1 cgd if (error) {
165 1.1 cgd brelse(bp);
166 1.1 cgd return (error);
167 1.1 cgd }
168 1.1 cgd if (n > 0)
169 1.1 cgd error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
170 1.1 cgd switch (vp->v_type) {
171 1.1 cgd case VREG:
172 1.1 cgd if (n+on == biosize || uio->uio_offset == np->n_size)
173 1.1 cgd bp->b_flags |= B_AGE;
174 1.1 cgd break;
175 1.1 cgd case VLNK:
176 1.1 cgd n = 0;
177 1.1 cgd break;
178 1.1 cgd case VDIR:
179 1.1 cgd uio->uio_offset = bp->b_blkno;
180 1.1 cgd break;
181 1.1 cgd };
182 1.1 cgd brelse(bp);
183 1.1 cgd } while (error == 0 && uio->uio_resid > 0 && n != 0);
184 1.1 cgd return (error);
185 1.1 cgd }
186 1.1 cgd
187 1.1 cgd /*
188 1.1 cgd * Vnode op for write using bio
189 1.1 cgd */
190 1.1 cgd nfs_write(vp, uio, ioflag, cred)
191 1.1 cgd register struct vnode *vp;
192 1.1 cgd register struct uio *uio;
193 1.1 cgd int ioflag;
194 1.1 cgd struct ucred *cred;
195 1.1 cgd {
196 1.1 cgd struct proc *p = uio->uio_procp;
197 1.1 cgd register int biosize;
198 1.1 cgd struct buf *bp;
199 1.1 cgd struct nfsnode *np = VTONFS(vp);
200 1.1 cgd struct vattr vattr;
201 1.1 cgd daddr_t lbn, bn;
202 1.1 cgd int n, on, error = 0;
203 1.1 cgd
204 1.1 cgd #ifdef DIAGNOSTIC
205 1.1 cgd if (uio->uio_rw != UIO_WRITE)
206 1.1 cgd panic("nfs_write mode");
207 1.1 cgd if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
208 1.1 cgd panic("nfs_write proc");
209 1.1 cgd #endif
210 1.1 cgd if (vp->v_type != VREG)
211 1.1 cgd return (EIO);
212 1.1 cgd /* Should we try and do this ?? */
213 1.1 cgd if (ioflag & (IO_APPEND | IO_SYNC)) {
214 1.1 cgd if (np->n_flag & NMODIFIED) {
215 1.1 cgd np->n_flag &= ~NMODIFIED;
216 1.1 cgd vinvalbuf(vp, TRUE);
217 1.1 cgd }
218 1.1 cgd if (ioflag & IO_APPEND) {
219 1.1 cgd np->n_attrstamp = 0;
220 1.1 cgd if (error = nfs_dogetattr(vp, &vattr, cred, 1, p))
221 1.1 cgd return (error);
222 1.1 cgd uio->uio_offset = np->n_size;
223 1.1 cgd }
224 1.1 cgd return (nfs_writerpc(vp, uio, cred));
225 1.1 cgd }
226 1.1 cgd #ifdef notdef
227 1.1 cgd cnt = uio->uio_resid;
228 1.1 cgd osize = np->n_size;
229 1.1 cgd #endif
230 1.1 cgd if (uio->uio_offset < 0)
231 1.1 cgd return (EINVAL);
232 1.1 cgd if (uio->uio_resid == 0)
233 1.1 cgd return (0);
234 1.1 cgd /*
235 1.1 cgd * Maybe this should be above the vnode op call, but so long as
236 1.1 cgd * file servers have no limits, i don't think it matters
237 1.1 cgd */
238 1.4 cgd if (p &&
239 1.4 cgd uio->uio_offset + uio->uio_resid >
240 1.1 cgd p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
241 1.1 cgd psignal(p, SIGXFSZ);
242 1.1 cgd return (EFBIG);
243 1.1 cgd }
244 1.1 cgd /*
245 1.1 cgd * I use nm_rsize, not nm_wsize so that all buffer cache blocks
246 1.1 cgd * will be the same size within a filesystem. nfs_writerpc will
247 1.1 cgd * still use nm_wsize when sizing the rpc's.
248 1.1 cgd */
249 1.1 cgd biosize = VFSTONFS(vp->v_mount)->nm_rsize;
250 1.1 cgd np->n_flag |= NMODIFIED;
251 1.3 andrew vnode_pager_uncache(vp);
252 1.1 cgd do {
253 1.1 cgd nfsstats.biocache_writes++;
254 1.1 cgd lbn = uio->uio_offset / biosize;
255 1.1 cgd on = uio->uio_offset & (biosize-1);
256 1.11 cgd n = min((unsigned)(biosize - on), uio->uio_resid);
257 1.1 cgd if (uio->uio_offset+n > np->n_size) {
258 1.1 cgd np->n_size = uio->uio_offset+n;
259 1.1 cgd vnode_pager_setsize(vp, np->n_size);
260 1.1 cgd }
261 1.1 cgd bn = lbn*(biosize/DEV_BSIZE);
262 1.1 cgd again:
263 1.9 cgd bp = getblk(vp, bn, biosize, 0, 0);
264 1.5 cgd if (bp->b_wcred == NOCRED && cred != NOCRED) {
265 1.1 cgd crhold(cred);
266 1.1 cgd bp->b_wcred = cred;
267 1.1 cgd }
268 1.1 cgd if (bp->b_dirtyend > 0) {
269 1.1 cgd /*
270 1.1 cgd * If the new write will leave a contiguous dirty
271 1.1 cgd * area, just update the b_dirtyoff and b_dirtyend,
272 1.1 cgd * otherwise force a write rpc of the old dirty area.
273 1.1 cgd */
274 1.1 cgd if (on <= bp->b_dirtyend && (on+n) >= bp->b_dirtyoff) {
275 1.11 cgd bp->b_dirtyoff = min(on, bp->b_dirtyoff);
276 1.11 cgd bp->b_dirtyend = max((on+n), bp->b_dirtyend);
277 1.1 cgd } else {
278 1.1 cgd bp->b_proc = p;
279 1.1 cgd if (error = bwrite(bp))
280 1.1 cgd return (error);
281 1.1 cgd goto again;
282 1.1 cgd }
283 1.1 cgd } else {
284 1.1 cgd bp->b_dirtyoff = on;
285 1.1 cgd bp->b_dirtyend = on+n;
286 1.1 cgd }
287 1.1 cgd if (error = uiomove(bp->b_un.b_addr + on, n, uio)) {
288 1.1 cgd brelse(bp);
289 1.1 cgd return (error);
290 1.1 cgd }
291 1.1 cgd if ((n+on) == biosize) {
292 1.1 cgd bp->b_flags |= B_AGE;
293 1.1 cgd bp->b_proc = (struct proc *)0;
294 1.1 cgd bawrite(bp);
295 1.1 cgd } else {
296 1.1 cgd bp->b_proc = (struct proc *)0;
297 1.1 cgd bdwrite(bp);
298 1.1 cgd }
299 1.1 cgd } while (error == 0 && uio->uio_resid > 0 && n != 0);
300 1.1 cgd #ifdef notdef
301 1.1 cgd /* Should we try and do this for nfs ?? */
302 1.1 cgd if (error && (ioflag & IO_UNIT)) {
303 1.1 cgd np->n_size = osize;
304 1.1 cgd uio->uio_offset -= cnt - uio->uio_resid;
305 1.1 cgd uio->uio_resid = cnt;
306 1.1 cgd }
307 1.1 cgd #endif
308 1.1 cgd return (error);
309 1.1 cgd }
310