summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2011-03-23 05:13:54 +0000
committermckusick <mckusick@FreeBSD.org>2011-03-23 05:13:54 +0000
commitbecd8ff499be28f5359ad9fdca0b85ea9be14da9 (patch)
tree8a27ca3a265b35590bb64393feba6aab22904fc5 /sys/ufs
parent7ae3cbd3a04cf28576a5797a0e5aa08d67e30a38 (diff)
downloadFreeBSD-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')
-rw-r--r--sys/ufs/ffs/ffs_alloc.c13
-rw-r--r--sys/ufs/ffs/ffs_extern.h9
-rw-r--r--sys/ufs/ffs/ffs_softdep.c45
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;
OpenPOWER on IntegriCloud