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