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.