nfs_bio.c revision 1.6 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.6 cgd * $Id: nfs_bio.c,v 1.6 1993/07/13 10:50:04 cgd Exp $
38 1.1 cgd */
39 1.1 cgd
40 1.1 cgd #include "param.h"
41 1.1 cgd #include "proc.h"
42 1.1 cgd #include "buf.h"
43 1.1 cgd #include "uio.h"
44 1.1 cgd #include "namei.h"
45 1.1 cgd #include "vnode.h"
46 1.1 cgd #include "trace.h"
47 1.1 cgd #include "mount.h"
48 1.1 cgd #include "resourcevar.h"
49 1.1 cgd
50 1.1 cgd #include "nfsnode.h"
51 1.1 cgd #include "nfsv2.h"
52 1.1 cgd #include "nfs.h"
53 1.1 cgd #include "nfsiom.h"
54 1.1 cgd #include "nfsmount.h"
55 1.1 cgd
56 1.1 cgd /* True and false, how exciting */
57 1.1 cgd #define TRUE 1
58 1.1 cgd #define FALSE 0
59 1.1 cgd
60 1.1 cgd /*
61 1.1 cgd * Vnode op for read using bio
62 1.1 cgd * Any similarity to readip() is purely coincidental
63 1.1 cgd */
64 1.1 cgd nfs_bioread(vp, uio, ioflag, cred)
65 1.1 cgd register struct vnode *vp;
66 1.1 cgd register struct uio *uio;
67 1.1 cgd int ioflag;
68 1.1 cgd struct ucred *cred;
69 1.1 cgd {
70 1.1 cgd register struct nfsnode *np = VTONFS(vp);
71 1.1 cgd register int biosize;
72 1.1 cgd struct buf *bp;
73 1.1 cgd struct vattr vattr;
74 1.1 cgd daddr_t lbn, bn, rablock;
75 1.1 cgd int diff, error = 0;
76 1.1 cgd long n, on;
77 1.1 cgd
78 1.1 cgd #ifdef lint
79 1.1 cgd ioflag = ioflag;
80 1.1 cgd #endif /* lint */
81 1.1 cgd #ifdef DIAGNOSTIC
82 1.1 cgd if (uio->uio_rw != UIO_READ)
83 1.1 cgd panic("nfs_read mode");
84 1.1 cgd #endif
85 1.1 cgd if (uio->uio_resid == 0)
86 1.1 cgd return (0);
87 1.1 cgd if (uio->uio_offset < 0 && vp->v_type != VDIR)
88 1.1 cgd return (EINVAL);
89 1.1 cgd biosize = VFSTONFS(vp->v_mount)->nm_rsize;
90 1.1 cgd /*
91 1.1 cgd * If the file's modify time on the server has changed since the
92 1.1 cgd * last read rpc or you have written to the file,
93 1.1 cgd * you may have lost data cache consistency with the
94 1.1 cgd * server, so flush all of the file's data out of the cache.
95 1.1 cgd * Then force a getattr rpc to ensure that you have up to date
96 1.1 cgd * attributes.
97 1.1 cgd * NB: This implies that cache data can be read when up to
98 1.1 cgd * NFS_ATTRTIMEO seconds out of date. If you find that you need current
99 1.1 cgd * attributes this could be forced by setting n_attrstamp to 0 before
100 1.1 cgd * the nfs_dogetattr() call.
101 1.1 cgd */
102 1.1 cgd if (vp->v_type != VLNK) {
103 1.1 cgd if (np->n_flag & NMODIFIED) {
104 1.1 cgd np->n_flag &= ~NMODIFIED;
105 1.1 cgd vinvalbuf(vp, TRUE);
106 1.1 cgd np->n_attrstamp = 0;
107 1.1 cgd np->n_direofoffset = 0;
108 1.1 cgd if (error = nfs_dogetattr(vp, &vattr, cred, 1,
109 1.1 cgd uio->uio_procp))
110 1.1 cgd return (error);
111 1.1 cgd np->n_mtime = vattr.va_mtime.tv_sec;
112 1.1 cgd } else {
113 1.1 cgd if (error = nfs_dogetattr(vp, &vattr, cred, 1,
114 1.1 cgd uio->uio_procp))
115 1.1 cgd return (error);
116 1.1 cgd if (np->n_mtime != vattr.va_mtime.tv_sec) {
117 1.1 cgd np->n_direofoffset = 0;
118 1.1 cgd vinvalbuf(vp, TRUE);
119 1.1 cgd np->n_mtime = vattr.va_mtime.tv_sec;
120 1.1 cgd }
121 1.1 cgd }
122 1.1 cgd }
123 1.1 cgd do {
124 1.1 cgd switch (vp->v_type) {
125 1.1 cgd case VREG:
126 1.1 cgd nfsstats.biocache_reads++;
127 1.1 cgd lbn = uio->uio_offset / biosize;
128 1.1 cgd on = uio->uio_offset & (biosize-1);
129 1.1 cgd n = MIN((unsigned)(biosize - on), uio->uio_resid);
130 1.1 cgd diff = np->n_size - uio->uio_offset;
131 1.1 cgd if (diff <= 0)
132 1.1 cgd return (error);
133 1.1 cgd if (diff < n)
134 1.1 cgd n = diff;
135 1.1 cgd bn = lbn*(biosize/DEV_BSIZE);
136 1.1 cgd rablock = (lbn+1)*(biosize/DEV_BSIZE);
137 1.1 cgd if (vp->v_lastr + 1 == lbn &&
138 1.1 cgd np->n_size > (rablock * DEV_BSIZE))
139 1.1 cgd error = breada(vp, bn, biosize, rablock, biosize,
140 1.1 cgd cred, &bp);
141 1.1 cgd else
142 1.1 cgd error = bread(vp, bn, biosize, cred, &bp);
143 1.1 cgd vp->v_lastr = lbn;
144 1.1 cgd if (bp->b_resid) {
145 1.1 cgd diff = (on >= (biosize-bp->b_resid)) ? 0 :
146 1.1 cgd (biosize-bp->b_resid-on);
147 1.1 cgd n = MIN(n, diff);
148 1.1 cgd }
149 1.1 cgd break;
150 1.1 cgd case VLNK:
151 1.1 cgd nfsstats.biocache_readlinks++;
152 1.1 cgd on = 0;
153 1.1 cgd error = bread(vp, (daddr_t)0, NFS_MAXPATHLEN, cred, &bp);
154 1.1 cgd n = MIN(uio->uio_resid, NFS_MAXPATHLEN - bp->b_resid);
155 1.1 cgd break;
156 1.1 cgd case VDIR:
157 1.1 cgd nfsstats.biocache_readdirs++;
158 1.1 cgd on = 0;
159 1.1 cgd error = bread(vp, uio->uio_offset, NFS_DIRBLKSIZ, cred, &bp);
160 1.1 cgd n = MIN(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid);
161 1.1 cgd break;
162 1.1 cgd };
163 1.1 cgd if (error) {
164 1.1 cgd brelse(bp);
165 1.1 cgd return (error);
166 1.1 cgd }
167 1.1 cgd if (n > 0)
168 1.1 cgd error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
169 1.1 cgd switch (vp->v_type) {
170 1.1 cgd case VREG:
171 1.1 cgd if (n+on == biosize || uio->uio_offset == np->n_size)
172 1.1 cgd bp->b_flags |= B_AGE;
173 1.1 cgd break;
174 1.1 cgd case VLNK:
175 1.1 cgd n = 0;
176 1.1 cgd break;
177 1.1 cgd case VDIR:
178 1.1 cgd uio->uio_offset = bp->b_blkno;
179 1.1 cgd break;
180 1.1 cgd };
181 1.1 cgd brelse(bp);
182 1.1 cgd } while (error == 0 && uio->uio_resid > 0 && n != 0);
183 1.1 cgd return (error);
184 1.1 cgd }
185 1.1 cgd
186 1.1 cgd /*
187 1.1 cgd * Vnode op for write using bio
188 1.1 cgd */
189 1.1 cgd nfs_write(vp, uio, ioflag, cred)
190 1.1 cgd register struct vnode *vp;
191 1.1 cgd register struct uio *uio;
192 1.1 cgd int ioflag;
193 1.1 cgd struct ucred *cred;
194 1.1 cgd {
195 1.1 cgd struct proc *p = uio->uio_procp;
196 1.1 cgd register int biosize;
197 1.1 cgd struct buf *bp;
198 1.1 cgd struct nfsnode *np = VTONFS(vp);
199 1.1 cgd struct vattr vattr;
200 1.1 cgd daddr_t lbn, bn;
201 1.1 cgd int n, on, error = 0;
202 1.1 cgd
203 1.1 cgd #ifdef DIAGNOSTIC
204 1.1 cgd if (uio->uio_rw != UIO_WRITE)
205 1.1 cgd panic("nfs_write mode");
206 1.1 cgd if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
207 1.1 cgd panic("nfs_write proc");
208 1.1 cgd #endif
209 1.1 cgd if (vp->v_type != VREG)
210 1.1 cgd return (EIO);
211 1.1 cgd /* Should we try and do this ?? */
212 1.1 cgd if (ioflag & (IO_APPEND | IO_SYNC)) {
213 1.1 cgd if (np->n_flag & NMODIFIED) {
214 1.1 cgd np->n_flag &= ~NMODIFIED;
215 1.1 cgd vinvalbuf(vp, TRUE);
216 1.1 cgd }
217 1.1 cgd if (ioflag & IO_APPEND) {
218 1.1 cgd np->n_attrstamp = 0;
219 1.1 cgd if (error = nfs_dogetattr(vp, &vattr, cred, 1, p))
220 1.1 cgd return (error);
221 1.1 cgd uio->uio_offset = np->n_size;
222 1.1 cgd }
223 1.1 cgd return (nfs_writerpc(vp, uio, cred));
224 1.1 cgd }
225 1.1 cgd #ifdef notdef
226 1.1 cgd cnt = uio->uio_resid;
227 1.1 cgd osize = np->n_size;
228 1.1 cgd #endif
229 1.1 cgd if (uio->uio_offset < 0)
230 1.1 cgd return (EINVAL);
231 1.1 cgd if (uio->uio_resid == 0)
232 1.1 cgd return (0);
233 1.1 cgd /*
234 1.1 cgd * Maybe this should be above the vnode op call, but so long as
235 1.1 cgd * file servers have no limits, i don't think it matters
236 1.1 cgd */
237 1.4 cgd if (p &&
238 1.4 cgd uio->uio_offset + uio->uio_resid >
239 1.1 cgd p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
240 1.1 cgd psignal(p, SIGXFSZ);
241 1.1 cgd return (EFBIG);
242 1.1 cgd }
243 1.1 cgd /*
244 1.1 cgd * I use nm_rsize, not nm_wsize so that all buffer cache blocks
245 1.1 cgd * will be the same size within a filesystem. nfs_writerpc will
246 1.1 cgd * still use nm_wsize when sizing the rpc's.
247 1.1 cgd */
248 1.1 cgd biosize = VFSTONFS(vp->v_mount)->nm_rsize;
249 1.1 cgd np->n_flag |= NMODIFIED;
250 1.3 andrew vnode_pager_uncache(vp);
251 1.1 cgd do {
252 1.1 cgd nfsstats.biocache_writes++;
253 1.1 cgd lbn = uio->uio_offset / biosize;
254 1.1 cgd on = uio->uio_offset & (biosize-1);
255 1.1 cgd n = MIN((unsigned)(biosize - on), uio->uio_resid);
256 1.1 cgd if (uio->uio_offset+n > np->n_size) {
257 1.1 cgd np->n_size = uio->uio_offset+n;
258 1.1 cgd vnode_pager_setsize(vp, np->n_size);
259 1.1 cgd }
260 1.1 cgd bn = lbn*(biosize/DEV_BSIZE);
261 1.1 cgd again:
262 1.1 cgd bp = getblk(vp, bn, biosize);
263 1.5 cgd if (bp->b_wcred == NOCRED && cred != NOCRED) {
264 1.1 cgd crhold(cred);
265 1.1 cgd bp->b_wcred = cred;
266 1.1 cgd }
267 1.1 cgd if (bp->b_dirtyend > 0) {
268 1.1 cgd /*
269 1.1 cgd * If the new write will leave a contiguous dirty
270 1.1 cgd * area, just update the b_dirtyoff and b_dirtyend,
271 1.1 cgd * otherwise force a write rpc of the old dirty area.
272 1.1 cgd */
273 1.1 cgd if (on <= bp->b_dirtyend && (on+n) >= bp->b_dirtyoff) {
274 1.1 cgd bp->b_dirtyoff = MIN(on, bp->b_dirtyoff);
275 1.1 cgd bp->b_dirtyend = MAX((on+n), bp->b_dirtyend);
276 1.1 cgd } else {
277 1.1 cgd bp->b_proc = p;
278 1.1 cgd if (error = bwrite(bp))
279 1.1 cgd return (error);
280 1.1 cgd goto again;
281 1.1 cgd }
282 1.1 cgd } else {
283 1.1 cgd bp->b_dirtyoff = on;
284 1.1 cgd bp->b_dirtyend = on+n;
285 1.1 cgd }
286 1.1 cgd if (error = uiomove(bp->b_un.b_addr + on, n, uio)) {
287 1.1 cgd brelse(bp);
288 1.1 cgd return (error);
289 1.1 cgd }
290 1.1 cgd if ((n+on) == biosize) {
291 1.1 cgd bp->b_flags |= B_AGE;
292 1.1 cgd bp->b_proc = (struct proc *)0;
293 1.1 cgd bawrite(bp);
294 1.1 cgd } else {
295 1.1 cgd bp->b_proc = (struct proc *)0;
296 1.1 cgd bdwrite(bp);
297 1.1 cgd }
298 1.1 cgd } while (error == 0 && uio->uio_resid > 0 && n != 0);
299 1.1 cgd #ifdef notdef
300 1.1 cgd /* Should we try and do this for nfs ?? */
301 1.1 cgd if (error && (ioflag & IO_UNIT)) {
302 1.1 cgd np->n_size = osize;
303 1.1 cgd uio->uio_offset -= cnt - uio->uio_resid;
304 1.1 cgd uio->uio_resid = cnt;
305 1.1 cgd }
306 1.1 cgd #endif
307 1.1 cgd return (error);
308 1.1 cgd }
309