7 |
functions are started in \texttt{do\_initcalls()}. |
functions are started in \texttt{do\_initcalls()}. |
8 |
|
|
9 |
\subsection{Function kswapd\_init()} |
\subsection{Function kswapd\_init()} |
10 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
11 |
\textit{Prototype: } |
\textit{Prototype: } |
12 |
\begin{verbatim} |
\begin{verbatim} |
13 |
static int __init kswapd_init(void) |
static int __init kswapd_init(void) |
24 |
\end{verbatim} |
\end{verbatim} |
25 |
|
|
26 |
\subsection{Function kswapd()} |
\subsection{Function kswapd()} |
27 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
28 |
\textit{Prototype: } |
\textit{Prototype: } |
29 |
\begin{verbatim} |
\begin{verbatim} |
30 |
int kswapd(void *unused) |
int kswapd(void *unused) |
147 |
freed soon. |
freed soon. |
148 |
|
|
149 |
\subsection{Function try\_to\_swap\_out()} |
\subsection{Function try\_to\_swap\_out()} |
150 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
151 |
\textit{Prototype: } |
\textit{Prototype: } |
152 |
\begin{verbatim} |
\begin{verbatim} |
153 |
int try_to_swap_out(struct mm_struct * mm, |
int try_to_swap_out(struct mm_struct * mm, |
157 |
struct page *page, |
struct page *page, |
158 |
zone_t * classzone) |
zone_t * classzone) |
159 |
\end{verbatim} |
\end{verbatim} |
160 |
|
|
161 |
|
The role of the \texttt{try\_to\_swap\_out()} function is to try |
162 |
|
to unmap pages from processes mapping them. This is the first |
163 |
|
part of the whole swap out process, since pages can only be freed |
164 |
|
if all processes mapping them have already been safely unmapped. |
165 |
|
Unmapping means that, given a page table entry (pte), either it |
166 |
|
is just cleared or remapped to a swap address. In both cases the |
167 |
|
present bit of the pte is off. Therefore, the process to which |
168 |
|
this pte belongs will not be able to access it directly, causing |
169 |
|
a page fault for any future access. |
170 |
|
|
171 |
|
This function returns an int value. That value will be 0 if no |
172 |
|
freeable page (ie, a page not mapped by any process any longer) |
173 |
|
has been freed. That will happen even in the case a page got |
174 |
|
unmapped from a process, but is still mapped by other processes. |
175 |
|
That return value will be 1 if a page has been freed from its |
176 |
|
last process (no process is mapping it at the moment this |
177 |
|
function exits). |
178 |
|
|
179 |
\begin{verbatim} |
\begin{verbatim} |
180 |
pte_t pte; |
pte_t pte; |
181 |
swp_entry_t entry; |
swp_entry_t entry; |
182 |
|
|
183 |
/* Don't look at this pte if it's been accessed recently. */ |
/* Don't look at this pte if it's been accessed recently. */ |
184 |
if ((vma->vm_flags & VM_LOCKED) || |
if ((vma->vm_flags & VM_LOCKED) |
185 |
ptep_test_and_clear_young(page_table)) { |
|| ptep_test_and_clear_young(page_table)) { |
186 |
mark_page_accessed(page); |
mark_page_accessed(page); |
187 |
return 0; |
return 0; |
188 |
} |
} |
189 |
|
\end{verbatim} |
190 |
|
|
191 |
|
That is part of VM aging process. Here, based on the young bit |
192 |
|
from page table entries (pte), \texttt{try\_to\_swap\_out()} sets |
193 |
|
this page as accessed. If it is the second time that this page is |
194 |
|
set as accessed and it happens that it is still on inactive list, |
195 |
|
\texttt{mark\_page\_accessed()} will move this page to the active |
196 |
|
list. |
197 |
|
|
198 |
|
\begin{verbatim} |
199 |
/* Don't bother unmapping pages that are active */ |
/* Don't bother unmapping pages that are active */ |
200 |
if (PageActive(page)) |
if (PageActive(page)) |
201 |
return 0; |
return 0; |
202 |
|
\end{verbatim} |
203 |
|
|
204 |
|
Active pages are supposed to have been accessed often, so it is |
205 |
|
worthless to unmap them since it is likely they will be mapped |
206 |
|
back soon. |
207 |
|
|
208 |
|
\begin{verbatim} |
209 |
/* Don't bother replenishing zones not under pressure.. */ |
/* Don't bother replenishing zones not under pressure.. */ |
210 |
if (!memclass(page_zone(page), classzone)) |
if (!memclass(page_zone(page), classzone)) |
211 |
return 0; |
return 0; |
212 |
|
\end{verbatim} |
213 |
|
|
214 |
|
Neither it is sensible to free pages from zones other that the |
215 |
|
ones that are under memory shortage. |
216 |
|
|
217 |
|
\begin{verbatim} |
218 |
if (TryLockPage(page)) |
if (TryLockPage(page)) |
219 |
return 0; |
return 0; |
220 |
|
\end{verbatim} |
221 |
|
|
222 |
|
The page is tried to lock at once given that the unmapping |
223 |
|
process is not dependant on an specific page and it is not worth |
224 |
|
to sleep to try to unmap any page. |
225 |
|
|
226 |
|
\begin{verbatim} |
227 |
/* From this point on, the odds are that we're going to |
/* From this point on, the odds are that we're going to |
228 |
* nuke this pte, so read and clear the pte. This hook |
* nuke this pte, so read and clear the pte. This hook |
229 |
* is needed on CPUs which update the accessed and dirty |
* is needed on CPUs which update the accessed and dirty |
232 |
flush_cache_page(vma, address); |
flush_cache_page(vma, address); |
233 |
pte = ptep_get_and_clear(page_table); |
pte = ptep_get_and_clear(page_table); |
234 |
flush_tlb_page(vma, address); |
flush_tlb_page(vma, address); |
235 |
|
\end{verbatim} |
236 |
|
|
237 |
|
Research. |
238 |
|
|
239 |
|
\begin{verbatim} |
240 |
if (pte_dirty(pte)) |
if (pte_dirty(pte)) |
241 |
set_page_dirty(page); |
set_page_dirty(page); |
242 |
|
\end{verbatim} |
243 |
|
|
244 |
|
\begin{verbatim} |
245 |
/* |
/* |
246 |
* Is the page already in the swap cache? If so, then |
* Is the page already in the swap cache? If so, then |
247 |
* we can just drop our reference to it without doing |
* we can just drop our reference to it without doing |
252 |
swap_duplicate(entry); |
swap_duplicate(entry); |
253 |
set_swap_pte: |
set_swap_pte: |
254 |
set_pte(page_table, swp_entry_to_pte(entry)); |
set_pte(page_table, swp_entry_to_pte(entry)); |
255 |
|
\end{verbatim} |
256 |
|
|
257 |
|
In the case this page has already been added to the swap cache, |
258 |
|
there is only the need to increase the swap counter (by |
259 |
|
\texttt{swap\_duplicate()}) and set this \emph{pte} to the swap |
260 |
|
address. The swap address is stored in the \texttt{index} field |
261 |
|
of the \texttt{struct page}. |
262 |
|
|
263 |
|
\begin{verbatim} |
264 |
drop_pte: |
drop_pte: |
265 |
mm->rss--; |
mm->rss--; |
266 |
UnlockPage(page); |
UnlockPage(page); |
270 |
return freeable; |
return freeable; |
271 |
} |
} |
272 |
} |
} |
273 |
|
\end{verbatim} |
274 |
|
|
275 |
|
If any process is no longer mapped to this page, the return value |
276 |
|
is 1, since this page is completely unmapped from the processes |
277 |
|
and can be freed. |
278 |
|
|
279 |
|
\begin{verbatim} |
280 |
/* |
/* |
281 |
* Is it a clean page? Then it must be recoverable |
* Is it a clean page? Then it must be recoverable |
282 |
* by just paging it in again, and we can just drop |
* by just paging it in again, and we can just drop |
302 |
*/ |
*/ |
303 |
if (page->buffers) |
if (page->buffers) |
304 |
goto preserve; |
goto preserve; |
305 |
|
\end{verbatim} |
306 |
|
|
307 |
|
Anonymous pages are pages without backing store, ie. not mapped |
308 |
|
to any address space. Anonymous buffer cache pages are anonymous |
309 |
|
pages with buffers. In particular, these pages have already been |
310 |
|
mapped to an address space, but aren't any longer. |
311 |
|
|
312 |
|
\begin{verbatim} |
313 |
/* |
/* |
314 |
* This is a dirty, swappable page. First of all, |
* This is a dirty, swappable page. First of all, |
315 |
* get a suitable swap entry for it, and make sure |
* get a suitable swap entry for it, and make sure |
329 |
set_page_dirty(page); |
set_page_dirty(page); |
330 |
goto set_swap_pte; |
goto set_swap_pte; |
331 |
} |
} |
332 |
|
\end{verbatim} |
333 |
|
|
334 |
|
That is a dirty and anonymous page, so let's get a swap entry for |
335 |
|
it in order to remap its \emph{pte} to this new address. Later |
336 |
|
this page is added to the swap cache, which will, for its turn, |
337 |
|
add it to the page cache and also the LRU lists (actually the |
338 |
|
inactive list). |
339 |
|
|
340 |
|
Given that this page has no backing store (recall it is an |
341 |
|
anonymous page), this page needs to be set as dirty in order to |
342 |
|
be written. |
343 |
|
|
344 |
|
\begin{verbatim} |
345 |
/* Raced with "speculative" read_swap_cache_async */ |
/* Raced with "speculative" read_swap_cache_async */ |
346 |
swap_free(entry); |
swap_free(entry); |
347 |
} |
} |
348 |
|
\end{verbatim} |
349 |
|
|
350 |
|
When servicing a page fault for a swap address, some pages are |
351 |
|
read ahead if the page is not present in the swap cache. In this |
352 |
|
case, the page is added to the swap cache with the address the |
353 |
|
system will be reading. However a particular swap address that |
354 |
|
will be read from the swap device (or partition) might have been |
355 |
|
provided to unmap a page here. When the |
356 |
|
\texttt{add\_to\_swap\_cache()} function does not return 0, it |
357 |
|
means that another page has been added to the swap cache with |
358 |
|
this very swap entry by the read ahead function. Thus it is |
359 |
|
necessary to drop the counter of this swap entry and get a new |
360 |
|
one. |
361 |
|
|
362 |
|
\begin{verbatim} |
363 |
/* No swap space left */ |
/* No swap space left */ |
364 |
preserve: |
preserve: |
365 |
set_pte(page_table, pte); |
set_pte(page_table, pte); |
366 |
UnlockPage(page); |
UnlockPage(page); |
367 |
return 0; |
return 0; |
368 |
\end{verbatim} |
\end{verbatim} |
369 |
|
|
370 |
|
No swap space is left, what \texttt{try\_to\_swap\_out()} is |
371 |
|
unable to unmap this anonymous page. Let's set the page table |
372 |
|
entry back to the original value and return zero since no |
373 |
|
freeable page has been unmapped in this try. |
374 |
|
|
375 |
\subsection{Function swap\_out\_pmd()} |
\subsection{Function swap\_out\_pmd()} |
376 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
377 |
\textit{Prototype: } |
\textit{Prototype: } |
378 |
\begin{verbatim} |
\begin{verbatim} |
379 |
int swap_out_pmd(struct mm_struct * mm, |
int swap_out_pmd(struct mm_struct * mm, |
424 |
|
|
425 |
|
|
426 |
\subsection{Function swap\_out\_pgd()} |
\subsection{Function swap\_out\_pgd()} |
427 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
428 |
\textit{Prototype: } |
\textit{Prototype: } |
429 |
\begin{verbatim} |
\begin{verbatim} |
430 |
int swap_out_pgd(struct mm_struct * mm, |
int swap_out_pgd(struct mm_struct * mm, |
466 |
|
|
467 |
|
|
468 |
\subsection{Function swap\_out\_vma()} |
\subsection{Function swap\_out\_vma()} |
469 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
470 |
\textit{Prototype: } |
\textit{Prototype: } |
471 |
\begin{verbatim} |
\begin{verbatim} |
472 |
int swap_out_vma(struct mm_struct * mm, |
int swap_out_vma(struct mm_struct * mm, |
501 |
|
|
502 |
|
|
503 |
\subsection{Function swap\_out\_mm()} |
\subsection{Function swap\_out\_mm()} |
504 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
505 |
\textit{Prototype: } |
\textit{Prototype: } |
506 |
\begin{verbatim} |
\begin{verbatim} |
507 |
int swap_out_mm(struct mm_struct * mm, |
int swap_out_mm(struct mm_struct * mm, |
551 |
|
|
552 |
|
|
553 |
\subsection{Function swap\_out()} |
\subsection{Function swap\_out()} |
554 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
555 |
\textit{Prototype: } |
\textit{Prototype: } |
556 |
\begin{verbatim} |
\begin{verbatim} |
557 |
int swap_out(unsigned int priority, |
int swap_out(unsigned int priority, |
603 |
|
|
604 |
|
|
605 |
\subsection{Function shrink\_cache()} |
\subsection{Function shrink\_cache()} |
606 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
607 |
\textit{Prototype: } |
\textit{Prototype: } |
608 |
\begin{verbatim} |
\begin{verbatim} |
609 |
int shrink_cache(int nr_pages, |
int shrink_cache(int nr_pages, |
803 |
|
|
804 |
|
|
805 |
\subsection{Function refill\_inactive()} |
\subsection{Function refill\_inactive()} |
806 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
807 |
\textit{Prototype: } |
\textit{Prototype: } |
808 |
\begin{verbatim} |
\begin{verbatim} |
809 |
void refill_inactive(int nr_pages) |
void refill_inactive(int nr_pages) |
838 |
|
|
839 |
|
|
840 |
\subsection{Function shrink\_caches()} |
\subsection{Function shrink\_caches()} |
841 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
842 |
\textit{Prototype: } |
\textit{Prototype: } |
843 |
\begin{verbatim} |
\begin{verbatim} |
844 |
int shrink_caches(zone_t * classzone, |
int shrink_caches(zone_t * classzone, |
909 |
|
|
910 |
|
|
911 |
\subsection{Function check\_classzone\_need\_balance()} |
\subsection{Function check\_classzone\_need\_balance()} |
912 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
913 |
\textit{Prototype: } |
\textit{Prototype: } |
914 |
\begin{verbatim} |
\begin{verbatim} |
915 |
int check_classzone_need_balance(zone_t * classzone) |
int check_classzone_need_balance(zone_t * classzone) |
933 |
|
|
934 |
|
|
935 |
\subsection{Function kswapd\_balance\_pgdat()} |
\subsection{Function kswapd\_balance\_pgdat()} |
936 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
937 |
\textit{Prototype: } |
\textit{Prototype: } |
938 |
\begin{verbatim} |
\begin{verbatim} |
939 |
int kswapd_balance_pgdat(pg_data_t * pgdat) |
int kswapd_balance_pgdat(pg_data_t * pgdat) |
968 |
|
|
969 |
|
|
970 |
\subsection{Function kswapd\_balance()} |
\subsection{Function kswapd\_balance()} |
971 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
972 |
\textit{Prototype: } |
\textit{Prototype: } |
973 |
\begin{verbatim} |
\begin{verbatim} |
974 |
void kswapd_balance(void) |
void kswapd_balance(void) |
992 |
|
|
993 |
|
|
994 |
\subsection{Function kswapd\_can\_sleep\_pgdat()} |
\subsection{Function kswapd\_can\_sleep\_pgdat()} |
995 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
996 |
\textit{Prototype: } |
\textit{Prototype: } |
997 |
\begin{verbatim} |
\begin{verbatim} |
998 |
int kswapd_can_sleep_pgdat(pg_data_t * pgdat) |
int kswapd_can_sleep_pgdat(pg_data_t * pgdat) |
1013 |
return 1; |
return 1; |
1014 |
\end{verbatim} |
\end{verbatim} |
1015 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1016 |
\subsection{Function kswapd\_can\_sleep()} |
\subsection{Function kswapd\_can\_sleep()} |
1017 |
|
\textit{File: }\url{mm/vmscan.c}\\ |
1018 |
\textit{Prototype: } |
\textit{Prototype: } |
1019 |
\begin{verbatim} |
\begin{verbatim} |
1020 |
int kswapd_can_sleep(void) |
int kswapd_can_sleep(void) |