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