xref: /csrg-svn/sys/nfs/nfs_bio.c (revision 40037)
138882Smacklem /*
238882Smacklem  * Copyright (c) 1989 The Regents of the University of California.
338882Smacklem  * All rights reserved.
438882Smacklem  *
538882Smacklem  * This code is derived from software contributed to Berkeley by
638882Smacklem  * Rick Macklem at The University of Guelph.
738882Smacklem  *
838882Smacklem  * Redistribution and use in source and binary forms are permitted
938882Smacklem  * provided that the above copyright notice and this paragraph are
1038882Smacklem  * duplicated in all such forms and that any documentation,
1138882Smacklem  * advertising materials, and other materials related to such
1238882Smacklem  * distribution and use acknowledge that the software was developed
1338882Smacklem  * by the University of California, Berkeley.  The name of the
1438882Smacklem  * University may not be used to endorse or promote products derived
1538882Smacklem  * from this software without specific prior written permission.
1638882Smacklem  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1738882Smacklem  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1838882Smacklem  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1938882Smacklem  *
20*40037Smckusick  *	@(#)nfs_bio.c	7.11 (Berkeley) 02/08/90
2138882Smacklem  */
2238882Smacklem 
2338882Smacklem #include "param.h"
2438882Smacklem #include "user.h"
2538882Smacklem #include "buf.h"
2638882Smacklem #include "vnode.h"
2738882Smacklem #include "trace.h"
2838882Smacklem #include "mount.h"
2938882Smacklem #include "nfsnode.h"
3039750Smckusick #include "nfsv2.h"
3139750Smckusick #include "nfs.h"
3238882Smacklem #include "nfsiom.h"
3338882Smacklem 
3438882Smacklem /* True and false, how exciting */
3538882Smacklem #define	TRUE	1
3638882Smacklem #define	FALSE	0
3738882Smacklem 
3838882Smacklem /*
3938882Smacklem  * Vnode op for read using bio
4038882Smacklem  * Any similarity to readip() is purely coincidental
4138882Smacklem  */
4239584Smckusick nfs_read(vp, uio, ioflag, cred)
4338882Smacklem 	register struct vnode *vp;
4438882Smacklem 	struct uio *uio;
4538882Smacklem 	int ioflag;
4638882Smacklem 	struct ucred *cred;
4738882Smacklem {
4838882Smacklem 	register struct nfsnode *np = VTONFS(vp);
4938882Smacklem 	struct buf *bp;
5038882Smacklem 	struct vattr vattr;
5138882Smacklem 	daddr_t lbn, bn, rablock;
5239487Smckusick 	int diff, error = 0;
5338882Smacklem 	long n, on;
5438882Smacklem 
5538882Smacklem 	/*
5638882Smacklem 	 * Avoid caching directories. Once everything is using getdirentries()
5738882Smacklem 	 * this will never happen anyhow.
5838882Smacklem 	 */
5939584Smckusick 	if (vp->v_type == VDIR)
6039584Smckusick 		return (nfs_readrpc(vp, uio, cred));
6138882Smacklem 	if (uio->uio_rw != UIO_READ)
6238882Smacklem 		panic("nfs_read mode");
6338882Smacklem 	if (vp->v_type != VREG)
6438882Smacklem 		panic("nfs_read type");
6538882Smacklem 	if (uio->uio_resid == 0)
6639584Smckusick 		return (0);
6739584Smckusick 	if (uio->uio_offset < 0)
6839584Smckusick 		return (EINVAL);
6938882Smacklem 	/*
7038882Smacklem 	 * If the file's modify time on the server has changed since the
7138882Smacklem 	 * last read rpc or you have written to the file,
7238882Smacklem 	 * you may have lost data cache consistency with the
7338882Smacklem 	 * server, so flush all of the file's data out of the cache.
7438882Smacklem 	 * This will implicitly bring the modify time up to date, since
7538882Smacklem 	 * up to date attributes are returned in the reply to any write rpc's
7638882Smacklem 	 * NB: This implies that cache data can be read when up to
7738882Smacklem 	 * NFS_ATTRTIMEO seconds out of date. If you find that you need current
7838882Smacklem 	 * attributes this could be forced by setting n_attrstamp to 0 before
7938882Smacklem 	 * the nfs_getattr() call.
8038882Smacklem 	 */
8138882Smacklem 	if (np->n_flag & NMODIFIED) {
8238882Smacklem 		np->n_flag &= ~NMODIFIED;
8339876Smckusick 		if (vinvalbuf(vp, TRUE)) {
8439750Smckusick 			if (error = nfs_getattr(vp, &vattr, cred))
8539750Smckusick 				return (error);
8639750Smckusick 			np->n_mtime = vattr.va_mtime.tv_sec;
8739750Smckusick 		}
8839876Smckusick 	} else if (vp->v_cleanblkhd || vp->v_dirtyblkhd) {
8938882Smacklem 		if (error = nfs_getattr(vp, &vattr, cred))
9039584Smckusick 			return (error);
9138882Smacklem 		if (np->n_mtime != vattr.va_mtime.tv_sec) {
9239750Smckusick 			vinvalbuf(vp, TRUE);
9338882Smacklem 			np->n_mtime = vattr.va_mtime.tv_sec;
9438882Smacklem 		}
9538882Smacklem 	}
9639340Smckusick 	np->n_flag |= NBUFFERED;
9738882Smacklem 	do {
9839750Smckusick 		nfsstats.biocache_reads++;
9938882Smacklem 		lbn = uio->uio_offset >> NFS_BIOSHIFT;
10038882Smacklem 		on = uio->uio_offset & (NFS_BIOSIZE-1);
10138882Smacklem 		n = MIN((unsigned)(NFS_BIOSIZE - on), uio->uio_resid);
10238882Smacklem 		diff = np->n_size - uio->uio_offset;
10338882Smacklem 		if (diff <= 0)
10439584Smckusick 			return (error);
10538882Smacklem 		if (diff < n)
10638882Smacklem 			n = diff;
10738882Smacklem 		bn = lbn*(NFS_BIOSIZE/DEV_BSIZE);
10838882Smacklem 		rablock = (lbn+1)*(NFS_BIOSIZE/DEV_BSIZE);
10939901Smckusick 		if (vp->v_lastr + 1 == lbn &&
11039901Smckusick 		    np->n_size > (rablock * DEV_BSIZE))
11138882Smacklem 			error = breada(vp, bn, NFS_BIOSIZE, rablock, NFS_BIOSIZE,
11238882Smacklem 				cred, &bp);
11338882Smacklem 		else
11438882Smacklem 			error = bread(vp, bn, NFS_BIOSIZE, cred, &bp);
11539901Smckusick 		vp->v_lastr = lbn;
11638882Smacklem 		if (bp->b_resid) {
11738882Smacklem 			diff = (on >= (NFS_BIOSIZE-bp->b_resid)) ? 0 :
11838882Smacklem 				(NFS_BIOSIZE-bp->b_resid-on);
11938882Smacklem 			n = MIN(n, diff);
12038882Smacklem 		}
12138882Smacklem 		if (error) {
12238882Smacklem 			brelse(bp);
12339584Smckusick 			return (error);
12438882Smacklem 		}
12538882Smacklem 		if (n > 0)
12638882Smacklem 			error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
12738882Smacklem 		if (n+on == NFS_BIOSIZE || uio->uio_offset == np->n_size)
12838882Smacklem 			bp->b_flags |= B_AGE;
12938882Smacklem 		brelse(bp);
13038882Smacklem 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
13138882Smacklem 	return (error);
13238882Smacklem }
13338882Smacklem 
13438882Smacklem /*
13538882Smacklem  * Vnode op for write using bio
13638882Smacklem  */
13739584Smckusick nfs_write(vp, uio, ioflag, cred)
13838882Smacklem 	register struct vnode *vp;
13938882Smacklem 	register struct uio *uio;
14038882Smacklem 	int ioflag;
14138882Smacklem 	struct ucred *cred;
14238882Smacklem {
14338882Smacklem 	struct buf *bp;
14438882Smacklem 	struct nfsnode *np = VTONFS(vp);
14538882Smacklem 	daddr_t lbn, bn;
14639584Smckusick 	int i, n, on, count, error = 0;
14738882Smacklem 
14838882Smacklem 	/* Should we try and do this ?? */
14938882Smacklem 	if (vp->v_type == VREG && (ioflag & IO_APPEND))
15039584Smckusick 		uio->uio_offset = np->n_size;
15139584Smckusick #ifdef notdef
15238882Smacklem 	cnt = uio->uio_resid;
15338882Smacklem 	osize = np->n_size;
15438882Smacklem #endif
15538882Smacklem 	if (uio->uio_rw != UIO_WRITE)
15638882Smacklem 		panic("nfs_write mode");
15738882Smacklem 	if (vp->v_type != VREG)
15838882Smacklem 		panic("nfs_write type");
15939584Smckusick 	if (uio->uio_offset < 0)
16039584Smckusick 		return (EINVAL);
16138882Smacklem 	if (uio->uio_resid == 0)
16239584Smckusick 		return (0);
16338882Smacklem 	/*
16438882Smacklem 	 * Maybe this should be above the vnode op call, but so long as
16538882Smacklem 	 * file servers have no limits, i don't think it matters
16638882Smacklem 	 */
16738882Smacklem 	if (vp->v_type == VREG &&
16838882Smacklem 	    uio->uio_offset + uio->uio_resid >
16938882Smacklem 	      u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
17038882Smacklem 		psignal(u.u_procp, SIGXFSZ);
17139584Smckusick 		return (EFBIG);
17238882Smacklem 	}
17339340Smckusick 	np->n_flag |= (NMODIFIED|NBUFFERED);
17438882Smacklem 	do {
17539750Smckusick 		nfsstats.biocache_writes++;
17638882Smacklem 		lbn = uio->uio_offset >> NFS_BIOSHIFT;
17738882Smacklem 		on = uio->uio_offset & (NFS_BIOSIZE-1);
17838882Smacklem 		n = MIN((unsigned)(NFS_BIOSIZE - on), uio->uio_resid);
17938882Smacklem 		if (uio->uio_offset+n > np->n_size)
18038882Smacklem 			np->n_size = uio->uio_offset+n;
18138882Smacklem 		bn = lbn*(NFS_BIOSIZE/DEV_BSIZE);
18238882Smacklem 		count = howmany(NFS_BIOSIZE, CLBYTES);
18338882Smacklem 		for (i = 0; i < count; i++)
18438882Smacklem 			munhash(vp, bn + i * CLBYTES / DEV_BSIZE);
185*40037Smckusick again:
18638882Smacklem 		bp = getblk(vp, bn, NFS_BIOSIZE);
18738882Smacklem 		if (bp->b_wcred == NOCRED) {
18838882Smacklem 			crhold(cred);
18938882Smacklem 			bp->b_wcred = cred;
19038882Smacklem 		}
19138882Smacklem 		if (bp->b_dirtyend > 0) {
19238882Smacklem 			/*
193*40037Smckusick 			 * If the new write will leave a contiguous dirty
194*40037Smckusick 			 * area, just update the b_dirtyoff and b_dirtyend,
195*40037Smckusick 			 * otherwise force a write rpc of the old dirty area.
19638882Smacklem 			 */
19738882Smacklem 			if (on <= bp->b_dirtyend && (on+n) >= bp->b_dirtyoff) {
19838882Smacklem 				bp->b_dirtyoff = MIN(on, bp->b_dirtyoff);
19938882Smacklem 				bp->b_dirtyend = MAX((on+n), bp->b_dirtyend);
20038882Smacklem 			} else {
201*40037Smckusick 				if (error = bwrite(bp))
20239584Smckusick 					return (error);
203*40037Smckusick 				goto again;
20438882Smacklem 			}
20538882Smacklem 		} else {
20638882Smacklem 			bp->b_dirtyoff = on;
20738882Smacklem 			bp->b_dirtyend = on+n;
20838882Smacklem 		}
209*40037Smckusick 		if (error = uiomove(bp->b_un.b_addr + on, n, uio)) {
210*40037Smckusick 			brelse(bp);
21139584Smckusick 			return (error);
212*40037Smckusick 		}
21338882Smacklem 		if ((n+on) == NFS_BIOSIZE) {
21438882Smacklem 			bp->b_flags |= B_AGE;
21538882Smacklem 			bawrite(bp);
21638882Smacklem 		} else {
21738882Smacklem 			bdwrite(bp);
21838882Smacklem 		}
21938882Smacklem 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
22038882Smacklem #ifdef notdef
22138882Smacklem 	/* Should we try and do this for nfs ?? */
22239584Smckusick 	if (error && (ioflag & IO_UNIT)) {
22338882Smacklem 		np->n_size = osize;
22439584Smckusick 		uio->uio_offset -= cnt - uio->uio_resid;
22539584Smckusick 		uio->uio_resid = cnt;
22639584Smckusick 	}
22738882Smacklem #endif
22838882Smacklem 	return (error);
22938882Smacklem }
230