nfs_bio.c revision 1.1 1 1.1 cgd /*
2 1.1 cgd * Copyright (c) 1989 The Regents of the University of California.
3 1.1 cgd * All rights reserved.
4 1.1 cgd *
5 1.1 cgd * This code is derived from software contributed to Berkeley by
6 1.1 cgd * Rick Macklem at The University of Guelph.
7 1.1 cgd *
8 1.1 cgd * Redistribution and use in source and binary forms, with or without
9 1.1 cgd * modification, are permitted provided that the following conditions
10 1.1 cgd * are met:
11 1.1 cgd * 1. Redistributions of source code must retain the above copyright
12 1.1 cgd * notice, this list of conditions and the following disclaimer.
13 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer in the
15 1.1 cgd * documentation and/or other materials provided with the distribution.
16 1.1 cgd * 3. All advertising materials mentioning features or use of this software
17 1.1 cgd * must display the following acknowledgement:
18 1.1 cgd * This product includes software developed by the University of
19 1.1 cgd * California, Berkeley and its contributors.
20 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
21 1.1 cgd * may be used to endorse or promote products derived from this software
22 1.1 cgd * without specific prior written permission.
23 1.1 cgd *
24 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 1.1 cgd * SUCH DAMAGE.
35 1.1 cgd *
36 1.1 cgd * @(#)nfs_bio.c 7.19 (Berkeley) 4/16/91
37 1.1 cgd */
38 1.1 cgd
39 1.1 cgd #include "param.h"
40 1.1 cgd #include "proc.h"
41 1.1 cgd #include "buf.h"
42 1.1 cgd #include "uio.h"
43 1.1 cgd #include "namei.h"
44 1.1 cgd #include "vnode.h"
45 1.1 cgd #include "trace.h"
46 1.1 cgd #include "mount.h"
47 1.1 cgd #include "resourcevar.h"
48 1.1 cgd
49 1.1 cgd #include "nfsnode.h"
50 1.1 cgd #include "nfsv2.h"
51 1.1 cgd #include "nfs.h"
52 1.1 cgd #include "nfsiom.h"
53 1.1 cgd #include "nfsmount.h"
54 1.1 cgd
55 1.1 cgd /* True and false, how exciting */
56 1.1 cgd #define TRUE 1
57 1.1 cgd #define FALSE 0
58 1.1 cgd
59 1.1 cgd /*
60 1.1 cgd * Vnode op for read using bio
61 1.1 cgd * Any similarity to readip() is purely coincidental
62 1.1 cgd */
63 1.1 cgd nfs_bioread(vp, uio, ioflag, cred)
64 1.1 cgd register struct vnode *vp;
65 1.1 cgd register struct uio *uio;
66 1.1 cgd int ioflag;
67 1.1 cgd struct ucred *cred;
68 1.1 cgd {
69 1.1 cgd register struct nfsnode *np = VTONFS(vp);
70 1.1 cgd register int biosize;
71 1.1 cgd struct buf *bp;
72 1.1 cgd struct vattr vattr;
73 1.1 cgd daddr_t lbn, bn, rablock;
74 1.1 cgd int diff, error = 0;
75 1.1 cgd long n, on;
76 1.1 cgd
77 1.1 cgd #ifdef lint
78 1.1 cgd ioflag = ioflag;
79 1.1 cgd #endif /* lint */
80 1.1 cgd #ifdef DIAGNOSTIC
81 1.1 cgd if (uio->uio_rw != UIO_READ)
82 1.1 cgd panic("nfs_read mode");
83 1.1 cgd #endif
84 1.1 cgd if (uio->uio_resid == 0)
85 1.1 cgd return (0);
86 1.1 cgd if (uio->uio_offset < 0 && vp->v_type != VDIR)
87 1.1 cgd return (EINVAL);
88 1.1 cgd biosize = VFSTONFS(vp->v_mount)->nm_rsize;
89 1.1 cgd /*
90 1.1 cgd * If the file's modify time on the server has changed since the
91 1.1 cgd * last read rpc or you have written to the file,
92 1.1 cgd * you may have lost data cache consistency with the
93 1.1 cgd * server, so flush all of the file's data out of the cache.
94 1.1 cgd * Then force a getattr rpc to ensure that you have up to date
95 1.1 cgd * attributes.
96 1.1 cgd * NB: This implies that cache data can be read when up to
97 1.1 cgd * NFS_ATTRTIMEO seconds out of date. If you find that you need current
98 1.1 cgd * attributes this could be forced by setting n_attrstamp to 0 before
99 1.1 cgd * the nfs_dogetattr() call.
100 1.1 cgd */
101 1.1 cgd if (vp->v_type != VLNK) {
102 1.1 cgd if (np->n_flag & NMODIFIED) {
103 1.1 cgd np->n_flag &= ~NMODIFIED;
104 1.1 cgd vinvalbuf(vp, TRUE);
105 1.1 cgd np->n_attrstamp = 0;
106 1.1 cgd np->n_direofoffset = 0;
107 1.1 cgd if (error = nfs_dogetattr(vp, &vattr, cred, 1,
108 1.1 cgd uio->uio_procp))
109 1.1 cgd return (error);
110 1.1 cgd np->n_mtime = vattr.va_mtime.tv_sec;
111 1.1 cgd } else {
112 1.1 cgd if (error = nfs_dogetattr(vp, &vattr, cred, 1,
113 1.1 cgd uio->uio_procp))
114 1.1 cgd return (error);
115 1.1 cgd if (np->n_mtime != vattr.va_mtime.tv_sec) {
116 1.1 cgd np->n_direofoffset = 0;
117 1.1 cgd vinvalbuf(vp, TRUE);
118 1.1 cgd np->n_mtime = vattr.va_mtime.tv_sec;
119 1.1 cgd }
120 1.1 cgd }
121 1.1 cgd }
122 1.1 cgd do {
123 1.1 cgd switch (vp->v_type) {
124 1.1 cgd case VREG:
125 1.1 cgd nfsstats.biocache_reads++;
126 1.1 cgd lbn = uio->uio_offset / biosize;
127 1.1 cgd on = uio->uio_offset & (biosize-1);
128 1.1 cgd n = MIN((unsigned)(biosize - on), uio->uio_resid);
129 1.1 cgd diff = np->n_size - uio->uio_offset;
130 1.1 cgd if (diff <= 0)
131 1.1 cgd return (error);
132 1.1 cgd if (diff < n)
133 1.1 cgd n = diff;
134 1.1 cgd bn = lbn*(biosize/DEV_BSIZE);
135 1.1 cgd rablock = (lbn+1)*(biosize/DEV_BSIZE);
136 1.1 cgd if (vp->v_lastr + 1 == lbn &&
137 1.1 cgd np->n_size > (rablock * DEV_BSIZE))
138 1.1 cgd error = breada(vp, bn, biosize, rablock, biosize,
139 1.1 cgd cred, &bp);
140 1.1 cgd else
141 1.1 cgd error = bread(vp, bn, biosize, cred, &bp);
142 1.1 cgd vp->v_lastr = lbn;
143 1.1 cgd if (bp->b_resid) {
144 1.1 cgd diff = (on >= (biosize-bp->b_resid)) ? 0 :
145 1.1 cgd (biosize-bp->b_resid-on);
146 1.1 cgd n = MIN(n, diff);
147 1.1 cgd }
148 1.1 cgd break;
149 1.1 cgd case VLNK:
150 1.1 cgd nfsstats.biocache_readlinks++;
151 1.1 cgd on = 0;
152 1.1 cgd error = bread(vp, (daddr_t)0, NFS_MAXPATHLEN, cred, &bp);
153 1.1 cgd n = MIN(uio->uio_resid, NFS_MAXPATHLEN - bp->b_resid);
154 1.1 cgd break;
155 1.1 cgd case VDIR:
156 1.1 cgd nfsstats.biocache_readdirs++;
157 1.1 cgd on = 0;
158 1.1 cgd error = bread(vp, uio->uio_offset, NFS_DIRBLKSIZ, cred, &bp);
159 1.1 cgd n = MIN(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid);
160 1.1 cgd break;
161 1.1 cgd };
162 1.1 cgd if (error) {
163 1.1 cgd brelse(bp);
164 1.1 cgd return (error);
165 1.1 cgd }
166 1.1 cgd if (n > 0)
167 1.1 cgd error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
168 1.1 cgd switch (vp->v_type) {
169 1.1 cgd case VREG:
170 1.1 cgd if (n+on == biosize || uio->uio_offset == np->n_size)
171 1.1 cgd bp->b_flags |= B_AGE;
172 1.1 cgd break;
173 1.1 cgd case VLNK:
174 1.1 cgd n = 0;
175 1.1 cgd break;
176 1.1 cgd case VDIR:
177 1.1 cgd uio->uio_offset = bp->b_blkno;
178 1.1 cgd break;
179 1.1 cgd };
180 1.1 cgd brelse(bp);
181 1.1 cgd } while (error == 0 && uio->uio_resid > 0 && n != 0);
182 1.1 cgd return (error);
183 1.1 cgd }
184 1.1 cgd
185 1.1 cgd /*
186 1.1 cgd * Vnode op for write using bio
187 1.1 cgd */
188 1.1 cgd nfs_write(vp, uio, ioflag, cred)
189 1.1 cgd register struct vnode *vp;
190 1.1 cgd register struct uio *uio;
191 1.1 cgd int ioflag;
192 1.1 cgd struct ucred *cred;
193 1.1 cgd {
194 1.1 cgd struct proc *p = uio->uio_procp;
195 1.1 cgd register int biosize;
196 1.1 cgd struct buf *bp;
197 1.1 cgd struct nfsnode *np = VTONFS(vp);
198 1.1 cgd struct vattr vattr;
199 1.1 cgd daddr_t lbn, bn;
200 1.1 cgd int n, on, error = 0;
201 1.1 cgd
202 1.1 cgd #ifdef DIAGNOSTIC
203 1.1 cgd if (uio->uio_rw != UIO_WRITE)
204 1.1 cgd panic("nfs_write mode");
205 1.1 cgd if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
206 1.1 cgd panic("nfs_write proc");
207 1.1 cgd #endif
208 1.1 cgd if (vp->v_type != VREG)
209 1.1 cgd return (EIO);
210 1.1 cgd /* Should we try and do this ?? */
211 1.1 cgd if (ioflag & (IO_APPEND | IO_SYNC)) {
212 1.1 cgd if (np->n_flag & NMODIFIED) {
213 1.1 cgd np->n_flag &= ~NMODIFIED;
214 1.1 cgd vinvalbuf(vp, TRUE);
215 1.1 cgd }
216 1.1 cgd if (ioflag & IO_APPEND) {
217 1.1 cgd np->n_attrstamp = 0;
218 1.1 cgd if (error = nfs_dogetattr(vp, &vattr, cred, 1, p))
219 1.1 cgd return (error);
220 1.1 cgd uio->uio_offset = np->n_size;
221 1.1 cgd }
222 1.1 cgd return (nfs_writerpc(vp, uio, cred));
223 1.1 cgd }
224 1.1 cgd #ifdef notdef
225 1.1 cgd cnt = uio->uio_resid;
226 1.1 cgd osize = np->n_size;
227 1.1 cgd #endif
228 1.1 cgd if (uio->uio_offset < 0)
229 1.1 cgd return (EINVAL);
230 1.1 cgd if (uio->uio_resid == 0)
231 1.1 cgd return (0);
232 1.1 cgd /*
233 1.1 cgd * Maybe this should be above the vnode op call, but so long as
234 1.1 cgd * file servers have no limits, i don't think it matters
235 1.1 cgd */
236 1.1 cgd if (uio->uio_offset + uio->uio_resid >
237 1.1 cgd p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
238 1.1 cgd psignal(p, SIGXFSZ);
239 1.1 cgd return (EFBIG);
240 1.1 cgd }
241 1.1 cgd /*
242 1.1 cgd * I use nm_rsize, not nm_wsize so that all buffer cache blocks
243 1.1 cgd * will be the same size within a filesystem. nfs_writerpc will
244 1.1 cgd * still use nm_wsize when sizing the rpc's.
245 1.1 cgd */
246 1.1 cgd biosize = VFSTONFS(vp->v_mount)->nm_rsize;
247 1.1 cgd np->n_flag |= NMODIFIED;
248 1.1 cgd do {
249 1.1 cgd nfsstats.biocache_writes++;
250 1.1 cgd lbn = uio->uio_offset / biosize;
251 1.1 cgd on = uio->uio_offset & (biosize-1);
252 1.1 cgd n = MIN((unsigned)(biosize - on), uio->uio_resid);
253 1.1 cgd if (uio->uio_offset+n > np->n_size) {
254 1.1 cgd np->n_size = uio->uio_offset+n;
255 1.1 cgd vnode_pager_setsize(vp, np->n_size);
256 1.1 cgd }
257 1.1 cgd bn = lbn*(biosize/DEV_BSIZE);
258 1.1 cgd again:
259 1.1 cgd bp = getblk(vp, bn, biosize);
260 1.1 cgd if (bp->b_wcred == NOCRED) {
261 1.1 cgd crhold(cred);
262 1.1 cgd bp->b_wcred = cred;
263 1.1 cgd }
264 1.1 cgd if (bp->b_dirtyend > 0) {
265 1.1 cgd /*
266 1.1 cgd * If the new write will leave a contiguous dirty
267 1.1 cgd * area, just update the b_dirtyoff and b_dirtyend,
268 1.1 cgd * otherwise force a write rpc of the old dirty area.
269 1.1 cgd */
270 1.1 cgd if (on <= bp->b_dirtyend && (on+n) >= bp->b_dirtyoff) {
271 1.1 cgd bp->b_dirtyoff = MIN(on, bp->b_dirtyoff);
272 1.1 cgd bp->b_dirtyend = MAX((on+n), bp->b_dirtyend);
273 1.1 cgd } else {
274 1.1 cgd bp->b_proc = p;
275 1.1 cgd if (error = bwrite(bp))
276 1.1 cgd return (error);
277 1.1 cgd goto again;
278 1.1 cgd }
279 1.1 cgd } else {
280 1.1 cgd bp->b_dirtyoff = on;
281 1.1 cgd bp->b_dirtyend = on+n;
282 1.1 cgd }
283 1.1 cgd if (error = uiomove(bp->b_un.b_addr + on, n, uio)) {
284 1.1 cgd brelse(bp);
285 1.1 cgd return (error);
286 1.1 cgd }
287 1.1 cgd if ((n+on) == biosize) {
288 1.1 cgd bp->b_flags |= B_AGE;
289 1.1 cgd bp->b_proc = (struct proc *)0;
290 1.1 cgd bawrite(bp);
291 1.1 cgd } else {
292 1.1 cgd bp->b_proc = (struct proc *)0;
293 1.1 cgd bdwrite(bp);
294 1.1 cgd }
295 1.1 cgd } while (error == 0 && uio->uio_resid > 0 && n != 0);
296 1.1 cgd #ifdef notdef
297 1.1 cgd /* Should we try and do this for nfs ?? */
298 1.1 cgd if (error && (ioflag & IO_UNIT)) {
299 1.1 cgd np->n_size = osize;
300 1.1 cgd uio->uio_offset -= cnt - uio->uio_resid;
301 1.1 cgd uio->uio_resid = cnt;
302 1.1 cgd }
303 1.1 cgd #endif
304 1.1 cgd return (error);
305 1.1 cgd }
306