]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/vm/vm_pageq.c
Add uma_zone_set_max() to add enforced limits to non vm obj backed zones.
[FreeBSD/FreeBSD.git] / sys / vm / vm_pageq.c
1 /*
2  *      (c)Copyright 1998, Matthew Dillon.  Terms for use and redistribution
3  *      are covered by the BSD Copyright as found in /usr/src/COPYRIGHT.
4  *
5  * $FreeBSD$
6  */
7
8 #include <sys/param.h>
9 #include <sys/systm.h>
10 #include <sys/lock.h>
11 #include <sys/malloc.h>
12 #include <sys/mutex.h>
13 #include <sys/proc.h>
14 #include <sys/vmmeter.h>
15 #include <sys/vnode.h>
16
17 #include <vm/vm.h>
18 #include <vm/vm_param.h>
19 #include <vm/vm_kern.h>
20 #include <vm/vm_object.h>
21 #include <vm/vm_page.h>
22 #include <vm/vm_pageout.h>
23 #include <vm/vm_pager.h>
24 #include <vm/vm_extern.h>
25
26 struct vpgqueues vm_page_queues[PQ_COUNT];
27 static struct mtx vm_pageq_mtx[PQ_COUNT];
28
29 void
30 vm_pageq_init(void) 
31 {
32         int i;
33
34         for (i = 0; i < PQ_L2_SIZE; i++) {
35                 vm_page_queues[PQ_FREE+i].cnt = &cnt.v_free_count;
36         }
37         for (i = 0; i < PQ_L2_SIZE; i++) {
38                 vm_page_queues[PQ_CACHE+i].cnt = &cnt.v_cache_count;
39         }
40         vm_page_queues[PQ_INACTIVE].cnt = &cnt.v_inactive_count;
41         vm_page_queues[PQ_ACTIVE].cnt = &cnt.v_active_count;
42         vm_page_queues[PQ_HOLD].cnt = &cnt.v_active_count;
43
44         for (i = 0; i < PQ_COUNT; i++) {
45                 TAILQ_INIT(&vm_page_queues[i].pl);
46                 mtx_init(&vm_pageq_mtx[i], "vm pageq mutex", MTX_DEF);
47         }
48 }
49
50 struct vpgqueues *
51 vm_pageq_aquire(int queue)
52 {
53         struct vpgqueues *vpq = NULL;
54
55         if (queue != PQ_NONE) {
56                 vpq = &vm_page_queues[queue];
57 #if 0
58                 mtx_lock(&vm_pageq_mtx[queue]);
59 #endif
60         }
61         return (vpq);
62 }
63
64 void
65 vm_pageq_release(struct vpgqueues *vpq)
66 {
67 #if 0
68         mtx_unlock(&vm_pageq_mtx[vpq - &vm_page_queues[0]]);
69 #endif
70 }
71
72 void
73 vm_pageq_requeue(vm_page_t m)
74 {
75         int queue = m->queue;
76         struct vpgqueues *vpq;
77
78         vpq = vm_pageq_aquire(queue);
79         TAILQ_REMOVE(&vpq->pl, m, pageq);
80         TAILQ_INSERT_TAIL(&vpq->pl, m, pageq);
81         vm_pageq_release(vpq);
82 }
83
84 /*
85  *      vm_pageq_enqueue:
86  *
87  */
88 void
89 vm_pageq_enqueue(int queue, vm_page_t m)
90 {
91         struct vpgqueues *vpq;
92
93         vpq = &vm_page_queues[queue];
94         m->queue = queue;
95         TAILQ_INSERT_TAIL(&vpq->pl, m, pageq);
96         ++*vpq->cnt;
97         ++vpq->lcnt;
98 }
99
100 /*
101  *      vm_add_new_page:
102  *
103  *      Add a new page to the freelist for use by the system.
104  *      Must be called at splhigh().
105  */
106 vm_page_t
107 vm_pageq_add_new_page(vm_offset_t pa)
108 {
109         vm_page_t m;
110
111         GIANT_REQUIRED;
112
113         ++cnt.v_page_count;
114         m = PHYS_TO_VM_PAGE(pa);
115         m->phys_addr = pa;
116         m->flags = 0;
117         m->pc = (pa >> PAGE_SHIFT) & PQ_L2_MASK;
118         vm_pageq_enqueue(m->pc + PQ_FREE, m);
119         return (m);
120 }
121
122 /*
123  * vm_pageq_remove_nowakeup:
124  *
125  *      vm_page_unqueue() without any wakeup
126  *
127  *      This routine must be called at splhigh().
128  *      This routine may not block.
129  */
130 void
131 vm_pageq_remove_nowakeup(vm_page_t m)
132 {
133         int queue = m->queue;
134         struct vpgqueues *pq;
135         if (queue != PQ_NONE) {
136                 pq = &vm_page_queues[queue];
137                 m->queue = PQ_NONE;
138                 TAILQ_REMOVE(&pq->pl, m, pageq);
139                 (*pq->cnt)--;
140                 pq->lcnt--;
141         }
142 }
143
144 /*
145  * vm_pageq_remove:
146  *
147  *      Remove a page from its queue.
148  *
149  *      This routine must be called at splhigh().
150  *      This routine may not block.
151  */
152 void
153 vm_pageq_remove(vm_page_t m)
154 {
155         int queue = m->queue;
156         struct vpgqueues *pq;
157
158         GIANT_REQUIRED;
159         if (queue != PQ_NONE) {
160                 m->queue = PQ_NONE;
161                 pq = &vm_page_queues[queue];
162                 TAILQ_REMOVE(&pq->pl, m, pageq);
163                 (*pq->cnt)--;
164                 pq->lcnt--;
165                 if ((queue - m->pc) == PQ_CACHE) {
166                         if (vm_paging_needed())
167                                 pagedaemon_wakeup();
168                 }
169         }
170 }
171
172 #if PQ_L2_SIZE > 1
173
174 /*
175  *      vm_pageq_find:
176  *
177  *      Find a page on the specified queue with color optimization.
178  *
179  *      The page coloring optimization attempts to locate a page
180  *      that does not overload other nearby pages in the object in
181  *      the cpu's L1 or L2 caches.  We need this optimization because 
182  *      cpu caches tend to be physical caches, while object spaces tend 
183  *      to be virtual.
184  *
185  *      This routine must be called at splvm().
186  *      This routine may not block.
187  *
188  *      This routine may only be called from the vm_page_list_find() macro
189  *      in vm_page.h
190  */
191 static __inline vm_page_t
192 _vm_pageq_find(int basequeue, int index)
193 {
194         int i;
195         vm_page_t m = NULL;
196         struct vpgqueues *pq;
197
198         GIANT_REQUIRED;
199         pq = &vm_page_queues[basequeue];
200
201         /*
202          * Note that for the first loop, index+i and index-i wind up at the
203          * same place.  Even though this is not totally optimal, we've already
204          * blown it by missing the cache case so we do not care.
205          */
206         for (i = PQ_L2_SIZE / 2; i > 0; --i) {
207                 if ((m = TAILQ_FIRST(&pq[(index + i) & PQ_L2_MASK].pl)) != NULL)
208                         break;
209
210                 if ((m = TAILQ_FIRST(&pq[(index - i) & PQ_L2_MASK].pl)) != NULL)
211                         break;
212         }
213         return (m);
214 }
215 #endif          /* PQ_L2_SIZE > 1 */
216
217 vm_page_t
218 vm_pageq_find(int basequeue, int index, boolean_t prefer_zero)
219 {
220         vm_page_t m;
221
222         GIANT_REQUIRED;
223
224 #if PQ_L2_SIZE > 1
225         if (prefer_zero) {
226                 m = TAILQ_LAST(&vm_page_queues[basequeue+index].pl, pglist);
227         } else {
228                 m = TAILQ_FIRST(&vm_page_queues[basequeue+index].pl);
229         }
230         if (m == NULL) {
231                 m = _vm_pageq_find(basequeue, index);
232         }
233 #else
234         if (prefer_zero) {
235                 m = TAILQ_LAST(&vm_page_queues[basequeue].pl, pglist);
236         } else {
237                 m = TAILQ_FIRST(&vm_page_queues[basequeue].pl);
238         }
239 #endif
240         return (m);
241 }
242