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.