Attachment 'dirhash_lowmem_head_2008-10-12.patch'

Download

   1 Index: sys/ufs/ufs/ufs_dirhash.c
   2 ===================================================================
   3 --- sys/ufs/ufs/ufs_dirhash.c	(revision 183812)
   4 +++ sys/ufs/ufs/ufs_dirhash.c	(working copy)
   5 @@ -49,6 +49,8 @@
   6  #include <sys/refcount.h>
   7  #include <sys/sysctl.h>
   8  #include <sys/sx.h>
   9 +#include <sys/eventhandler.h>
  10 +#include <sys/time.h>
  11  #include <vm/uma.h>
  12  
  13  #include <ufs/ufs/quota.h>
  14 @@ -81,6 +83,13 @@
  15  static int ufs_dirhashcheck = 0;
  16  SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_docheck, CTLFLAG_RW, &ufs_dirhashcheck,
  17      0, "enable extra sanity tests");
  18 +static int ufs_dirhashlowmemcount = 0;
  19 +SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_lowmemcount, CTLFLAG_RD, 
  20 +    &ufs_dirhashlowmemcount, 0, "number of times low memory hook called");
  21 +static int ufs_dirhashreclaimage = 5;
  22 +SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_reclaimage, CTLFLAG_RW, 
  23 +    &ufs_dirhashreclaimage, 0, 
  24 +    "max time in seconds of hash inactivity before deletion in low VM events");
  25  
  26  
  27  static int ufsdirhash_hash(struct dirhash *dh, char *name, int namelen);
  28 @@ -90,6 +99,7 @@
  29  	   doff_t offset);
  30  static doff_t ufsdirhash_getprev(struct direct *dp, doff_t offset);
  31  static int ufsdirhash_recycle(int wanted);
  32 +static void ufsdirhash_lowmem(void);
  33  static void ufsdirhash_free_locked(struct inode *ip);
  34  
  35  static uma_zone_t	ufsdirhash_zone;
  36 @@ -107,6 +117,7 @@
  37  /* Protects: ufsdirhash_list, `dh_list' field, ufs_dirhashmem. */
  38  static struct mtx	ufsdirhash_mtx;
  39  
  40 +
  41  /*
  42   * Locking:
  43   *
  44 @@ -372,6 +383,7 @@
  45  	dh->dh_seqopt = 0;
  46  	dh->dh_seqoff = 0;
  47  	dh->dh_score = DH_SCOREINIT;
  48 +	dh->dh_lastused = time_second;
  49  
  50  	/*
  51  	 * Use non-blocking mallocs so that we will revert to a linear
  52 @@ -548,6 +560,9 @@
  53  	/* Update the score. */
  54  	if (dh->dh_score < DH_SCOREMAX)
  55  		dh->dh_score++;
  56 +
  57 +	/* Update last used time. */
  58 +	dh->dh_lastused = time_second;
  59  	DIRHASHLIST_UNLOCK();
  60  
  61  	vp = ip->i_vnode;
  62 @@ -790,6 +805,9 @@
  63  		dh->dh_hused++;
  64  	DH_ENTRY(dh, slot) = offset;
  65  
  66 +	/* Update last used time. */
  67 +	dh->dh_lastused = time_second;
  68 +
  69  	/* Update the per-block summary info. */
  70  	ufsdirhash_adjfree(dh, offset, -DIRSIZ(0, dirp));
  71  	ufsdirhash_release(dh);
  72 @@ -1129,6 +1147,46 @@
  73  }
  74  
  75  /*
  76 + * Delete the given dirhash and reclaim its memory. Assumes that 
  77 + * ufsdirhash_list is locked, and leaves it locked. Also assumes 
  78 + * that dh is locked. Returns the amount of memory freed.
  79 + */
  80 +static int
  81 +ufsdirhash_destroy(struct dirhash *dh)
  82 +{
  83 +	doff_t **hash;
  84 +	u_int8_t *blkfree;
  85 +	int i, mem, narrays;
  86 +
  87 +	KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list"));
  88 +
  89 +	/* Remove it from the list and detach its memory. */
  90 +	TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
  91 +	dh->dh_onlist = 0;
  92 +	hash = dh->dh_hash;
  93 +	dh->dh_hash = NULL;
  94 +	blkfree = dh->dh_blkfree;
  95 +	dh->dh_blkfree = NULL;
  96 +	narrays = dh->dh_narrays;
  97 +	mem = dh->dh_memreq;
  98 +	dh->dh_memreq = 0;
  99 +
 100 +	/* Unlock everything, free the detached memory. */
 101 +	ufsdirhash_release(dh);
 102 +	DIRHASHLIST_UNLOCK();
 103 +	for (i = 0; i < narrays; i++)
 104 +		DIRHASH_BLKFREE(hash[i]);
 105 +	FREE(hash, M_DIRHASH);
 106 +	FREE(blkfree, M_DIRHASH);
 107 +
 108 +	/* Account for the returned memory. */
 109 +	DIRHASHLIST_LOCK();
 110 +	ufs_dirhashmem -= mem;
 111 +
 112 +	return (mem);
 113 +}
 114 +
 115 +/*
 116   * Try to free up `wanted' bytes by stealing memory from existing
 117   * dirhashes. Returns zero with list locked if successful.
 118   */
 119 @@ -1136,9 +1194,6 @@
 120  ufsdirhash_recycle(int wanted)
 121  {
 122  	struct dirhash *dh;
 123 -	doff_t **hash;
 124 -	u_int8_t *blkfree;
 125 -	int i, mem, narrays;
 126  
 127  	DIRHASHLIST_LOCK();
 128  	dh = TAILQ_FIRST(&ufsdirhash_list);
 129 @@ -1148,6 +1203,7 @@
 130  			DIRHASHLIST_UNLOCK();
 131  			return (-1);
 132  		}
 133 +
 134  		/*
 135  		 * If we can't lock it it's in use and we don't want to
 136  		 * recycle it anyway.
 137 @@ -1156,37 +1212,60 @@
 138  			dh = TAILQ_NEXT(dh, dh_list);
 139  			continue;
 140  		}
 141 -		KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list"));
 142  
 143 -		/* Remove it from the list and detach its memory. */
 144 -		TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
 145 -		dh->dh_onlist = 0;
 146 -		hash = dh->dh_hash;
 147 -		dh->dh_hash = NULL;
 148 -		blkfree = dh->dh_blkfree;
 149 -		dh->dh_blkfree = NULL;
 150 -		narrays = dh->dh_narrays;
 151 -		mem = dh->dh_memreq;
 152 -		dh->dh_memreq = 0;
 153 +		ufsdirhash_destroy(dh);
 154  
 155 -		/* Unlock everything, free the detached memory. */
 156 -		ufsdirhash_release(dh);
 157 -		DIRHASHLIST_UNLOCK();
 158 -		for (i = 0; i < narrays; i++)
 159 -			DIRHASH_BLKFREE(hash[i]);
 160 -		FREE(hash, M_DIRHASH);
 161 -		FREE(blkfree, M_DIRHASH);
 162 -
 163 -		/* Account for the returned memory, and repeat if necessary. */
 164 -		DIRHASHLIST_LOCK();
 165 -		ufs_dirhashmem -= mem;
 166 +		/* Repeat if necessary. */
 167  		dh = TAILQ_FIRST(&ufsdirhash_list);
 168  	}
 169  	/* Success; return with list locked. */
 170  	return (0);
 171  }
 172  
 173 +/*
 174 + * Calback that frees some dirhashes when the system is low on virtual memory.
 175 + */
 176 +static void
 177 +ufsdirhash_lowmem()
 178 +{
 179 +	struct dirhash *dh;
 180 +	int memfreed = 0;
 181 +	/* XXX: this 10% may need to be adjusted */
 182 +	int memwanted = ufs_dirhashmem / 10;
 183  
 184 +	ufs_dirhashlowmemcount++;
 185 +
 186 +	DIRHASHLIST_LOCK();
 187 +	/* 
 188 +	 * Delete dirhashes not used for more than ufs_dirhashreclaimage 
 189 +	 * seconds. If we can't get a lock on the dirhash, it will be skipped.
 190 +	 */
 191 +	for (dh = TAILQ_FIRST(&ufsdirhash_list); dh != NULL; dh = 
 192 +	     TAILQ_NEXT(dh, dh_list)) {
 193 +		if (!sx_try_xlock(&dh->dh_lock))
 194 +			continue;
 195 +		if (time_second - dh->dh_lastused > ufs_dirhashreclaimage)
 196 +			memfreed += ufsdirhash_destroy(dh);
 197 +		/* Unlock if we didn't delete the dirhash */
 198 +		else
 199 +			ufsdirhash_release(dh);
 200 +	}
 201 +	
 202 +	/* 
 203 +	 * If not enough memory was freed, keep deleting hashes from the head 
 204 +	 * of the dirhash list. The ones closest to the head should be the 
 205 +	 * oldest. 
 206 +	 */
 207 +	for (dh = TAILQ_FIRST(&ufsdirhash_list); memfreed < memwanted &&
 208 +	     dh !=NULL; dh = TAILQ_NEXT(dh, dh_list)) {
 209 +		if (!sx_try_xlock(&dh->dh_lock))
 210 +			continue;
 211 +		memfreed += ufsdirhash_destroy(dh);
 212 +	}
 213 +	DIRHASHLIST_UNLOCK();
 214 +}
 215 +
 216 +
 217  void
 218  ufsdirhash_init()
 219  {
 220 @@ -1194,6 +1273,10 @@
 221  	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
 222  	mtx_init(&ufsdirhash_mtx, "dirhash list", NULL, MTX_DEF);
 223  	TAILQ_INIT(&ufsdirhash_list);
 224 +	
 225 +	/* Register a callback function to handle low memory signals */
 226 +	EVENTHANDLER_REGISTER(vm_lowmem, ufsdirhash_lowmem, NULL, 
 227 +	    EVENTHANDLER_PRI_FIRST);
 228  }
 229  
 230  void
 231 Index: sys/ufs/ufs/dirhash.h
 232 ===================================================================
 233 --- sys/ufs/ufs/dirhash.h	(revision 183812)
 234 +++ sys/ufs/ufs/dirhash.h	(working copy)
 235 @@ -105,6 +105,8 @@
 236  
 237  	int	dh_onlist;	/* true if on the ufsdirhash_list chain */
 238  
 239 +	time_t	dh_lastused;	/* time the dirhash was last read or written*/
 240 +
 241  	/* Protected by ufsdirhash_mtx. */
 242  	TAILQ_ENTRY(dirhash) dh_list;	/* chain of all dirhashes */
 243  };

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.

You are not allowed to attach a file to this page.