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