Attachment 'dirhash_lowmem_7-stable_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 @@ -47,6 +47,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 @@ -79,6 +81,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 @@ -87,7 +96,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  
  36  static uma_zone_t	ufsdirhash_zone;
  37  
  38 @@ -215,6 +226,7 @@
  39  	dh->dh_seqopt = 0;
  40  	dh->dh_seqoff = 0;
  41  	dh->dh_score = DH_SCOREINIT;
  42 +	dh->dh_lastused = time_second;
  43  	ip->i_dirhash = dh;
  44  
  45  	bmask = VFSTOUFS(vp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
  46 @@ -377,6 +389,9 @@
  47  	if (dh->dh_score < DH_SCOREMAX)
  48  		dh->dh_score++;
  49  
  50 +	/* Update last used time. */
  51 +	dh->dh_lastused = time_second;
  52 +
  53  	vp = ip->i_vnode;
  54  	bmask = VFSTOUFS(vp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
  55  	blkoff = -1;
  56 @@ -643,6 +658,9 @@
  57  		dh->dh_hused++;
  58  	DH_ENTRY(dh, slot) = offset;
  59  
  60 +	/* Update last used time. */
  61 +	dh->dh_lastused = time_second;
  62 +
  63  	/* Update the per-block summary info. */
  64  	ufsdirhash_adjfree(dh, offset, -DIRSIZ(0, dirp));
  65  	DIRHASH_UNLOCK(dh);
  66 @@ -1014,6 +1032,48 @@
  67  }
  68  
  69  /*
  70 + * Delete the given dirhash and reclaim its memory. Assumes that 
  71 + * ufsdirhash_list is locked, and leaves it locked. Also assumes 
  72 + * that dh is locked. Returns the amount of memory freed.
  73 + */
  74 +static int
  75 +ufsdirhash_destroy(struct dirhash *dh)
  76 +{
  77 +	doff_t **hash;
  78 +	u_int8_t *blkfree;
  79 +	int i, mem, narrays;
  80 +
  81 +	KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list"));
  82 +
  83 +	/* Remove it from the list and detach its memory. */
  84 +	TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
  85 +	dh->dh_onlist = 0;
  86 +	hash = dh->dh_hash;
  87 +	dh->dh_hash = NULL;
  88 +	blkfree = dh->dh_blkfree;
  89 +	dh->dh_blkfree = NULL;
  90 +	narrays = dh->dh_narrays;
  91 +	mem = narrays * sizeof(*dh->dh_hash) +
  92 +	    narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) +
  93 +	    dh->dh_nblk * sizeof(*dh->dh_blkfree);
  94 +
  95 +	/* Unlock everything, free the detached memory. */
  96 +	DIRHASH_UNLOCK(dh);
  97 +	DIRHASHLIST_UNLOCK();
  98 +	for (i = 0; i < narrays; i++)
  99 +		DIRHASH_BLKFREE(hash[i]);
 100 +	FREE(hash, M_DIRHASH);
 101 +	FREE(blkfree, M_DIRHASH);
 102 +
 103 +	/* Account for the returned memory. */
 104 +	DIRHASHLIST_LOCK();
 105 +	ufs_dirhashmem -= mem;
 106 +
 107 +	return (mem);
 108 +}
 109 +
 110 +
 111 +/*
 112   * Try to free up `wanted' bytes by stealing memory from existing
 113   * dirhashes. Returns zero with list locked if successful.
 114   */
 115 @@ -1021,9 +1081,6 @@
 116  ufsdirhash_recycle(int wanted)
 117  {
 118  	struct dirhash *dh;
 119 -	doff_t **hash;
 120 -	u_int8_t *blkfree;
 121 -	int i, mem, narrays;
 122  
 123  	DIRHASHLIST_LOCK();
 124  	while (wanted + ufs_dirhashmem > ufs_dirhashmaxmem) {
 125 @@ -1033,7 +1090,6 @@
 126  			return (-1);
 127  		}
 128  		DIRHASH_LOCK(dh);
 129 -		KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list"));
 130  
 131  		/* Decrement the score; only recycle if it becomes zero. */
 132  		if (--dh->dh_score > 0) {
 133 @@ -1042,35 +1098,53 @@
 134  			return (-1);
 135  		}
 136  
 137 -		/* Remove it from the list and detach its memory. */
 138 -		TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
 139 -		dh->dh_onlist = 0;
 140 -		hash = dh->dh_hash;
 141 -		dh->dh_hash = NULL;
 142 -		blkfree = dh->dh_blkfree;
 143 -		dh->dh_blkfree = NULL;
 144 -		narrays = dh->dh_narrays;
 145 -		mem = narrays * sizeof(*dh->dh_hash) +
 146 -		    narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) +
 147 -		    dh->dh_nblk * sizeof(*dh->dh_blkfree);
 148 -
 149 -		/* Unlock everything, free the detached memory. */
 150 -		DIRHASH_UNLOCK(dh);
 151 -		DIRHASHLIST_UNLOCK();
 152 -		for (i = 0; i < narrays; i++)
 153 -			DIRHASH_BLKFREE(hash[i]);
 154 -		FREE(hash, M_DIRHASH);
 155 -		FREE(blkfree, M_DIRHASH);
 156 -
 157 -		/* Account for the returned memory, and repeat if necessary. */
 158 -		DIRHASHLIST_LOCK();
 159 -		ufs_dirhashmem -= mem;
 160 +		/* Destroy the dirhash, and repeat if necessary. */
 161 +		ufsdirhash_destroy(dh);
 162  	}
 163  	/* Success; return with list locked. */
 164  	return (0);
 165  }
 166  
 167 +/*
 168 + * Calback that frees some dirhashes when the system is low on virtual memory.
 169 + */
 170 +static void
 171 +ufsdirhash_lowmem()
 172 +{
 173 +	struct dirhash *dh;
 174 +	int memfreed = 0;
 175 +	/* XXX: this 10% may need to be adjusted */
 176 +	int memwanted = ufs_dirhashmem / 10;
 177  
 178 +	ufs_dirhashlowmemcount++;
 179 +
 180 +	DIRHASHLIST_LOCK();
 181 +	/* 
 182 +	 * Delete dirhashes not used for more than ufs_dirhashreclaimage 
 183 +	 * seconds.
 184 +	 */
 185 +	for (dh = TAILQ_FIRST(&ufsdirhash_list); dh != NULL; dh = 
 186 +	     TAILQ_NEXT(dh, dh_list)) {
 187 +		if (time_second - dh->dh_lastused > ufs_dirhashreclaimage) {
 188 +			DIRHASH_LOCK(dh);
 189 +			memfreed += ufsdirhash_destroy(dh);
 190 +		}
 191 +	}
 192 +	
 193 +	/* 
 194 +	 * If not enough memory was freed, keep deleting hashes from the head 
 195 +	 * of the dirhash list. The ones closest to the head should be the 
 196 +	 * oldest. 
 197 +	 */
 198 +	for (dh = TAILQ_FIRST(&ufsdirhash_list); memfreed < memwanted &&
 199 +	     dh !=NULL; dh = TAILQ_NEXT(dh, dh_list)) {
 200 +		DIRHASH_LOCK(dh);
 201 +		memfreed += ufsdirhash_destroy(dh);
 202 +	}
 203 +	DIRHASHLIST_UNLOCK();
 204 +}
 205 +
 206 +
 207  void
 208  ufsdirhash_init()
 209  {
 210 @@ -1078,6 +1152,11 @@
 211  	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
 212  	mtx_init(&ufsdirhash_mtx, "dirhash list", NULL, MTX_DEF);
 213  	TAILQ_INIT(&ufsdirhash_list);
 214 +
 215 +	/* Register a callback function to handle low memory signals */
 216 +	EVENTHANDLER_REGISTER(vm_lowmem, ufsdirhash_lowmem, NULL, 
 217 +	    EVENTHANDLER_PRI_FIRST);
 218 +
 219  }
 220  
 221  void
 222 Index: sys/ufs/ufs/dirhash.h
 223 ===================================================================
 224 --- sys/ufs/ufs/dirhash.h	(revision 181728)
 225 +++ sys/ufs/ufs/dirhash.h	(working copy)
 226 @@ -100,6 +100,8 @@
 227  
 228  	int	dh_onlist;	/* true if on the ufsdirhash_list chain */
 229  
 230 +	time_t	dh_lastused;	/* time the dirhash was last read or written*/
 231 +
 232  	/* Protected by ufsdirhash_mtx. */
 233  	TAILQ_ENTRY(dirhash) dh_list;	/* chain of all dirhashes */
 234  };

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.