12 |
\subsection{Function kswapd\_init()} |
\subsection{Function kswapd\_init()} |
13 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
14 |
\textit{Prototype: } |
\textit{Prototype: } |
15 |
\begin{verbatim} |
\begin{verbatim} |
16 |
static int __init kswapd_init(void) |
static int __init kswapd_init(void) |
17 |
\end{verbatim} |
\end{verbatim} |
18 |
|
|
19 |
This initialization function simply performs any necessary swap |
This initialization function simply performs any necessary swap |
20 |
setup and starts \texttt{kswapd()} function as a kernel thread. |
setup and starts \texttt{kswapd()} function as a kernel thread. |
21 |
|
|
22 |
\begin{verbatim} |
\begin{verbatim} |
23 |
printk("Starting kswapd\n"); |
printk("Starting kswapd\n"); |
24 |
swap_setup(); |
swap_setup(); |
25 |
kernel_thread(kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); |
kernel_thread(kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); |
26 |
return 0; |
return 0; |
27 |
\end{verbatim} |
\end{verbatim} |
28 |
|
|
29 |
\subsection{Function kswapd()} |
\subsection{Function kswapd()} |
30 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
31 |
\textit{Prototype: } |
\textit{Prototype: } |
32 |
\begin{verbatim} |
\begin{verbatim} |
33 |
int kswapd(void *unused) |
int kswapd(void *unused) |
34 |
\end{verbatim} |
\end{verbatim} |
35 |
|
|
36 |
The \texttt{kswap()} function is run as a kernel thread. Its main |
The \texttt{kswap()} function is run as a kernel thread. Its main |
37 |
role in the virtual memory system is to perform the pageout |
role in the virtual memory system is to perform the pageout |
40 |
for allocation. This process is done on a per-zone basis for |
for allocation. This process is done on a per-zone basis for |
41 |
each node (if it is a NUMA system). |
each node (if it is a NUMA system). |
42 |
|
|
43 |
\begin{verbatim} |
\begin{verbatim} |
44 |
struct task_struct *tsk = current; |
struct task_struct *tsk = current; |
45 |
DECLARE_WAITQUEUE(wait, tsk); |
DECLARE_WAITQUEUE(wait, tsk); |
46 |
\end{verbatim} |
\end{verbatim} |
47 |
|
|
48 |
A waitqueue is declared to be added to the \texttt{kswapd\_wait} |
A waitqueue is declared to be added to the \texttt{kswapd\_wait} |
49 |
waitqueue header below. It will be used by |
waitqueue header below. It will be used by |
50 |
\texttt{\_\_alloc\_pages()} to know if it can wake up and to |
\texttt{\_\_alloc\_pages()} to know if it can wake up and to |
51 |
actually wake up kswapd process. |
actually wake up kswapd process. |
52 |
|
|
53 |
\begin{verbatim} |
\begin{verbatim} |
54 |
daemonize(); |
daemonize(); |
55 |
strcpy(tsk->comm, "kswapd"); |
strcpy(tsk->comm, "kswapd"); |
56 |
sigfillset(&tsk->blocked); |
sigfillset(&tsk->blocked); |
57 |
\end{verbatim} |
|
58 |
|
/* |
59 |
\begin{verbatim} |
* Tell the memory management that we're a "memory allocator", |
60 |
/* |
* and that if we need more memory we should get access to it |
61 |
* Tell the memory management that we're a "memory allocator", |
* regardless (see "__alloc_pages()"). "kswapd" should |
62 |
* and that if we need more memory we should get access to it |
* never get caught in the normal page freeing logic. |
63 |
* regardless (see "__alloc_pages()"). "kswapd" should |
* |
64 |
* never get caught in the normal page freeing logic. |
* (Kswapd normally doesn't need memory anyway, but sometimes |
65 |
* |
* you need a small amount of memory in order to be able to |
66 |
* (Kswapd normally doesn't need memory anyway, but sometimes |
* page out something else, and this flag essentially protects |
67 |
* you need a small amount of memory in order to be able to |
* us from recursively trying to free more memory as we're |
68 |
* page out something else, and this flag essentially protects |
* trying to free the first piece of memory in the first place). |
69 |
* us from recursively trying to free more memory as we're |
*/ |
70 |
* trying to free the first piece of memory in the first place). |
tsk->flags |= PF_MEMALLOC; |
71 |
*/ |
|
72 |
tsk->flags |= PF_MEMALLOC; |
/* |
73 |
|
* Kswapd main loop. |
74 |
/* |
*/ |
75 |
* Kswapd main loop. |
for (;;) { |
76 |
*/ |
__set_current_state(TASK_INTERRUPTIBLE); |
77 |
for (;;) { |
\end{verbatim} |
|
__set_current_state(TASK_INTERRUPTIBLE); |
|
|
\end{verbatim} |
|
78 |
|
|
79 |
That sets the task flag to be interruptible if \texttt{kswap} |
That sets the task flag to be interruptible if \texttt{kswap} |
80 |
sleeps below. |
sleeps below. |
81 |
|
|
82 |
\begin{verbatim} |
\begin{verbatim} |
83 |
add_wait_queue(&kswapd_wait, &wait); |
add_wait_queue(&kswapd_wait, &wait); |
84 |
\end{verbatim} |
\end{verbatim} |
85 |
|
|
86 |
Adding \texttt{wait} to the \texttt{kswapd\_wait} waitqueue header |
Adding \texttt{wait} to the \texttt{kswapd\_wait} waitqueue header |
87 |
turns \texttt{kswapd\_wait} into an \textbf{active} wait queue. In |
turns \texttt{kswapd\_wait} into an \textbf{active} wait queue. In |
89 |
free pages in any zone is under the minimum limit, \texttt{kswap} |
free pages in any zone is under the minimum limit, \texttt{kswap} |
90 |
will be able to be awaken (if it is sleeping). |
will be able to be awaken (if it is sleeping). |
91 |
|
|
92 |
\begin{verbatim} |
\begin{verbatim} |
93 |
mb(); |
mb(); |
94 |
\end{verbatim} |
\end{verbatim} |
95 |
|
|
96 |
This stands for \emph{memory barrier} and ensures that memory |
This stands for \emph{memory barrier} and ensures that memory |
97 |
ordering will happen, ie, that on a SMP system each CPU have the |
ordering will happen, ie, that on a SMP system each CPU have the |
98 |
same view of the memory. |
same view of the memory. |
99 |
|
|
100 |
\begin{verbatim} |
\begin{verbatim} |
101 |
if (kswapd_can_sleep()) |
if (kswapd_can_sleep()) |
102 |
schedule(); |
schedule(); |
103 |
\end{verbatim} |
\end{verbatim} |
104 |
|
|
105 |
Here \texttt{kswapd} checks if any zone in any node needs to be |
Here \texttt{kswapd} checks if any zone in any node needs to be |
106 |
balanced. A zone will be marked ``to be balanced'' (actually |
balanced. A zone will be marked ``to be balanced'' (actually |
110 |
has to be balanced, \texttt{kswapd} sleeps by calling |
has to be balanced, \texttt{kswapd} sleeps by calling |
111 |
\texttt{schedule()}. |
\texttt{schedule()}. |
112 |
|
|
113 |
\begin{verbatim} |
\begin{verbatim} |
114 |
__set_current_state(TASK_RUNNING); |
__set_current_state(TASK_RUNNING); |
115 |
remove_wait_queue(&kswapd_wait, &wait); |
remove_wait_queue(&kswapd_wait, &wait); |
116 |
\end{verbatim} |
\end{verbatim} |
117 |
|
|
118 |
After \texttt{kswapd} is waken up, its current task state is set |
After \texttt{kswapd} is waken up, its current task state is set |
119 |
to \texttt{RUNNING} and \texttt{wait} is removed from |
to \texttt{RUNNING} and \texttt{wait} is removed from |
122 |
any longer, since that \texttt{kswapd} will be already running |
any longer, since that \texttt{kswapd} will be already running |
123 |
trying to balance all zones under memory shortage. |
trying to balance all zones under memory shortage. |
124 |
|
|
125 |
\begin{verbatim} |
\begin{verbatim} |
126 |
/* |
/* |
127 |
* If we actually get into a low-memory situation, |
* If we actually get into a low-memory situation, |
128 |
* the processes needing more memory will wake us |
* the processes needing more memory will wake us |
129 |
* up on a more timely basis. |
* up on a more timely basis. |
130 |
*/ |
*/ |
131 |
kswapd_balance(); |
kswapd_balance(); |
132 |
\end{verbatim} |
\end{verbatim} |
133 |
|
|
134 |
That's the part of \texttt{kswapd} where it actually does it |
That's the part of \texttt{kswapd} where it actually does it |
135 |
work. The \texttt{kswapd\_balance()} tries to free enough pages |
work. The \texttt{kswapd\_balance()} tries to free enough pages |
137 |
freeing a number of pages to make the zone to end up having more |
freeing a number of pages to make the zone to end up having more |
138 |
free pages than its minimum watermark. |
free pages than its minimum watermark. |
139 |
|
|
140 |
\begin{verbatim} |
\begin{verbatim} |
141 |
run_task_queue(&tq_disk); |
run_task_queue(&tq_disk); |
142 |
} |
} |
143 |
\end{verbatim} |
\end{verbatim} |
144 |
|
|
145 |
Now it runs the task queue tq\_disk to perform disk related bottom |
Now it runs the task queue tq\_disk to perform disk related bottom |
146 |
half activities. Since \texttt{kswapd} might have written some |
half activities. Since \texttt{kswapd} might have written some |
150 |
\subsection{Function try\_to\_swap\_out()} |
\subsection{Function try\_to\_swap\_out()} |
151 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
152 |
\textit{Prototype: } |
\textit{Prototype: } |
153 |
\begin{verbatim} |
\begin{verbatim} |
154 |
int try_to_swap_out(struct mm_struct * mm, |
int try_to_swap_out(struct mm_struct * mm, |
155 |
struct vm_area_struct* vma, |
struct vm_area_struct* vma, |
156 |
unsigned long address, |
unsigned long address, |
157 |
pte_t * page_table, |
pte_t * page_table, |
158 |
struct page *page, |
struct page *page, |
159 |
zone_t * classzone) |
zone_t * classzone) |
160 |
\end{verbatim} |
\end{verbatim} |
161 |
|
|
162 |
The role of the \texttt{try\_to\_swap\_out()} function is to try |
The role of the \texttt{try\_to\_swap\_out()} function is to try |
163 |
to unmap pages from processes mapping them. This is the first |
to unmap pages from processes mapping them. This is the first |
177 |
last process (no process is mapping it at the moment this |
last process (no process is mapping it at the moment this |
178 |
function exits). |
function exits). |
179 |
|
|
180 |
\begin{verbatim} |
\begin{verbatim} |
181 |
pte_t pte; |
pte_t pte; |
182 |
swp_entry_t entry; |
swp_entry_t entry; |
183 |
|
|
184 |
/* Don't look at this pte if it's been accessed recently. */ |
/* Don't look at this pte if it's been accessed recently. */ |
185 |
if ((vma->vm_flags & VM_LOCKED) |
if ((vma->vm_flags & VM_LOCKED) |
186 |
|| ptep_test_and_clear_young(page_table)) { |
|| ptep_test_and_clear_young(page_table)) { |
187 |
mark_page_accessed(page); |
mark_page_accessed(page); |
188 |
return 0; |
return 0; |
189 |
} |
} |
190 |
\end{verbatim} |
\end{verbatim} |
191 |
|
|
192 |
That is part of VM aging process. Here, based on the young bit |
That is part of VM aging process. Here, based on the young bit |
193 |
from page table entries (pte), \texttt{try\_to\_swap\_out()} sets |
from page table entries (pte), \texttt{try\_to\_swap\_out()} sets |
196 |
\texttt{mark\_page\_accessed()} will move this page to the active |
\texttt{mark\_page\_accessed()} will move this page to the active |
197 |
list. |
list. |
198 |
|
|
199 |
\begin{verbatim} |
\begin{verbatim} |
200 |
/* Don't bother unmapping pages that are active */ |
/* Don't bother unmapping pages that are active */ |
201 |
if (PageActive(page)) |
if (PageActive(page)) |
202 |
return 0; |
return 0; |
203 |
\end{verbatim} |
\end{verbatim} |
204 |
|
|
205 |
Active pages are supposed to have been accessed often, so it is |
Active pages are supposed to have been accessed often, so it is |
206 |
worthless to unmap them since it is likely they will be mapped |
worthless to unmap them since it is likely they will be mapped |
207 |
back soon. |
back soon. |
208 |
|
|
209 |
\begin{verbatim} |
\begin{verbatim} |
210 |
/* Don't bother replenishing zones not under pressure.. */ |
/* Don't bother replenishing zones not under pressure.. */ |
211 |
if (!memclass(page_zone(page), classzone)) |
if (!memclass(page_zone(page), classzone)) |
212 |
return 0; |
return 0; |
213 |
\end{verbatim} |
\end{verbatim} |
214 |
|
|
215 |
Neither it is sensible to free pages from zones other that the |
Neither it is sensible to free pages from zones other that the |
216 |
ones that are under memory shortage. |
ones that are under memory shortage. |
217 |
|
|
218 |
\begin{verbatim} |
\begin{verbatim} |
219 |
if (TryLockPage(page)) |
if (TryLockPage(page)) |
220 |
return 0; |
return 0; |
221 |
\end{verbatim} |
\end{verbatim} |
222 |
|
|
223 |
The page is tried to lock at once given that the unmapping |
The page is tried to lock at once given that the unmapping |
224 |
process is not dependant on an specific page and it is not worth |
process is not dependant on an specific page and it is not worth |
225 |
to sleep to try to unmap any page. |
to sleep to try to unmap any page. |
226 |
|
|
227 |
\begin{verbatim} |
\begin{verbatim} |
228 |
/* From this point on, the odds are that we're going to |
/* From this point on, the odds are that we're going to |
229 |
* nuke this pte, so read and clear the pte. This hook |
* nuke this pte, so read and clear the pte. This hook |
230 |
* is needed on CPUs which update the accessed and dirty |
* is needed on CPUs which update the accessed and dirty |
231 |
* bits in hardware. |
* bits in hardware. |
232 |
*/ |
*/ |
233 |
flush_cache_page(vma, address); |
flush_cache_page(vma, address); |
234 |
pte = ptep_get_and_clear(page_table); |
pte = ptep_get_and_clear(page_table); |
235 |
flush_tlb_page(vma, address); |
flush_tlb_page(vma, address); |
236 |
\end{verbatim} |
\end{verbatim} |
237 |
|
|
238 |
Research. |
Research. |
239 |
|
|
240 |
\begin{verbatim} |
\begin{verbatim} |
241 |
if (pte_dirty(pte)) |
if (pte_dirty(pte)) |
242 |
set_page_dirty(page); |
set_page_dirty(page); |
243 |
\end{verbatim} |
\end{verbatim} |
244 |
|
|
245 |
\begin{verbatim} |
\begin{verbatim} |
246 |
/* |
/* |
247 |
* Is the page already in the swap cache? If so, then |
* Is the page already in the swap cache? If so, then |
248 |
* we can just drop our reference to it without doing |
* we can just drop our reference to it without doing |
249 |
* any IO - it's already up-to-date on disk. |
* any IO - it's already up-to-date on disk. |
250 |
*/ |
*/ |
251 |
if (PageSwapCache(page)) { |
if (PageSwapCache(page)) { |
252 |
entry.val = page->index; |
entry.val = page->index; |
253 |
swap_duplicate(entry); |
swap_duplicate(entry); |
254 |
set_swap_pte: |
set_swap_pte: |
255 |
set_pte(page_table, swp_entry_to_pte(entry)); |
set_pte(page_table, swp_entry_to_pte(entry)); |
256 |
\end{verbatim} |
\end{verbatim} |
257 |
|
|
258 |
In the case this page has already been added to the swap cache, |
In the case this page has already been added to the swap cache, |
259 |
there is only the need to increase the swap counter (by |
there is only the need to increase the swap counter (by |
261 |
address. The swap address is stored in the \texttt{index} field |
address. The swap address is stored in the \texttt{index} field |
262 |
of the \texttt{struct page}. |
of the \texttt{struct page}. |
263 |
|
|
264 |
\begin{verbatim} |
\begin{verbatim} |
265 |
drop_pte: |
drop_pte: |
266 |
mm->rss--; |
mm->rss--; |
267 |
UnlockPage(page); |
UnlockPage(page); |
268 |
{ |
{ |
269 |
int freeable = page_count(page) - !!page->buffers <= 2; |
int freeable = page_count(page) - !!page->buffers <= 2; |
270 |
page_cache_release(page); |
page_cache_release(page); |
271 |
return freeable; |
return freeable; |
272 |
} |
} |
273 |
} |
} |
274 |
\end{verbatim} |
\end{verbatim} |
275 |
|
|
276 |
If any process is no longer mapped to this page, the return value |
If any process is no longer mapped to this page, the return value |
277 |
is 1, since this page is completely unmapped from the processes |
is 1, since this page is completely unmapped from the processes |
278 |
and can be freed. |
and can be freed. |
279 |
|
|
280 |
\begin{verbatim} |
\begin{verbatim} |
281 |
/* |
/* |
282 |
* Is it a clean page? Then it must be recoverable |
* Is it a clean page? Then it must be recoverable |
283 |
* by just paging it in again, and we can just drop |
* by just paging it in again, and we can just drop |
284 |
* it.. or if it's dirty but has backing store, |
* it.. or if it's dirty but has backing store, |
285 |
* just mark the page dirty and drop it. |
* just mark the page dirty and drop it. |
286 |
* |
* |
287 |
* However, this won't actually free any real |
* However, this won't actually free any real |
288 |
* memory, as the page will just be in the page cache |
* memory, as the page will just be in the page cache |
289 |
* somewhere, and as such we should just continue |
* somewhere, and as such we should just continue |
290 |
* our scan. |
* our scan. |
291 |
* |
* |
292 |
* Basically, this just makes it possible for us to do |
* Basically, this just makes it possible for us to do |
293 |
* some real work in the future in "refill_inactive()". |
* some real work in the future in "refill_inactive()". |
294 |
*/ |
*/ |
295 |
if (page->mapping) |
if (page->mapping) |
296 |
goto drop_pte; |
goto drop_pte; |
297 |
if (!PageDirty(page)) |
if (!PageDirty(page)) |
298 |
goto drop_pte; |
goto drop_pte; |
299 |
|
|
300 |
/* |
/* |
301 |
* Anonymous buffercache pages can be left behind by |
* Anonymous buffercache pages can be left behind by |
302 |
* concurrent truncate and pagefault. |
* concurrent truncate and pagefault. |
303 |
*/ |
*/ |
304 |
if (page->buffers) |
if (page->buffers) |
305 |
goto preserve; |
goto preserve; |
306 |
\end{verbatim} |
\end{verbatim} |
307 |
|
|
308 |
Anonymous pages are pages without backing store, ie. not mapped |
Anonymous pages are pages without backing store, ie. not mapped |
309 |
to any address space. Anonymous buffer cache pages are anonymous |
to any address space. Anonymous buffer cache pages are anonymous |
310 |
pages with buffers. In particular, these pages have already been |
pages with buffers. In particular, these pages have already been |
311 |
mapped to an address space, but aren't any longer. |
mapped to an address space, but aren't any longer. |
312 |
|
|
313 |
\begin{verbatim} |
\begin{verbatim} |
314 |
/* |
/* |
315 |
* This is a dirty, swappable page. First of all, |
* This is a dirty, swappable page. First of all, |
316 |
* get a suitable swap entry for it, and make sure |
* get a suitable swap entry for it, and make sure |
317 |
* we have the swap cache set up to associate the |
* we have the swap cache set up to associate the |
318 |
* page with that swap entry. |
* page with that swap entry. |
319 |
*/ |
*/ |
320 |
for (;;) { |
for (;;) { |
321 |
entry = get_swap_page(); |
entry = get_swap_page(); |
322 |
if (!entry.val) |
if (!entry.val) |
323 |
break; |
break; |
324 |
/* Add it to the swap cache and mark it dirty |
/* Add it to the swap cache and mark it dirty |
325 |
* (adding to the page cache will clear the dirty |
* (adding to the page cache will clear the dirty |
326 |
* and uptodate bits, so we need to do it again) |
* and uptodate bits, so we need to do it again) |
327 |
*/ |
*/ |
328 |
if (add_to_swap_cache(page, entry) == 0) { |
if (add_to_swap_cache(page, entry) == 0) { |
329 |
SetPageUptodate(page); |
SetPageUptodate(page); |
330 |
set_page_dirty(page); |
set_page_dirty(page); |
331 |
goto set_swap_pte; |
goto set_swap_pte; |
332 |
} |
} |
333 |
\end{verbatim} |
\end{verbatim} |
334 |
|
|
335 |
That is a dirty and anonymous page, so let's get a swap entry for |
That is a dirty and anonymous page, so let's get a swap entry for |
336 |
it in order to remap its \emph{pte} to this new address. Later |
it in order to remap its \emph{pte} to this new address. Later |
342 |
anonymous page), this page needs to be set as dirty in order to |
anonymous page), this page needs to be set as dirty in order to |
343 |
be written. |
be written. |
344 |
|
|
345 |
\begin{verbatim} |
\begin{verbatim} |
346 |
/* Raced with "speculative" read_swap_cache_async */ |
/* Raced with "speculative" read_swap_cache_async */ |
347 |
swap_free(entry); |
swap_free(entry); |
348 |
} |
} |
349 |
\end{verbatim} |
\end{verbatim} |
350 |
|
|
351 |
When servicing a page fault for a swap address, some pages are |
When servicing a page fault for a swap address, some pages are |
352 |
read ahead if the page is not present in the swap cache. In this |
read ahead if the page is not present in the swap cache. In this |
360 |
necessary to drop the counter of this swap entry and get a new |
necessary to drop the counter of this swap entry and get a new |
361 |
one. |
one. |
362 |
|
|
363 |
\begin{verbatim} |
\begin{verbatim} |
364 |
/* No swap space left */ |
/* No swap space left */ |
365 |
preserve: |
preserve: |
366 |
set_pte(page_table, pte); |
set_pte(page_table, pte); |
367 |
UnlockPage(page); |
UnlockPage(page); |
368 |
return 0; |
return 0; |
369 |
\end{verbatim} |
\end{verbatim} |
370 |
|
|
371 |
No swap space is left, what \texttt{try\_to\_swap\_out()} is |
No swap space is left, what \texttt{try\_to\_swap\_out()} is |
372 |
unable to unmap this anonymous page. Let's set the page table |
unable to unmap this anonymous page. Let's set the page table |
376 |
\subsection{Function swap\_out\_pmd()} |
\subsection{Function swap\_out\_pmd()} |
377 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
378 |
\textit{Prototype: } |
\textit{Prototype: } |
379 |
\begin{verbatim} |
\begin{verbatim} |
380 |
int swap_out_pmd(struct mm_struct * mm, |
int swap_out_pmd(struct mm_struct * mm, |
381 |
struct vm_area_struct * vma, |
struct vm_area_struct * vma, |
382 |
pmd_t *dir, unsigned long address, |
pmd_t *dir, unsigned long address, |
383 |
unsigned long end, int count, |
unsigned long end, int count, |
384 |
zone_t * classzone) |
zone_t * classzone) |
385 |
\end{verbatim} |
\end{verbatim} |
386 |
|
|
387 |
|
For the page middle directory passed as parameter (\texttt{dir}), |
388 |
\begin{verbatim} |
this function scan all the page table entries of it. It returns |
389 |
pte_t * pte; |
the number of pages missed to reach the requested number of |
390 |
unsigned long pmd_end; |
completely unmapped pages (\texttt{count} parameter). |
391 |
|
|
392 |
if (pmd_none(*dir)) |
\begin{verbatim} |
393 |
return count; |
pte_t * pte; |
394 |
if (pmd_bad(*dir)) { |
unsigned long pmd_end; |
395 |
pmd_ERROR(*dir); |
|
396 |
pmd_clear(dir); |
if (pmd_none(*dir)) |
397 |
return count; |
return count; |
398 |
} |
\end{verbatim} |
399 |
|
|
400 |
pte = pte_offset(dir, address); |
Does this page middle directory offset point to no page table? |
401 |
|
There is nothing to do, so just return. |
402 |
pmd_end = (address + PMD_SIZE) & PMD_MASK; |
|
403 |
if (end > pmd_end) |
\begin{verbatim} |
404 |
end = pmd_end; |
if (pmd_bad(*dir)) { |
405 |
|
pmd_ERROR(*dir); |
406 |
do { |
pmd_clear(dir); |
407 |
if (pte_present(*pte)) { |
return count; |
408 |
struct page *page = pte_page(*pte); |
} |
409 |
|
\end{verbatim} |
410 |
if (VALID_PAGE(page) && !PageReserved(page)) { |
|
411 |
count -= try_to_swap_out(mm, vma, address, pte, page, classzone); |
Check if the contents of this memory address points to a valid |
412 |
if (!count) { |
page table. If it does not, print an error message |
413 |
address += PAGE_SIZE; |
(\texttt{pmd\_ERROR}), clear this entry and return. |
414 |
break; |
|
415 |
} |
\begin{verbatim} |
416 |
} |
pte = pte_offset(dir, address); |
417 |
|
\end{verbatim} |
418 |
|
|
419 |
|
From the page middle directory pointer and the address, get the |
420 |
|
pointer to a page table. |
421 |
|
|
422 |
|
\begin{verbatim} |
423 |
|
pmd_end = (address + PMD_SIZE) & PMD_MASK; |
424 |
|
if (end > pmd_end) |
425 |
|
end = pmd_end; |
426 |
|
\end{verbatim} |
427 |
|
|
428 |
|
Computes the end of the page table pointed by this page middle |
429 |
|
directory entry. If the end of the VM area is beyond the end of |
430 |
|
this page table, set this variable (\texttt{end}) to this value. |
431 |
|
|
432 |
|
\begin{verbatim} |
433 |
|
do { |
434 |
|
if (pte_present(*pte)) { |
435 |
|
\end{verbatim} |
436 |
|
|
437 |
|
Only page table entries that are mapped to pages in memory can be |
438 |
|
unmapped. That way, page table entries set to no page or set to |
439 |
|
swap addresses are not scanned by \texttt{try\_to\_swap\_out()}. |
440 |
|
|
441 |
|
\begin{verbatim} |
442 |
|
struct page *page = pte_page(*pte); |
443 |
|
|
444 |
|
if (VALID_PAGE(page) && !PageReserved(page)) { |
445 |
|
\end{verbatim} |
446 |
|
|
447 |
|
Given the page table entry (pte), get the page to which this page |
448 |
|
table entry is mapped and check if it is a valid address as well |
449 |
|
as if it not reserved. Reserved pages cannot be unmapped from |
450 |
|
their processes. |
451 |
|
|
452 |
|
\begin{verbatim} |
453 |
|
count -= try_to_swap_out(mm, vma, address, |
454 |
|
pte, page, classzone); |
455 |
|
\end{verbatim} |
456 |
|
|
457 |
|
Call \texttt{try\_to\_swap\_out()} function that will try to |
458 |
|
unmap this page (\texttt{page} variable) from the page table |
459 |
|
entry which is mapped to it. It will return 1 if it has unmapped |
460 |
|
and this page is freeable. The return value of 0 does not mean |
461 |
|
that the page is still mapped, but simply that it is not |
462 |
|
freeable (ie, it is mapped to other processes). |
463 |
|
|
464 |
|
\begin{verbatim} |
465 |
|
if (!count) { |
466 |
|
address += PAGE_SIZE; |
467 |
|
break; |
468 |
} |
} |
469 |
address += PAGE_SIZE; |
\end{verbatim} |
470 |
pte++; |
|
471 |
} while (address && (address < end)); |
If the initial requested number of completely unmapped pages have |
472 |
mm->swap_address = address; |
been reached, return. Since the \texttt{swap\_address} (the last |
473 |
return count; |
address scanned to be swapped out) of the \texttt{mm\_struct} is |
474 |
\end{verbatim} |
updated here, add the page size to the address variable, since |
475 |
|
this address has been scanned and the scan should be resumed from |
476 |
|
the next address. |
477 |
|
|
478 |
|
\begin{verbatim} |
479 |
|
} |
480 |
|
} |
481 |
|
address += PAGE_SIZE; |
482 |
|
pte++; |
483 |
|
} while (address && (address < end)); |
484 |
|
\end{verbatim} |
485 |
|
|
486 |
|
Update the \texttt{address} variable to the next address and the |
487 |
|
\texttt{pte} pointer to the next offset to be scanned. In the |
488 |
|
case this address is beyond the VM area end, stop the loop. |
489 |
|
|
490 |
|
\begin{verbatim} |
491 |
|
mm->swap_address = address; |
492 |
|
return count; |
493 |
|
\end{verbatim} |
494 |
|
|
495 |
|
Update the \texttt{mm\_struct} last address scanned in order to |
496 |
|
swap out and return the \texttt{count} variable, which informs |
497 |
|
the number of pages missed to reach the inital requested number |
498 |
|
of completely unmapped pages. |
499 |
|
|
|
|
|
500 |
\subsection{Function swap\_out\_pgd()} |
\subsection{Function swap\_out\_pgd()} |
501 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
502 |
\textit{Prototype: } |
\textit{Prototype: } |
503 |
\begin{verbatim} |
\begin{verbatim} |
504 |
int swap_out_pgd(struct mm_struct * mm, |
int swap_out_pgd(struct mm_struct * mm, |
505 |
struct vm_area_struct * vma, |
struct vm_area_struct * vma, |
506 |
pgd_t *dir, unsigned long address, |
pgd_t *dir, unsigned long address, |
507 |
unsigned long end, int count, |
unsigned long end, int count, |
508 |
zone_t * classzone) |
zone_t * classzone) |
509 |
\end{verbatim} |
\end{verbatim} |
510 |
|
|
511 |
\begin{verbatim} |
For a given page global directory offset, this function scan all |
512 |
pmd_t * pmd; |
the page middle directories of it. It returns an int value, which |
513 |
unsigned long pgd_end; |
means how many pages are missing to the requested number of |
514 |
|
completely unmapped pages (\texttt{count} parameter). |
515 |
if (pgd_none(*dir)) |
|
516 |
return count; |
\begin{verbatim} |
517 |
if (pgd_bad(*dir)) { |
pmd_t * pmd; |
518 |
pgd_ERROR(*dir); |
unsigned long pgd_end; |
519 |
pgd_clear(dir); |
|
520 |
return count; |
if (pgd_none(*dir)) |
521 |
} |
return count; |
522 |
|
\end{verbatim} |
523 |
pmd = pmd_offset(dir, address); |
|
524 |
|
If this page global directory does not have a page middle |
525 |
|
directory, return. |
526 |
|
|
527 |
|
\begin{verbatim} |
528 |
|
if (pgd_bad(*dir)) { |
529 |
|
pgd_ERROR(*dir); |
530 |
|
pgd_clear(dir); |
531 |
|
return count; |
532 |
|
} |
533 |
|
\end{verbatim} |
534 |
|
|
535 |
|
Checks if the entry points to a bad page table. In this case, |
536 |
|
prints that there is an error (\texttt{pgd\_ERROR()}) and clear |
537 |
|
this entry. |
538 |
|
|
539 |
|
\begin{verbatim} |
540 |
|
pmd = pmd_offset(dir, address); |
541 |
|
\end{verbatim} |
542 |
|
|
543 |
|
From the page global directory entry and the address, get the |
544 |
|
offset in the page middle directory. |
545 |
|
|
546 |
|
\begin{verbatim} |
547 |
|
pgd_end = (address + PGDIR_SIZE) & PGDIR_MASK; |
548 |
|
if (pgd_end && (end > pgd_end)) |
549 |
|
end = pgd_end; |
550 |
|
\end{verbatim} |
551 |
|
|
552 |
|
Obtain the end of the space addressable by this page global |
553 |
|
directory. If the end of the VM area is greater than the end of |
554 |
|
this page global directory, the new \texttt{end} will be the pgd |
555 |
|
boundary. |
556 |
|
|
557 |
|
\begin{verbatim} |
558 |
|
do { |
559 |
|
count = swap_out_pmd(mm, vma, pmd, address, end, count, |
560 |
|
classzone); |
561 |
|
\end{verbatim} |
562 |
|
|
563 |
|
For every page middle directory, scan all its page tables in |
564 |
|
\texttt{swap\_out\_pmd()} function. |
565 |
|
|
566 |
|
\begin{verbatim} |
567 |
|
if (!count) |
568 |
|
break; |
569 |
|
\end{verbatim} |
570 |
|
|
571 |
|
The return value of \texttt{swap\_out\_pmd()} function tells how |
572 |
|
many pages still need to be unmapped to reach the initial |
573 |
|
requested number. If all the needed pages have been unmapped, it |
574 |
|
is time to return. |
575 |
|
|
576 |
|
\begin{verbatim} |
577 |
|
address = (address + PMD_SIZE) & PMD_MASK; |
578 |
|
pmd++; |
579 |
|
} while (address && (address < end)); |
580 |
|
return count; |
581 |
|
\end{verbatim} |
582 |
|
|
583 |
|
Now go to the next page middle directory, updating the start |
584 |
|
address of it (\texttt{address} variable) and the offset |
585 |
|
(\texttt{pmd} variable). |
586 |
|
|
|
pgd_end = (address + PGDIR_SIZE) & PGDIR_MASK; |
|
|
if (pgd_end && (end > pgd_end)) |
|
|
end = pgd_end; |
|
|
|
|
|
do { |
|
|
count = swap_out_pmd(mm, vma, pmd, address, end, count, classzone); |
|
|
if (!count) |
|
|
break; |
|
|
address = (address + PMD_SIZE) & PMD_MASK; |
|
|
pmd++; |
|
|
} while (address && (address < end)); |
|
|
return count; |
|
|
\end{verbatim} |
|
|
|
|
|
|
|
|
|
|
|
|
|
587 |
\subsection{Function swap\_out\_vma()} |
\subsection{Function swap\_out\_vma()} |
588 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
589 |
\textit{Prototype: } |
\textit{Prototype: } |
590 |
\begin{verbatim} |
\begin{verbatim} |
591 |
int swap_out_vma(struct mm_struct * mm, |
int swap_out_vma(struct mm_struct * mm, |
592 |
struct vm_area_struct * vma, |
struct vm_area_struct * vma, |
593 |
unsigned long address, |
unsigned long address, |
594 |
int count, zone_t * classzone) |
int count, zone_t * classzone) |
595 |
\end{verbatim} |
\end{verbatim} |
596 |
|
|
597 |
\begin{verbatim} |
This function scans a VM area (\texttt{vma} parameter), returning |
598 |
pgd_t *pgdir; |
the number of pages missed to reach the requested number of |
599 |
unsigned long end; |
completely unmapped pages (\texttt{count} parameter). |
600 |
|
|
601 |
/* Don't swap out areas which are reserved */ |
\begin{verbatim} |
602 |
if (vma->vm_flags & VM_RESERVED) |
pgd_t *pgdir; |
603 |
return count; |
unsigned long end; |
604 |
|
|
605 |
pgdir = pgd_offset(mm, address); |
/* Don't swap out areas which are reserved */ |
606 |
|
if (vma->vm_flags & VM_RESERVED) |
607 |
end = vma->vm_end; |
return count; |
608 |
BUG_ON(address >= end); |
\end{verbatim} |
609 |
do { |
|
610 |
count = swap_out_pgd(mm, vma, pgdir, address, end, count, classzone); |
Some special cases define the VM area as reserved |
611 |
if (!count) |
(\texttt{VM\_RESERVED} flag) to avoid this VM area to have its |
612 |
break; |
entries unmapped. |
613 |
address = (address + PGDIR_SIZE) & PGDIR_MASK; |
|
614 |
pgdir++; |
\begin{verbatim} |
615 |
} while (address && (address < end)); |
pgdir = pgd_offset(mm, address); |
616 |
return count; |
\end{verbatim} |
617 |
\end{verbatim} |
|
618 |
|
Now, based on the \texttt{mm\_struct} and the \texttt{address}, |
619 |
|
get the offset in the process page global directory to scan. |
620 |
|
|
621 |
|
\begin{verbatim} |
622 |
|
end = vma->vm_end; |
623 |
|
BUG_ON(address >= end); |
624 |
|
do { |
625 |
|
count = swap_out_pgd(mm, vma, pgdir, address, end, count, |
626 |
|
classzone); |
627 |
|
\end{verbatim} |
628 |
|
|
629 |
|
Call \texttt{swap\_out\_pgd()} to swap out this part of the page |
630 |
|
global directory. The \texttt{address} and \texttt{end} |
631 |
|
parameters tells the beginning and end of the memory address to |
632 |
|
be scanned. |
633 |
|
|
634 |
|
\begin{verbatim} |
635 |
|
if (!count) |
636 |
|
break; |
637 |
|
\end{verbatim} |
638 |
|
|
639 |
|
Could unmap the requested number of pages? In this case, leave |
640 |
|
the loop and return. |
641 |
|
|
642 |
|
\begin{verbatim} |
643 |
|
address = (address + PGDIR_SIZE) & PGDIR_MASK; |
644 |
|
pgdir++; |
645 |
|
} while (address && (address < end)); |
646 |
|
return count; |
647 |
|
\end{verbatim} |
648 |
|
|
649 |
|
Updates the \texttt{address} variable to the next page global |
650 |
|
directory offset and \texttt{pgdir} variable to the next offset. |
651 |
|
If it did not reach the end of this VM area address space, scan |
652 |
|
the next page global directory offset. |
653 |
|
|
654 |
\subsection{Function swap\_out\_mm()} |
\subsection{Function swap\_out\_mm()} |
655 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
656 |
\textit{Prototype: } |
\textit{Prototype: } |
657 |
\begin{verbatim} |
\begin{verbatim} |
658 |
int swap_out_mm(struct mm_struct * mm, |
int swap_out_mm(struct mm_struct * mm, |
659 |
int count, int * mmcounter, |
int count, int * mmcounter, |
660 |
zone_t * classzone) |
zone_t * classzone) |
661 |
\end{verbatim} |
\end{verbatim} |
662 |
|
|
663 |
\begin{verbatim} |
Given a \texttt{mm\_struct} (\texttt{mm} parameter), this |
664 |
unsigned long address; |
function scans all its VM areas. It returns how many pages were |
665 |
struct vm_area_struct* vma; |
missing to get to the initial request amount (\texttt{count} |
666 |
|
parameter). If return value is zero, it means that all the |
667 |
/* |
requested pages were completely unmapped. |
668 |
* Find the proper vm-area after freezing the vma chain |
|
669 |
* and ptes. |
\begin{verbatim} |
670 |
*/ |
unsigned long address; |
671 |
spin_lock(&mm->page_table_lock); |
struct vm_area_struct* vma; |
672 |
address = mm->swap_address; |
|
673 |
if (address == TASK_SIZE || swap_mm != mm) { |
/* |
674 |
/* We raced: don't count this mm but try again */ |
* Find the proper vm-area after freezing the vma chain |
675 |
++*mmcounter; |
* and ptes. |
676 |
|
*/ |
677 |
|
spin_lock(&mm->page_table_lock); |
678 |
|
address = mm->swap_address; |
679 |
|
if (address == TASK_SIZE || swap_mm != mm) { |
680 |
|
/* We raced: don't count this mm but try again */ |
681 |
|
++*mmcounter; |
682 |
|
goto out_unlock; |
683 |
|
} |
684 |
|
\end{verbatim} |
685 |
|
|
686 |
|
Check for a race condition. Before getting to this point, another |
687 |
|
code path might have been faster than the current one and scanned |
688 |
|
all the address space of this task. Besides that, it could even |
689 |
|
have been completely scanned and another \texttt{mm\_struct} is |
690 |
|
the current one to be scanned. In either case, increment the |
691 |
|
\texttt{mmcounter} variable in order to make the caller function |
692 |
|
to try it again (if unable to unmap the necessary pages first). |
693 |
|
|
694 |
|
\begin{verbatim} |
695 |
|
vma = find_vma(mm, address); |
696 |
|
\end{verbatim} |
697 |
|
|
698 |
|
Find the first VM area that ends after this \texttt{address}. |
699 |
|
|
700 |
|
\begin{verbatim} |
701 |
|
if (vma) { |
702 |
|
if (address < vma->vm_start) |
703 |
|
address = vma->vm_start; |
704 |
|
\end{verbatim} |
705 |
|
|
706 |
|
Set \texttt{address} variable which will be passed as the start |
707 |
|
of VM area that \texttt{swap\_out\_vma()} function will scan. |
708 |
|
This is needed for the first call. |
709 |
|
|
710 |
|
\begin{verbatim} |
711 |
|
for (;;) { |
712 |
|
count = swap_out_vma(mm, vma, address, count, |
713 |
|
classzone); |
714 |
|
\end{verbatim} |
715 |
|
|
716 |
|
Call \texttt{swap\_out\_vma()} to scan all the VM area address |
717 |
|
space. |
718 |
|
|
719 |
|
\begin{verbatim} |
720 |
|
vma = vma->vm_next; |
721 |
|
if (!vma) |
722 |
|
break; |
723 |
|
if (!count) |
724 |
goto out_unlock; |
goto out_unlock; |
725 |
} |
address = vma->vm_start; |
726 |
vma = find_vma(mm, address); |
} |
727 |
if (vma) { |
} |
728 |
if (address < vma->vm_start) |
\end{verbatim} |
729 |
address = vma->vm_start; |
|
730 |
|
Set \texttt{vma} variable to the next VM area. If there are no VM |
731 |
for (;;) { |
areas to be scanned, leave the while loop. If the number of pages |
732 |
count = swap_out_vma(mm, vma, address, count, classzone); |
to be unmapped has been reached, leave the function since this VM |
733 |
vma = vma->vm_next; |
area scan can be continued. Otherwise, set \texttt{address} to |
734 |
if (!vma) |
the beginning of the next VM area and go on. |
735 |
break; |
|
736 |
if (!count) |
\begin{verbatim} |
737 |
goto out_unlock; |
/* Indicate that we reached the end of address space */ |
738 |
address = vma->vm_start; |
mm->swap_address = TASK_SIZE; |
739 |
} |
\end{verbatim} |
740 |
} |
|
741 |
/* Indicate that we reached the end of address space */ |
If all VM areas have been scanned, set the \texttt{swap\_address} |
742 |
mm->swap_address = TASK_SIZE; |
of \texttt{mm\_struct} to \texttt{TASK\_SIZE} to mark it as |
743 |
|
having been completely scanned. |
744 |
out_unlock: |
|
745 |
spin_unlock(&mm->page_table_lock); |
\begin{verbatim} |
746 |
return count; |
out_unlock: |
747 |
\end{verbatim} |
spin_unlock(&mm->page_table_lock); |
748 |
|
return count; |
749 |
|
\end{verbatim} |
750 |
|
|
751 |
|
Here simply returns the number of pages missing to the initial |
752 |
|
amount of pages to be completely unmapped. |
753 |
|
|
754 |
\subsection{Function swap\_out()} |
\subsection{Function swap\_out()} |
755 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
756 |
\textit{Prototype: } |
\textit{Prototype: } |
757 |
\begin{verbatim} |
\begin{verbatim} |
758 |
int swap_out(unsigned int priority, |
int swap_out(unsigned int priority, |
759 |
unsigned int gfp_mask, |
unsigned int gfp_mask, |
760 |
zone_t * classzone) |
zone_t * classzone) |
761 |
\end{verbatim} |
\end{verbatim} |
762 |
|
|
763 |
\begin{verbatim} |
This function picks a task which will have its page table |
764 |
int counter, nr_pages = SWAP_CLUSTER_MAX; |
scanned. To be more specific, a \texttt{mm\_struct} -- which is |
765 |
struct mm_struct *mm; |
one per task -- is chosen. |
766 |
|
|
767 |
counter = mmlist_nr; |
It returns if all the active tasks have been scanned or the |
768 |
do { |
requested number of pages unmapped completely from the processes |
769 |
if (unlikely(current->need_resched)) { |
(defined below) has been achieved. The return value is an int |
770 |
__set_current_state(TASK_RUNNING); |
which means that the number of requested pages has been achieved |
771 |
schedule(); |
(return value: 1) or not (return value: 0) |
772 |
} |
|
773 |
|
\begin{verbatim} |
774 |
|
int counter, nr_pages = SWAP_CLUSTER_MAX; |
775 |
|
\end{verbatim} |
776 |
|
|
777 |
|
The goal is to unmap \texttt{nr\_pages} pages from the process to |
778 |
|
be selected. |
779 |
|
|
780 |
|
\begin{verbatim} |
781 |
|
struct mm_struct *mm; |
782 |
|
|
783 |
|
counter = mmlist_nr; |
784 |
|
do { |
785 |
|
if (unlikely(current->need_resched)) { |
786 |
|
__set_current_state(TASK_RUNNING); |
787 |
|
schedule(); |
788 |
|
} |
789 |
|
\end{verbatim} |
790 |
|
|
791 |
|
Improve fairness by rescheduling the current task. |
792 |
|
|
793 |
|
\begin{verbatim} |
794 |
|
spin_lock(&mmlist_lock); |
795 |
|
mm = swap_mm; |
796 |
|
\end{verbatim} |
797 |
|
|
798 |
|
Set \texttt{mm} variable to the latest \texttt{mm\_struct} which |
799 |
|
has been scanned (or is being scanned). |
800 |
|
|
801 |
|
\begin{verbatim} |
802 |
|
while (mm->swap_address == TASK_SIZE || mm == &init_mm) { |
803 |
|
\end{verbatim} |
804 |
|
|
805 |
|
If no task has ever been scanned (second condition) or all the |
806 |
|
address space of this task has been scanned (first condition), |
807 |
|
try to get a new \texttt{mm\_struct} to scan. |
808 |
|
|
809 |
|
\begin{verbatim} |
810 |
|
mm->swap_address = 0; |
811 |
|
\end{verbatim} |
812 |
|
|
813 |
|
Zeroing \texttt{swap\_address} makes this \texttt{mm\_struct} |
814 |
|
available again to be scanned. |
815 |
|
|
816 |
|
\begin{verbatim} |
817 |
|
mm = list_entry(mm->mmlist.next, struct mm_struct, mmlist); |
818 |
|
\end{verbatim} |
819 |
|
|
820 |
|
Pick the next \texttt{mm\_struct} in the \texttt{mmlist}, which |
821 |
|
is the list of all active \texttt{mm\_struct}s. |
822 |
|
|
823 |
|
\begin{verbatim} |
824 |
|
if (mm == swap_mm) |
825 |
|
goto empty; |
826 |
|
\end{verbatim} |
827 |
|
|
828 |
|
In the case the list is empty, return. |
829 |
|
|
830 |
|
\begin{verbatim} |
831 |
|
swap_mm = mm; |
832 |
|
} |
833 |
|
\end{verbatim} |
834 |
|
|
835 |
|
Now check (in the while condition) if this \texttt{mm\_struct} |
836 |
|
can be scanned. Otherwise, try to get a new one. |
837 |
|
|
838 |
|
\begin{verbatim} |
839 |
|
/* Make sure the mm doesn't disappear |
840 |
|
when we drop the lock.. */ |
841 |
|
atomic_inc(&mm->mm_users); |
842 |
|
spin_unlock(&mmlist_lock); |
843 |
|
|
844 |
|
nr_pages = swap_out_mm(mm, nr_pages, &counter, classzone); |
845 |
|
\end{verbatim} |
846 |
|
|
847 |
|
Chosen an \texttt{mm\_struct()}, call \texttt{swap\_out\_mm()} |
848 |
|
function, which will ``swap out'' the VM areas of this |
849 |
|
\texttt{mm\_struct}. |
850 |
|
|
851 |
|
\begin{verbatim} |
852 |
|
mmput(mm); |
853 |
|
\end{verbatim} |
854 |
|
|
855 |
|
Once all the VM areas have been scanned, decrement the |
856 |
|
\texttt{mm\_struct} counter, deleting if it is the last |
857 |
|
reference. |
858 |
|
|
859 |
spin_lock(&mmlist_lock); |
\begin{verbatim} |
860 |
mm = swap_mm; |
if (!nr_pages) |
861 |
while (mm->swap_address == TASK_SIZE || mm == &init_mm) { |
return 1; |
862 |
mm->swap_address = 0; |
\end{verbatim} |
|
mm = list_entry(mm->mmlist.next, struct mm_struct, mmlist); |
|
|
if (mm == swap_mm) |
|
|
goto empty; |
|
|
swap_mm = mm; |
|
|
} |
|
|
|
|
|
/* Make sure the mm doesn't disappear when we drop the lock.. */ |
|
|
atomic_inc(&mm->mm_users); |
|
|
spin_unlock(&mmlist_lock); |
|
863 |
|
|
864 |
nr_pages = swap_out_mm(mm, nr_pages, &counter, classzone); |
No remaining pages to be unmapped? This function is sucessful, so |
865 |
|
it is time to return. |
866 |
|
|
867 |
mmput(mm); |
\begin{verbatim} |
868 |
|
} while (--counter >= 0); |
869 |
|
|
870 |
if (!nr_pages) |
return 0; |
|
return 1; |
|
|
} while (--counter >= 0); |
|
871 |
|
|
872 |
return 0; |
empty: |
873 |
|
spin_unlock(&mmlist_lock); |
874 |
empty: |
return 0; |
875 |
spin_unlock(&mmlist_lock); |
\end{verbatim} |
876 |
return 0; |
|
877 |
\end{verbatim} |
Unsuccesful since either the \texttt{mmlist} does not have other |
878 |
|
\texttt{mm\_struct}s or even after scanning all \texttt{mmlist}, |
879 |
|
it was unable to unmap the requested number of pages. |
880 |
|
|
881 |
\subsection{Function shrink\_cache()} |
\subsection{Function shrink\_cache()} |
882 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
883 |
\textit{Prototype: } |
\textit{Prototype: } |
884 |
\begin{verbatim} |
\begin{verbatim} |
885 |
int shrink_cache(int nr_pages, |
int shrink_cache(int nr_pages, |
886 |
zone_t * classzone, |
zone_t * classzone, |
887 |
unsigned int gfp_mask, |
unsigned int gfp_mask, |
888 |
int priority) |
int priority) |
889 |
\end{verbatim} |
\end{verbatim} |
890 |
|
|
891 |
This function shrinks the page and swap cache, checking the |
This function shrinks the page and swap cache, checking the |
892 |
inactive list and trying to free pages from it. It may be needed |
inactive list and trying to free pages from it. It may be needed |
900 |
number of pages. For example, a return value of 3 means that this |
number of pages. For example, a return value of 3 means that this |
901 |
function was able of free (\texttt{nr\_pages} - 3) pages. |
function was able of free (\texttt{nr\_pages} - 3) pages. |
902 |
|
|
903 |
\begin{verbatim} |
\begin{verbatim} |
904 |
struct list_head * entry; |
struct list_head * entry; |
905 |
int max_scan = nr_inactive_pages / priority; |
int max_scan = nr_inactive_pages / priority; |
906 |
int max_mapped = min((nr_pages <\< (10 - priority)), max_scan / 10); |
int max_mapped = min((nr_pages < < (10 - priority)), |
907 |
\end{verbatim} |
max_scan / 10); |
908 |
|
\end{verbatim} |
909 |
|
|
910 |
Here it is calculated how many pages at most will be scanned by |
Here it is calculated how many pages at most will be scanned by |
911 |
this function (if it can't return first). This value is based on |
this function (if it can't return first). This value is based on |
920 |
(\texttt{max\_scan} and \texttt{max\_mapped}) are known as |
(\texttt{max\_scan} and \texttt{max\_mapped}) are known as |
921 |
\emph{magic values}. |
\emph{magic values}. |
922 |
|
|
923 |
\begin{verbatim} |
\begin{verbatim} |
924 |
spin_lock(&pagemap_lru_lock); |
spin_lock(&pagemap_lru_lock); |
925 |
while (--max_scan >= 0 && (entry = inactive_list.prev) != &inactive_list) { |
while (--max_scan >= 0 && |
926 |
\end{verbatim} |
(entry = inactive_list.prev) != &inactive_list) { |
927 |
|
\end{verbatim} |
928 |
|
|
929 |
The while is very clear. It is scanned the minimum value between |
The while is very clear. It is scanned the minimum value between |
930 |
\texttt{max\_scan} number of pages and the whole inactive list. |
\texttt{max\_scan} number of pages and the whole inactive list. |
933 |
number of mapped pages is reached or the requested number of pages |
number of mapped pages is reached or the requested number of pages |
934 |
has been freed, this function will return too. |
has been freed, this function will return too. |
935 |
|
|
936 |
\begin{verbatim} |
\begin{verbatim} |
937 |
struct page * page; |
struct page * page; |
938 |
|
|
939 |
if (unlikely(current->need_resched)) { |
if (unlikely(current->need_resched)) { |
940 |
spin_unlock(&pagemap_lru_lock); |
spin_unlock(&pagemap_lru_lock); |
941 |
__set_current_state(TASK_RUNNING); |
__set_current_state(TASK_RUNNING); |
942 |
schedule(); |
schedule(); |
943 |
spin_lock(&pagemap_lru_lock); |
spin_lock(&pagemap_lru_lock); |
944 |
continue; |
continue; |
945 |
} |
} |
946 |
\end{verbatim} |
\end{verbatim} |
947 |
|
|
948 |
Improve fairness among process by rescheduling the process if it |
Improve fairness among process by rescheduling the process if it |
949 |
has been for a long time using CPU resources. |
has been for a long time using CPU resources. |
950 |
|
|
951 |
\begin{verbatim} |
\begin{verbatim} |
952 |
page = list_entry(entry, struct page, lru); |
page = list_entry(entry, struct page, lru); |
953 |
|
|
954 |
BUG_ON(!PageLRU(page)); |
BUG_ON(!PageLRU(page)); |
955 |
BUG_ON(PageActive(page)); |
BUG_ON(PageActive(page)); |
956 |
|
|
957 |
list_del(entry); |
list_del(entry); |
958 |
list_add(entry, &inactive_list); |
list_add(entry, &inactive_list); |
959 |
\end{verbatim} |
\end{verbatim} |
960 |
|
|
961 |
Obtain the page from \texttt{struct list\_head} pointer, and move |
Obtain the page from \texttt{struct list\_head} pointer, and move |
962 |
it to the back of the inactive list. |
it to the back of the inactive list. |
963 |
|
|
964 |
\begin{verbatim} |
\begin{verbatim} |
965 |
/* |
/* |
966 |
* Zero page counts can happen because we unlink the pages |
* Zero page counts can happen because we unlink the pages |
967 |
* _after_ decrementing the usage count.. |
* _after_ decrementing the usage count.. |
968 |
*/ |
*/ |
969 |
if (unlikely(!page_count(page))) |
if (unlikely(!page_count(page))) |
970 |
continue; |
continue; |
971 |
\end{verbatim} |
\end{verbatim} |
972 |
|
|
973 |
Since the page may be removed from lru lists after having its |
Since the page may be removed from lru lists after having its |
974 |
counter decremented, a race condition may happen: this page gets |
counter decremented, a race condition may happen: this page gets |
976 |
unlinked from the lru lists. The above \texttt{if} handles this |
unlinked from the lru lists. The above \texttt{if} handles this |
977 |
case. |
case. |
978 |
|
|
979 |
\begin{verbatim} |
\begin{verbatim} |
980 |
if (!memclass(page_zone(page), classzone)) |
if (!memclass(page_zone(page), classzone)) |
981 |
continue; |
continue; |
982 |
\end{verbatim} |
\end{verbatim} |
983 |
|
|
984 |
Only check pages that are from the zone which is under pressure. |
Only check pages that are from the zone which is under pressure. |
985 |
|
|
986 |
\begin{verbatim} |
\begin{verbatim} |
987 |
/* Racy check to avoid trylocking when not worthwhile */ |
/* Racy check to avoid trylocking when not worthwhile */ |
988 |
if (!page->buffers && (page_count(page) != 1 || !page->mapping)) |
if (!page->buffers && (page_count(page) != 1 || !page->mapping)) |
989 |
goto page_mapped; |
goto page_mapped; |
990 |
\end{verbatim} |
\end{verbatim} |
991 |
|
|
992 |
Before trying to lock the page, first check if it is mapped or |
Before trying to lock the page, first check if it is mapped or |
993 |
anonymous and does not have buffers to be freed. If that is true, |
anonymous and does not have buffers to be freed. If that is true, |
995 |
even if mapped to processes, go on to try to free them (what may |
even if mapped to processes, go on to try to free them (what may |
996 |
imply to synchronize them if busy). |
imply to synchronize them if busy). |
997 |
|
|
998 |
\begin{verbatim} |
\begin{verbatim} |
999 |
/* |
/* |
1000 |
* The page is locked. IO in progress? |
* The page is locked. IO in progress? |
1001 |
* Move it to the back of the list. |
* Move it to the back of the list. |
1002 |
*/ |
*/ |
1003 |
if (unlikely(TryLockPage(page))) { |
if (unlikely(TryLockPage(page))) { |
1004 |
if (PageLaunder(page) && (gfp_mask & __GFP_FS)) { |
if (PageLaunder(page) && (gfp_mask & __GFP_FS)) { |
1005 |
page_cache_get(page); |
page_cache_get(page); |
1006 |
spin_unlock(&pagemap_lru_lock); |
spin_unlock(&pagemap_lru_lock); |
1007 |
wait_on_page(page); |
wait_on_page(page); |
1008 |
page_cache_release(page); |
page_cache_release(page); |
1009 |
spin_lock(&pagemap_lru_lock); |
spin_lock(&pagemap_lru_lock); |
1010 |
} |
} |
1011 |
continue; |
continue; |
1012 |
} |
} |
1013 |
\end{verbatim} |
\end{verbatim} |
1014 |
|
|
1015 |
Try to lock the page at once. If it is locked and PageLaunder bit |
Try to lock the page at once. If it is locked and PageLaunder bit |
1016 |
is true, wait until it gets unlocked. PageLaunder will be only set |
is true, wait until it gets unlocked. PageLaunder will be only set |
1025 |
the list}). It does not make sense since the page has already |
the list}). It does not make sense since the page has already |
1026 |
been moved to the back of the list. |
been moved to the back of the list. |
1027 |
|
|
1028 |
\begin{verbatim} |
\begin{verbatim} |
1029 |
if (PageDirty(page) && is_page_cache_freeable(page) && page->mapping) { |
if (PageDirty(page) && is_page_cache_freeable(page) && |
1030 |
\end{verbatim} |
page->mapping) { |
1031 |
|
\end{verbatim} |
1032 |
|
|
1033 |
Dirty pages, completely unmapped by processes and that are in the |
Dirty pages, completely unmapped by processes and that are in the |
1034 |
page cache (swap cache is only a part of it) are eligible to be |
page cache (swap cache is only a part of it) are eligible to be |
1036 |
accesses this page, it will be only remapped after the IO is |
accesses this page, it will be only remapped after the IO is |
1037 |
complete, ie, the faultin path is able lock this page. |
complete, ie, the faultin path is able lock this page. |
1038 |
|
|
1039 |
\begin{verbatim} |
\begin{verbatim} |
1040 |
/* |
/* |
1041 |
* It is not critical here to write it only if |
* It is not critical here to write it only if |
1042 |
* the page is unmapped beause any direct writer |
* the page is unmapped beause any direct writer |
1043 |
* like O_DIRECT would set the PG_dirty bitflag |
* like O_DIRECT would set the PG_dirty bitflag |
1044 |
* on the phisical page after having successfully |
* on the phisical page after having successfully |
1045 |
* pinned it and after the I/O to the page is finished, |
* pinned it and after the I/O to the page is finished, |
1046 |
* so the direct writes to the page cannot get lost. |
* so the direct writes to the page cannot get lost. |
1047 |
*/ |
*/ |
1048 |
int (*writepage)(struct page *); |
int (*writepage)(struct page *); |
1049 |
|
|
1050 |
writepage = page->mapping->a_ops->writepage; |
writepage = page->mapping->a_ops->writepage; |
1051 |
if ((gfp_mask & __GFP_FS) && writepage) { |
if ((gfp_mask & __GFP_FS) && writepage) { |
1052 |
ClearPageDirty(page); |
ClearPageDirty(page); |
1053 |
SetPageLaunder(page); |
SetPageLaunder(page); |
1054 |
page_cache_get(page); |
page_cache_get(page); |
1055 |
spin_unlock(&pagemap_lru_lock); |
spin_unlock(&pagemap_lru_lock); |
1056 |
|
|
1057 |
writepage(page); |
writepage(page); |
1058 |
page_cache_release(page); |
page_cache_release(page); |
1059 |
|
|
1060 |
spin_lock(&pagemap_lru_lock); |
spin_lock(&pagemap_lru_lock); |
1061 |
continue; |
continue; |
1062 |
} |
} |
1063 |
} |
} |
1064 |
\end{verbatim} |
\end{verbatim} |
1065 |
|
|
1066 |
Only pages from page cache which have the \texttt{writepage()} |
Only pages from page cache which have the \texttt{writepage()} |
1067 |
function defined can be cleaned. Actually, the \texttt{gfp\_mask} |
function defined can be cleaned. Actually, the \texttt{gfp\_mask} |
1071 |
is called. Here a reference to the page is got in order to avoid |
is called. Here a reference to the page is got in order to avoid |
1072 |
it to be ocasionally freed in the meanwhile. |
it to be ocasionally freed in the meanwhile. |
1073 |
|
|
1074 |
\begin{verbatim} |
\begin{verbatim} |
1075 |
/* |
/* |
1076 |
* If the page has buffers, try to free the buffer mappings |
* If the page has buffers, try to free the buffer mappings |
1077 |
* associated with this page. If we succeed we try to free |
* associated with this page. If we succeed we try to free |
1078 |
* the page as well. |
* the page as well. |
1079 |
*/ |
*/ |
1080 |
if (page->buffers) { |
if (page->buffers) { |
1081 |
spin_unlock(&pagemap_lru_lock); |
spin_unlock(&pagemap_lru_lock); |
1082 |
|
|
1083 |
/* avoid to free a locked page */ |
/* avoid to free a locked page */ |
1084 |
page_cache_get(page); |
page_cache_get(page); |
1085 |
|
|
1086 |
if (try_to_release_page(page, gfp_mask)) { |
if (try_to_release_page(page, gfp_mask)) { |
1087 |
\end{verbatim} |
\end{verbatim} |
1088 |
|
|
1089 |
Does the page have buffers? No matter if is completely unmapped |
Does the page have buffers? No matter if is completely unmapped |
1090 |
from its processes, try to free them by calling |
from its processes, try to free them by calling |
1093 |
free the buffers if they are clean, otherwise will synchronize them |
free the buffers if they are clean, otherwise will synchronize them |
1094 |
(\texttt{gfp\_mask} must allow that). |
(\texttt{gfp\_mask} must allow that). |
1095 |
|
|
1096 |
\begin{verbatim} |
\begin{verbatim} |
1097 |
if (!page->mapping) { |
if (!page->mapping) { |
1098 |
/* |
/* |
1099 |
* We must not allow an anon page |
* We must not allow an anon page |
1100 |
* with no buffers to be visible on |
* with no buffers to be visible on |
1101 |
* the LRU, so we unlock the page after |
* the LRU, so we unlock the page after |
1102 |
* taking the lru lock |
* taking the lru lock |
1103 |
*/ |
*/ |
1104 |
spin_lock(&pagemap_lru_lock); |
spin_lock(&pagemap_lru_lock); |
1105 |
UnlockPage(page); |
UnlockPage(page); |
1106 |
__lru_cache_del(page); |
__lru_cache_del(page); |
1107 |
|
|
1108 |
/* effectively free the page here */ |
/* effectively free the page here */ |
1109 |
page_cache_release(page); |
page_cache_release(page); |
1110 |
|
|
1111 |
if (--nr_pages) |
if (--nr_pages) |
1112 |
continue; |
continue; |
1113 |
break; |
break; |
1114 |
\end{verbatim} |
\end{verbatim} |
1115 |
|
|
1116 |
The page has had its buffers freed. Is it an anonymous page? In |
The page has had its buffers freed. Is it an anonymous page? In |
1117 |
order to be an anonymous page with buffers, it must have already |
order to be an anonymous page with buffers, it must have already |
1120 |
invalidate/truncate its pages. In this case, simply remove the page |
invalidate/truncate its pages. In this case, simply remove the page |
1121 |
from the inactive list and release it. |
from the inactive list and release it. |
1122 |
|
|
1123 |
\begin{verbatim} |
\begin{verbatim} |
1124 |
} else { |
} else { |
1125 |
/* |
/* |
1126 |
* The page is still in pagecache so undo the stuff |
* The page is still in pagecache so undo |
1127 |
* before the try_to_release_page since we've not |
* the stuff before the try_to_release_page |
1128 |
* finished and we can now try the next step. |
* since we've not finished and we can now |
1129 |
*/ |
* try the next step. |
1130 |
page_cache_release(page); |
*/ |
1131 |
|
page_cache_release(page); |
1132 |
|
|
1133 |
spin_lock(&pagemap_lru_lock); |
spin_lock(&pagemap_lru_lock); |
1134 |
} |
} |
1135 |
\end{verbatim} |
\end{verbatim} |
1136 |
|
|
1137 |
The pages's buffers are gone, so go on to the next step since the |
The pages's buffers are gone, so go on to the next step since the |
1138 |
page is still in the page cache. It needs to be removed from the |
page is still in the page cache. It needs to be removed from the |
1140 |
give up on i since it is still to be unmapped and it is not |
give up on i since it is still to be unmapped and it is not |
1141 |
freeable at this moment. |
freeable at this moment. |
1142 |
|
|
1143 |
\begin{verbatim} |
\begin{verbatim} |
1144 |
} else { |
} else { |
1145 |
/* failed to drop the buffers so stop here */ |
/* failed to drop the buffers so stop here */ |
1146 |
UnlockPage(page); |
UnlockPage(page); |
1147 |
page_cache_release(page); |
page_cache_release(page); |
1148 |
|
|
1149 |
spin_lock(&pagemap_lru_lock); |
spin_lock(&pagemap_lru_lock); |
1150 |
continue; |
continue; |
1151 |
} |
} |
1152 |
} |
} |
1153 |
\end{verbatim} |
\end{verbatim} |
1154 |
|
|
1155 |
The buffers could not be freed, so give up on this page. It is time |
The buffers could not be freed, so give up on this page. It is time |
1156 |
to try another page from the inactive list. |
to try another page from the inactive list. |
1157 |
|
|
1158 |
\begin{verbatim} |
\begin{verbatim} |
1159 |
spin_lock(&pagecache_lock); |
spin_lock(&pagecache_lock); |
1160 |
|
|
1161 |
/* |
/* |
1162 |
* this is the non-racy check for busy page. |
* this is the non-racy check for busy page. |
1163 |
*/ |
*/ |
1164 |
if (!page->mapping || !is_page_cache_freeable(page)) { |
if (!page->mapping || !is_page_cache_freeable(page)) { |
1165 |
spin_unlock(&pagecache_lock); |
spin_unlock(&pagecache_lock); |
1166 |
UnlockPage(page); |
UnlockPage(page); |
1167 |
page_mapped: |
page_mapped: |
1168 |
if (--max_mapped >= 0) |
if (--max_mapped >= 0) |
1169 |
continue; |
continue; |
1170 |
\end{verbatim} |
\end{verbatim} |
1171 |
|
|
1172 |
For anonymous pages without buffers, that is a race check since |
For anonymous pages without buffers, that is a race check since |
1173 |
they probably have been removed from the page cache in the |
they probably have been removed from the page cache in the |
1175 |
and are still mapped by processes, it is time to account them to |
and are still mapped by processes, it is time to account them to |
1176 |
\texttt{max\_mapped} variable. |
\texttt{max\_mapped} variable. |
1177 |
|
|
1178 |
\begin{verbatim} |
\begin{verbatim} |
1179 |
/* |
/* |
1180 |
* Alert! We've found too many mapped pages on the |
* Alert! We've found too many mapped pages on the |
1181 |
* inactive list, so we start swapping out now! |
* inactive list, so we start swapping out now! |
1182 |
*/ |
*/ |
1183 |
spin_unlock(&pagemap_lru_lock); |
spin_unlock(&pagemap_lru_lock); |
1184 |
swap_out(priority, gfp_mask, classzone); |
swap_out(priority, gfp_mask, classzone); |
1185 |
return nr_pages; |
return nr_pages; |
1186 |
} |
} |
1187 |
\end{verbatim} |
\end{verbatim} |
1188 |
|
|
1189 |
When a \texttt{max\_mapped} number of pages have been observed to |
When a \texttt{max\_mapped} number of pages have been observed to |
1190 |
be mapped to processes, it is time to start unmapping pages that |
be mapped to processes, it is time to start unmapping pages that |
1193 |
reaching a \texttt{max\_mapped} number of mapped pages is one of |
reaching a \texttt{max\_mapped} number of mapped pages is one of |
1194 |
the conditions to stop the scan process. |
the conditions to stop the scan process. |
1195 |
|
|
1196 |
\begin{verbatim} |
\begin{verbatim} |
1197 |
/* |
/* |
1198 |
* It is critical to check PageDirty _after_ we made sure |
* It is critical to check PageDirty _after_ we made sure |
1199 |
* the page is freeable* so not in use by anybody. |
* the page is freeable* so not in use by anybody. |
1200 |
*/ |
*/ |
1201 |
if (PageDirty(page)) { |
if (PageDirty(page)) { |
1202 |
spin_unlock(&pagecache_lock); |
spin_unlock(&pagecache_lock); |
1203 |
UnlockPage(page); |
UnlockPage(page); |
1204 |
continue; |
continue; |
1205 |
} |
} |
1206 |
\end{verbatim} |
\end{verbatim} |
1207 |
|
|
1208 |
To do |
To do |
1209 |
|
|
1210 |
\begin{verbatim} |
\begin{verbatim} |
1211 |
/* point of no return */ |
/* point of no return */ |
1212 |
if (likely(!PageSwapCache(page))) { |
if (likely(!PageSwapCache(page))) { |
1213 |
__remove_inode_page(page); |
__remove_inode_page(page); |
1214 |
spin_unlock(&pagecache_lock); |
spin_unlock(&pagecache_lock); |
1215 |
} else { |
} else { |
1216 |
swp_entry_t swap; |
swp_entry_t swap; |
1217 |
swap.val = page->index; |
swap.val = page->index; |
1218 |
__delete_from_swap_cache(page); |
__delete_from_swap_cache(page); |
1219 |
spin_unlock(&pagecache_lock); |
spin_unlock(&pagecache_lock); |
1220 |
swap_free(swap); |
swap_free(swap); |
1221 |
} |
} |
1222 |
|
|
1223 |
__lru_cache_del(page); |
__lru_cache_del(page); |
1224 |
UnlockPage(page); |
UnlockPage(page); |
1225 |
|
|
1226 |
/* effectively free the page here */ |
/* effectively free the page here */ |
1227 |
page_cache_release(page); |
page_cache_release(page); |
1228 |
|
|
1229 |
|
if (--nr_pages) |
1230 |
|
continue; |
1231 |
|
break; |
1232 |
|
} |
1233 |
|
spin_unlock(&pagemap_lru_lock); |
1234 |
|
|
1235 |
if (--nr_pages) |
return nr_pages; |
1236 |
continue; |
\end{verbatim} |
|
break; |
|
|
} |
|
|
spin_unlock(&pagemap_lru_lock); |
|
|
|
|
|
return nr_pages; |
|
|
\end{verbatim} |
|
1237 |
|
|
1238 |
That is the part of the code where the page is not mapped by any |
That is the part of the code where the page is not mapped by any |
1239 |
process, it is not dirty and does not have buffers, so it can |
process, it is not dirty and does not have buffers, so it can |
1244 |
\subsection{Function refill\_inactive()} |
\subsection{Function refill\_inactive()} |
1245 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
1246 |
\textit{Prototype: } |
\textit{Prototype: } |
1247 |
\begin{verbatim} |
\begin{verbatim} |
1248 |
void refill_inactive(int nr_pages) |
void refill_inactive(int nr_pages) |
1249 |
\end{verbatim} |
\end{verbatim} |
1250 |
This function moves pages from the active list to the inactive list. |
This function moves pages from the active list to the inactive list. |
1251 |
\begin{verbatim} |
\begin{verbatim} |
1252 |
struct list_head * entry; |
struct list_head * entry; |
1253 |
|
|
1254 |
spin_lock(&pagemap_lru_lock); |
spin_lock(&pagemap_lru_lock); |
1255 |
entry = active_list.prev; |
entry = active_list.prev; |
1256 |
while (nr_pages && entry != &active_list) { |
while (nr_pages && entry != &active_list) { |
1257 |
struct page * page; |
struct page * page; |
1258 |
|
|
1259 |
page = list_entry(entry, struct page, lru); |
page = list_entry(entry, struct page, lru); |
1260 |
entry = entry->prev; |
entry = entry->prev; |
1261 |
if (PageTestandClearReferenced(page)) { |
if (PageTestandClearReferenced(page)) { |
1262 |
list_del(&page->lru); |
list_del(&page->lru); |
1263 |
list_add(&page->lru, &active_list); |
list_add(&page->lru, &active_list); |
1264 |
continue; |
continue; |
1265 |
} |
} |
1266 |
|
|
1267 |
nr_pages--; |
nr_pages--; |
1268 |
|
|
1269 |
del_page_from_active_list(page); |
del_page_from_active_list(page); |
1270 |
add_page_to_inactive_list(page); |
add_page_to_inactive_list(page); |
1271 |
SetPageReferenced(page); |
SetPageReferenced(page); |
1272 |
} |
} |
1273 |
spin_unlock(&pagemap_lru_lock); |
spin_unlock(&pagemap_lru_lock); |
1274 |
\end{verbatim} |
\end{verbatim} |
1275 |
|
|
1276 |
|
|
1277 |
|
|
1279 |
\subsection{Function shrink\_caches()} |
\subsection{Function shrink\_caches()} |
1280 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
1281 |
\textit{Prototype: } |
\textit{Prototype: } |
1282 |
\begin{verbatim} |
\begin{verbatim} |
1283 |
int shrink_caches(zone_t * classzone, |
int shrink_caches(zone_t * classzone, |
1284 |
int priority, |
int priority, |
1285 |
unsigned int gfp_mask, |
unsigned int gfp_mask, |
1286 |
int nr_pages) |
int nr_pages) |
1287 |
\end{verbatim} |
\end{verbatim} |
1288 |
|
|
1289 |
\begin{verbatim} |
\begin{verbatim} |
1290 |
int chunk_size = nr_pages; |
int chunk_size = nr_pages; |
1291 |
unsigned long ratio; |
unsigned long ratio; |
1292 |
|
|
1293 |
nr_pages -= kmem_cache_reap(gfp_mask); |
nr_pages -= kmem_cache_reap(gfp_mask); |
1294 |
if (nr_pages <= 0) |
if (nr_pages <= 0) |
1295 |
return 0; |
return 0; |
1296 |
|
|
1297 |
nr_pages = chunk_size; |
nr_pages = chunk_size; |
1298 |
/* try to keep the active list 2/3 of the size of the cache */ |
/* try to keep the active list 2/3 of the size of the cache */ |
1299 |
ratio = (unsigned long) nr_pages * |
ratio = (unsigned long) nr_pages * |
1300 |
nr_active_pages / ((nr_inactive_pages + 1) * 2); |
nr_active_pages / ((nr_inactive_pages + 1) * 2); |
1301 |
refill_inactive(ratio); |
refill_inactive(ratio); |
1302 |
|
|
1303 |
nr_pages = shrink_cache(nr_pages, classzone, gfp_mask, priority); |
nr_pages = shrink_cache(nr_pages, classzone, gfp_mask, |
1304 |
if (nr_pages <= 0) |
priority); |
1305 |
return 0; |
if (nr_pages <= 0) |
1306 |
|
return 0; |
1307 |
shrink_dcache_memory(priority, gfp_mask); |
|
1308 |
shrink_icache_memory(priority, gfp_mask); |
shrink_dcache_memory(priority, gfp_mask); |
1309 |
#ifdef CONFIG_QUOTA |
shrink_icache_memory(priority, gfp_mask); |
1310 |
shrink_dqcache_memory(DEF_PRIORITY, gfp_mask); |
#ifdef CONFIG_QUOTA |
1311 |
#endif |
shrink_dqcache_memory(DEF_PRIORITY, gfp_mask); |
1312 |
|
#endif |
1313 |
|
|
1314 |
return nr_pages; |
return nr_pages; |
1315 |
\end{verbatim} |
\end{verbatim} |
1316 |
|
|
1317 |
|
|
1318 |
|
|
1320 |
|
|
1321 |
\subsection{Function try\_to\_free\_pages()}\label{fun:ttfp} |
\subsection{Function try\_to\_free\_pages()}\label{fun:ttfp} |
1322 |
\textit{Prototype: } |
\textit{Prototype: } |
1323 |
\begin{verbatim} |
\begin{verbatim} |
1324 |
int try_to_free_pages(zone_t *classzone, |
int try_to_free_pages(zone_t *classzone, |
1325 |
unsigned int gfp_mask, |
unsigned int gfp_mask, |
1326 |
unsigned int order) |
unsigned int order) |
1327 |
\end{verbatim} |
\end{verbatim} |
1328 |
|
|
1329 |
|
\begin{verbatim} |
1330 |
|
int priority = DEF_PRIORITY; |
1331 |
|
int nr_pages = SWAP_CLUSTER_MAX; |
1332 |
|
|
1333 |
|
gfp_mask = pf_gfp_mask(gfp_mask); |
1334 |
|
do { |
1335 |
|
nr_pages = shrink_caches(classzone, priority, gfp_mask, |
1336 |
|
nr_pages); |
1337 |
|
if (nr_pages <= 0) |
1338 |
|
return 1; |
1339 |
|
} while (--priority); |
1340 |
|
|
1341 |
\begin{verbatim} |
/* |
1342 |
int priority = DEF_PRIORITY; |
* Hmm.. Cache shrink failed - time to kill something? |
1343 |
int nr_pages = SWAP_CLUSTER_MAX; |
* Mhwahahhaha! This is the part I really like. Giggle. |
1344 |
|
*/ |
1345 |
gfp_mask = pf_gfp_mask(gfp_mask); |
out_of_memory(); |
1346 |
do { |
return 0; |
1347 |
nr_pages = shrink_caches(classzone, priority, gfp_mask, nr_pages); |
\end{verbatim} |
|
if (nr_pages <= 0) |
|
|
return 1; |
|
|
} while (--priority); |
|
|
|
|
|
/* |
|
|
* Hmm.. Cache shrink failed - time to kill something? |
|
|
* Mhwahahhaha! This is the part I really like. Giggle. |
|
|
*/ |
|
|
out_of_memory(); |
|
|
return 0; |
|
|
\end{verbatim} |
|
1348 |
|
|
1349 |
|
|
1350 |
|
|
1352 |
\subsection{Function check\_classzone\_need\_balance()} |
\subsection{Function check\_classzone\_need\_balance()} |
1353 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
1354 |
\textit{Prototype: } |
\textit{Prototype: } |
1355 |
\begin{verbatim} |
\begin{verbatim} |
1356 |
int check_classzone_need_balance(zone_t * classzone) |
int check_classzone_need_balance(zone_t * classzone) |
1357 |
\end{verbatim} |
\end{verbatim} |
1358 |
|
|
1359 |
|
|
1360 |
\begin{verbatim} |
\begin{verbatim} |
1361 |
zone_t * first_classzone; |
zone_t * first_classzone; |
1362 |
|
|
1363 |
first_classzone = classzone->zone_pgdat->node_zones; |
first_classzone = classzone->zone_pgdat->node_zones; |
1364 |
while (classzone >= first_classzone) { |
while (classzone >= first_classzone) { |
1365 |
if (classzone->free_pages > classzone->pages_high) |
if (classzone->free_pages > classzone->pages_high) |
1366 |
return 0; |
return 0; |
1367 |
classzone--; |
classzone--; |
1368 |
} |
} |
1369 |
return 1; |
return 1; |
1370 |
\end{verbatim} |
\end{verbatim} |
1371 |
|
|
1372 |
|
|
1373 |
|
|
1376 |
\subsection{Function kswapd\_balance\_pgdat()} |
\subsection{Function kswapd\_balance\_pgdat()} |
1377 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
1378 |
\textit{Prototype: } |
\textit{Prototype: } |
1379 |
\begin{verbatim} |
\begin{verbatim} |
1380 |
int kswapd_balance_pgdat(pg_data_t * pgdat) |
int kswapd_balance_pgdat(pg_data_t * pgdat) |
1381 |
\end{verbatim} |
\end{verbatim} |
1382 |
|
|
1383 |
\begin{verbatim} |
\begin{verbatim} |
1384 |
int need_more_balance = 0, i; |
int need_more_balance = 0, i; |
1385 |
zone_t * zone; |
zone_t * zone; |
1386 |
|
|
1387 |
for (i = pgdat->nr_zones-1; i >= 0; i--) { |
for (i = pgdat->nr_zones-1; i >= 0; i--) { |
1388 |
zone = pgdat->node_zones + i; |
zone = pgdat->node_zones + i; |
1389 |
if (unlikely(current->need_resched)) |
if (unlikely(current->need_resched)) |
1390 |
schedule(); |
schedule(); |
1391 |
if (!zone->need_balance) |
if (!zone->need_balance) |
1392 |
continue; |
continue; |
1393 |
if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) { |
if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) { |
1394 |
zone->need_balance = 0; |
zone->need_balance = 0; |
1395 |
__set_current_state(TASK_INTERRUPTIBLE); |
__set_current_state(TASK_INTERRUPTIBLE); |
1396 |
schedule_timeout(HZ); |
schedule_timeout(HZ); |
1397 |
continue; |
continue; |
1398 |
} |
} |
1399 |
if (check_classzone_need_balance(zone)) |
if (check_classzone_need_balance(zone)) |
1400 |
need_more_balance = 1; |
need_more_balance = 1; |
1401 |
else |
else |
1402 |
zone->need_balance = 0; |
zone->need_balance = 0; |
1403 |
} |
} |
1404 |
|
|
1405 |
return need_more_balance; |
return need_more_balance; |
1406 |
\end{verbatim} |
\end{verbatim} |
1407 |
|
|
1408 |
|
|
1409 |
|
|
1411 |
\subsection{Function kswapd\_balance()} |
\subsection{Function kswapd\_balance()} |
1412 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
1413 |
\textit{Prototype: } |
\textit{Prototype: } |
1414 |
\begin{verbatim} |
\begin{verbatim} |
1415 |
void kswapd_balance(void) |
void kswapd_balance(void) |
1416 |
\end{verbatim} |
\end{verbatim} |
1417 |
|
|
1418 |
\begin{verbatim} |
\begin{verbatim} |
1419 |
int need_more_balance; |
int need_more_balance; |
1420 |
pg_data_t * pgdat; |
pg_data_t * pgdat; |
1421 |
|
|
1422 |
do { |
do { |
1423 |
need_more_balance = 0; |
need_more_balance = 0; |
1424 |
pgdat = pgdat_list; |
pgdat = pgdat_list; |
1425 |
do |
do |
1426 |
need_more_balance |= kswapd_balance_pgdat(pgdat); |
need_more_balance |= kswapd_balance_pgdat(pgdat); |
1427 |
while ((pgdat = pgdat->node_next)); |
while ((pgdat = pgdat->node_next)); |
1428 |
} while (need_more_balance); |
} while (need_more_balance); |
1429 |
\end{verbatim} |
\end{verbatim} |
1430 |
|
|
1431 |
|
|
1432 |
|
|
1435 |
\subsection{Function kswapd\_can\_sleep\_pgdat()} |
\subsection{Function kswapd\_can\_sleep\_pgdat()} |
1436 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
1437 |
\textit{Prototype: } |
\textit{Prototype: } |
1438 |
\begin{verbatim} |
\begin{verbatim} |
1439 |
int kswapd_can_sleep_pgdat(pg_data_t * pgdat) |
int kswapd_can_sleep_pgdat(pg_data_t * pgdat) |
1440 |
\end{verbatim} |
\end{verbatim} |
1441 |
|
|
1442 |
|
|
1443 |
|
\begin{verbatim} |
1444 |
|
zone_t * zone; |
1445 |
|
int i; |
1446 |
|
|
1447 |
|
for (i = pgdat->nr_zones-1; i >= 0; i--) { |
1448 |
|
zone = pgdat->node_zones + i; |
1449 |
|
if (!zone->need_balance) |
1450 |
|
continue; |
1451 |
|
return 0; |
1452 |
|
} |
1453 |
|
|
1454 |
\begin{verbatim} |
return 1; |
1455 |
zone_t * zone; |
\end{verbatim} |
|
int i; |
|
|
|
|
|
for (i = pgdat->nr_zones-1; i >= 0; i--) { |
|
|
zone = pgdat->node_zones + i; |
|
|
if (!zone->need_balance) |
|
|
continue; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
return 1; |
|
|
\end{verbatim} |
|
1456 |
|
|
1457 |
\subsection{Function kswapd\_can\_sleep()} |
\subsection{Function kswapd\_can\_sleep()} |
1458 |
\textit{File: }\url{mm/vmscan.c}\\ |
\textit{File: }\url{mm/vmscan.c}\\ |
1459 |
\textit{Prototype: } |
\textit{Prototype: } |
1460 |
\begin{verbatim} |
\begin{verbatim} |
1461 |
int kswapd_can_sleep(void) |
int kswapd_can_sleep(void) |
1462 |
\end{verbatim} |
\end{verbatim} |
1463 |
|
|
1464 |
|
|
1465 |
\begin{verbatim} |
\begin{verbatim} |
1466 |
pg_data_t * pgdat; |
pg_data_t * pgdat; |
1467 |
|
|
1468 |
|
pgdat = pgdat_list; |
1469 |
|
do { |
1470 |
|
if (kswapd_can_sleep_pgdat(pgdat)) |
1471 |
|
continue; |
1472 |
|
return 0; |
1473 |
|
} while ((pgdat = pgdat->node_next)); |
1474 |
|
|
1475 |
pgdat = pgdat_list; |
return 1; |
1476 |
do { |
\end{verbatim} |
|
if (kswapd_can_sleep_pgdat(pgdat)) |
|
|
continue; |
|
|
return 0; |
|
|
} while ((pgdat = pgdat->node_next)); |
|
|
|
|
|
return 1; |
|
|
\end{verbatim} |
|
1477 |
|
|
1478 |
\section{Mechanism} |
\section{Mechanism} |
1479 |
swapfile.c |
swapfile.c |