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