version 1.76.4.8, 2007/10/09 13:45:17 |
version 1.77, 2007/04/19 11:05:14 |
|
|
__KERNEL_RCSID(1, "$NetBSD$"); |
__KERNEL_RCSID(1, "$NetBSD$"); |
|
|
#ifdef LFS_READWRITE |
#ifdef LFS_READWRITE |
|
#define BLKSIZE(a, b, c) blksize(a, b, c) |
#define FS struct lfs |
#define FS struct lfs |
#define I_FS i_lfs |
#define I_FS i_lfs |
#define READ lfs_read |
#define READ lfs_read |
Line 44 __KERNEL_RCSID(1, "$NetBSD$"); |
|
Line 45 __KERNEL_RCSID(1, "$NetBSD$"); |
|
#define fs_bsize lfs_bsize |
#define fs_bsize lfs_bsize |
#define fs_bmask lfs_bmask |
#define fs_bmask lfs_bmask |
#else |
#else |
|
#define BLKSIZE(a, b, c) blksize(a, b, c) |
#define FS struct fs |
#define FS struct fs |
#define I_FS i_fs |
#define I_FS i_fs |
#define READ ffs_read |
#define READ ffs_read |
|
|
struct ufsmount *ump; |
struct ufsmount *ump; |
struct buf *bp; |
struct buf *bp; |
FS *fs; |
FS *fs; |
|
void *win; |
vsize_t bytelen; |
vsize_t bytelen; |
daddr_t lbn, nextlbn; |
daddr_t lbn, nextlbn; |
off_t bytesinfile; |
off_t bytesinfile; |
long size, xfersize, blkoffset; |
long size, xfersize, blkoffset; |
int error, ioflag; |
int error, flags, ioflag; |
bool usepc = false; |
bool usepc = false; |
|
|
vp = ap->a_vp; |
vp = ap->a_vp; |
|
|
if (uio->uio_resid == 0) |
if (uio->uio_resid == 0) |
return (0); |
return (0); |
|
|
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
if ((error = fstrans_start(vp->v_mount, FSTRANS_SHARED)) != 0) |
|
return error; |
|
|
if (uio->uio_offset >= ip->i_size) |
if (uio->uio_offset >= ip->i_size) |
goto out; |
goto out; |
|
|
uio->uio_resid); |
uio->uio_resid); |
if (bytelen == 0) |
if (bytelen == 0) |
break; |
break; |
error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice, |
|
UBC_READ | UBC_PARTIALOK | |
win = ubc_alloc(&vp->v_uobj, uio->uio_offset, |
(UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0)); |
&bytelen, advice, UBC_READ); |
|
error = uiomove(win, bytelen, uio); |
|
flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0; |
|
ubc_release(win, flags); |
if (error) |
if (error) |
break; |
break; |
} |
} |
|
|
break; |
break; |
lbn = lblkno(fs, uio->uio_offset); |
lbn = lblkno(fs, uio->uio_offset); |
nextlbn = lbn + 1; |
nextlbn = lbn + 1; |
size = blksize(fs, ip, lbn); |
size = BLKSIZE(fs, ip, lbn); |
blkoffset = blkoff(fs, uio->uio_offset); |
blkoffset = blkoff(fs, uio->uio_offset); |
xfersize = MIN(MIN(fs->fs_bsize - blkoffset, uio->uio_resid), |
xfersize = MIN(MIN(fs->fs_bsize - blkoffset, uio->uio_resid), |
bytesinfile); |
bytesinfile); |
|
|
if (lblktosize(fs, nextlbn) >= ip->i_size) |
if (lblktosize(fs, nextlbn) >= ip->i_size) |
error = bread(vp, lbn, size, NOCRED, &bp); |
error = bread(vp, lbn, size, NOCRED, &bp); |
else { |
else { |
int nextsize = blksize(fs, ip, nextlbn); |
int nextsize = BLKSIZE(fs, ip, nextlbn); |
error = breadn(vp, lbn, |
error = breadn(vp, lbn, |
size, &nextlbn, &nextsize, 1, NOCRED, &bp); |
size, &nextlbn, &nextsize, 1, NOCRED, &bp); |
} |
} |
|
|
error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio); |
error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio); |
if (error) |
if (error) |
break; |
break; |
brelse(bp, 0); |
brelse(bp); |
} |
} |
if (bp != NULL) |
if (bp != NULL) |
brelse(bp, 0); |
brelse(bp); |
|
|
out: |
out: |
if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) { |
if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) { |
|
|
off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize; |
off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize; |
int blkoffset, error, flags, ioflag, resid, size, xfersize; |
int blkoffset, error, flags, ioflag, resid, size, xfersize; |
int aflag; |
int aflag; |
|
int ubc_alloc_flags, ubc_release_flags; |
int extended=0; |
int extended=0; |
|
void *win; |
vsize_t bytelen; |
vsize_t bytelen; |
bool async; |
bool async; |
bool usepc = false; |
bool usepc = false; |
|
|
if (uio->uio_resid == 0) |
if (uio->uio_resid == 0) |
return (0); |
return (0); |
|
|
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
if ((error = fstrans_start(vp->v_mount, FSTRANS_SHARED)) != 0) |
|
return error; |
|
|
flags = ioflag & IO_SYNC ? B_SYNC : 0; |
flags = ioflag & IO_SYNC ? B_SYNC : 0; |
async = vp->v_mount->mnt_flag & MNT_ASYNC; |
async = vp->v_mount->mnt_flag & MNT_ASYNC; |
|
|
off_t eob; |
off_t eob; |
|
|
eob = blkroundup(fs, osize); |
eob = blkroundup(fs, osize); |
uvm_vnp_setwritesize(vp, eob); |
|
error = ufs_balloc_range(vp, osize, eob - osize, cred, aflag); |
error = ufs_balloc_range(vp, osize, eob - osize, cred, aflag); |
if (error) |
if (error) |
goto out; |
goto out; |
if (flags & B_SYNC) { |
if (flags & B_SYNC) { |
mutex_enter(&vp->v_interlock); |
vp->v_size = eob; |
|
simple_lock(&vp->v_interlock); |
VOP_PUTPAGES(vp, trunc_page(osize & fs->fs_bmask), |
VOP_PUTPAGES(vp, trunc_page(osize & fs->fs_bmask), |
round_page(eob), PGO_CLEANIT | PGO_SYNCIO); |
round_page(eob), PGO_CLEANIT | PGO_SYNCIO); |
} |
} |
} |
} |
|
|
|
ubc_alloc_flags = UBC_WRITE; |
while (uio->uio_resid > 0) { |
while (uio->uio_resid > 0) { |
int ubc_flags = UBC_WRITE; |
bool extending; /* if we're extending a whole block */ |
bool overwrite; /* if we're overwrite a whole block */ |
|
off_t newoff; |
off_t newoff; |
|
|
if (ioflag & IO_DIRECT) { |
if (ioflag & IO_DIRECT) { |
|
|
* since the new blocks will be inaccessible until the write |
* since the new blocks will be inaccessible until the write |
* is complete. |
* is complete. |
*/ |
*/ |
overwrite = uio->uio_offset >= preallocoff && |
extending = uio->uio_offset >= preallocoff && |
uio->uio_offset < endallocoff; |
uio->uio_offset < endallocoff; |
if (!overwrite && (vp->v_vflag & VV_MAPPED) == 0 && |
|
blkoff(fs, uio->uio_offset) == 0 && |
|
(uio->uio_offset & PAGE_MASK) == 0) { |
|
vsize_t len; |
|
|
|
len = trunc_page(bytelen); |
|
len -= blkoff(fs, len); |
|
if (len > 0) { |
|
overwrite = true; |
|
bytelen = len; |
|
} |
|
} |
|
|
|
newoff = oldoff + bytelen; |
if (!extending) { |
if (vp->v_size < newoff) { |
|
uvm_vnp_setwritesize(vp, newoff); |
|
} |
|
|
|
if (!overwrite) { |
|
error = ufs_balloc_range(vp, uio->uio_offset, bytelen, |
error = ufs_balloc_range(vp, uio->uio_offset, bytelen, |
cred, aflag); |
cred, aflag); |
if (error) |
if (error) |
break; |
break; |
|
ubc_alloc_flags &= ~UBC_FAULTBUSY; |
} else { |
} else { |
genfs_node_wrlock(vp); |
genfs_node_wrlock(vp); |
error = GOP_ALLOC(vp, uio->uio_offset, bytelen, |
error = GOP_ALLOC(vp, uio->uio_offset, bytelen, |
|
|
genfs_node_unlock(vp); |
genfs_node_unlock(vp); |
if (error) |
if (error) |
break; |
break; |
ubc_flags |= UBC_FAULTBUSY; |
ubc_alloc_flags |= UBC_FAULTBUSY; |
} |
} |
|
|
/* |
/* |
* copy the data. |
* copy the data. |
*/ |
*/ |
|
|
ubc_flags |= UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0; |
win = ubc_alloc(&vp->v_uobj, uio->uio_offset, &bytelen, |
error = ubc_uiomove(&vp->v_uobj, uio, bytelen, UVM_ADV_RANDOM, |
UVM_ADV_NORMAL, ubc_alloc_flags); |
ubc_flags); |
error = uiomove(win, bytelen, uio); |
|
if (error && extending) { |
|
/* |
|
* if we haven't initialized the pages yet, |
|
* do it now. it's safe to use memset here |
|
* because we just mapped the pages above. |
|
*/ |
|
memset(win, 0, bytelen); |
|
} |
|
ubc_release_flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0; |
|
ubc_release(win, ubc_release_flags); |
|
|
/* |
/* |
* update UVM's notion of the size now that we've |
* update UVM's notion of the size now that we've |
|
|
* otherwise ffs_truncate can't flush soft update states. |
* otherwise ffs_truncate can't flush soft update states. |
*/ |
*/ |
|
|
|
newoff = oldoff + bytelen; |
if (vp->v_size < newoff) { |
if (vp->v_size < newoff) { |
uvm_vnp_setsize(vp, newoff); |
uvm_vnp_setsize(vp, newoff); |
extended = 1; |
extended = 1; |
|
|
|
|
#ifndef LFS_READWRITE |
#ifndef LFS_READWRITE |
if (!async && oldoff >> 16 != uio->uio_offset >> 16) { |
if (!async && oldoff >> 16 != uio->uio_offset >> 16) { |
mutex_enter(&vp->v_interlock); |
simple_lock(&vp->v_interlock); |
error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16, |
error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16, |
(uio->uio_offset >> 16) << 16, PGO_CLEANIT); |
(uio->uio_offset >> 16) << 16, PGO_CLEANIT); |
if (error) |
if (error) |
|
|
#endif |
#endif |
} |
} |
if (error == 0 && ioflag & IO_SYNC) { |
if (error == 0 && ioflag & IO_SYNC) { |
mutex_enter(&vp->v_interlock); |
simple_lock(&vp->v_interlock); |
error = VOP_PUTPAGES(vp, trunc_page(origoff & fs->fs_bmask), |
error = VOP_PUTPAGES(vp, trunc_page(origoff & fs->fs_bmask), |
round_page(blkroundup(fs, uio->uio_offset)), |
round_page(blkroundup(fs, uio->uio_offset)), |
PGO_CLEANIT | PGO_SYNCIO); |
PGO_CLEANIT | PGO_SYNCIO); |
|
|
goto out; |
goto out; |
|
|
bcache: |
bcache: |
mutex_enter(&vp->v_interlock); |
simple_lock(&vp->v_interlock); |
VOP_PUTPAGES(vp, trunc_page(origoff), round_page(origoff + resid), |
VOP_PUTPAGES(vp, trunc_page(origoff), round_page(origoff + resid), |
PGO_CLEANIT | PGO_FREE | PGO_SYNCIO); |
PGO_CLEANIT | PGO_FREE | PGO_SYNCIO); |
while (uio->uio_resid > 0) { |
while (uio->uio_resid > 0) { |
|
|
uvm_vnp_setsize(vp, ip->i_size); |
uvm_vnp_setsize(vp, ip->i_size); |
extended = 1; |
extended = 1; |
} |
} |
size = blksize(fs, ip, lbn) - bp->b_resid; |
size = BLKSIZE(fs, ip, lbn) - bp->b_resid; |
if (xfersize > size) |
if (xfersize > size) |
xfersize = size; |
xfersize = size; |
|
|
|
|
* so we need to invalidate it. |
* so we need to invalidate it. |
*/ |
*/ |
if (error && (flags & B_CLRBUF) == 0) { |
if (error && (flags & B_CLRBUF) == 0) { |
brelse(bp, BC_INVAL); |
bp->b_flags |= B_INVAL; |
|
brelse(bp); |
break; |
break; |
} |
} |
#ifdef LFS_READWRITE |
#ifdef LFS_READWRITE |