* Copyright (c) 1993 The Regents of the University of California.
* %sccs.include.redist.c%
* @(#)ufs_readwrite.c 8.1 (Berkeley) %G%
#define BLKSIZE(a, b, c) blksize(a)
#define fs_bsize lfs_bsize
#define fs_maxfilesize lfs_maxfilesize
#define BLKSIZE(a, b, c) blksize(a, b, c)
struct vop_read_args
/* {
register struct vnode
*vp
;
register struct inode
*ip
;
register struct uio
*uio
;
long size
, xfersize
, blkoffset
;
int type
, nextsize
, error
;
if (uio
->uio_rw
!= UIO_READ
)
if (vp
->v_type
== VLNK
) {
if ((int)ip
->i_size
< vp
->v_mount
->mnt_maxsymlinklen
)
panic("%s: short symlink", READ
);
} else if (vp
->v_type
!= VREG
&& vp
->v_type
!= VDIR
)
if ((u_quad_t
)uio
->uio_offset
> fs
->fs_maxfilesize
)
for (error
= 0, bp
= NULL
; uio
->uio_resid
> 0; bp
= NULL
) {
if ((bytesinfile
= ip
->i_size
- uio
->uio_offset
) <= 0)
lbn
= lblkno(fs
, uio
->uio_offset
);
size
= BLKSIZE(fs
, ip
, lbn
);
blkoffset
= blkoff(fs
, uio
->uio_offset
);
xfersize
= fs
->fs_bsize
- blkoffset
;
if (uio
->uio_resid
< xfersize
)
xfersize
= uio
->uio_resid
;
if (bytesinfile
< xfersize
)
(void)lfs_check(vp
, lbn
);
error
= cluster_read(vp
, ip
->i_size
, lbn
, size
, NOCRED
, &bp
);
if (lblktosize(fs
, nextlbn
) > ip
->i_size
) {
error
= bread(vp
, lbn
, size
, NOCRED
, &bp
);
ip
->i_size
, lbn
, size
, NOCRED
, &bp
);
} else if (lbn
- 1 == vp
->v_lastr
) {
nextsize
= BLKSIZE(fs
, ip
, nextlbn
);
size
, &nextlbn
, &nextsize
, 1, NOCRED
, &bp
);
error
= bread(vp
, lbn
, size
, NOCRED
, &bp
);
* We should only get non-zero b_resid when an I/O error
* has occurred, which should cause us to break above.
* However, if the short read did not cause an error,
* then we want to ensure that we do not uiomove bad
uiomove(bp
->b_un
.b_addr
+ blkoffset
, (int)xfersize
, uio
))
if (S_ISREG(mode
) && (xfersize
+ blkoffset
== fs
->fs_bsize
||
uio
->uio_offset
== ip
->i_size
))
struct vop_write_args
/* {
register struct vnode
*vp
;
register struct uio
*uio
;
register struct inode
*ip
;
int blkoffset
, error
, flags
, ioflag
, newblock
, resid
, size
, xfersize
;
if (uio
->uio_rw
!= UIO_WRITE
)
panic("%s: mode", WRITE
);
uio
->uio_offset
= ip
->i_size
;
if ((ip
->i_flags
& APPEND
) && uio
->uio_offset
!= ip
->i_size
)
if ((ioflag
& IO_SYNC
) == 0)
panic("%s: nonsync dir write", WRITE
);
panic("%s: type", WRITE
);
if (uio
->uio_offset
< 0 ||
(u_quad_t
)uio
->uio_offset
+ uio
->uio_resid
> fs
->fs_maxfilesize
)
* 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 (vp
->v_type
== VREG
&& p
&&
uio
->uio_offset
+ uio
->uio_resid
>
p
->p_rlimit
[RLIMIT_FSIZE
].rlim_cur
) {
flags
= ioflag
& IO_SYNC
? B_SYNC
: 0;
for (error
= 0; uio
->uio_resid
> 0;) {
lbn
= lblkno(fs
, uio
->uio_offset
);
blkoffset
= blkoff(fs
, uio
->uio_offset
);
xfersize
= fs
->fs_bsize
- blkoffset
;
if (uio
->uio_resid
< xfersize
)
xfersize
= uio
->uio_resid
;
(void)lfs_check(vp
, lbn
);
error
= lfs_balloc(vp
, xfersize
, lbn
, &bp
);
if (fs
->fs_bsize
> xfersize
)
lbn
, blkoffset
+ xfersize
, ap
->a_cred
, &bp
, flags
);
if (uio
->uio_offset
+ xfersize
> ip
->i_size
) {
ip
->i_size
= uio
->uio_offset
+ xfersize
;
vnode_pager_setsize(vp
, (u_long
)ip
->i_size
);
(void)vnode_pager_uncache(vp
);
size
= BLKSIZE(fs
, ip
, lbn
) - bp
->b_resid
;
uiomove(bp
->b_un
.b_addr
+ blkoffset
, (int)xfersize
, uio
);
else if (xfersize
+ blkoffset
== fs
->fs_bsize
)
cluster_write(bp
, ip
->i_size
);
if (error
|| xfersize
== 0)
ip
->i_flag
|= IUPD
| ICHG
;
* If we successfully wrote any data, and we are not the superuser
* we clear the setuid and setgid bits as a precaution against
if (resid
> uio
->uio_resid
&& ap
->a_cred
&& ap
->a_cred
->cr_uid
!= 0)
ip
->i_mode
&= ~(ISUID
| ISGID
);
(void)VOP_TRUNCATE(vp
, osize
,
ioflag
& IO_SYNC
, ap
->a_cred
, uio
->uio_procp
);
uio
->uio_offset
-= resid
- uio
->uio_resid
;
} else if (resid
> uio
->uio_resid
&& (ioflag
& IO_SYNC
))
error
= VOP_UPDATE(vp
, &time
, &time
, 1);