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