Attachment 'dirhash_lowmem_event_2008-7-12.patch'
Download 1 ==== //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/dirhash.h#1 - /Users/snb/Documents/soc/perforce/snb-dirhash/sys-ufs-ufs/dirhash.h ====
2 --- /tmp/tmp.23276.25 2008-07-07 23:06:16.000000000 +0200
3 +++ /Users/snb/Documents/soc/perforce/snb-dirhash/sys-ufs-ufs/dirhash.h 2008-07-06 23:16:04.000000000 +0200
4 @@ -68,6 +68,12 @@
5 #define DH_SCOREINIT 8 /* initial dh_score when dirhash built */
6 #define DH_SCOREMAX 64 /* max dh_score value */
7
8 +/*
9 + * If a vm_lowmem signal is received, we will try to free memory by
10 + * deleting all hashes older than DH_RECLAIMAGE seconds.
11 + */
12 +#define DH_RECLAIMAGE 5
13 +
14 /*
15 * The main hash table has 2 levels. It is an array of pointers to
16 * blocks of DH_NBLKOFF offsets.
17 @@ -101,6 +107,8 @@
18
19 int dh_onlist; /* true if on the ufsdirhash_list chain */
20
21 + time_t dh_lastused; /* time the dirhash was last read or written*/
22 +
23 /* Protected by ufsdirhash_mtx. */
24 TAILQ_ENTRY(dirhash) dh_list; /* chain of all dirhashes */
25 };
26 ==== //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/ufs_dirhash.c#1 - /Users/snb/Documents/soc/perforce/snb-dirhash/sys-ufs-ufs/ufs_dirhash.c ====
27 --- /tmp/tmp.23276.28 2008-07-07 23:06:16.000000000 +0200
28 +++ /Users/snb/Documents/soc/perforce/snb-dirhash/sys-ufs-ufs/ufs_dirhash.c 2008-07-07 14:10:15.000000000 +0200
29 @@ -48,6 +48,8 @@
30 #include <sys/vnode.h>
31 #include <sys/mount.h>
32 #include <sys/sysctl.h>
33 +#include <sys/eventhandler.h>
34 +#include <sys/time.h>
35 #include <vm/uma.h>
36
37 #include <ufs/ufs/quota.h>
38 @@ -80,6 +82,9 @@
39 static int ufs_dirhashcheck = 0;
40 SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_docheck, CTLFLAG_RW, &ufs_dirhashcheck,
41 0, "enable extra sanity tests");
42 +static int ufs_dirhashlowmemcount = 0;
43 +SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_lowmemcount, CTLFLAG_RD,
44 + &ufs_dirhashlowmemcount, 0, "number of times low memory hook called");
45
46
47 static int ufsdirhash_hash(struct dirhash *dh, char *name, int namelen);
48 @@ -88,7 +93,9 @@
49 static int ufsdirhash_findslot(struct dirhash *dh, char *name, int namelen,
50 doff_t offset);
51 static doff_t ufsdirhash_getprev(struct direct *dp, doff_t offset);
52 +static int ufsdirhash_destroy(struct dirhash *dh);
53 static int ufsdirhash_recycle(int wanted);
54 +static void ufsdirhash_lowmem(void);
55 static void ufsdirhash_free_locked(struct inode *ip);
56
57 static uma_zone_t ufsdirhash_zone;
58 @@ -324,6 +331,7 @@
59 dh->dh_seqopt = 0;
60 dh->dh_seqoff = 0;
61 dh->dh_score = DH_SCOREINIT;
62 + dh->dh_lastused = time_second;
63
64 /*
65 * Use non-blocking mallocs so that we will revert to a linear
66 @@ -494,6 +502,9 @@
67 /* Update the score. */
68 if (dh->dh_score < DH_SCOREMAX)
69 dh->dh_score++;
70 +
71 + /* Update last used time. */
72 + dh->dh_lastused = time_second;
73 DIRHASHLIST_UNLOCK();
74
75 vp = ip->i_vnode;
76 @@ -736,6 +747,9 @@
77 dh->dh_hused++;
78 DH_ENTRY(dh, slot) = offset;
79
80 + /* Update last used time. */
81 + dh->dh_lastused = time_second;
82 +
83 /* Update the per-block summary info. */
84 ufsdirhash_adjfree(dh, offset, -DIRSIZ(0, dirp));
85 ufsdirhash_release(dh);
86 @@ -1075,6 +1089,46 @@
87 }
88
89 /*
90 + * Delete the given dirhash and reclaim its memory. Assumes that
91 + * ufsdirhash_list is locked, and leaves it locked. Also assumes
92 + * that dh is locked. Returns the amount of memory freed.
93 + */
94 +static int
95 +ufsdirhash_destroy(struct dirhash *dh)
96 +{
97 + doff_t **hash;
98 + u_int8_t *blkfree;
99 + int i, mem, narrays;
100 +
101 + KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list"));
102 +
103 + /* Remove it from the list and detach its memory. */
104 + TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
105 + dh->dh_onlist = 0;
106 + hash = dh->dh_hash;
107 + dh->dh_hash = NULL;
108 + blkfree = dh->dh_blkfree;
109 + dh->dh_blkfree = NULL;
110 + narrays = dh->dh_narrays;
111 + mem = dh->dh_memreq;
112 + dh->dh_memreq = 0;
113 +
114 + /* Unlock everything, free the detached memory. */
115 + ufsdirhash_release(dh);
116 + DIRHASHLIST_UNLOCK();
117 + for (i = 0; i < narrays; i++)
118 + DIRHASH_BLKFREE(hash[i]);
119 + FREE(hash, M_DIRHASH);
120 + FREE(blkfree, M_DIRHASH);
121 +
122 + /* Account for the returned memory. */
123 + DIRHASHLIST_LOCK();
124 + ufs_dirhashmem -= mem;
125 +
126 + return (mem);
127 +}
128 +
129 +/*
130 * Try to free up `wanted' bytes by stealing memory from existing
131 * dirhashes. Returns zero with list locked if successful.
132 */
133 @@ -1082,9 +1136,6 @@
134 ufsdirhash_recycle(int wanted)
135 {
136 struct dirhash *dh;
137 - doff_t **hash;
138 - u_int8_t *blkfree;
139 - int i, mem, narrays;
140
141 DIRHASHLIST_LOCK();
142 dh = TAILQ_FIRST(&ufsdirhash_list);
143 @@ -1094,6 +1145,7 @@
144 DIRHASHLIST_UNLOCK();
145 return (-1);
146 }
147 +
148 /*
149 * If we can't lock it it's in use and we don't want to
150 * recycle it anyway.
151 @@ -1102,36 +1154,54 @@
152 dh = TAILQ_NEXT(dh, dh_list);
153 continue;
154 }
155 - KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list"));
156
157 - /* Remove it from the list and detach its memory. */
158 - TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
159 - dh->dh_onlist = 0;
160 - hash = dh->dh_hash;
161 - dh->dh_hash = NULL;
162 - blkfree = dh->dh_blkfree;
163 - dh->dh_blkfree = NULL;
164 - narrays = dh->dh_narrays;
165 - mem = dh->dh_memreq;
166 - dh->dh_memreq = 0;
167 + ufsdirhash_destroy(dh);
168
169 - /* Unlock everything, free the detached memory. */
170 - ufsdirhash_release(dh);
171 - DIRHASHLIST_UNLOCK();
172 - for (i = 0; i < narrays; i++)
173 - DIRHASH_BLKFREE(hash[i]);
174 - FREE(hash, M_DIRHASH);
175 - FREE(blkfree, M_DIRHASH);
176 -
177 - /* Account for the returned memory, and repeat if necessary. */
178 - DIRHASHLIST_LOCK();
179 - ufs_dirhashmem -= mem;
180 + /* Repeat if necessary. */
181 dh = TAILQ_FIRST(&ufsdirhash_list);
182 }
183 /* Success; return with list locked. */
184 return (0);
185 }
186
187 +/*
188 + * Calback that frees some dirhashes when the system is low on virtual memory.
189 + */
190 +static void
191 +ufsdirhash_lowmem()
192 +{
193 + struct dirhash *dh;
194 + int memfreed = 0;
195 +
196 + ufs_dirhashlowmemcount++;
197 +
198 + DIRHASHLIST_LOCK();
199 + /*
200 + * Delete all dirhashes not used for more than DH_RECLAIMAGE seconds.
201 + * If we can't get a lock on the dirhash, it will be skipped.
202 + */
203 + for (dh = TAILQ_FIRST(&ufsdirhash_list); dh != NULL; dh =
204 + TAILQ_NEXT(dh, dh_list)) {
205 + if (time_second - dh->dh_lastused > DH_RECLAIMAGE &&
206 + lockmgr(&dh->dh_lock, LK_EXCLUSIVE | LK_NOWAIT, NULL))
207 + memfreed += ufsdirhash_destroy(dh);
208 + }
209 +
210 + /*
211 + * If no hashes were old enough, instead try deleting a single dirhash
212 + * from the end of the list.
213 + */
214 + dh = TAILQ_FIRST(&ufsdirhash_list);
215 + while (memfreed == 0 && dh != NULL) {
216 + if (lockmgr(&dh->dh_lock, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
217 + dh = TAILQ_NEXT(dh, dh_list);
218 + continue;
219 + }
220 + memfreed += ufsdirhash_destroy(dh);
221 + }
222 + DIRHASHLIST_UNLOCK();
223 +}
224 +
225
226 void
227 ufsdirhash_init()
228 @@ -1140,6 +1210,10 @@
229 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
230 mtx_init(&ufsdirhash_mtx, "dirhash list", NULL, MTX_DEF);
231 TAILQ_INIT(&ufsdirhash_list);
232 +
233 + /* Register a callback function to handle low memory signals */
234 + EVENTHANDLER_REGISTER(vm_lowmem, ufsdirhash_lowmem, NULL,
235 + EVENTHANDLER_PRI_FIRST);
236 }
237
238 void
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.