make ffs_subr.c work with fsck(8) again
[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 *
b40809cc 10 * @(#)nfs_bio.c 7.19 (Berkeley) %G%
39d108be
RM
11 */
12
13#include "param.h"
4547a923 14#include "proc.h"
39d108be 15#include "buf.h"
b40809cc
KM
16#include "uio.h"
17#include "namei.h"
39d108be
RM
18#include "vnode.h"
19#include "trace.h"
20#include "mount.h"
4547a923
MK
21#include "resourcevar.h"
22
39d108be 23#include "nfsnode.h"
e8540f59
KM
24#include "nfsv2.h"
25#include "nfs.h"
39d108be 26#include "nfsiom.h"
f0f1cbaa 27#include "nfsmount.h"
39d108be
RM
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 */
f0f1cbaa 37nfs_bioread(vp, uio, ioflag, cred)
39d108be 38 register struct vnode *vp;
170bfd05 39 register struct uio *uio;
39d108be
RM
40 int ioflag;
41 struct ucred *cred;
42{
43 register struct nfsnode *np = VTONFS(vp);
170bfd05 44 register int biosize;
39d108be
RM
45 struct buf *bp;
46 struct vattr vattr;
47 daddr_t lbn, bn, rablock;
13576453 48 int diff, error = 0;
39d108be 49 long n, on;
39d108be 50
d4e5799e
KM
51#ifdef lint
52 ioflag = ioflag;
53#endif /* lint */
b40809cc 54#ifdef DIAGNOSTIC
39d108be
RM
55 if (uio->uio_rw != UIO_READ)
56 panic("nfs_read mode");
b40809cc 57#endif
39d108be 58 if (uio->uio_resid == 0)
b71430cc 59 return (0);
f0f1cbaa 60 if (uio->uio_offset < 0 && vp->v_type != VDIR)
b71430cc 61 return (EINVAL);
170bfd05 62 biosize = VFSTONFS(vp->v_mount)->nm_rsize;
39d108be
RM
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.
f0f1cbaa
KM
68 * Then force a getattr rpc to ensure that you have up to date
69 * attributes.
39d108be
RM
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
170bfd05 73 * the nfs_dogetattr() call.
39d108be 74 */
f0f1cbaa
KM
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;
b40809cc
KM
81 if (error = nfs_dogetattr(vp, &vattr, cred, 1,
82 uio->uio_procp))
e8540f59
KM
83 return (error);
84 np->n_mtime = vattr.va_mtime.tv_sec;
f0f1cbaa 85 } else {
b40809cc
KM
86 if (error = nfs_dogetattr(vp, &vattr, cred, 1,
87 uio->uio_procp))
f0f1cbaa
KM
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 }
39d108be
RM
94 }
95 }
96 do {
f0f1cbaa
KM
97 switch (vp->v_type) {
98 case VREG:
e8540f59 99 nfsstats.biocache_reads++;
170bfd05
KM
100 lbn = uio->uio_offset / biosize;
101 on = uio->uio_offset & (biosize-1);
102 n = MIN((unsigned)(biosize - on), uio->uio_resid);
39d108be
RM
103 diff = np->n_size - uio->uio_offset;
104 if (diff <= 0)
b71430cc 105 return (error);
39d108be
RM
106 if (diff < n)
107 n = diff;
170bfd05
KM
108 bn = lbn*(biosize/DEV_BSIZE);
109 rablock = (lbn+1)*(biosize/DEV_BSIZE);
d1a28114
KM
110 if (vp->v_lastr + 1 == lbn &&
111 np->n_size > (rablock * DEV_BSIZE))
170bfd05 112 error = breada(vp, bn, biosize, rablock, biosize,
39d108be
RM
113 cred, &bp);
114 else
170bfd05 115 error = bread(vp, bn, biosize, cred, &bp);
d1a28114 116 vp->v_lastr = lbn;
39d108be 117 if (bp->b_resid) {
170bfd05
KM
118 diff = (on >= (biosize-bp->b_resid)) ? 0 :
119 (biosize-bp->b_resid-on);
f0f1cbaa 120 n = MIN(n, diff);
39d108be 121 }
f0f1cbaa
KM
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;
b40809cc
KM
132 error = bread(vp, uio->uio_offset, NFS_DIRBLKSIZ, cred, &bp);
133 n = MIN(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid);
f0f1cbaa
KM
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:
170bfd05 144 if (n+on == biosize || uio->uio_offset == np->n_size)
39d108be 145 bp->b_flags |= B_AGE;
f0f1cbaa
KM
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);
39d108be 155 } while (error == 0 && uio->uio_resid > 0 && n != 0);
39d108be
RM
156 return (error);
157}
158
159/*
160 * Vnode op for write using bio
161 */
b71430cc 162nfs_write(vp, uio, ioflag, cred)
39d108be
RM
163 register struct vnode *vp;
164 register struct uio *uio;
39d108be
RM
165 int ioflag;
166 struct ucred *cred;
167{
b40809cc 168 struct proc *p = uio->uio_procp;
170bfd05 169 register int biosize;
39d108be
RM
170 struct buf *bp;
171 struct nfsnode *np = VTONFS(vp);
f0f1cbaa 172 struct vattr vattr;
39d108be 173 daddr_t lbn, bn;
3c15394b 174 int n, on, error = 0;
39d108be 175
b40809cc 176#ifdef DIAGNOSTIC
f0f1cbaa
KM
177 if (uio->uio_rw != UIO_WRITE)
178 panic("nfs_write mode");
b40809cc
KM
179 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
180 panic("nfs_write proc");
181#endif
f0f1cbaa
KM
182 if (vp->v_type != VREG)
183 return (EIO);
39d108be 184 /* Should we try and do this ?? */
170bfd05 185 if (ioflag & (IO_APPEND | IO_SYNC)) {
f0f1cbaa
KM
186 if (np->n_flag & NMODIFIED) {
187 np->n_flag &= ~NMODIFIED;
188 vinvalbuf(vp, TRUE);
189 }
170bfd05
KM
190 if (ioflag & IO_APPEND) {
191 np->n_attrstamp = 0;
b40809cc 192 if (error = nfs_dogetattr(vp, &vattr, cred, 1, p))
170bfd05
KM
193 return (error);
194 uio->uio_offset = np->n_size;
195 }
b40809cc 196 return (nfs_writerpc(vp, uio, cred));
f0f1cbaa 197 }
39d108be 198#ifdef notdef
b71430cc 199 cnt = uio->uio_resid;
39d108be
RM
200 osize = np->n_size;
201#endif
b71430cc
KM
202 if (uio->uio_offset < 0)
203 return (EINVAL);
39d108be 204 if (uio->uio_resid == 0)
b71430cc 205 return (0);
39d108be
RM
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 */
f0f1cbaa 210 if (uio->uio_offset + uio->uio_resid >
4547a923
MK
211 p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
212 psignal(p, SIGXFSZ);
b71430cc 213 return (EFBIG);
39d108be 214 }
170bfd05
KM
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;
f0f1cbaa 221 np->n_flag |= NMODIFIED;
39d108be 222 do {
e8540f59 223 nfsstats.biocache_writes++;
170bfd05
KM
224 lbn = uio->uio_offset / biosize;
225 on = uio->uio_offset & (biosize-1);
226 n = MIN((unsigned)(biosize - on), uio->uio_resid);
8986c97c 227 if (uio->uio_offset+n > np->n_size) {
39d108be 228 np->n_size = uio->uio_offset+n;
8986c97c
KM
229 vnode_pager_setsize(vp, np->n_size);
230 }
170bfd05 231 bn = lbn*(biosize/DEV_BSIZE);
141671b8 232again:
170bfd05 233 bp = getblk(vp, bn, biosize);
39d108be
RM
234 if (bp->b_wcred == NOCRED) {
235 crhold(cred);
236 bp->b_wcred = cred;
237 }
238 if (bp->b_dirtyend > 0) {
239 /*
141671b8
KM
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.
39d108be
RM
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 {
4547a923 248 bp->b_proc = p;
141671b8 249 if (error = bwrite(bp))
b71430cc 250 return (error);
141671b8 251 goto again;
39d108be
RM
252 }
253 } else {
254 bp->b_dirtyoff = on;
255 bp->b_dirtyend = on+n;
256 }
141671b8
KM
257 if (error = uiomove(bp->b_un.b_addr + on, n, uio)) {
258 brelse(bp);
b71430cc 259 return (error);
141671b8 260 }
170bfd05 261 if ((n+on) == biosize) {
39d108be 262 bp->b_flags |= B_AGE;
f0f1cbaa 263 bp->b_proc = (struct proc *)0;
39d108be
RM
264 bawrite(bp);
265 } else {
f0f1cbaa 266 bp->b_proc = (struct proc *)0;
39d108be
RM
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 ?? */
b71430cc 272 if (error && (ioflag & IO_UNIT)) {
39d108be 273 np->n_size = osize;
b71430cc
KM
274 uio->uio_offset -= cnt - uio->uio_resid;
275 uio->uio_resid = cnt;
276 }
39d108be 277#endif
39d108be
RM
278 return (error);
279}