Changeset View
Changeset View
Standalone View
Standalone View
sys/ufs/ffs/ffs_inode.c
Show First 20 Lines • Show All 177 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
ffs_truncate(vp, length, flags, cred) | ffs_truncate(vp, length, flags, cred) | ||||
struct vnode *vp; | struct vnode *vp; | ||||
off_t length; | off_t length; | ||||
int flags; | int flags; | ||||
struct ucred *cred; | struct ucred *cred; | ||||
{ | { | ||||
struct inode *ip; | struct inode *ip; | ||||
ufs2_daddr_t bn, lbn, lastblock, lastiblock[NIADDR], indir_lbn[NIADDR]; | ufs2_daddr_t bn, lbn, lastblock, lastiblock[UFS_NIADDR]; | ||||
ufs2_daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR]; | ufsw_daddr_t indir_lbn[UFS_NIADDR], oldblks[UFS_NDADDR + UFS_NIADDR]; | ||||
ufs2_daddr_t newblks[UFS_NDADDR + UFS_NIADDR]; | |||||
ufs2_daddr_t count, blocksreleased = 0, datablocks, blkno; | ufs2_daddr_t count, blocksreleased = 0, datablocks, blkno; | ||||
struct bufobj *bo; | struct bufobj *bo; | ||||
struct fs *fs; | struct fs *fs; | ||||
struct buf *bp; | struct buf *bp; | ||||
struct ufsmount *ump; | struct ufsmount *ump; | ||||
int softdeptrunc, journaltrunc; | int softdeptrunc, journaltrunc; | ||||
int needextclean, extblocks; | int needextclean, extblocks; | ||||
int offset, size, level, nblocks; | int offset, size, level, nblocks; | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | #ifdef QUOTA | ||||
(void) chkdq(ip, -extblocks, NOCRED, 0); | (void) chkdq(ip, -extblocks, NOCRED, 0); | ||||
#endif | #endif | ||||
vinvalbuf(vp, V_ALT, 0, 0); | vinvalbuf(vp, V_ALT, 0, 0); | ||||
vn_pages_remove(vp, | vn_pages_remove(vp, | ||||
OFF_TO_IDX(lblktosize(fs, -extblocks)), 0); | OFF_TO_IDX(lblktosize(fs, -extblocks)), 0); | ||||
osize = ip->i_din2->di_extsize; | osize = ip->i_din2->di_extsize; | ||||
ip->i_din2->di_blocks -= extblocks; | ip->i_din2->di_blocks -= extblocks; | ||||
ip->i_din2->di_extsize = 0; | ip->i_din2->di_extsize = 0; | ||||
for (i = 0; i < NXADDR; i++) { | for (i = 0; i < UFS_NXADDR; i++) { | ||||
oldblks[i] = ip->i_din2->di_extb[i]; | oldblks[i] = ip->i_din2->di_extb[i]; | ||||
ip->i_din2->di_extb[i] = 0; | ip->i_din2->di_extb[i] = 0; | ||||
} | } | ||||
ip->i_flag |= IN_CHANGE; | ip->i_flag |= IN_CHANGE; | ||||
if ((error = ffs_update(vp, waitforupdate))) | if ((error = ffs_update(vp, waitforupdate))) | ||||
return (error); | return (error); | ||||
for (i = 0; i < NXADDR; i++) { | for (i = 0; i < UFS_NXADDR; i++) { | ||||
if (oldblks[i] == 0) | if (oldblks[i] == 0) | ||||
continue; | continue; | ||||
ffs_blkfree(ump, fs, ITODEVVP(ip), oldblks[i], | ffs_blkfree(ump, fs, ITODEVVP(ip), oldblks[i], | ||||
sblksize(fs, osize, i), ip->i_number, | sblksize(fs, osize, i), ip->i_number, | ||||
vp->v_type, NULL); | vp->v_type, NULL); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
/* | /* | ||||
* Lookup block number for a given offset. Zero length files | * Lookup block number for a given offset. Zero length files | ||||
* have no blocks, so return a blkno of -1. | * have no blocks, so return a blkno of -1. | ||||
*/ | */ | ||||
lbn = lblkno(fs, length - 1); | lbn = lblkno(fs, length - 1); | ||||
if (length == 0) { | if (length == 0) { | ||||
blkno = -1; | blkno = -1; | ||||
} else if (lbn < NDADDR) { | } else if (lbn < UFS_NDADDR) { | ||||
blkno = DIP(ip, i_db[lbn]); | blkno = DIP(ip, i_db[lbn]); | ||||
} else { | } else { | ||||
error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn), fs->fs_bsize, | error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn), fs->fs_bsize, | ||||
cred, BA_METAONLY, &bp); | cred, BA_METAONLY, &bp); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
indiroff = (lbn - NDADDR) % NINDIR(fs); | indiroff = (lbn - UFS_NDADDR) % NINDIR(fs); | ||||
if (I_IS_UFS1(ip)) | if (I_IS_UFS1(ip)) | ||||
blkno = ((ufs1_daddr_t *)(bp->b_data))[indiroff]; | blkno = ((ufs1_daddr_t *)(bp->b_data))[indiroff]; | ||||
else | else | ||||
blkno = ((ufs2_daddr_t *)(bp->b_data))[indiroff]; | blkno = ((ufs2_daddr_t *)(bp->b_data))[indiroff]; | ||||
/* | /* | ||||
* If the block number is non-zero, then the indirect block | * If the block number is non-zero, then the indirect block | ||||
* must have been previously allocated and need not be written. | * must have been previously allocated and need not be written. | ||||
* If the block number is zero, then we may have allocated | * If the block number is zero, then we may have allocated | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | if (blkno != 0 && offset == 0) { | ||||
/* | /* | ||||
* When we are doing soft updates and the UFS_BALLOC | * When we are doing soft updates and the UFS_BALLOC | ||||
* above fills in a direct block hole with a full sized | * above fills in a direct block hole with a full sized | ||||
* block that will be truncated down to a fragment below, | * block that will be truncated down to a fragment below, | ||||
* we must flush out the block dependency with an FSYNC | * we must flush out the block dependency with an FSYNC | ||||
* so that we do not get a soft updates inconsistency | * so that we do not get a soft updates inconsistency | ||||
* when we create the fragment below. | * when we create the fragment below. | ||||
*/ | */ | ||||
if (DOINGSOFTDEP(vp) && lbn < NDADDR && | if (DOINGSOFTDEP(vp) && lbn < UFS_NDADDR && | ||||
fragroundup(fs, blkoff(fs, length)) < fs->fs_bsize && | fragroundup(fs, blkoff(fs, length)) < fs->fs_bsize && | ||||
(error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0) | (error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0) | ||||
return (error); | return (error); | ||||
ip->i_size = length; | ip->i_size = length; | ||||
DIP_SET(ip, i_size, length); | DIP_SET(ip, i_size, length); | ||||
size = blksize(fs, ip, lbn); | size = blksize(fs, ip, lbn); | ||||
if (vp->v_type != VDIR && offset != 0) | if (vp->v_type != VDIR && offset != 0) | ||||
bzero((char *)bp->b_data + offset, | bzero((char *)bp->b_data + offset, | ||||
Show All 11 Lines | #endif | ||||
} | } | ||||
/* | /* | ||||
* Calculate index into inode's block list of | * Calculate index into inode's block list of | ||||
* last direct and indirect blocks (if any) | * last direct and indirect blocks (if any) | ||||
* which we want to keep. Lastblock is -1 when | * which we want to keep. Lastblock is -1 when | ||||
* the file is truncated to 0. | * the file is truncated to 0. | ||||
*/ | */ | ||||
lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; | lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; | ||||
lastiblock[SINGLE] = lastblock - NDADDR; | lastiblock[SINGLE] = lastblock - UFS_NDADDR; | ||||
lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); | lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); | ||||
lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); | lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); | ||||
nblocks = btodb(fs->fs_bsize); | nblocks = btodb(fs->fs_bsize); | ||||
/* | /* | ||||
* Update file and block pointers on disk before we start freeing | * Update file and block pointers on disk before we start freeing | ||||
* blocks. If we crash before free'ing blocks below, the blocks | * blocks. If we crash before free'ing blocks below, the blocks | ||||
* will be returned to the free list. lastiblock values are also | * will be returned to the free list. lastiblock values are also | ||||
* normalized to -1 for calls to ffs_indirtrunc below. | * normalized to -1 for calls to ffs_indirtrunc below. | ||||
*/ | */ | ||||
for (level = TRIPLE; level >= SINGLE; level--) { | for (level = TRIPLE; level >= SINGLE; level--) { | ||||
oldblks[NDADDR + level] = DIP(ip, i_ib[level]); | oldblks[UFS_NDADDR + level] = DIP(ip, i_ib[level]); | ||||
if (lastiblock[level] < 0) { | if (lastiblock[level] < 0) { | ||||
DIP_SET(ip, i_ib[level], 0); | DIP_SET(ip, i_ib[level], 0); | ||||
lastiblock[level] = -1; | lastiblock[level] = -1; | ||||
} | } | ||||
} | } | ||||
for (i = 0; i < NDADDR; i++) { | for (i = 0; i < UFS_NDADDR; i++) { | ||||
oldblks[i] = DIP(ip, i_db[i]); | oldblks[i] = DIP(ip, i_db[i]); | ||||
if (i > lastblock) | if (i > lastblock) | ||||
DIP_SET(ip, i_db[i], 0); | DIP_SET(ip, i_db[i], 0); | ||||
} | } | ||||
ip->i_flag |= IN_CHANGE | IN_UPDATE; | ip->i_flag |= IN_CHANGE | IN_UPDATE; | ||||
allerror = ffs_update(vp, waitforupdate); | allerror = ffs_update(vp, waitforupdate); | ||||
/* | /* | ||||
* Having written the new inode to disk, save its new configuration | * Having written the new inode to disk, save its new configuration | ||||
* and put back the old block pointers long enough to process them. | * and put back the old block pointers long enough to process them. | ||||
* Note that we save the new block configuration so we can check it | * Note that we save the new block configuration so we can check it | ||||
* when we are done. | * when we are done. | ||||
*/ | */ | ||||
for (i = 0; i < NDADDR; i++) { | for (i = 0; i < UFS_NDADDR; i++) { | ||||
newblks[i] = DIP(ip, i_db[i]); | newblks[i] = DIP(ip, i_db[i]); | ||||
DIP_SET(ip, i_db[i], oldblks[i]); | DIP_SET(ip, i_db[i], oldblks[i]); | ||||
} | } | ||||
for (i = 0; i < NIADDR; i++) { | for (i = 0; i < UFS_NIADDR; i++) { | ||||
newblks[NDADDR + i] = DIP(ip, i_ib[i]); | newblks[UFS_NDADDR + i] = DIP(ip, i_ib[i]); | ||||
DIP_SET(ip, i_ib[i], oldblks[NDADDR + i]); | DIP_SET(ip, i_ib[i], oldblks[UFS_NDADDR + i]); | ||||
} | } | ||||
ip->i_size = osize; | ip->i_size = osize; | ||||
DIP_SET(ip, i_size, osize); | DIP_SET(ip, i_size, osize); | ||||
error = vtruncbuf(vp, cred, length, fs->fs_bsize); | error = vtruncbuf(vp, cred, length, fs->fs_bsize); | ||||
if (error && (allerror == 0)) | if (error && (allerror == 0)) | ||||
allerror = error; | allerror = error; | ||||
/* | /* | ||||
* Indirect blocks first. | * Indirect blocks first. | ||||
*/ | */ | ||||
indir_lbn[SINGLE] = -NDADDR; | indir_lbn[SINGLE] = -UFS_NDADDR; | ||||
indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1; | indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1; | ||||
indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1; | indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1; | ||||
for (level = TRIPLE; level >= SINGLE; level--) { | for (level = TRIPLE; level >= SINGLE; level--) { | ||||
bn = DIP(ip, i_ib[level]); | bn = DIP(ip, i_ib[level]); | ||||
if (bn != 0) { | if (bn != 0) { | ||||
error = ffs_indirtrunc(ip, indir_lbn[level], | error = ffs_indirtrunc(ip, indir_lbn[level], | ||||
fsbtodb(fs, bn), lastiblock[level], level, &count); | fsbtodb(fs, bn), lastiblock[level], level, &count); | ||||
if (error) | if (error) | ||||
Show All 9 Lines | for (level = TRIPLE; level >= SINGLE; level--) { | ||||
} | } | ||||
if (lastiblock[level] >= 0) | if (lastiblock[level] >= 0) | ||||
goto done; | goto done; | ||||
} | } | ||||
/* | /* | ||||
* All whole direct blocks or frags. | * All whole direct blocks or frags. | ||||
*/ | */ | ||||
for (i = NDADDR - 1; i > lastblock; i--) { | for (i = UFS_NDADDR - 1; i > lastblock; i--) { | ||||
long bsize; | long bsize; | ||||
bn = DIP(ip, i_db[i]); | bn = DIP(ip, i_db[i]); | ||||
if (bn == 0) | if (bn == 0) | ||||
continue; | continue; | ||||
DIP_SET(ip, i_db[i], 0); | DIP_SET(ip, i_db[i], 0); | ||||
bsize = blksize(fs, ip, i); | bsize = blksize(fs, ip, i); | ||||
ffs_blkfree(ump, fs, ump->um_devvp, bn, bsize, ip->i_number, | ffs_blkfree(ump, fs, ump->um_devvp, bn, bsize, ip->i_number, | ||||
Show All 31 Lines | if (oldspace - newspace > 0) { | ||||
ffs_blkfree(ump, fs, ump->um_devvp, bn, | ffs_blkfree(ump, fs, ump->um_devvp, bn, | ||||
oldspace - newspace, ip->i_number, vp->v_type, NULL); | oldspace - newspace, ip->i_number, vp->v_type, NULL); | ||||
blocksreleased += btodb(oldspace - newspace); | blocksreleased += btodb(oldspace - newspace); | ||||
} | } | ||||
} | } | ||||
done: | done: | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
for (level = SINGLE; level <= TRIPLE; level++) | for (level = SINGLE; level <= TRIPLE; level++) | ||||
if (newblks[NDADDR + level] != DIP(ip, i_ib[level])) | if (newblks[UFS_NDADDR + level] != DIP(ip, i_ib[level])) | ||||
panic("ffs_truncate1"); | panic("ffs_truncate1"); | ||||
for (i = 0; i < NDADDR; i++) | for (i = 0; i < UFS_NDADDR; i++) | ||||
if (newblks[i] != DIP(ip, i_db[i])) | if (newblks[i] != DIP(ip, i_db[i])) | ||||
panic("ffs_truncate2"); | panic("ffs_truncate2"); | ||||
BO_LOCK(bo); | BO_LOCK(bo); | ||||
if (length == 0 && | if (length == 0 && | ||||
(fs->fs_magic != FS_UFS2_MAGIC || ip->i_din2->di_extsize == 0) && | (fs->fs_magic != FS_UFS2_MAGIC || ip->i_din2->di_extsize == 0) && | ||||
(bo->bo_dirty.bv_cnt > 0 || bo->bo_clean.bv_cnt > 0)) | (bo->bo_dirty.bv_cnt > 0 || bo->bo_clean.bv_cnt > 0)) | ||||
panic("ffs_truncate3"); | panic("ffs_truncate3"); | ||||
BO_UNLOCK(bo); | BO_UNLOCK(bo); | ||||
▲ Show 20 Lines • Show All 174 Lines • Show Last 20 Lines |