Attachment 'dirhash_lowmem_event_2008-6-28.patch'
Download 1 --- ufs_dirhash.c.orig 2008-06-05 16:24:13.000000000 -0700
2 +++ ufs_dirhash.c 2008-06-22 18:18:39.000000000 -0700
3 @@ -48,6 +48,7 @@
4 #include <sys/vnode.h>
5 #include <sys/mount.h>
6 #include <sys/sysctl.h>
7 +#include <sys/eventhandler.h>
8 #include <vm/uma.h>
9
10 #include <ufs/ufs/quota.h>
11 @@ -80,6 +81,9 @@
12 static int ufs_dirhashcheck = 0;
13 SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_docheck, CTLFLAG_RW, &ufs_dirhashcheck,
14 0, "enable extra sanity tests");
15 +static int ufs_dirhashlowmemcount = 0;
16 +SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_lowmemcount, CTLFLAG_RD,
17 + &ufs_dirhashlowmemcount, 0, "number of times low memory hook called");
18
19
20 static int ufsdirhash_hash(struct dirhash *dh, char *name, int namelen);
21 @@ -88,7 +92,9 @@
22 static int ufsdirhash_findslot(struct dirhash *dh, char *name, int namelen,
23 doff_t offset);
24 static doff_t ufsdirhash_getprev(struct direct *dp, doff_t offset);
25 +static int ufsdirhash_destroy(void);
26 static int ufsdirhash_recycle(int wanted);
27 +static void ufsdirhash_lowmem(void);
28 static void ufsdirhash_free_locked(struct inode *ip);
29
30 static uma_zone_t ufsdirhash_zone;
31 @@ -1075,17 +1081,71 @@
32 }
33
34 /*
35 - * Try to free up `wanted' bytes by stealing memory from existing
36 - * dirhashes. Returns zero with list locked if successful.
37 + * Delete the first dirhash on the list and reclaim its memory.
38 + * Assumes that ufsdirhash_list is locked, and leaves it locked.
39 + * If unable to obtain a lock on the first dirhash, moves down
40 + * the list until it can lock a dirhash and destroys it. Returns
41 + * the amount of memory freed, or -1 if unable to find any
42 + * dirhashes that can be destroyed.
43 */
44 static int
45 -ufsdirhash_recycle(int wanted)
46 +ufsdirhash_destroy()
47 {
48 struct dirhash *dh;
49 doff_t **hash;
50 u_int8_t *blkfree;
51 int i, mem, narrays;
52
53 + dh = TAILQ_FIRST(&ufsdirhash_list);
54 + if (dh == NULL)
55 + return (-1);
56 +
57 + /*
58 + * If we can't lock it it's in use and we don't want to
59 + * destroy it anyway. Go on to the next in the list.
60 + */
61 + while (lockmgr(&dh->dh_lock, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
62 + dh = TAILQ_NEXT(dh, dh_list);
63 + if (dh == NULL)
64 + return (-1);
65 + }
66 + KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list"));
67 +
68 + /* Remove it from the list and detach its memory. */
69 + TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
70 + dh->dh_onlist = 0;
71 + hash = dh->dh_hash;
72 + dh->dh_hash = NULL;
73 + blkfree = dh->dh_blkfree;
74 + dh->dh_blkfree = NULL;
75 + narrays = dh->dh_narrays;
76 + mem = dh->dh_memreq;
77 + dh->dh_memreq = 0;
78 +
79 + /* Unlock everything, free the detached memory. */
80 + ufsdirhash_release(dh);
81 + DIRHASHLIST_UNLOCK();
82 + for (i = 0; i < narrays; i++)
83 + DIRHASH_BLKFREE(hash[i]);
84 + FREE(hash, M_DIRHASH);
85 + FREE(blkfree, M_DIRHASH);
86 +
87 + /* Account for the returned memory. */
88 + DIRHASHLIST_LOCK();
89 + ufs_dirhashmem -= mem;
90 +
91 + return (mem);
92 +}
93 +
94 +/*
95 + * Try to free up `wanted' bytes by stealing memory from existing
96 + * dirhashes. Returns zero with list locked if successful.
97 + */
98 +static int
99 +ufsdirhash_recycle(int wanted)
100 +{
101 + struct dirhash *dh;
102 +
103 DIRHASHLIST_LOCK();
104 dh = TAILQ_FIRST(&ufsdirhash_list);
105 while (wanted + ufs_dirhashmem > ufs_dirhashmaxmem) {
106 @@ -1094,44 +1154,36 @@
107 DIRHASHLIST_UNLOCK();
108 return (-1);
109 }
110 - /*
111 - * If we can't lock it it's in use and we don't want to
112 - * recycle it anyway.
113 - */
114 - if (lockmgr(&dh->dh_lock, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
115 - dh = TAILQ_NEXT(dh, dh_list);
116 - continue;
117 - }
118 - KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list"));
119
120 - /* Remove it from the list and detach its memory. */
121 - TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
122 - dh->dh_onlist = 0;
123 - hash = dh->dh_hash;
124 - dh->dh_hash = NULL;
125 - blkfree = dh->dh_blkfree;
126 - dh->dh_blkfree = NULL;
127 - narrays = dh->dh_narrays;
128 - mem = dh->dh_memreq;
129 - dh->dh_memreq = 0;
130 + /* Try deleting a dirhash. Give up if we can't delete any. */
131 + if (ufsdirhash_destroy() < 0)
132 + return (-1);
133
134 - /* Unlock everything, free the detached memory. */
135 - ufsdirhash_release(dh);
136 - DIRHASHLIST_UNLOCK();
137 - for (i = 0; i < narrays; i++)
138 - DIRHASH_BLKFREE(hash[i]);
139 - FREE(hash, M_DIRHASH);
140 - FREE(blkfree, M_DIRHASH);
141 -
142 - /* Account for the returned memory, and repeat if necessary. */
143 - DIRHASHLIST_LOCK();
144 - ufs_dirhashmem -= mem;
145 + /* Repeat if necessary. */
146 dh = TAILQ_FIRST(&ufsdirhash_list);
147 }
148 /* Success; return with list locked. */
149 return (0);
150 }
151
152 +/*
153 + * Calback that frees some dirhashes when the system is low on virtual memory.
154 + */
155 +static void
156 +ufsdirhash_lowmem()
157 +{
158 + ufs_dirhashlowmemcount++;
159 +
160 + DIRHASHLIST_LOCK();
161 + if (ufs_dirhashmem > 0)
162 + /*
163 + * Try deleting only one dirhash for now, and don't bother
164 + * to check if it worked.
165 + */
166 + ufsdirhash_destroy();
167 + DIRHASHLIST_UNLOCK();
168 +}
169 +
170
171 void
172 ufsdirhash_init()
173 @@ -1140,6 +1192,10 @@
174 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
175 mtx_init(&ufsdirhash_mtx, "dirhash list", NULL, MTX_DEF);
176 TAILQ_INIT(&ufsdirhash_list);
177 +
178 + /* Register a callback function to handle low memory signals */
179 + EVENTHANDLER_REGISTER(vm_lowmem, ufsdirhash_lowmem, NULL,
180 + EVENTHANDLER_PRI_FIRST);
181 }
182
183 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.