Changeset View
Changeset View
Standalone View
Standalone View
sys/ufs/ffs/ffs_balloc.c
Show First 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | if (size > fs->fs_bsize) | ||||
panic("ffs_balloc_ufs1: blk too big"); | panic("ffs_balloc_ufs1: blk too big"); | ||||
*bpp = NULL; | *bpp = NULL; | ||||
if (flags & IO_EXT) | if (flags & IO_EXT) | ||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
if (lbn < 0) | if (lbn < 0) | ||||
return (EFBIG); | return (EFBIG); | ||||
gbflags = (flags & BA_UNMAPPED) != 0 ? GB_UNMAPPED : 0; | gbflags = (flags & BA_UNMAPPED) != 0 ? GB_UNMAPPED : 0; | ||||
vn_seqc_write_begin(vp); | |||||
/* | /* | ||||
* If the next write will extend the file into a new block, | * If the next write will extend the file into a new block, | ||||
* and the file is currently composed of a fragment | * and the file is currently composed of a fragment | ||||
* this fragment has to be extended to be a full block. | * this fragment has to be extended to be a full block. | ||||
*/ | */ | ||||
lastlbn = lblkno(fs, ip->i_size); | lastlbn = lblkno(fs, ip->i_size); | ||||
if (lastlbn < UFS_NDADDR && lastlbn < lbn) { | if (lastlbn < UFS_NDADDR && lastlbn < lbn) { | ||||
nb = lastlbn; | nb = lastlbn; | ||||
osize = blksize(fs, ip, nb); | osize = blksize(fs, ip, nb); | ||||
if (osize < fs->fs_bsize && osize > 0) { | if (osize < fs->fs_bsize && osize > 0) { | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
error = ffs_realloccg(ip, nb, dp->di_db[nb], | error = ffs_realloccg(ip, nb, dp->di_db[nb], | ||||
ffs_blkpref_ufs1(ip, lastlbn, (int)nb, | ffs_blkpref_ufs1(ip, lastlbn, (int)nb, | ||||
&dp->di_db[0]), osize, (int)fs->fs_bsize, flags, | &dp->di_db[0]), osize, (int)fs->fs_bsize, flags, | ||||
cred, &bp); | cred, &bp); | ||||
if (error) | if (error) | ||||
return (error); | goto done; | ||||
if (DOINGSOFTDEP(vp)) | if (DOINGSOFTDEP(vp)) | ||||
softdep_setup_allocdirect(ip, nb, | softdep_setup_allocdirect(ip, nb, | ||||
dbtofsb(fs, bp->b_blkno), dp->di_db[nb], | dbtofsb(fs, bp->b_blkno), dp->di_db[nb], | ||||
fs->fs_bsize, osize, bp); | fs->fs_bsize, osize, bp); | ||||
ip->i_size = smalllblktosize(fs, nb + 1); | ip->i_size = smalllblktosize(fs, nb + 1); | ||||
dp->di_size = ip->i_size; | dp->di_size = ip->i_size; | ||||
dp->di_db[nb] = dbtofsb(fs, bp->b_blkno); | dp->di_db[nb] = dbtofsb(fs, bp->b_blkno); | ||||
UFS_INODE_SET_FLAG(ip, | UFS_INODE_SET_FLAG(ip, | ||||
Show All 13 Lines | if (lbn < UFS_NDADDR) { | ||||
if (flags & BA_METAONLY) | if (flags & BA_METAONLY) | ||||
panic("ffs_balloc_ufs1: BA_METAONLY for direct block"); | panic("ffs_balloc_ufs1: BA_METAONLY for direct block"); | ||||
nb = dp->di_db[lbn]; | nb = dp->di_db[lbn]; | ||||
if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) { | if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) { | ||||
if ((flags & BA_CLRBUF) != 0) { | if ((flags & BA_CLRBUF) != 0) { | ||||
error = bread(vp, lbn, fs->fs_bsize, NOCRED, | error = bread(vp, lbn, fs->fs_bsize, NOCRED, | ||||
&bp); | &bp); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | goto done; | ||||
} else { | } else { | ||||
bp = getblk(vp, lbn, fs->fs_bsize, 0, 0, | bp = getblk(vp, lbn, fs->fs_bsize, 0, 0, | ||||
gbflags); | gbflags); | ||||
if (bp == NULL) | if (bp == NULL) { | ||||
return (EIO); | error = EIO; | ||||
goto done; | |||||
} | |||||
vfs_bio_clrbuf(bp); | vfs_bio_clrbuf(bp); | ||||
} | } | ||||
bp->b_blkno = fsbtodb(fs, nb); | bp->b_blkno = fsbtodb(fs, nb); | ||||
*bpp = bp; | *bpp = bp; | ||||
return (0); | error = 0; | ||||
goto done; | |||||
} | } | ||||
if (nb != 0) { | if (nb != 0) { | ||||
/* | /* | ||||
* Consider need to reallocate a fragment. | * Consider need to reallocate a fragment. | ||||
*/ | */ | ||||
osize = fragroundup(fs, blkoff(fs, ip->i_size)); | osize = fragroundup(fs, blkoff(fs, ip->i_size)); | ||||
nsize = fragroundup(fs, size); | nsize = fragroundup(fs, size); | ||||
if (nsize <= osize) { | if (nsize <= osize) { | ||||
error = bread(vp, lbn, osize, NOCRED, &bp); | error = bread(vp, lbn, osize, NOCRED, &bp); | ||||
if (error) { | if (error) | ||||
return (error); | goto done; | ||||
} | |||||
bp->b_blkno = fsbtodb(fs, nb); | bp->b_blkno = fsbtodb(fs, nb); | ||||
} else { | } else { | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
error = ffs_realloccg(ip, lbn, dp->di_db[lbn], | error = ffs_realloccg(ip, lbn, dp->di_db[lbn], | ||||
ffs_blkpref_ufs1(ip, lbn, (int)lbn, | ffs_blkpref_ufs1(ip, lbn, (int)lbn, | ||||
&dp->di_db[0]), osize, nsize, flags, | &dp->di_db[0]), osize, nsize, flags, | ||||
cred, &bp); | cred, &bp); | ||||
if (error) | if (error) | ||||
return (error); | goto done; | ||||
if (DOINGSOFTDEP(vp)) | if (DOINGSOFTDEP(vp)) | ||||
softdep_setup_allocdirect(ip, lbn, | softdep_setup_allocdirect(ip, lbn, | ||||
dbtofsb(fs, bp->b_blkno), nb, | dbtofsb(fs, bp->b_blkno), nb, | ||||
nsize, osize, bp); | nsize, osize, bp); | ||||
} | } | ||||
} else { | } else { | ||||
if (ip->i_size < smalllblktosize(fs, lbn + 1)) | if (ip->i_size < smalllblktosize(fs, lbn + 1)) | ||||
nsize = fragroundup(fs, size); | nsize = fragroundup(fs, size); | ||||
else | else | ||||
nsize = fs->fs_bsize; | nsize = fs->fs_bsize; | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
error = ffs_alloc(ip, lbn, | error = ffs_alloc(ip, lbn, | ||||
ffs_blkpref_ufs1(ip, lbn, (int)lbn, &dp->di_db[0]), | ffs_blkpref_ufs1(ip, lbn, (int)lbn, &dp->di_db[0]), | ||||
nsize, flags, cred, &newb); | nsize, flags, cred, &newb); | ||||
if (error) | if (error) | ||||
return (error); | goto done; | ||||
bp = getblk(vp, lbn, nsize, 0, 0, gbflags); | bp = getblk(vp, lbn, nsize, 0, 0, gbflags); | ||||
bp->b_blkno = fsbtodb(fs, newb); | bp->b_blkno = fsbtodb(fs, newb); | ||||
if (flags & BA_CLRBUF) | if (flags & BA_CLRBUF) | ||||
vfs_bio_clrbuf(bp); | vfs_bio_clrbuf(bp); | ||||
if (DOINGSOFTDEP(vp)) | if (DOINGSOFTDEP(vp)) | ||||
softdep_setup_allocdirect(ip, lbn, newb, 0, | softdep_setup_allocdirect(ip, lbn, newb, 0, | ||||
nsize, 0, bp); | nsize, 0, bp); | ||||
} | } | ||||
dp->di_db[lbn] = dbtofsb(fs, bp->b_blkno); | dp->di_db[lbn] = dbtofsb(fs, bp->b_blkno); | ||||
UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE | IN_IBLKDATA); | UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE | IN_IBLKDATA); | ||||
*bpp = bp; | *bpp = bp; | ||||
return (0); | error = 0; | ||||
goto done; | |||||
} | } | ||||
/* | /* | ||||
* Determine the number of levels of indirection. | * Determine the number of levels of indirection. | ||||
*/ | */ | ||||
pref = 0; | pref = 0; | ||||
if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0) | if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0) | ||||
return(error); | goto done; | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
if (num < 1) | if (num < 1) | ||||
panic ("ffs_balloc_ufs1: ufs_getlbns returned indirect block"); | panic ("ffs_balloc_ufs1: ufs_getlbns returned indirect block"); | ||||
#endif | #endif | ||||
saved_inbdflush = curthread_pflags_set(TDP_INBDFLUSH); | saved_inbdflush = curthread_pflags_set(TDP_INBDFLUSH); | ||||
/* | /* | ||||
* Fetch the first indirect block allocating if necessary. | * Fetch the first indirect block allocating if necessary. | ||||
*/ | */ | ||||
--num; | --num; | ||||
nb = dp->di_ib[indirs[0].in_off]; | nb = dp->di_ib[indirs[0].in_off]; | ||||
allocib = NULL; | allocib = NULL; | ||||
allocblk = allociblk; | allocblk = allociblk; | ||||
lbns_remfree = lbns; | lbns_remfree = lbns; | ||||
if (nb == 0) { | if (nb == 0) { | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
pref = ffs_blkpref_ufs1(ip, lbn, -indirs[0].in_off - 1, | pref = ffs_blkpref_ufs1(ip, lbn, -indirs[0].in_off - 1, | ||||
(ufs1_daddr_t *)0); | (ufs1_daddr_t *)0); | ||||
if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, | if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, | ||||
flags, cred, &newb)) != 0) { | flags, cred, &newb)) != 0) { | ||||
curthread_pflags_restore(saved_inbdflush); | curthread_pflags_restore(saved_inbdflush); | ||||
return (error); | goto done; | ||||
} | } | ||||
pref = newb + fs->fs_frag; | pref = newb + fs->fs_frag; | ||||
nb = newb; | nb = newb; | ||||
MPASS(allocblk < allociblk + nitems(allociblk)); | MPASS(allocblk < allociblk + nitems(allociblk)); | ||||
MPASS(lbns_remfree < lbns + nitems(lbns)); | MPASS(lbns_remfree < lbns + nitems(lbns)); | ||||
*allocblk++ = nb; | *allocblk++ = nb; | ||||
*lbns_remfree++ = indirs[1].in_lbn; | *lbns_remfree++ = indirs[1].in_lbn; | ||||
bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, gbflags); | bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, gbflags); | ||||
▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | for (i = 1;;) { | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* If asked only for the indirect block, then return it. | * If asked only for the indirect block, then return it. | ||||
*/ | */ | ||||
if (flags & BA_METAONLY) { | if (flags & BA_METAONLY) { | ||||
curthread_pflags_restore(saved_inbdflush); | curthread_pflags_restore(saved_inbdflush); | ||||
*bpp = bp; | *bpp = bp; | ||||
return (0); | error = 0; | ||||
goto done; | |||||
} | } | ||||
/* | /* | ||||
* Get the data block, allocating if necessary. | * Get the data block, allocating if necessary. | ||||
*/ | */ | ||||
if (nb == 0) { | if (nb == 0) { | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
/* | /* | ||||
* If allocating metadata at the front of the cylinder | * If allocating metadata at the front of the cylinder | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | if (flags & IO_SYNC) { | ||||
bwrite(bp); | bwrite(bp); | ||||
} else { | } else { | ||||
if (bp->b_bufsize == fs->fs_bsize) | if (bp->b_bufsize == fs->fs_bsize) | ||||
bp->b_flags |= B_CLUSTEROK; | bp->b_flags |= B_CLUSTEROK; | ||||
bdwrite(bp); | bdwrite(bp); | ||||
} | } | ||||
curthread_pflags_restore(saved_inbdflush); | curthread_pflags_restore(saved_inbdflush); | ||||
*bpp = nbp; | *bpp = nbp; | ||||
return (0); | error = 0; | ||||
goto done; | |||||
} | } | ||||
brelse(bp); | brelse(bp); | ||||
if (flags & BA_CLRBUF) { | if (flags & BA_CLRBUF) { | ||||
int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT; | int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT; | ||||
if (seqcount != 0 && | if (seqcount != 0 && | ||||
(vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0 && | (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0 && | ||||
!(vm_page_count_severe() || buf_dirty_count_severe())) { | !(vm_page_count_severe() || buf_dirty_count_severe())) { | ||||
error = cluster_read(vp, ip->i_size, lbn, | error = cluster_read(vp, ip->i_size, lbn, | ||||
(int)fs->fs_bsize, NOCRED, | (int)fs->fs_bsize, NOCRED, | ||||
MAXBSIZE, seqcount, gbflags, &nbp); | MAXBSIZE, seqcount, gbflags, &nbp); | ||||
} else { | } else { | ||||
error = bread_gb(vp, lbn, (int)fs->fs_bsize, NOCRED, | error = bread_gb(vp, lbn, (int)fs->fs_bsize, NOCRED, | ||||
gbflags, &nbp); | gbflags, &nbp); | ||||
} | } | ||||
if (error) { | if (error) { | ||||
brelse(nbp); | brelse(nbp); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
} else { | } else { | ||||
nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, gbflags); | nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, gbflags); | ||||
nbp->b_blkno = fsbtodb(fs, nb); | nbp->b_blkno = fsbtodb(fs, nb); | ||||
} | } | ||||
curthread_pflags_restore(saved_inbdflush); | curthread_pflags_restore(saved_inbdflush); | ||||
*bpp = nbp; | *bpp = nbp; | ||||
return (0); | error = 0; | ||||
goto done; | |||||
fail: | fail: | ||||
curthread_pflags_restore(saved_inbdflush); | curthread_pflags_restore(saved_inbdflush); | ||||
/* | /* | ||||
* If we have failed to allocate any blocks, simply return the error. | * If we have failed to allocate any blocks, simply return the error. | ||||
* This is the usual case and avoids the need to fsync the file. | * This is the usual case and avoids the need to fsync the file. | ||||
*/ | */ | ||||
if (allocblk == allociblk && allocib == NULL && unwindidx == -1) | if (allocblk == allociblk && allocib == NULL && unwindidx == -1) | ||||
return (error); | goto done; | ||||
/* | /* | ||||
* If we have failed part way through block allocation, we | * If we have failed part way through block allocation, we | ||||
* have to deallocate any indirect blocks that we have allocated. | * have to deallocate any indirect blocks that we have allocated. | ||||
* We have to fsync the file before we start to get rid of all | * We have to fsync the file before we start to get rid of all | ||||
* of its dependencies so that we do not leave them dangling. | * of its dependencies so that we do not leave them dangling. | ||||
* We have to sync it at the end so that the soft updates code | * We have to sync it at the end so that the soft updates code | ||||
* does not find any untracked changes. Although this is really | * does not find any untracked changes. Although this is really | ||||
* slow, running out of disk space is not expected to be a common | * slow, running out of disk space is not expected to be a common | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | if (bp != NULL) { | ||||
(intmax_t)bp->b_lblkno, (uintmax_t)bp->b_blkno, | (intmax_t)bp->b_lblkno, (uintmax_t)bp->b_blkno, | ||||
(uintmax_t)fsbtodb(fs, *blkp)); | (uintmax_t)fsbtodb(fs, *blkp)); | ||||
} | } | ||||
lbns_remfree++; | lbns_remfree++; | ||||
#endif | #endif | ||||
ffs_blkfree(ump, fs, ump->um_devvp, *blkp, fs->fs_bsize, | ffs_blkfree(ump, fs, ump->um_devvp, *blkp, fs->fs_bsize, | ||||
ip->i_number, vp->v_type, NULL, SINGLETON_KEY); | ip->i_number, vp->v_type, NULL, SINGLETON_KEY); | ||||
} | } | ||||
done: | |||||
vn_seqc_write_end(vp); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Balloc defines the structure of file system storage | * Balloc defines the structure of file system storage | ||||
* by allocating the physical blocks on a device given | * by allocating the physical blocks on a device given | ||||
* the inode and the logical block number in a file. | * the inode and the logical block number in a file. | ||||
* This is the allocation strategy for UFS2. Above is | * This is the allocation strategy for UFS2. Above is | ||||
Show All 29 Lines | ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size, | ||||
reclaimed = 0; | reclaimed = 0; | ||||
if (size > fs->fs_bsize) | if (size > fs->fs_bsize) | ||||
panic("ffs_balloc_ufs2: blk too big"); | panic("ffs_balloc_ufs2: blk too big"); | ||||
*bpp = NULL; | *bpp = NULL; | ||||
if (lbn < 0) | if (lbn < 0) | ||||
return (EFBIG); | return (EFBIG); | ||||
gbflags = (flags & BA_UNMAPPED) != 0 ? GB_UNMAPPED : 0; | gbflags = (flags & BA_UNMAPPED) != 0 ? GB_UNMAPPED : 0; | ||||
vn_seqc_write_begin(vp); | |||||
/* | /* | ||||
* Check for allocating external data. | * Check for allocating external data. | ||||
*/ | */ | ||||
if (flags & IO_EXT) { | if (flags & IO_EXT) { | ||||
if (lbn >= UFS_NXADDR) | if (lbn >= UFS_NXADDR) { | ||||
return (EFBIG); | error = EFBIG; | ||||
goto done; | |||||
} | |||||
/* | /* | ||||
* If the next write will extend the data into a new block, | * If the next write will extend the data into a new block, | ||||
* and the data is currently composed of a fragment | * and the data is currently composed of a fragment | ||||
* this fragment has to be extended to be a full block. | * this fragment has to be extended to be a full block. | ||||
*/ | */ | ||||
lastlbn = lblkno(fs, dp->di_extsize); | lastlbn = lblkno(fs, dp->di_extsize); | ||||
if (lastlbn < lbn) { | if (lastlbn < lbn) { | ||||
nb = lastlbn; | nb = lastlbn; | ||||
osize = sblksize(fs, dp->di_extsize, nb); | osize = sblksize(fs, dp->di_extsize, nb); | ||||
if (osize < fs->fs_bsize && osize > 0) { | if (osize < fs->fs_bsize && osize > 0) { | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
error = ffs_realloccg(ip, -1 - nb, | error = ffs_realloccg(ip, -1 - nb, | ||||
dp->di_extb[nb], | dp->di_extb[nb], | ||||
ffs_blkpref_ufs2(ip, lastlbn, (int)nb, | ffs_blkpref_ufs2(ip, lastlbn, (int)nb, | ||||
&dp->di_extb[0]), osize, | &dp->di_extb[0]), osize, | ||||
(int)fs->fs_bsize, flags, cred, &bp); | (int)fs->fs_bsize, flags, cred, &bp); | ||||
if (error) | if (error) | ||||
return (error); | goto done; | ||||
if (DOINGSOFTDEP(vp)) | if (DOINGSOFTDEP(vp)) | ||||
softdep_setup_allocext(ip, nb, | softdep_setup_allocext(ip, nb, | ||||
dbtofsb(fs, bp->b_blkno), | dbtofsb(fs, bp->b_blkno), | ||||
dp->di_extb[nb], | dp->di_extb[nb], | ||||
fs->fs_bsize, osize, bp); | fs->fs_bsize, osize, bp); | ||||
dp->di_extsize = smalllblktosize(fs, nb + 1); | dp->di_extsize = smalllblktosize(fs, nb + 1); | ||||
dp->di_extb[nb] = dbtofsb(fs, bp->b_blkno); | dp->di_extb[nb] = dbtofsb(fs, bp->b_blkno); | ||||
bp->b_xflags |= BX_ALTDATA; | bp->b_xflags |= BX_ALTDATA; | ||||
Show All 9 Lines | if (flags & IO_EXT) { | ||||
* All blocks are direct blocks | * All blocks are direct blocks | ||||
*/ | */ | ||||
if (flags & BA_METAONLY) | if (flags & BA_METAONLY) | ||||
panic("ffs_balloc_ufs2: BA_METAONLY for ext block"); | panic("ffs_balloc_ufs2: BA_METAONLY for ext block"); | ||||
nb = dp->di_extb[lbn]; | nb = dp->di_extb[lbn]; | ||||
if (nb != 0 && dp->di_extsize >= smalllblktosize(fs, lbn + 1)) { | if (nb != 0 && dp->di_extsize >= smalllblktosize(fs, lbn + 1)) { | ||||
error = bread_gb(vp, -1 - lbn, fs->fs_bsize, NOCRED, | error = bread_gb(vp, -1 - lbn, fs->fs_bsize, NOCRED, | ||||
gbflags, &bp); | gbflags, &bp); | ||||
if (error) { | if (error) | ||||
return (error); | goto done; | ||||
} | |||||
bp->b_blkno = fsbtodb(fs, nb); | bp->b_blkno = fsbtodb(fs, nb); | ||||
bp->b_xflags |= BX_ALTDATA; | bp->b_xflags |= BX_ALTDATA; | ||||
*bpp = bp; | *bpp = bp; | ||||
return (0); | goto done; | ||||
} | } | ||||
if (nb != 0) { | if (nb != 0) { | ||||
/* | /* | ||||
* Consider need to reallocate a fragment. | * Consider need to reallocate a fragment. | ||||
*/ | */ | ||||
osize = fragroundup(fs, blkoff(fs, dp->di_extsize)); | osize = fragroundup(fs, blkoff(fs, dp->di_extsize)); | ||||
nsize = fragroundup(fs, size); | nsize = fragroundup(fs, size); | ||||
if (nsize <= osize) { | if (nsize <= osize) { | ||||
error = bread_gb(vp, -1 - lbn, osize, NOCRED, | error = bread_gb(vp, -1 - lbn, osize, NOCRED, | ||||
gbflags, &bp); | gbflags, &bp); | ||||
if (error) { | if (error) | ||||
return (error); | goto done; | ||||
} | |||||
bp->b_blkno = fsbtodb(fs, nb); | bp->b_blkno = fsbtodb(fs, nb); | ||||
bp->b_xflags |= BX_ALTDATA; | bp->b_xflags |= BX_ALTDATA; | ||||
} else { | } else { | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
error = ffs_realloccg(ip, -1 - lbn, | error = ffs_realloccg(ip, -1 - lbn, | ||||
dp->di_extb[lbn], | dp->di_extb[lbn], | ||||
ffs_blkpref_ufs2(ip, lbn, (int)lbn, | ffs_blkpref_ufs2(ip, lbn, (int)lbn, | ||||
&dp->di_extb[0]), osize, nsize, flags, | &dp->di_extb[0]), osize, nsize, flags, | ||||
cred, &bp); | cred, &bp); | ||||
if (error) | if (error) | ||||
return (error); | goto done; | ||||
bp->b_xflags |= BX_ALTDATA; | bp->b_xflags |= BX_ALTDATA; | ||||
if (DOINGSOFTDEP(vp)) | if (DOINGSOFTDEP(vp)) | ||||
softdep_setup_allocext(ip, lbn, | softdep_setup_allocext(ip, lbn, | ||||
dbtofsb(fs, bp->b_blkno), nb, | dbtofsb(fs, bp->b_blkno), nb, | ||||
nsize, osize, bp); | nsize, osize, bp); | ||||
} | } | ||||
} else { | } else { | ||||
if (dp->di_extsize < smalllblktosize(fs, lbn + 1)) | if (dp->di_extsize < smalllblktosize(fs, lbn + 1)) | ||||
nsize = fragroundup(fs, size); | nsize = fragroundup(fs, size); | ||||
else | else | ||||
nsize = fs->fs_bsize; | nsize = fs->fs_bsize; | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
error = ffs_alloc(ip, lbn, | error = ffs_alloc(ip, lbn, | ||||
ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_extb[0]), | ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_extb[0]), | ||||
nsize, flags, cred, &newb); | nsize, flags, cred, &newb); | ||||
if (error) | if (error) | ||||
return (error); | goto done; | ||||
bp = getblk(vp, -1 - lbn, nsize, 0, 0, gbflags); | bp = getblk(vp, -1 - lbn, nsize, 0, 0, gbflags); | ||||
bp->b_blkno = fsbtodb(fs, newb); | bp->b_blkno = fsbtodb(fs, newb); | ||||
bp->b_xflags |= BX_ALTDATA; | bp->b_xflags |= BX_ALTDATA; | ||||
if (flags & BA_CLRBUF) | if (flags & BA_CLRBUF) | ||||
vfs_bio_clrbuf(bp); | vfs_bio_clrbuf(bp); | ||||
if (DOINGSOFTDEP(vp)) | if (DOINGSOFTDEP(vp)) | ||||
softdep_setup_allocext(ip, lbn, newb, 0, | softdep_setup_allocext(ip, lbn, newb, 0, | ||||
nsize, 0, bp); | nsize, 0, bp); | ||||
} | } | ||||
dp->di_extb[lbn] = dbtofsb(fs, bp->b_blkno); | dp->di_extb[lbn] = dbtofsb(fs, bp->b_blkno); | ||||
UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_IBLKDATA); | UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_IBLKDATA); | ||||
*bpp = bp; | *bpp = bp; | ||||
return (0); | error = 0; | ||||
goto done; | |||||
} | } | ||||
/* | /* | ||||
* If the next write will extend the file into a new block, | * If the next write will extend the file into a new block, | ||||
* and the file is currently composed of a fragment | * and the file is currently composed of a fragment | ||||
* this fragment has to be extended to be a full block. | * this fragment has to be extended to be a full block. | ||||
*/ | */ | ||||
lastlbn = lblkno(fs, ip->i_size); | lastlbn = lblkno(fs, ip->i_size); | ||||
if (lastlbn < UFS_NDADDR && lastlbn < lbn) { | if (lastlbn < UFS_NDADDR && lastlbn < lbn) { | ||||
nb = lastlbn; | nb = lastlbn; | ||||
osize = blksize(fs, ip, nb); | osize = blksize(fs, ip, nb); | ||||
if (osize < fs->fs_bsize && osize > 0) { | if (osize < fs->fs_bsize && osize > 0) { | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
error = ffs_realloccg(ip, nb, dp->di_db[nb], | error = ffs_realloccg(ip, nb, dp->di_db[nb], | ||||
ffs_blkpref_ufs2(ip, lastlbn, (int)nb, | ffs_blkpref_ufs2(ip, lastlbn, (int)nb, | ||||
&dp->di_db[0]), osize, (int)fs->fs_bsize, | &dp->di_db[0]), osize, (int)fs->fs_bsize, | ||||
flags, cred, &bp); | flags, cred, &bp); | ||||
if (error) | if (error) | ||||
return (error); | goto done; | ||||
if (DOINGSOFTDEP(vp)) | if (DOINGSOFTDEP(vp)) | ||||
softdep_setup_allocdirect(ip, nb, | softdep_setup_allocdirect(ip, nb, | ||||
dbtofsb(fs, bp->b_blkno), | dbtofsb(fs, bp->b_blkno), | ||||
dp->di_db[nb], | dp->di_db[nb], | ||||
fs->fs_bsize, osize, bp); | fs->fs_bsize, osize, bp); | ||||
ip->i_size = smalllblktosize(fs, nb + 1); | ip->i_size = smalllblktosize(fs, nb + 1); | ||||
dp->di_size = ip->i_size; | dp->di_size = ip->i_size; | ||||
dp->di_db[nb] = dbtofsb(fs, bp->b_blkno); | dp->di_db[nb] = dbtofsb(fs, bp->b_blkno); | ||||
Show All 12 Lines | if (lbn < UFS_NDADDR) { | ||||
if (flags & BA_METAONLY) | if (flags & BA_METAONLY) | ||||
panic("ffs_balloc_ufs2: BA_METAONLY for direct block"); | panic("ffs_balloc_ufs2: BA_METAONLY for direct block"); | ||||
nb = dp->di_db[lbn]; | nb = dp->di_db[lbn]; | ||||
if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) { | if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) { | ||||
if ((flags & BA_CLRBUF) != 0) { | if ((flags & BA_CLRBUF) != 0) { | ||||
error = bread_gb(vp, lbn, fs->fs_bsize, NOCRED, | error = bread_gb(vp, lbn, fs->fs_bsize, NOCRED, | ||||
gbflags, &bp); | gbflags, &bp); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | goto done; | ||||
} else { | } else { | ||||
bp = getblk(vp, lbn, fs->fs_bsize, 0, 0, | bp = getblk(vp, lbn, fs->fs_bsize, 0, 0, | ||||
gbflags); | gbflags); | ||||
if (bp == NULL) | if (bp == NULL) { | ||||
return (EIO); | error = EIO; | ||||
goto done; | |||||
} | |||||
vfs_bio_clrbuf(bp); | vfs_bio_clrbuf(bp); | ||||
} | } | ||||
bp->b_blkno = fsbtodb(fs, nb); | bp->b_blkno = fsbtodb(fs, nb); | ||||
*bpp = bp; | *bpp = bp; | ||||
return (0); | error = 0; | ||||
goto done; | |||||
} | } | ||||
if (nb != 0) { | if (nb != 0) { | ||||
/* | /* | ||||
* Consider need to reallocate a fragment. | * Consider need to reallocate a fragment. | ||||
*/ | */ | ||||
osize = fragroundup(fs, blkoff(fs, ip->i_size)); | osize = fragroundup(fs, blkoff(fs, ip->i_size)); | ||||
nsize = fragroundup(fs, size); | nsize = fragroundup(fs, size); | ||||
if (nsize <= osize) { | if (nsize <= osize) { | ||||
error = bread_gb(vp, lbn, osize, NOCRED, | error = bread_gb(vp, lbn, osize, NOCRED, | ||||
gbflags, &bp); | gbflags, &bp); | ||||
if (error) { | if (error) | ||||
return (error); | goto done; | ||||
} | |||||
bp->b_blkno = fsbtodb(fs, nb); | bp->b_blkno = fsbtodb(fs, nb); | ||||
} else { | } else { | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
error = ffs_realloccg(ip, lbn, dp->di_db[lbn], | error = ffs_realloccg(ip, lbn, dp->di_db[lbn], | ||||
ffs_blkpref_ufs2(ip, lbn, (int)lbn, | ffs_blkpref_ufs2(ip, lbn, (int)lbn, | ||||
&dp->di_db[0]), osize, nsize, flags, | &dp->di_db[0]), osize, nsize, flags, | ||||
cred, &bp); | cred, &bp); | ||||
if (error) | if (error) | ||||
return (error); | goto done; | ||||
if (DOINGSOFTDEP(vp)) | if (DOINGSOFTDEP(vp)) | ||||
softdep_setup_allocdirect(ip, lbn, | softdep_setup_allocdirect(ip, lbn, | ||||
dbtofsb(fs, bp->b_blkno), nb, | dbtofsb(fs, bp->b_blkno), nb, | ||||
nsize, osize, bp); | nsize, osize, bp); | ||||
} | } | ||||
} else { | } else { | ||||
if (ip->i_size < smalllblktosize(fs, lbn + 1)) | if (ip->i_size < smalllblktosize(fs, lbn + 1)) | ||||
nsize = fragroundup(fs, size); | nsize = fragroundup(fs, size); | ||||
else | else | ||||
nsize = fs->fs_bsize; | nsize = fs->fs_bsize; | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
error = ffs_alloc(ip, lbn, | error = ffs_alloc(ip, lbn, | ||||
ffs_blkpref_ufs2(ip, lbn, (int)lbn, | ffs_blkpref_ufs2(ip, lbn, (int)lbn, | ||||
&dp->di_db[0]), nsize, flags, cred, &newb); | &dp->di_db[0]), nsize, flags, cred, &newb); | ||||
if (error) | if (error) | ||||
return (error); | goto done; | ||||
bp = getblk(vp, lbn, nsize, 0, 0, gbflags); | bp = getblk(vp, lbn, nsize, 0, 0, gbflags); | ||||
bp->b_blkno = fsbtodb(fs, newb); | bp->b_blkno = fsbtodb(fs, newb); | ||||
if (flags & BA_CLRBUF) | if (flags & BA_CLRBUF) | ||||
vfs_bio_clrbuf(bp); | vfs_bio_clrbuf(bp); | ||||
if (DOINGSOFTDEP(vp)) | if (DOINGSOFTDEP(vp)) | ||||
softdep_setup_allocdirect(ip, lbn, newb, 0, | softdep_setup_allocdirect(ip, lbn, newb, 0, | ||||
nsize, 0, bp); | nsize, 0, bp); | ||||
} | } | ||||
dp->di_db[lbn] = dbtofsb(fs, bp->b_blkno); | dp->di_db[lbn] = dbtofsb(fs, bp->b_blkno); | ||||
UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE | IN_IBLKDATA); | UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE | IN_IBLKDATA); | ||||
*bpp = bp; | *bpp = bp; | ||||
return (0); | error = 0; | ||||
goto done; | |||||
} | } | ||||
/* | /* | ||||
* Determine the number of levels of indirection. | * Determine the number of levels of indirection. | ||||
*/ | */ | ||||
pref = 0; | pref = 0; | ||||
if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0) | if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0) | ||||
return(error); | goto done; | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
if (num < 1) | if (num < 1) | ||||
panic ("ffs_balloc_ufs2: ufs_getlbns returned indirect block"); | panic ("ffs_balloc_ufs2: ufs_getlbns returned indirect block"); | ||||
#endif | #endif | ||||
saved_inbdflush = curthread_pflags_set(TDP_INBDFLUSH); | saved_inbdflush = curthread_pflags_set(TDP_INBDFLUSH); | ||||
/* | /* | ||||
* Fetch the first indirect block allocating if necessary. | * Fetch the first indirect block allocating if necessary. | ||||
*/ | */ | ||||
--num; | --num; | ||||
nb = dp->di_ib[indirs[0].in_off]; | nb = dp->di_ib[indirs[0].in_off]; | ||||
allocib = NULL; | allocib = NULL; | ||||
allocblk = allociblk; | allocblk = allociblk; | ||||
lbns_remfree = lbns; | lbns_remfree = lbns; | ||||
if (nb == 0) { | if (nb == 0) { | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
pref = ffs_blkpref_ufs2(ip, lbn, -indirs[0].in_off - 1, | pref = ffs_blkpref_ufs2(ip, lbn, -indirs[0].in_off - 1, | ||||
(ufs2_daddr_t *)0); | (ufs2_daddr_t *)0); | ||||
if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, | if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, | ||||
flags, cred, &newb)) != 0) { | flags, cred, &newb)) != 0) { | ||||
curthread_pflags_restore(saved_inbdflush); | curthread_pflags_restore(saved_inbdflush); | ||||
return (error); | goto done; | ||||
} | } | ||||
pref = newb + fs->fs_frag; | pref = newb + fs->fs_frag; | ||||
nb = newb; | nb = newb; | ||||
MPASS(allocblk < allociblk + nitems(allociblk)); | MPASS(allocblk < allociblk + nitems(allociblk)); | ||||
MPASS(lbns_remfree < lbns + nitems(lbns)); | MPASS(lbns_remfree < lbns + nitems(lbns)); | ||||
*allocblk++ = nb; | *allocblk++ = nb; | ||||
*lbns_remfree++ = indirs[1].in_lbn; | *lbns_remfree++ = indirs[1].in_lbn; | ||||
bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, | bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, | ||||
▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | for (i = 1;;) { | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* If asked only for the indirect block, then return it. | * If asked only for the indirect block, then return it. | ||||
*/ | */ | ||||
if (flags & BA_METAONLY) { | if (flags & BA_METAONLY) { | ||||
curthread_pflags_restore(saved_inbdflush); | curthread_pflags_restore(saved_inbdflush); | ||||
*bpp = bp; | *bpp = bp; | ||||
return (0); | error = 0; | ||||
goto done; | |||||
} | } | ||||
/* | /* | ||||
* Get the data block, allocating if necessary. | * Get the data block, allocating if necessary. | ||||
*/ | */ | ||||
if (nb == 0) { | if (nb == 0) { | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
/* | /* | ||||
* If allocating metadata at the front of the cylinder | * If allocating metadata at the front of the cylinder | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | if (flags & IO_SYNC) { | ||||
bwrite(bp); | bwrite(bp); | ||||
} else { | } else { | ||||
if (bp->b_bufsize == fs->fs_bsize) | if (bp->b_bufsize == fs->fs_bsize) | ||||
bp->b_flags |= B_CLUSTEROK; | bp->b_flags |= B_CLUSTEROK; | ||||
bdwrite(bp); | bdwrite(bp); | ||||
} | } | ||||
curthread_pflags_restore(saved_inbdflush); | curthread_pflags_restore(saved_inbdflush); | ||||
*bpp = nbp; | *bpp = nbp; | ||||
return (0); | error = 0; | ||||
goto done; | |||||
} | } | ||||
brelse(bp); | brelse(bp); | ||||
/* | /* | ||||
* If requested clear invalid portions of the buffer. If we | * If requested clear invalid portions of the buffer. If we | ||||
* have to do a read-before-write (typical if BA_CLRBUF is set), | * have to do a read-before-write (typical if BA_CLRBUF is set), | ||||
* try to do some read-ahead in the sequential case to reduce | * try to do some read-ahead in the sequential case to reduce | ||||
* the number of I/O transactions. | * the number of I/O transactions. | ||||
*/ | */ | ||||
Show All 14 Lines | if (error) { | ||||
goto fail; | goto fail; | ||||
} | } | ||||
} else { | } else { | ||||
nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, gbflags); | nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, gbflags); | ||||
nbp->b_blkno = fsbtodb(fs, nb); | nbp->b_blkno = fsbtodb(fs, nb); | ||||
} | } | ||||
curthread_pflags_restore(saved_inbdflush); | curthread_pflags_restore(saved_inbdflush); | ||||
*bpp = nbp; | *bpp = nbp; | ||||
return (0); | error = 0; | ||||
goto done; | |||||
fail: | fail: | ||||
curthread_pflags_restore(saved_inbdflush); | curthread_pflags_restore(saved_inbdflush); | ||||
/* | /* | ||||
* If we have failed to allocate any blocks, simply return the error. | * If we have failed to allocate any blocks, simply return the error. | ||||
* This is the usual case and avoids the need to fsync the file. | * This is the usual case and avoids the need to fsync the file. | ||||
*/ | */ | ||||
if (allocblk == allociblk && allocib == NULL && unwindidx == -1) | if (allocblk == allociblk && allocib == NULL && unwindidx == -1) | ||||
return (error); | goto done; | ||||
/* | /* | ||||
* If we have failed part way through block allocation, we | * If we have failed part way through block allocation, we | ||||
* have to deallocate any indirect blocks that we have allocated. | * have to deallocate any indirect blocks that we have allocated. | ||||
* We have to fsync the file before we start to get rid of all | * We have to fsync the file before we start to get rid of all | ||||
* of its dependencies so that we do not leave them dangling. | * of its dependencies so that we do not leave them dangling. | ||||
* We have to sync it at the end so that the soft updates code | * We have to sync it at the end so that the soft updates code | ||||
* does not find any untracked changes. Although this is really | * does not find any untracked changes. Although this is really | ||||
* slow, running out of disk space is not expected to be a common | * slow, running out of disk space is not expected to be a common | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | if (bp != NULL) { | ||||
(intmax_t)bp->b_lblkno, (uintmax_t)bp->b_blkno, | (intmax_t)bp->b_lblkno, (uintmax_t)bp->b_blkno, | ||||
(uintmax_t)fsbtodb(fs, *blkp)); | (uintmax_t)fsbtodb(fs, *blkp)); | ||||
} | } | ||||
lbns_remfree++; | lbns_remfree++; | ||||
#endif | #endif | ||||
ffs_blkfree(ump, fs, ump->um_devvp, *blkp, fs->fs_bsize, | ffs_blkfree(ump, fs, ump->um_devvp, *blkp, fs->fs_bsize, | ||||
ip->i_number, vp->v_type, NULL, SINGLETON_KEY); | ip->i_number, vp->v_type, NULL, SINGLETON_KEY); | ||||
} | } | ||||
done: | |||||
vn_seqc_write_end(vp); | |||||
return (error); | return (error); | ||||
} | } |