Attachment 'dirhash_lowmem_head_2008-8-14.patch'

Download

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

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.