* Copyright (c) 1989 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Rick Macklem at The University of Guelph.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* @(#)nfs_bio.c 7.19 (Berkeley) 4/16/91
/* True and false, how exciting */
* Vnode op for read using bio
* Any similarity to readip() is purely coincidental
nfs_bioread(vp
, uio
, ioflag
, cred
)
register struct vnode
*vp
;
register struct uio
*uio
;
register struct nfsnode
*np
= VTONFS(vp
);
daddr_t lbn
, bn
, rablock
;
if (uio
->uio_rw
!= UIO_READ
)
if (uio
->uio_offset
< 0 && vp
->v_type
!= VDIR
)
biosize
= VFSTONFS(vp
->v_mount
)->nm_rsize
;
* If the file's modify time on the server has changed since the
* last read rpc or you have written to the file,
* you may have lost data cache consistency with the
* server, so flush all of the file's data out of the cache.
* Then force a getattr rpc to ensure that you have up to date
* NB: This implies that cache data can be read when up to
* NFS_ATTRTIMEO seconds out of date. If you find that you need current
* attributes this could be forced by setting n_attrstamp to 0 before
* the nfs_dogetattr() call.
if (vp
->v_type
!= VLNK
) {
if (np
->n_flag
& NMODIFIED
) {
np
->n_flag
&= ~NMODIFIED
;
if (error
= nfs_dogetattr(vp
, &vattr
, cred
, 1,
np
->n_mtime
= vattr
.va_mtime
.tv_sec
;
if (error
= nfs_dogetattr(vp
, &vattr
, cred
, 1,
if (np
->n_mtime
!= vattr
.va_mtime
.tv_sec
) {
np
->n_mtime
= vattr
.va_mtime
.tv_sec
;
nfsstats
.biocache_reads
++;
lbn
= uio
->uio_offset
/ biosize
;
on
= uio
->uio_offset
& (biosize
-1);
n
= MIN((unsigned)(biosize
- on
), uio
->uio_resid
);
diff
= np
->n_size
- uio
->uio_offset
;
bn
= lbn
*(biosize
/DEV_BSIZE
);
rablock
= (lbn
+1)*(biosize
/DEV_BSIZE
);
if (vp
->v_lastr
+ 1 == lbn
&&
np
->n_size
> (rablock
* DEV_BSIZE
))
error
= breada(vp
, bn
, biosize
, rablock
, biosize
,
error
= bread(vp
, bn
, biosize
, cred
, &bp
);
diff
= (on
>= (biosize
-bp
->b_resid
)) ? 0 :
(biosize
-bp
->b_resid
-on
);
nfsstats
.biocache_readlinks
++;
error
= bread(vp
, (daddr_t
)0, NFS_MAXPATHLEN
, cred
, &bp
);
n
= MIN(uio
->uio_resid
, NFS_MAXPATHLEN
- bp
->b_resid
);
nfsstats
.biocache_readdirs
++;
error
= bread(vp
, uio
->uio_offset
, NFS_DIRBLKSIZ
, cred
, &bp
);
n
= MIN(uio
->uio_resid
, NFS_DIRBLKSIZ
- bp
->b_resid
);
error
= uiomove(bp
->b_un
.b_addr
+ on
, (int)n
, uio
);
if (n
+on
== biosize
|| uio
->uio_offset
== np
->n_size
)
uio
->uio_offset
= bp
->b_blkno
;
} while (error
== 0 && uio
->uio_resid
> 0 && n
!= 0);
* Vnode op for write using bio
nfs_write(vp
, uio
, ioflag
, cred
)
register struct vnode
*vp
;
register struct uio
*uio
;
struct proc
*p
= uio
->uio_procp
;
struct nfsnode
*np
= VTONFS(vp
);
if (uio
->uio_rw
!= UIO_WRITE
)
if (uio
->uio_segflg
== UIO_USERSPACE
&& uio
->uio_procp
!= curproc
)
/* Should we try and do this ?? */
if (ioflag
& (IO_APPEND
| IO_SYNC
)) {
if (np
->n_flag
& NMODIFIED
) {
np
->n_flag
&= ~NMODIFIED
;
if (ioflag
& IO_APPEND
) {
if (error
= nfs_dogetattr(vp
, &vattr
, cred
, 1, p
))
uio
->uio_offset
= np
->n_size
;
return (nfs_writerpc(vp
, uio
, cred
));
* Maybe this should be above the vnode op call, but so long as
* file servers have no limits, i don't think it matters
if (uio
->uio_offset
+ uio
->uio_resid
>
p
->p_rlimit
[RLIMIT_FSIZE
].rlim_cur
) {
* I use nm_rsize, not nm_wsize so that all buffer cache blocks
* will be the same size within a filesystem. nfs_writerpc will
* still use nm_wsize when sizing the rpc's.
biosize
= VFSTONFS(vp
->v_mount
)->nm_rsize
;
nfsstats
.biocache_writes
++;
lbn
= uio
->uio_offset
/ biosize
;
on
= uio
->uio_offset
& (biosize
-1);
n
= MIN((unsigned)(biosize
- on
), uio
->uio_resid
);
if (uio
->uio_offset
+n
> np
->n_size
) {
np
->n_size
= uio
->uio_offset
+n
;
vnode_pager_setsize(vp
, np
->n_size
);
bn
= lbn
*(biosize
/DEV_BSIZE
);
bp
= getblk(vp
, bn
, biosize
);
if (bp
->b_wcred
== NOCRED
) {
if (bp
->b_dirtyend
> 0) {
* If the new write will leave a contiguous dirty
* area, just update the b_dirtyoff and b_dirtyend,
* otherwise force a write rpc of the old dirty area.
if (on
<= bp
->b_dirtyend
&& (on
+n
) >= bp
->b_dirtyoff
) {
bp
->b_dirtyoff
= MIN(on
, bp
->b_dirtyoff
);
bp
->b_dirtyend
= MAX((on
+n
), bp
->b_dirtyend
);
if (error
= uiomove(bp
->b_un
.b_addr
+ on
, n
, uio
)) {
bp
->b_proc
= (struct proc
*)0;
bp
->b_proc
= (struct proc
*)0;
} while (error
== 0 && uio
->uio_resid
> 0 && n
!= 0);
/* Should we try and do this for nfs ?? */
if (error
&& (ioflag
& IO_UNIT
)) {
uio
->uio_offset
-= cnt
- uio
->uio_resid
;