Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 23 Mar 2011 05:13:54 +0000 (UTC)
From:      Kirk McKusick <mckusick@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r219895 - head/sys/ufs/ffs
Message-ID:  <201103230513.p2N5DsCb082175@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mckusick
Date: Wed Mar 23 05:13:54 2011
New Revision: 219895
URL: http://svn.freebsd.org/changeset/base/219895

Log:
  Add retry code analogous to the block allocation retry code
  to avoid running out of inodes.
  
  Reported by: Peter Holm

Modified:
  head/sys/ufs/ffs/ffs_alloc.c
  head/sys/ufs/ffs/ffs_extern.h
  head/sys/ufs/ffs/ffs_softdep.c

Modified: head/sys/ufs/ffs/ffs_alloc.c
==============================================================================
--- head/sys/ufs/ffs/ffs_alloc.c	Wed Mar 23 03:58:55 2011	(r219894)
+++ head/sys/ufs/ffs/ffs_alloc.c	Wed Mar 23 05:13:54 2011	(r219895)
@@ -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");

Modified: head/sys/ufs/ffs/ffs_extern.h
==============================================================================
--- head/sys/ufs/ffs/ffs_extern.h	Wed Mar 23 03:58:55 2011	(r219894)
+++ head/sys/ufs/ffs/ffs_extern.h	Wed Mar 23 05:13:54 2011	(r219895)
@@ -120,7 +120,7 @@ int	softdep_flushfiles(struct mount *, i
 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 *);
 

Modified: head/sys/ufs/ffs/ffs_softdep.c
==============================================================================
--- head/sys/ufs/ffs/ffs_softdep.c	Wed Mar 23 03:58:55 2011	(r219894)
+++ head/sys/ufs/ffs/ffs_softdep.c	Wed Mar 23 05:13:54 2011	(r219895)
@@ -1105,10 +1105,7 @@ static int *stat_countp;	/* statistic to
 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, prevdirre
 	 */
 	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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201103230513.p2N5DsCb082175>