Attachment 'dirhash_lowmem_7-stable_2008-8-14.patch'
Download
Toggle line numbers
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.