diff options
author | mckusick <mckusick@FreeBSD.org> | 2011-03-23 05:13:54 +0000 |
---|---|---|
committer | mckusick <mckusick@FreeBSD.org> | 2011-03-23 05:13:54 +0000 |
commit | becd8ff499be28f5359ad9fdca0b85ea9be14da9 (patch) | |
tree | 8a27ca3a265b35590bb64393feba6aab22904fc5 /sys/ufs/ffs | |
parent | 7ae3cbd3a04cf28576a5797a0e5aa08d67e30a38 (diff) | |
download | FreeBSD-src-becd8ff499be28f5359ad9fdca0b85ea9be14da9.zip FreeBSD-src-becd8ff499be28f5359ad9fdca0b85ea9be14da9.tar.gz |
Add retry code analogous to the block allocation retry code
to avoid running out of inodes.
Reported by: Peter Holm
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r-- | sys/ufs/ffs/ffs_alloc.c | 13 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_extern.h | 9 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 45 |
3 files changed, 46 insertions, 21 deletions
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index b5e00e6..44d1f32 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -219,7 +219,7 @@ nospace: #endif if (fs->fs_pendingblocks > 0 && reclaimed == 0) { reclaimed = 1; - softdep_request_cleanup(fs, ITOV(ip)); + softdep_request_cleanup(fs, ITOV(ip), FLUSH_BLOCKS_WAIT); goto retry; } UFS_UNLOCK(ump); @@ -420,7 +420,7 @@ nospace: */ if (fs->fs_pendingblocks > 0 && reclaimed == 0) { reclaimed = 1; - softdep_request_cleanup(fs, vp); + softdep_request_cleanup(fs, vp, FLUSH_BLOCKS_WAIT); UFS_UNLOCK(ump); if (bp) { brelse(bp); @@ -936,7 +936,7 @@ ffs_valloc(pvp, mode, cred, vpp) struct ufsmount *ump; ino_t ino, ipref; u_int cg; - int error, error1; + int error, error1, reclaimed; static struct timeval lastfail; static int curfail; @@ -946,6 +946,8 @@ ffs_valloc(pvp, mode, cred, vpp) ump = pip->i_ump; UFS_LOCK(ump); + reclaimed = 0; +retry: if (fs->fs_cstotal.cs_nifree == 0) goto noinodes; @@ -1019,6 +1021,11 @@ dup_alloc: (*vpp)->v_op = &ffs_vnodeops1; return (0); noinodes: + if (fs->fs_pendinginodes > 0 && reclaimed == 0) { + reclaimed = 1; + softdep_request_cleanup(fs, pvp, FLUSH_INODES_WAIT); + goto retry; + } UFS_UNLOCK(ump); if (ppsratecheck(&lastfail, &curfail, 1)) { ffs_fserr(fs, pip->i_number, "out of inodes"); diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index 7011623..4b93cea 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -120,7 +120,7 @@ int softdep_flushfiles(struct mount *, int, struct thread *); void softdep_update_inodeblock(struct inode *, struct buf *, int); void softdep_load_inodeblock(struct inode *); void softdep_freefile(struct vnode *, ino_t, int); -int softdep_request_cleanup(struct fs *, struct vnode *); +int softdep_request_cleanup(struct fs *, struct vnode *, int); void softdep_setup_freeblocks(struct inode *, off_t, int); void softdep_setup_inomapdep(struct buf *, struct inode *, ino_t); void softdep_setup_blkmapdep(struct buf *, struct mount *, ufs2_daddr_t, @@ -147,6 +147,13 @@ int softdep_waitidle(struct mount *); int softdep_prealloc(struct vnode *, int); int softdep_journal_lookup(struct mount *, struct vnode **); +/* + * Things to request flushing in softdep_request_cleanup() + */ +#define FLUSH_INODES 1 +#define FLUSH_INODES_WAIT 2 +#define FLUSH_BLOCKS 3 +#define FLUSH_BLOCKS_WAIT 4 int ffs_rdonly(struct inode *); diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 4964bed..76da0a2 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -1105,10 +1105,7 @@ static int *stat_countp; /* statistic to count in proc_waiting timeout */ static struct callout softdep_callout; static int req_pending; static int req_clear_inodedeps; /* syncer process flush some inodedeps */ -#define FLUSH_INODES 1 static int req_clear_remove; /* syncer process flush some freeblks */ -#define FLUSH_REMOVE 2 -#define FLUSH_REMOVE_WAIT 3 static long num_freeblkdep; /* number of freeblks workitems allocated */ /* @@ -7131,7 +7128,7 @@ newdirrem(bp, dp, ip, isrmdir, prevdirremp) */ ACQUIRE_LOCK(&lk); if (!(ip->i_flags & SF_SNAPSHOT) && num_dirrem > max_softdeps / 2) - (void) request_cleanup(ITOV(dp)->v_mount, FLUSH_REMOVE); + (void) request_cleanup(ITOV(dp)->v_mount, FLUSH_BLOCKS); num_dirrem += 1; FREE_LOCK(&lk); dirrem = malloc(sizeof(struct dirrem), @@ -10868,19 +10865,22 @@ softdep_slowdown(vp) /* * Called by the allocation routines when they are about to fail - * in the hope that we can free up some disk space. + * in the hope that we can free up the requested resource (inodes + * or disk space). * * First check to see if the work list has anything on it. If it has, - * clean up entries until we successfully free some space. Because this - * process holds inodes locked, we cannot handle any remove requests - * that might block on a locked inode as that could lead to deadlock. - * If the worklist yields no free space, encourage the syncer daemon - * to help us. In no event will we try for longer than tickdelay seconds. + * clean up entries until we successfully free the requested resource. + * Because this process holds inodes locked, we cannot handle any remove + * requests that might block on a locked inode as that could lead to + * deadlock. If the worklist yields none of the requested resource, + * encourage the syncer daemon to help us. In no event will we try for + * longer than tickdelay seconds. */ int -softdep_request_cleanup(fs, vp) +softdep_request_cleanup(fs, vp, resource) struct fs *fs; struct vnode *vp; + int resource; { struct ufsmount *ump; long starttime; @@ -10889,7 +10889,12 @@ softdep_request_cleanup(fs, vp) ump = VTOI(vp)->i_ump; mtx_assert(UFS_MTX(ump), MA_OWNED); - needed = fs->fs_cstotal.cs_nbfree + fs->fs_contigsumsize; + if (resource == FLUSH_BLOCKS_WAIT) + needed = fs->fs_cstotal.cs_nbfree + fs->fs_contigsumsize; + else if (resource == FLUSH_INODES_WAIT) + needed = fs->fs_cstotal.cs_nifree + 2; + else + return (0); starttime = time_second + tickdelay; /* * If we are being called because of a process doing a @@ -10903,7 +10908,10 @@ softdep_request_cleanup(fs, vp) if (error != 0) return (0); } - while (fs->fs_pendingblocks > 0 && fs->fs_cstotal.cs_nbfree <= needed) { + while ((resource == FLUSH_BLOCKS_WAIT && fs->fs_pendingblocks > 0 && + fs->fs_cstotal.cs_nbfree <= needed) || + (resource == FLUSH_INODES_WAIT && fs->fs_pendinginodes > 0 && + fs->fs_cstotal.cs_nifree <= needed)) { if (time_second > starttime) return (0); UFS_UNLOCK(ump); @@ -10916,7 +10924,7 @@ softdep_request_cleanup(fs, vp) UFS_LOCK(ump); continue; } - request_cleanup(UFSTOVFS(ump), FLUSH_REMOVE_WAIT); + request_cleanup(UFSTOVFS(ump), resource); FREE_LOCK(&lk); UFS_LOCK(ump); } @@ -10963,7 +10971,9 @@ request_cleanup(mp, resource) * Next, we attempt to speed up the syncer process. If that * is successful, then we allow the process to continue. */ - if (softdep_speedup() && resource != FLUSH_REMOVE_WAIT) + if (softdep_speedup() && + resource != FLUSH_BLOCKS_WAIT && + resource != FLUSH_INODES_WAIT) return(0); /* * If we are resource constrained on inode dependencies, try @@ -10978,13 +10988,14 @@ request_cleanup(mp, resource) switch (resource) { case FLUSH_INODES: + case FLUSH_INODES_WAIT: stat_ino_limit_push += 1; req_clear_inodedeps += 1; stat_countp = &stat_ino_limit_hit; break; - case FLUSH_REMOVE: - case FLUSH_REMOVE_WAIT: + case FLUSH_BLOCKS: + case FLUSH_BLOCKS_WAIT: stat_blk_limit_push += 1; req_clear_remove += 1; stat_countp = &stat_blk_limit_hit; |