merge inode and nfsnode tables into a single vnode table
[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 *
00b72154 20 * @(#)nfs_bio.c 7.3 (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"
30#include "nfsiom.h"
31
32/* True and false, how exciting */
33#define TRUE 1
34#define FALSE 0
35
36/*
37 * Vnode op for read using bio
38 * Any similarity to readip() is purely coincidental
39 */
40nfs_read(vp, uio, offp, ioflag, cred)
41 register struct vnode *vp;
42 struct uio *uio;
43 off_t *offp;
44 int ioflag;
45 struct ucred *cred;
46{
47 register struct nfsnode *np = VTONFS(vp);
48 struct buf *bp;
49 struct vattr vattr;
50 daddr_t lbn, bn, rablock;
51 int error = 0;
52 int diff;
53 long n, on;
54 int count;
55
56 if (!(ioflag & IO_NODELOCKED))
57 nfs_lock(vp);
39d108be
RM
58 /*
59 * Avoid caching directories. Once everything is using getdirentries()
60 * this will never happen anyhow.
61 */
62 if (vp->v_type == VDIR) {
63 error = nfs_readrpc(vp, uio, offp, cred);
ffe6f482
KM
64 if (!(ioflag & IO_NODELOCKED))
65 nfs_unlock(vp);
66 return (error);
39d108be 67 }
ffe6f482 68 uio->uio_offset = *offp;
39d108be
RM
69 count = uio->uio_resid;
70 if (uio->uio_rw != UIO_READ)
71 panic("nfs_read mode");
72 if (vp->v_type != VREG)
73 panic("nfs_read type");
74 if (uio->uio_resid == 0)
75 goto out;
76 if (uio->uio_offset < 0) {
77 error = EINVAL;
78 goto out;
79 }
80 /*
81 * If the file's modify time on the server has changed since the
82 * last read rpc or you have written to the file,
83 * you may have lost data cache consistency with the
84 * server, so flush all of the file's data out of the cache.
85 * This will implicitly bring the modify time up to date, since
86 * up to date attributes are returned in the reply to any write rpc's
87 * NB: This implies that cache data can be read when up to
88 * NFS_ATTRTIMEO seconds out of date. If you find that you need current
89 * attributes this could be forced by setting n_attrstamp to 0 before
90 * the nfs_getattr() call.
91 */
92 if (np->n_flag & NMODIFIED) {
93 np->n_flag &= ~NMODIFIED;
ffe6f482 94 if (error = nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE))
39d108be
RM
95 goto out;
96 if (error = nfs_getattr(vp, &vattr, cred))
97 goto out;
39d108be
RM
98 np->n_mtime = vattr.va_mtime.tv_sec;
99 } else {
100 if (error = nfs_getattr(vp, &vattr, cred))
101 goto out;
102 if (np->n_mtime != vattr.va_mtime.tv_sec) {
00b72154
KM
103 if (error = nfs_blkflush(vp, (daddr_t)0,
104 np->n_size, TRUE))
39d108be 105 goto out;
39d108be
RM
106 np->n_mtime = vattr.va_mtime.tv_sec;
107 }
108 }
ffe6f482 109 np->n_flag |= NBUFFERED;
39d108be
RM
110 do {
111 lbn = uio->uio_offset >> NFS_BIOSHIFT;
112 on = uio->uio_offset & (NFS_BIOSIZE-1);
113 n = MIN((unsigned)(NFS_BIOSIZE - on), uio->uio_resid);
114 diff = np->n_size - uio->uio_offset;
115 if (diff <= 0)
116 goto out;
117 if (diff < n)
118 n = diff;
119 bn = lbn*(NFS_BIOSIZE/DEV_BSIZE);
120 rablock = (lbn+1)*(NFS_BIOSIZE/DEV_BSIZE);
00b72154 121 if (np->n_lastr+1 == lbn && np->n_size > (rablock*DEV_BSIZE))
39d108be
RM
122 error = breada(vp, bn, NFS_BIOSIZE, rablock, NFS_BIOSIZE,
123 cred, &bp);
124 else
125 error = bread(vp, bn, NFS_BIOSIZE, cred, &bp);
126 np->n_lastr = lbn;
127 if (bp->b_resid) {
128 diff = (on >= (NFS_BIOSIZE-bp->b_resid)) ? 0 :
129 (NFS_BIOSIZE-bp->b_resid-on);
130 n = MIN(n, diff);
131 }
132 if (error) {
133 brelse(bp);
134 goto out;
135 }
136 if (n > 0)
137 error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
138 if (n+on == NFS_BIOSIZE || uio->uio_offset == np->n_size)
139 bp->b_flags |= B_AGE;
140 brelse(bp);
141 } while (error == 0 && uio->uio_resid > 0 && n != 0);
142out:
143 *offp = uio->uio_offset;
ffe6f482 144 if (!(ioflag & IO_NODELOCKED))
39d108be
RM
145 nfs_unlock(vp);
146 return (error);
147}
148
149/*
150 * Vnode op for write using bio
151 */
152nfs_write(vp, uio, offp, ioflag, cred)
153 register struct vnode *vp;
154 register struct uio *uio;
155 off_t *offp;
156 int ioflag;
157 struct ucred *cred;
158{
159 struct buf *bp;
160 struct nfsnode *np = VTONFS(vp);
161 daddr_t lbn, bn;
162 int i, n, on;
163 int flags, count, size;
164 int error = 0;
165 int cnt;
166 u_long osize;
167
168 if ((ioflag & IO_NODELOCKED) == 0)
169 nfs_lock(vp);
170 /* Should we try and do this ?? */
171 if (vp->v_type == VREG && (ioflag & IO_APPEND))
172 *offp = np->n_size;
173 uio->uio_offset = *offp;
174 cnt = uio->uio_resid;
175#ifdef notdef
176 osize = np->n_size;
177#endif
178 if (uio->uio_rw != UIO_WRITE)
179 panic("nfs_write mode");
180 if (vp->v_type != VREG)
181 panic("nfs_write type");
182 if (uio->uio_offset < 0) {
183 error = EINVAL;
184 goto out;
185 }
186 if (uio->uio_resid == 0)
187 goto out;
188 /*
189 * Maybe this should be above the vnode op call, but so long as
190 * file servers have no limits, i don't think it matters
191 */
192 if (vp->v_type == VREG &&
193 uio->uio_offset + uio->uio_resid >
194 u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
195 psignal(u.u_procp, SIGXFSZ);
196 error = EFBIG;
197 goto out;
198 }
ffe6f482 199 np->n_flag |= (NMODIFIED|NBUFFERED);
39d108be
RM
200 do {
201 lbn = uio->uio_offset >> NFS_BIOSHIFT;
202 on = uio->uio_offset & (NFS_BIOSIZE-1);
203 n = MIN((unsigned)(NFS_BIOSIZE - on), uio->uio_resid);
204 if (uio->uio_offset+n > np->n_size)
205 np->n_size = uio->uio_offset+n;
206 bn = lbn*(NFS_BIOSIZE/DEV_BSIZE);
207 count = howmany(NFS_BIOSIZE, CLBYTES);
208 for (i = 0; i < count; i++)
209 munhash(vp, bn + i * CLBYTES / DEV_BSIZE);
210 bp = getblk(vp, bn, NFS_BIOSIZE);
211 if (bp->b_wcred == NOCRED) {
212 crhold(cred);
213 bp->b_wcred = cred;
214 }
215 if (bp->b_dirtyend > 0) {
216 /*
217 * Iff the new write will leave a contiguous
218 * dirty area, just update the b_dirtyoff and
219 * b_dirtyend
220 * otherwise force a write rpc of the old dirty
221 * area
222 */
223 if (on <= bp->b_dirtyend && (on+n) >= bp->b_dirtyoff) {
224 bp->b_dirtyoff = MIN(on, bp->b_dirtyoff);
225 bp->b_dirtyend = MAX((on+n), bp->b_dirtyend);
226 } else {
227 /*
228 * Like bwrite() but without the brelse
229 */
230 bp->b_flags &= ~(B_READ | B_DONE |
231 B_ERROR | B_DELWRI | B_ASYNC);
232 u.u_ru.ru_oublock++;
233 VOP_STRATEGY(bp);
234 error = biowait(bp);
235 if (bp->b_flags & B_ERROR) {
236 brelse(bp);
237 if (bp->b_error)
238 error = bp->b_error;
239 else
240 error = EIO;
241 goto out;
242 }
243 bp->b_dirtyoff = on;
244 bp->b_dirtyend = on+n;
245 }
246 } else {
247 bp->b_dirtyoff = on;
248 bp->b_dirtyend = on+n;
249 }
250 if (error = uiomove(bp->b_un.b_addr + on, n, uio))
251 goto out;
252 if ((n+on) == NFS_BIOSIZE) {
253 bp->b_flags |= B_AGE;
254 bawrite(bp);
255 } else {
256 bdwrite(bp);
257 }
258 } while (error == 0 && uio->uio_resid > 0 && n != 0);
259#ifdef notdef
260 /* Should we try and do this for nfs ?? */
261 if (error && (ioflag & IO_UNIT))
262 np->n_size = osize;
263 else
264#endif
265 *offp += cnt - uio->uio_resid;
266out:
267 if ((ioflag & IO_NODELOCKED) == 0)
268 nfs_unlock(vp);
269 return (error);
270}
271
272/*
273 * Flush and invalidate all of the buffers associated with the blocks of vp
274 */
275nfs_blkflush(vp, blkno, size, invalidate)
276 struct vnode *vp;
277 daddr_t blkno;
278 long size;
279 int invalidate;
280{
281 register struct buf *ep;
282 struct buf *dp;
00b72154 283 daddr_t curblk, nextblk, ecurblk, lastblk;
39d108be 284 int s, error, allerrors = 0;
00b72154
KM
285
286 /*
287 * Iterate through each possible hash chain.
288 */
289 lastblk = blkno + btodb(size+DEV_BSIZE-1) - 1;
290 for (curblk = blkno; curblk <= lastblk; curblk = nextblk) {
291#if RND & (RND-1)
292 nextblk = ((curblk / RND) + 1) * RND;
293#else
294 nextblk = ((curblk & ~(RND-1)) + RND);
295#endif
296 ecurblk = nextblk > lastblk ? lastblk : nextblk - 1;
297 dp = BUFHASH(vp, curblk);
39d108be 298loop:
00b72154
KM
299 for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) {
300 if (ep->b_vp != vp || (ep->b_flags & B_INVAL))
301 continue;
302 /* look for overlap */
303 if (ep->b_bcount == 0 || ep->b_blkno > ecurblk ||
304 ep->b_blkno + btodb(ep->b_bcount) <= curblk)
305 continue;
306 s = splbio();
307 if (ep->b_flags&B_BUSY) {
308 ep->b_flags |= B_WANTED;
309 sleep((caddr_t)ep, PRIBIO+1);
310 splx(s);
311 goto loop;
312 }
313 if (ep->b_flags & B_DELWRI) {
314 splx(s);
315 notavail(ep);
316 if (error = bwrite(ep))
317 allerrors = error;
318 goto loop;
319 }
320 splx(s);
39d108be 321 if (invalidate) {
00b72154 322 notavail(ep);
39d108be
RM
323 ep->b_flags |= B_INVAL;
324 brelvp(ep);
00b72154 325 brelse(ep);
39d108be 326 }
00b72154 327 }
39d108be
RM
328 }
329 return (allerrors);
330}