PERFORCE change 144800 for review

Nick Barkas snb at FreeBSD.org
Sun Jul 6 21:16:24 UTC 2008


http://perforce.freebsd.org/chv.cgi?CH=144800

Change 144800 by snb at snb_toro on 2008/07/06 21:16:04

	Upon receipt of vm_lowmem() signals, try deleting all dirhashes older
	       than DH_RECLAIMAGE, set here to five seconds for now. If all the
	       dirhashes are newer than this, just fall back to trying to delete the
	       one at the beginning of ufsdirhash_list.
	
	       DH_RECLAIMAGE probably will need tweaking, and so far dh_lastused is
	       only being updated during calls to ufsdirhash_build(),
	       ufsdirhash_lookup(), and ufsdirhash_add(). It may need to be updated
	       when other functions are called as well. Also, I have not yet tested
	       this code. This is a check point before I lose my network connection.

Affected files ...

.. //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/dirhash.h#2 edit
.. //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/ufs_dirhash.c#5 edit

Differences ...

==== //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/dirhash.h#2 (text+ko) ====

@@ -68,6 +68,12 @@
 #define DH_SCOREINIT	8	/* initial dh_score when dirhash built */
 #define DH_SCOREMAX	64	/* max dh_score value */
 
+/* 
+ * If a vm_lowmem signal is received, we will try to free memory by 
+ * deleting all hashes older than DH_RECLAIMAGE seconds. 
+ */
+#define DH_RECLAIMAGE	5
+
 /*
  * The main hash table has 2 levels. It is an array of pointers to
  * blocks of DH_NBLKOFF offsets.
@@ -101,6 +107,8 @@
 
 	int	dh_onlist;	/* true if on the ufsdirhash_list chain */
 
+	time_t	dh_lastused;	/* time the dirhash was last read or written*/
+
 	/* Protected by ufsdirhash_mtx. */
 	TAILQ_ENTRY(dirhash) dh_list;	/* chain of all dirhashes */
 };

==== //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/ufs_dirhash.c#5 (text+ko) ====

@@ -49,6 +49,7 @@
 #include <sys/mount.h>
 #include <sys/sysctl.h>
 #include <sys/eventhandler.h>
+#include <sys/time.h>
 #include <vm/uma.h>
 
 #include <ufs/ufs/quota.h>
@@ -92,7 +93,8 @@
 static int ufsdirhash_findslot(struct dirhash *dh, char *name, int namelen,
 	   doff_t offset);
 static doff_t ufsdirhash_getprev(struct direct *dp, doff_t offset);
-static int ufsdirhash_destroy(void);
+static int ufsdirhash_destroy(struct dirhash *dh);
+static int ufsdirhash_destroy_first(void);
 static int ufsdirhash_recycle(int wanted);
 static void ufsdirhash_lowmem(void);
 static void ufsdirhash_free_locked(struct inode *ip);
@@ -330,6 +332,7 @@
 	dh->dh_seqopt = 0;
 	dh->dh_seqoff = 0;
 	dh->dh_score = DH_SCOREINIT;
+	dh->dh_lastused = time_second;
 
 	/*
 	 * Use non-blocking mallocs so that we will revert to a linear
@@ -500,6 +503,9 @@
 	/* Update the score. */
 	if (dh->dh_score < DH_SCOREMAX)
 		dh->dh_score++;
+
+	/* Update last used time. */
+	dh->dh_lastused = time_second;
 	DIRHASHLIST_UNLOCK();
 
 	vp = ip->i_vnode;
@@ -742,6 +748,9 @@
 		dh->dh_hused++;
 	DH_ENTRY(dh, slot) = offset;
 
+	/* Update last used time. */
+	dh->dh_lastused = time_second;
+
 	/* Update the per-block summary info. */
 	ufsdirhash_adjfree(dh, offset, -DIRSIZ(0, dirp));
 	ufsdirhash_release(dh);
@@ -1081,34 +1090,17 @@
 }
 
 /*
- * Delete the first dirhash on the list and reclaim its memory. 
- * Assumes that ufsdirhash_list is locked, and leaves it locked. 
- * If unable to obtain a lock on the first dirhash, moves down 
- * the list until it can lock a dirhash and destroys it. Returns 
- * the amount of memory freed, or -1 if unable to find any 
- * dirhashes that can be destroyed.
+ * Delete the given dirhash and reclaim its memory. Assumes that 
+ * ufsdirhash_list is locked, and leaves it locked. Also assumes 
+ * that dh is locked. Returns the amount of memory freed.
  */
 static int
-ufsdirhash_destroy()
+ufsdirhash_destroy(struct dirhash *dh)
 {
-	struct dirhash *dh;
 	doff_t **hash;
 	u_int8_t *blkfree;
 	int i, mem, narrays;
 
-	dh = TAILQ_FIRST(&ufsdirhash_list);
-	if (dh == NULL)
-		return (-1);
-
-	/*
-	 * If we can't lock it it's in use and we don't want to
-	 * destroy it anyway. Go on to the next in the list.
-	 */
-	while (lockmgr(&dh->dh_lock, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
-		dh = TAILQ_NEXT(dh, dh_list);
-		if (dh == NULL)
-			return (-1);
-	}
 	KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list"));
 
 	/* Remove it from the list and detach its memory. */
@@ -1132,7 +1124,7 @@
 
 	/* Account for the returned memory. */
 	DIRHASHLIST_LOCK();
-	ufs_dirhashmem -= mem;	
+	ufs_dirhashmem -= mem;
 
 	return (mem);
 }
@@ -1155,9 +1147,16 @@
 			return (-1);
 		}
 
-		/* Try deleting a dirhash. Give up if we can't delete any. */
-		if (ufsdirhash_destroy() < 0)
-			return (-1);
+		/*
+		 * If we can't lock it it's in use and we don't want to
+		 * recycle it anyway.
+		 */
+		if (lockmgr(&dh->dh_lock, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
+			dh = TAILQ_NEXT(dh, dh_list);
+			continue;
+		}
+
+		ufsdirhash_destroy(dh);
 
 		/* Repeat if necessary. */
 		dh = TAILQ_FIRST(&ufsdirhash_list);
@@ -1172,15 +1171,35 @@
 static void
 ufsdirhash_lowmem()
 {
+	struct dirhash *dh;
+	int memfreed = 0;
+
 	ufs_dirhashlowmemcount++;
 
 	DIRHASHLIST_LOCK();
-	if (ufs_dirhashmem > 0)
-		/* 
-		 * Try deleting only one dirhash for now, and don't bother  
-		 * to check if it worked.
-		 */
-		ufsdirhash_destroy();
+	/* 
+	 * Delete all dirhashes not used for more than DH_RECLAIMAGE seconds. 
+	 * If we can't get a lock on the dirhash, it will be skipped.
+	 */
+	for (dh = TAILQ_FIRST(&ufsdirhash_list); dh != NULL; dh = 
+	     TAILQ_NEXT(dh, dh_list)) {
+		if (time_second - dh->dh_lastused > DH_RECLAIMAGE && 
+		    lockmgr(&dh->dh_lock, LK_EXCLUSIVE | LK_NOWAIT, NULL))
+			memfreed += ufsdirhash_destroy(dh);
+	}
+	
+	/* 
+	 * If no hashes were old enough, instead try deleting a single dirhash 
+	 * from the end of the list.
+	 */
+	dh = TAILQ_FIRST(&ufsdirhash_list);
+	while (memfreed == 0 && dh != NULL) {
+		if (lockmgr(&dh->dh_lock, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
+			dh = TAILQ_NEXT(dh, dh_list);
+			continue;
+		}
+		memfreed += ufsdirhash_destroy(dh);
+	}
 	DIRHASHLIST_UNLOCK();
 }
 


More information about the p4-projects mailing list