Changeset View
Standalone View
sys/ufs/ffs/ffs_alloc.c
Show First 20 Lines • Show All 216 Lines • ▼ Show 20 Lines | #ifdef QUOTA | ||||
(void) chkdq(ip, -btodb(size), cred, FORCE); | (void) chkdq(ip, -btodb(size), cred, FORCE); | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
#endif | #endif | ||||
if (reclaimed == 0 && (flags & IO_BUFLOCKED) == 0) { | if (reclaimed == 0 && (flags & IO_BUFLOCKED) == 0) { | ||||
reclaimed = 1; | reclaimed = 1; | ||||
softdep_request_cleanup(fs, ITOV(ip), cred, FLUSH_BLOCKS_WAIT); | softdep_request_cleanup(fs, ITOV(ip), cred, FLUSH_BLOCKS_WAIT); | ||||
goto retry; | goto retry; | ||||
} | } | ||||
if (ffs_fsfail_cleanup_locked(ump, 0)) { | |||||
UFS_UNLOCK(ump); | |||||
return (ENXIO); | |||||
} | |||||
if (reclaimed > 0 && | if (reclaimed > 0 && | ||||
ppsratecheck(&ump->um_last_fullmsg, &ump->um_secs_fullmsg, 1)) { | ppsratecheck(&ump->um_last_fullmsg, &ump->um_secs_fullmsg, 1)) { | ||||
UFS_UNLOCK(ump); | UFS_UNLOCK(ump); | ||||
ffs_fserr(fs, ip->i_number, "filesystem full"); | ffs_fserr(fs, ip->i_number, "filesystem full"); | ||||
uprintf("\n%s: write failed, filesystem is full\n", | uprintf("\n%s: write failed, filesystem is full\n", | ||||
fs->fs_fsmnt); | fs->fs_fsmnt); | ||||
} else { | } else { | ||||
UFS_UNLOCK(ump); | UFS_UNLOCK(ump); | ||||
▲ Show 20 Lines • Show All 209 Lines • ▼ Show 20 Lines | if (reclaimed == 0 && (flags & IO_BUFLOCKED) == 0) { | ||||
if (bp) { | if (bp) { | ||||
brelse(bp); | brelse(bp); | ||||
bp = NULL; | bp = NULL; | ||||
} | } | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
softdep_request_cleanup(fs, vp, cred, FLUSH_BLOCKS_WAIT); | softdep_request_cleanup(fs, vp, cred, FLUSH_BLOCKS_WAIT); | ||||
goto retry; | goto retry; | ||||
} | } | ||||
if (bp) | |||||
brelse(bp); | |||||
if (ffs_fsfail_cleanup_locked(ump, 0)) { | |||||
UFS_UNLOCK(ump); | |||||
return (ENXIO); | |||||
} | |||||
if (reclaimed > 0 && | if (reclaimed > 0 && | ||||
ppsratecheck(&ump->um_last_fullmsg, &ump->um_secs_fullmsg, 1)) { | ppsratecheck(&ump->um_last_fullmsg, &ump->um_secs_fullmsg, 1)) { | ||||
UFS_UNLOCK(ump); | UFS_UNLOCK(ump); | ||||
ffs_fserr(fs, ip->i_number, "filesystem full"); | ffs_fserr(fs, ip->i_number, "filesystem full"); | ||||
uprintf("\n%s: write failed, filesystem is full\n", | uprintf("\n%s: write failed, filesystem is full\n", | ||||
fs->fs_fsmnt); | fs->fs_fsmnt); | ||||
} else { | } else { | ||||
UFS_UNLOCK(ump); | UFS_UNLOCK(ump); | ||||
} | } | ||||
if (bp) | |||||
brelse(bp); | |||||
return (ENOSPC); | return (ENOSPC); | ||||
} | } | ||||
/* | /* | ||||
* Reallocate a sequence of blocks into a contiguous sequence of blocks. | * Reallocate a sequence of blocks into a contiguous sequence of blocks. | ||||
* | * | ||||
* The vnode and an array of buffer pointers for a range of sequential | * The vnode and an array of buffer pointers for a range of sequential | ||||
* logical blocks to be made contiguous is given. The allocator attempts | * logical blocks to be made contiguous is given. The allocator attempts | ||||
▲ Show 20 Lines • Show All 628 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct inode *pip; | struct inode *pip; | ||||
struct fs *fs; | struct fs *fs; | ||||
struct inode *ip; | struct inode *ip; | ||||
struct timespec ts; | struct timespec ts; | ||||
struct ufsmount *ump; | struct ufsmount *ump; | ||||
ino_t ino, ipref; | ino_t ino, ipref; | ||||
u_int cg; | u_int cg; | ||||
int error, error1, reclaimed; | int error, reclaimed; | ||||
*vpp = NULL; | *vpp = NULL; | ||||
pip = VTOI(pvp); | pip = VTOI(pvp); | ||||
ump = ITOUMP(pip); | ump = ITOUMP(pip); | ||||
fs = ump->um_fs; | fs = ump->um_fs; | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
reclaimed = 0; | reclaimed = 0; | ||||
Show All 18 Lines | retry: | ||||
} else { | } else { | ||||
if (fs->fs_contigdirs[cg] > 0) | if (fs->fs_contigdirs[cg] > 0) | ||||
fs->fs_contigdirs[cg]--; | fs->fs_contigdirs[cg]--; | ||||
} | } | ||||
ino = (ino_t)ffs_hashalloc(pip, cg, ipref, mode, 0, | ino = (ino_t)ffs_hashalloc(pip, cg, ipref, mode, 0, | ||||
(allocfcn_t *)ffs_nodealloccg); | (allocfcn_t *)ffs_nodealloccg); | ||||
if (ino == 0) | if (ino == 0) | ||||
goto noinodes; | goto noinodes; | ||||
/* | /* | ||||
* Get rid of the cached old vnode, force allocation of a new vnode | * Get rid of the cached old vnode, force allocation of a new vnode | ||||
* for this inode. | * for this inode. If this fails, release the allocated ino and | ||||
* return the error. | |||||
*/ | */ | ||||
error = ffs_vgetf(pvp->v_mount, ino, LK_EXCLUSIVE, vpp, FFSV_REPLACE); | if ((error = ffs_vgetf(pvp->v_mount, ino, LK_EXCLUSIVE, vpp, | ||||
if (error) { | FFSV_FORCEINSMQ | FFSV_REPLACE)) != 0) { | ||||
kib: Why do you unconditionally use FFSV_FORCEINSMQ ? This defeats forced unmounts.
(And I have a… | |||||
Done Inline ActionsYea, we did discuss this before, but I never finished following up on it, sorry about that. Could you elaborate on exactly how this defeats forced unmounts? We haven't seen any problems in testing. insmntque1() only starts rejecting new requests after MNTK_UNMOUNTF is set in dounmount(), and in ffs_unmount() one of the first things we do is call vfs_write_suspend_umnt(), which will block any further operations which might use FFSV_FORCEINSMQ and wait for any such operations in progress to complete. I don't see anything in between those two points which requires that insmntque1() will already be rejecting new vnodes, is there something of that nature that I'm overlooking? chs: Yea, we did discuss this before, but I never finished following up on it, sorry about that. | |||||
Not Done Inline ActionsThis might be indeed less an issue now that we suspend filesystem on unmount. Otherwise, always using FORCEINSMQ there means that umount cannot flush(9) vnodes that are being created after the unmount started, so it cannot ever finish. As you see, old code (on the left) only used FORCEINSMQ to recheck for dup alloc, but otherwise did vput() immediately, which together with ip->i_mode == 0 caused immediate reclamation, under the vnode lock. This is actually a nice property of the code, and I fill uneasy breaking it, even if suspend at unmount allows us to claim that the change is formally correct. Anyway, I will not block the change on this issue, lets work it out later. kib: This might be indeed less an issue now that we suspend filesystem on unmount. Otherwise… | |||||
error1 = ffs_vgetf(pvp->v_mount, ino, LK_EXCLUSIVE, vpp, | |||||
FFSV_FORCEINSMQ | FFSV_REPLACE); | |||||
ffs_vfree(pvp, ino, mode); | ffs_vfree(pvp, ino, mode); | ||||
if (error1 == 0) { | |||||
ip = VTOI(*vpp); | |||||
if (ip->i_mode) | |||||
goto dup_alloc; | |||||
UFS_INODE_SET_FLAG(ip, IN_MODIFIED); | |||||
vput(*vpp); | |||||
} | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | |||||
* We got an inode, so check mode and panic if it is already allocated. | |||||
*/ | |||||
ip = VTOI(*vpp); | ip = VTOI(*vpp); | ||||
if (ip->i_mode) { | if (ip->i_mode) { | ||||
dup_alloc: | |||||
printf("mode = 0%o, inum = %ju, fs = %s\n", | printf("mode = 0%o, inum = %ju, fs = %s\n", | ||||
ip->i_mode, (uintmax_t)ip->i_number, fs->fs_fsmnt); | ip->i_mode, (uintmax_t)ip->i_number, fs->fs_fsmnt); | ||||
panic("ffs_valloc: dup alloc"); | panic("ffs_valloc: dup alloc"); | ||||
} | } | ||||
if (DIP(ip, i_blocks) && (fs->fs_flags & FS_UNCLEAN) == 0) { /* XXX */ | if (DIP(ip, i_blocks) && (fs->fs_flags & FS_UNCLEAN) == 0) { /* XXX */ | ||||
printf("free inode %s/%lu had %ld blocks\n", | printf("free inode %s/%lu had %ld blocks\n", | ||||
fs->fs_fsmnt, (u_long)ino, (long)DIP(ip, i_blocks)); | fs->fs_fsmnt, (u_long)ino, (long)DIP(ip, i_blocks)); | ||||
DIP_SET(ip, i_blocks, 0); | DIP_SET(ip, i_blocks, 0); | ||||
Show All 22 Lines | retry: | ||||
} | } | ||||
return (0); | return (0); | ||||
noinodes: | noinodes: | ||||
if (reclaimed == 0) { | if (reclaimed == 0) { | ||||
reclaimed = 1; | reclaimed = 1; | ||||
softdep_request_cleanup(fs, pvp, cred, FLUSH_INODES_WAIT); | softdep_request_cleanup(fs, pvp, cred, FLUSH_INODES_WAIT); | ||||
goto retry; | goto retry; | ||||
} | } | ||||
if (ffs_fsfail_cleanup_locked(ump, 0)) { | |||||
UFS_UNLOCK(ump); | |||||
return (ENXIO); | |||||
} | |||||
if (ppsratecheck(&ump->um_last_fullmsg, &ump->um_secs_fullmsg, 1)) { | if (ppsratecheck(&ump->um_last_fullmsg, &ump->um_secs_fullmsg, 1)) { | ||||
UFS_UNLOCK(ump); | UFS_UNLOCK(ump); | ||||
ffs_fserr(fs, pip->i_number, "out of inodes"); | ffs_fserr(fs, pip->i_number, "out of inodes"); | ||||
uprintf("\n%s: create/symlink failed, no inodes free\n", | uprintf("\n%s: create/symlink failed, no inodes free\n", | ||||
fs->fs_fsmnt); | fs->fs_fsmnt); | ||||
} else { | } else { | ||||
UFS_UNLOCK(ump); | UFS_UNLOCK(ump); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,017 Lines • ▼ Show 20 Lines | ffs_blkfree_cg(ump, fs, devvp, bno, size, inum, dephd) | ||||
ufs2_daddr_t bno; | ufs2_daddr_t bno; | ||||
long size; | long size; | ||||
ino_t inum; | ino_t inum; | ||||
struct workhead *dephd; | struct workhead *dephd; | ||||
{ | { | ||||
struct mount *mp; | struct mount *mp; | ||||
struct cg *cgp; | struct cg *cgp; | ||||
struct buf *bp; | struct buf *bp; | ||||
daddr_t dbn; | |||||
ufs1_daddr_t fragno, cgbno; | ufs1_daddr_t fragno, cgbno; | ||||
int i, blk, frags, bbase, error; | int i, blk, frags, bbase, error; | ||||
u_int cg; | u_int cg; | ||||
u_int8_t *blksfree; | u_int8_t *blksfree; | ||||
struct cdev *dev; | struct cdev *dev; | ||||
cg = dtog(fs, bno); | cg = dtog(fs, bno); | ||||
if (devvp->v_type == VREG) { | if (devvp->v_type == VREG) { | ||||
Show All 16 Lines | #ifdef INVARIANTS | ||||
} | } | ||||
#endif | #endif | ||||
if ((u_int)bno >= fs->fs_size) { | if ((u_int)bno >= fs->fs_size) { | ||||
printf("bad block %jd, ino %lu\n", (intmax_t)bno, | printf("bad block %jd, ino %lu\n", (intmax_t)bno, | ||||
(u_long)inum); | (u_long)inum); | ||||
ffs_fserr(fs, inum, "bad block"); | ffs_fserr(fs, inum, "bad block"); | ||||
return; | return; | ||||
} | } | ||||
if ((error = ffs_getcg(fs, devvp, cg, 0, &bp, &cgp)) != 0) | if ((error = ffs_getcg(fs, devvp, cg, GB_CVTENXIO, &bp, &cgp)) != 0) { | ||||
if (!ffs_fsfail_cleanup(ump, error) || | |||||
!MOUNTEDSOFTDEP(UFSTOVFS(ump)) || devvp->v_type != VCHR) | |||||
return; | return; | ||||
if (devvp->v_type == VREG) | |||||
dbn = fragstoblks(fs, cgtod(fs, cg)); | |||||
else | |||||
dbn = fsbtodb(fs, cgtod(fs, cg)); | |||||
error = getblkx(devvp, dbn, dbn, fs->fs_cgsize, 0, 0, 0, &bp); | |||||
if (error != 0) { | |||||
printf("%s: unexpected error %d from getblkx\n", | |||||
__func__, error); | |||||
return; | |||||
} | |||||
softdep_setup_blkfree(UFSTOVFS(ump), bp, bno, | |||||
numfrags(fs, size), dephd); | |||||
bp->b_flags |= B_RELBUF | B_NOCACHE; | |||||
bp->b_flags &= ~B_CACHE; | |||||
bawrite(bp); | |||||
return; | |||||
} | |||||
cgbno = dtogd(fs, bno); | cgbno = dtogd(fs, bno); | ||||
blksfree = cg_blksfree(cgp); | blksfree = cg_blksfree(cgp); | ||||
UFS_LOCK(ump); | UFS_LOCK(ump); | ||||
if (size == fs->fs_bsize) { | if (size == fs->fs_bsize) { | ||||
fragno = fragstoblks(fs, cgbno); | fragno = fragstoblks(fs, cgbno); | ||||
if (!ffs_isfreeblock(fs, blksfree, fragno)) { | if (!ffs_isfreeblock(fs, blksfree, fragno)) { | ||||
if (devvp->v_type == VREG) { | if (devvp->v_type == VREG) { | ||||
UFS_UNLOCK(ump); | UFS_UNLOCK(ump); | ||||
▲ Show 20 Lines • Show All 503 Lines • ▼ Show 20 Lines | ffs_freefile(ump, fs, devvp, ino, mode, wkhd) | ||||
struct fs *fs; | struct fs *fs; | ||||
struct vnode *devvp; | struct vnode *devvp; | ||||
ino_t ino; | ino_t ino; | ||||
int mode; | int mode; | ||||
struct workhead *wkhd; | struct workhead *wkhd; | ||||
{ | { | ||||
struct cg *cgp; | struct cg *cgp; | ||||
struct buf *bp; | struct buf *bp; | ||||
daddr_t dbn; | |||||
int error; | int error; | ||||
u_int cg; | u_int cg; | ||||
u_int8_t *inosused; | u_int8_t *inosused; | ||||
struct cdev *dev; | struct cdev *dev; | ||||
ino_t cgino; | ino_t cgino; | ||||
cg = ino_to_cg(fs, ino); | cg = ino_to_cg(fs, ino); | ||||
if (devvp->v_type == VREG) { | if (devvp->v_type == VREG) { | ||||
/* devvp is a snapshot */ | /* devvp is a snapshot */ | ||||
MPASS(devvp->v_mount->mnt_data == ump); | MPASS(devvp->v_mount->mnt_data == ump); | ||||
dev = ump->um_devvp->v_rdev; | dev = ump->um_devvp->v_rdev; | ||||
} else if (devvp->v_type == VCHR) { | } else if (devvp->v_type == VCHR) { | ||||
/* devvp is a normal disk device */ | /* devvp is a normal disk device */ | ||||
dev = devvp->v_rdev; | dev = devvp->v_rdev; | ||||
} else { | } else { | ||||
bp = NULL; | bp = NULL; | ||||
return (0); | return (0); | ||||
} | } | ||||
if (ino >= fs->fs_ipg * fs->fs_ncg) | if (ino >= fs->fs_ipg * fs->fs_ncg) | ||||
panic("ffs_freefile: range: dev = %s, ino = %ju, fs = %s", | panic("ffs_freefile: range: dev = %s, ino = %ju, fs = %s", | ||||
devtoname(dev), (uintmax_t)ino, fs->fs_fsmnt); | devtoname(dev), (uintmax_t)ino, fs->fs_fsmnt); | ||||
if ((error = ffs_getcg(fs, devvp, cg, 0, &bp, &cgp)) != 0) | if ((error = ffs_getcg(fs, devvp, cg, GB_CVTENXIO, &bp, &cgp)) != 0) { | ||||
if (!ffs_fsfail_cleanup(ump, error) || | |||||
!MOUNTEDSOFTDEP(UFSTOVFS(ump)) || devvp->v_type != VCHR) | |||||
return (error); | return (error); | ||||
if (devvp->v_type == VREG) | |||||
dbn = fragstoblks(fs, cgtod(fs, cg)); | |||||
else | |||||
dbn = fsbtodb(fs, cgtod(fs, cg)); | |||||
error = getblkx(devvp, dbn, dbn, fs->fs_cgsize, 0, 0, 0, &bp); | |||||
if (error != 0) { | |||||
printf("%s: unexpected error %d from getblkx\n", | |||||
__func__, error); | |||||
return (error); | |||||
} | |||||
softdep_setup_inofree(UFSTOVFS(ump), bp, ino, wkhd); | |||||
bp->b_flags |= B_RELBUF | B_NOCACHE; | |||||
bp->b_flags &= ~B_CACHE; | |||||
bawrite(bp); | |||||
return (error); | |||||
} | |||||
inosused = cg_inosused(cgp); | inosused = cg_inosused(cgp); | ||||
cgino = ino % fs->fs_ipg; | cgino = ino % fs->fs_ipg; | ||||
if (isclr(inosused, cgino)) { | if (isclr(inosused, cgino)) { | ||||
printf("dev = %s, ino = %ju, fs = %s\n", devtoname(dev), | printf("dev = %s, ino = %ju, fs = %s\n", devtoname(dev), | ||||
(uintmax_t)ino, fs->fs_fsmnt); | (uintmax_t)ino, fs->fs_fsmnt); | ||||
if (fs->fs_ronly == 0) | if (fs->fs_ronly == 0) | ||||
panic("ffs_freefile: freeing free inode"); | panic("ffs_freefile: freeing free inode"); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 667 Lines • Show Last 20 Lines |
Why do you unconditionally use FFSV_FORCEINSMQ ? This defeats forced unmounts.
(And I have a memory that this was already discussed).