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 |
TODO |
Read the page table entry data into pte. Also clear it in the |
239 |
|
page table to avoid having this pte modified in the meanwhile |
240 |
|
(for example in cases where CPUs that update bits like accessed |
241 |
|
and dirty in hardware, like told in the comment). |
242 |
|
|
243 |
\begin{verbatim} |
\begin{verbatim} |
244 |
if (pte_dirty(pte)) |
if (pte_dirty(pte)) |
2165 |
\begin{verbatim} |
\begin{verbatim} |
2166 |
int can_share_swap_page(struct page *page) |
int can_share_swap_page(struct page *page) |
2167 |
\end{verbatim} |
\end{verbatim} |
2168 |
|
|
2169 |
TODO |
This function returns an int value that means if this page can be |
2170 |
|
shared (return value: one) or not (return value: zero). Here ``to |
2171 |
|
be shared'' means that this page nor its swap entry are mapped by |
2172 |
|
other process. |
2173 |
|
|
2174 |
\begin{verbatim} |
\begin{verbatim} |
2175 |
int retval = 0; |
int retval = 0; |
2177 |
if (!PageLocked(page)) |
if (!PageLocked(page)) |
2178 |
BUG(); |
BUG(); |
2179 |
switch (page_count(page)) { |
switch (page_count(page)) { |
2180 |
|
\end{verbatim} |
2181 |
|
|
2182 |
|
Start checking if it can be shared looking into its page counter. |
2183 |
|
|
2184 |
|
\begin{verbatim} |
2185 |
case 3: |
case 3: |
2186 |
if (!page->buffers) |
if (!page->buffers) |
2187 |
break; |
break; |
2188 |
/* Fallthrough */ |
/* Fallthrough */ |
2189 |
|
\end{verbatim} |
2190 |
|
|
2191 |
|
A page with its counter set to 3 either is mapped by a process or |
2192 |
|
have buffers. If it doesn't have buffers, it is surely mapped by |
2193 |
|
a process, so return zero. |
2194 |
|
|
2195 |
|
\begin{verbatim} |
2196 |
case 2: |
case 2: |
2197 |
if (!PageSwapCache(page)) |
if (!PageSwapCache(page)) |
2198 |
break; |
break; |
2199 |
|
\end{verbatim} |
2200 |
|
|
2201 |
|
Check if the page is in the swap cache. Mapped pages that are not |
2202 |
|
in the swap cache must return zero. |
2203 |
|
|
2204 |
|
\begin{verbatim} |
2205 |
retval = exclusive_swap_page(page); |
retval = exclusive_swap_page(page); |
2206 |
|
\end{verbatim} |
2207 |
|
|
2208 |
|
For cases where that is a swap cache page with counter 3 and |
2209 |
|
buffers or counter 2, check if that is an exclusive swap page by |
2210 |
|
calling \texttt{exclusive\_swap\_page()}. That function will |
2211 |
|
check again the page counter and also the swap count for the swap |
2212 |
|
entry this page is set to. In the case no process has mapped this |
2213 |
|
page in the meanwhile and also the swap entry is exclusive. The |
2214 |
|
return value of \texttt{exclusive\_swap\_page()} function will be |
2215 |
|
the return value of this very function. |
2216 |
|
|
2217 |
|
\begin{verbatim} |
2218 |
break; |
break; |
2219 |
case 1: |
case 1: |
2220 |
if (PageReserved(page)) |
if (PageReserved(page)) |
2224 |
return retval; |
return retval; |
2225 |
\end{verbatim} |
\end{verbatim} |
2226 |
|
|
2227 |
|
Pages with counter 1 can be shared. |
2228 |
|
|
2229 |
\subsection{Function remove\_exclusive\_swap\_page()} |
\subsection{Function remove\_exclusive\_swap\_page()} |
2230 |
\textit{File: }\url{mm/swapfile.c}\\ |
\textit{File: }\url{mm/swapfile.c}\\ |
2231 |
\textit{Prototype: } |
\textit{Prototype: } |
2232 |
\begin{verbatim} |
\begin{verbatim} |
2233 |
int remove_exclusive_swap_page(struct page *page) |
int remove_exclusive_swap_page(struct page *page) |
2234 |
\end{verbatim} |
\end{verbatim} |
2235 |
|
|
2236 |
TODO |
This function performs the same task as |
2237 |
|
\texttt{exclusive\_swap\_page()}, checking if the page nor its |
2238 |
|
swap entry are not mapped by processes, and removing the page |
2239 |
|
from swap cache in this case. It returns an int value, which is |
2240 |
|
one if the page was removed and zero otherwise. |
2241 |
|
|
2242 |
\begin{verbatim} |
\begin{verbatim} |
2243 |
int retval; |
int retval; |
2246 |
|
|
2247 |
if (!PageLocked(page)) |
if (!PageLocked(page)) |
2248 |
BUG(); |
BUG(); |
2249 |
|
\end{verbatim} |
2250 |
|
|
2251 |
|
The page is supposed to be locked, so BUG() if it is unlocked. |
2252 |
|
|
2253 |
|
\begin{verbatim} |
2254 |
if (!PageSwapCache(page)) |
if (!PageSwapCache(page)) |
2255 |
return 0; |
return 0; |
2256 |
|
\end{verbatim} |
2257 |
|
|
2258 |
|
Since the page might have been removed from swap cache before the |
2259 |
|
caller got the lock on it, check if the page is still in the swap |
2260 |
|
cache. If it is not, return zero (it was not removed). |
2261 |
|
|
2262 |
|
\begin{verbatim} |
2263 |
/* 2: us + cache */ |
/* 2: us + cache */ |
2264 |
if (page_count(page) - !!page->buffers != 2) |
if (page_count(page) - !!page->buffers != 2) |
2265 |
return 0; |
return 0; |
2266 |
|
\end{verbatim} |
2267 |
|
|
2268 |
|
Pages that have more than 2 users (plus eventual buffers) are |
2269 |
|
mapped by some process, so they are not exclusive and cannot be |
2270 |
|
remove. So, return zero. |
2271 |
|
|
2272 |
|
The page count is checked without the \texttt{pagecache\_lock} |
2273 |
|
held, but will be rechecked below with this lock held. |
2274 |
|
|
2275 |
|
\begin{verbatim} |
2276 |
entry.val = page->index; |
entry.val = page->index; |
2277 |
p = swap_info_get(entry); |
p = swap_info_get(entry); |
2278 |
if (!p) |
if (!p) |
2279 |
return 0; |
return 0; |
2280 |
|
\end{verbatim} |
2281 |
|
|
2282 |
|
Lock the swap list and swap device of the swap entry this page is |
2283 |
|
set to. If that is an invalid entry (\texttt{swap\_info\_get()} |
2284 |
|
returns NULL in this case), return zero. |
2285 |
|
|
2286 |
|
\begin{verbatim} |
2287 |
/* Is the only swap cache user the cache itself? */ |
/* Is the only swap cache user the cache itself? */ |
2288 |
retval = 0; |
retval = 0; |
2289 |
if (p->swap_map[SWP_OFFSET(entry)] == 1) { |
if (p->swap_map[SWP_OFFSET(entry)] == 1) { |
2290 |
|
\end{verbatim} |
2291 |
|
|
2292 |
|
Verify the number of users of this swap entry. If more than one, |
2293 |
|
it is not exclusive, so unlock the swap device, the lists and |
2294 |
|
return zero (see below). |
2295 |
|
|
2296 |
|
\begin{verbatim} |
2297 |
/* Recheck the page count with the pagecache |
/* Recheck the page count with the pagecache |
2298 |
lock held.. */ |
lock held.. */ |
2299 |
spin_lock(&pagecache_lock); |
spin_lock(&pagecache_lock); |
2305 |
spin_unlock(&pagecache_lock); |
spin_unlock(&pagecache_lock); |
2306 |
} |
} |
2307 |
swap_info_put(p); |
swap_info_put(p); |
2308 |
|
\end{verbatim} |
2309 |
|
|
2310 |
|
For swap entries which the swap cache page is the only user, |
2311 |
|
recheck the counter with \texttt{pagecache\_lock} held. If the |
2312 |
|
page is still unmapped by processes, delete it from swap cache. |
2313 |
|
Set it dirty in ordert to be kept by the swap out code. |
2314 |
|
|
2315 |
|
\begin{verbatim} |
2316 |
if (retval) { |
if (retval) { |
2317 |
block_flushpage(page, 0); |
block_flushpage(page, 0); |
2318 |
swap_free(entry); |
swap_free(entry); |
2321 |
|
|
2322 |
return retval; |
return retval; |
2323 |
\end{verbatim} |
\end{verbatim} |
2324 |
|
|
2325 |
|
For pages removed from swap cache, flush them to the disk, drop |
2326 |
|
their reference on the swap entry and drop the reference got by |
2327 |
|
page cache when it was added to the swap cache. |
2328 |
|
|
2329 |
\subsection{Function free\_swap\_and\_cache()} |
\subsection{Function free\_swap\_and\_cache()} |
2330 |
\textit{File: }\url{mm/swapfile.c}\\ |
\textit{File: }\url{mm/swapfile.c}\\ |
2332 |
\begin{verbatim} |
\begin{verbatim} |
2333 |
void free_swap_and_cache(swp_entry_t entry) |
void free_swap_and_cache(swp_entry_t entry) |
2334 |
\end{verbatim} |
\end{verbatim} |
2335 |
|
|
2336 |
TODO |
Given a swap entry, this function will decrease its reference |
2337 |
|
counter (calling \texttt{swap\_entry\_free()}). In the case the |
2338 |
|
counter, after decreased, gets to one, check if this last |
2339 |
|
reference belongs to a swap cache page, trying to free it (only |
2340 |
|
if it could be locked at once). |
2341 |
|
|
2342 |
\begin{verbatim} |
\begin{verbatim} |
2343 |
struct swap_info_struct * p; |
struct swap_info_struct * p; |
2344 |
struct page *page = NULL; |
struct page *page = NULL; |
2345 |
|
|
2346 |
p = swap_info_get(entry); |
p = swap_info_get(entry); |
2347 |
|
\end{verbatim} |
2348 |
|
|
2349 |
|
Lock the swap list and the swap device of this entry, returning |
2350 |
|
the pointer to the swap device info structure. |
2351 |
|
|
2352 |
|
\begin{verbatim} |
2353 |
if (p) { |
if (p) { |
2354 |
if (swap_entry_free(p, SWP_OFFSET(entry)) == 1) |
if (swap_entry_free(p, SWP_OFFSET(entry)) == 1) |
2355 |
|
\end{verbatim} |
2356 |
|
|
2357 |
|
If a valid entry, decrease its reference counter calling |
2358 |
|
\texttt{swap\_entry\_free()}. |
2359 |
|
|
2360 |
|
\begin{verbatim} |
2361 |
page = find_trylock_page(&swapper_space, |
page = find_trylock_page(&swapper_space, |
2362 |
entry.val); |
entry.val); |
2363 |
|
\end{verbatim} |
2364 |
|
|
2365 |
|
After decreasing, there is only one reference on this swap entry, |
2366 |
|
so check if this reference is owned by a swap cacha page, trying |
2367 |
|
to lock it at once (i.e, without sleeping to lock). |
2368 |
|
|
2369 |
|
\begin{verbatim} |
2370 |
swap_info_put(p); |
swap_info_put(p); |
2371 |
} |
} |
2372 |
|
\end{verbatim} |
2373 |
|
|
2374 |
|
Unlock the swap list and the swap device after freeing the swap |
2375 |
|
entry. |
2376 |
|
|
2377 |
|
\begin{verbatim} |
2378 |
if (page) { |
if (page) { |
2379 |
page_cache_get(page); |
page_cache_get(page); |
2380 |
/* Only cache user (+us), or swap space full? Free it! */ |
/* Only cache user (+us), or swap space full? Free it! */ |
2387 |
page_cache_release(page); |
page_cache_release(page); |
2388 |
} |
} |
2389 |
\end{verbatim} |
\end{verbatim} |
2390 |
|
|
2391 |
|
The swap cache page has been found and could be locked at once, |
2392 |
|
so check if the page does not have other users and free it, |
2393 |
|
removing it from swap cache. Also it can be removed from swap |
2394 |
|
cache if the swap is full. |
2395 |
|
|
2396 |
\subsection{Function unuse\_pte()} |
\subsection{Function unuse\_pte()} |
2397 |
\textit{File: }\url{mm/swapfile.c}\\ |
\textit{File: }\url{mm/swapfile.c}\\ |
2421 |
if (unlikely(pte_none(pte) || pte_present(pte))) |
if (unlikely(pte_none(pte) || pte_present(pte))) |
2422 |
return; |
return; |
2423 |
\end{verbatim} |
\end{verbatim} |
2424 |
|
|
2425 |
TODO |
Seems redundant, but checks if the page table entry is NULL |
2426 |
|
(\texttt{pte\_none()}) or have an address which has the present |
2427 |
|
bit on (i.e, not swap entries). That is needed because |
2428 |
|
\texttt{pte\_to\_swp\_entry()} is architecture dependant and may |
2429 |
|
change some lower bits, turning out that the first condition end |
2430 |
|
up being true for a page table entry not set to a swap entry. |
2431 |
|
|
2432 |
\begin{verbatim} |
\begin{verbatim} |
2433 |
get_page(page); |
get_page(page); |
2498 |
} while (address && (address < end)); |
} while (address && (address < end)); |
2499 |
\end{verbatim} |
\end{verbatim} |
2500 |
|
|
|
TODO |
|
|
|
|
2501 |
For every page table entry, until it reaches the end of this page |
For every page table entry, until it reaches the end of this page |
2502 |
middle directory, call \texttt{unuse\_pte()} which will check the |
middle directory, call \texttt{unuse\_pte()} which will check the |
2503 |
page table entry data and will unuse it if it's the case. |
page table entry data and will unuse it if it's the case. |
2558 |
} while (address && (address < end)); |
} while (address && (address < end)); |
2559 |
\end{verbatim} |
\end{verbatim} |
2560 |
|
|
|
TODO |
|
|
|
|
2561 |
For every page middle directory, until it reaches the end of this |
For every page middle directory, until it reaches the end of this |
2562 |
page global directory, call \texttt{unuse\_pmd()} which will |
page global directory, call \texttt{unuse\_pmd()} which will |
2563 |
check the page middle directory and unuse all of its page table |
check the page middle directory and unuse all of its page table |
2591 |
} while (start && (start < end)); |
} while (start && (start < end)); |
2592 |
\end{verbatim} |
\end{verbatim} |
2593 |
|
|
|
TODO |
|
|
|
|
2594 |
The first page global directory is already passed as parameter |
The first page global directory is already passed as parameter |
2595 |
(\texttt{pgdir} parameter). So, for every page middle directory, |
(\texttt{pgdir} parameter). So, for every page middle directory, |
2596 |
until it reaches the end of this vm area, call |
until it reaches the end of this vm area, call |
2597 |
\texttt{unuse\_pgd()} which will check the page global directory |
\texttt{unuse\_pgd()} which will check the page middle directory |
2598 |
and unuse all of its page table entries it if it's the case. |
and unuse all of its page table entries it if it's the case. |
2599 |
|
|
2600 |
\subsection{Function unuse\_process()} |
\subsection{Function unuse\_process()} |
2960 |
return retval; |
return retval; |
2961 |
\end{verbatim} |
\end{verbatim} |
2962 |
|
|
|
TODO |
|
|
|
|
2963 |
\subsection{Function sys\_swapoff()} |
\subsection{Function sys\_swapoff()} |
2964 |
\textit{File: }\url{mm/swapfile.c}\\ |
\textit{File: }\url{mm/swapfile.c}\\ |
2965 |
\textit{Prototype: } |
\textit{Prototype: } |
2982 |
if (!capable(CAP_SYS_ADMIN)) |
if (!capable(CAP_SYS_ADMIN)) |
2983 |
return -EPERM; |
return -EPERM; |
2984 |
\end{verbatim} |
\end{verbatim} |
2985 |
|
|
2986 |
Check capabilities. TODO. |
Check capabilities of this process, before going on. If they do |
2987 |
|
not allow performing this task, return \texttt{-EPERM} (not |
2988 |
|
permitted) error. |
2989 |
|
|
2990 |
\begin{verbatim} |
\begin{verbatim} |
2991 |
err = user_path_walk(specialfile, &nd); |
err = user_path_walk(specialfile, &nd); |
3097 |
path_release(&nd); |
path_release(&nd); |
3098 |
\end{verbatim} |
\end{verbatim} |
3099 |
|
|
3100 |
And drop the reference on the nameidata for this swap type since |
Drop the reference on this dentry and vfsmnt got when this swap |
3101 |
it will not be used any longer. |
was activated in \texttt{sys\_swapon()}. |
3102 |
|
|
3103 |
\begin{verbatim} |
\begin{verbatim} |
3104 |
swap_list_lock(); |
swap_list_lock(); |
3119 |
\end{verbatim} |
\end{verbatim} |
3120 |
|
|
3121 |
With the swap list and device properly locked, zero the swap type |
With the swap list and device properly locked, zero the swap type |
3122 |
structure and free the \texttt{swap\_map} table. The \texttt{nd} |
structure and free the \texttt{swap\_map} table. Also set the |
3123 |
variable is reused because (TODO: have to understand that). |
return value (\texttt{err}) to zero. |
3124 |
|
|
3125 |
\begin{verbatim} |
\begin{verbatim} |
3126 |
out_dput: |
out_dput: |
3129 |
out: |
out: |
3130 |
return err; |
return err; |
3131 |
\end{verbatim} |
\end{verbatim} |
3132 |
|
|
3133 |
TODO |
Unlock the global kernel lock, drop the reference on the dentry |
3134 |
|
and vfsmnt got when the pathname was looked up and return. |
3135 |
|
|
3136 |
\subsection{Function get\_swaparea\_info()} |
\subsection{Function get\_swaparea\_info()} |
3137 |
\textit{File: }\url{mm/swapfile.c}\\ |
\textit{File: }\url{mm/swapfile.c}\\ |
3292 |
return -EPERM; |
return -EPERM; |
3293 |
\end{verbatim} |
\end{verbatim} |
3294 |
|
|
3295 |
Capabilities. TODO. |
Check capabilities of this process, before going on. If they do |
3296 |
|
not allow performing this task, return \texttt{-EPERM} (not |
3297 |
|
permitted) error. |
3298 |
|
|
3299 |
\begin{verbatim} |
\begin{verbatim} |
3300 |
lock_kernel(); |
lock_kernel(); |
3390 |
devfs_handle_t de; |
devfs_handle_t de; |
3391 |
|
|
3392 |
p->swap_device = dev; |
p->swap_device = dev; |
3393 |
|
\end{verbatim} |
3394 |
|
|
3395 |
|
Store the device into the \texttt{swap\_device}. |
3396 |
|
|
3397 |
|
\begin{verbatim} |
3398 |
set_blocksize(dev, PAGE_SIZE); |
set_blocksize(dev, PAGE_SIZE); |
3399 |
\end{verbatim} |
\end{verbatim} |
3400 |
|
|
3401 |
Set the \texttt{swap\_device} to the device of the dentry inode |
Set the device block size to \texttt{PAGE\_SIZE}. |
|
also also set the blocksize to the \texttt{PAGE\_SIZE} size. |
|
3402 |
|
|
3403 |
\begin{verbatim} |
\begin{verbatim} |
3404 |
bd_acquire(swap_inode); |
bd_acquire(swap_inode); |
3405 |
|
\end{verbatim} |
3406 |
|
|
3407 |
|
Get a reference on the block device, if it exists. Or acquire a |
3408 |
|
new block device structure, setting the \texttt{swap\_inode} to |
3409 |
|
this block device. |
3410 |
|
|
3411 |
|
\begin{verbatim} |
3412 |
bdev = swap_inode->i_bdev; |
bdev = swap_inode->i_bdev; |
3413 |
de = devfs_get_handle_from_inode(swap_inode); |
de = devfs_get_handle_from_inode(swap_inode); |
3414 |
/* Increments module use count */ |
/* Increments module use count */ |
3415 |
bdops = devfs_get_ops(de); |
bdops = devfs_get_ops(de); |
3416 |
if (bdops) bdev->bd_op = bdops; |
if (bdops) bdev->bd_op = bdops; |
3417 |
|
\end{verbatim} |
3418 |
|
|
3419 |
|
If using devfs, get the handle, increment the modules usage |
3420 |
|
counter and define the block device operations. |
3421 |
|
|
3422 |
|
\begin{verbatim} |
3423 |
error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, |
error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, |
3424 |
BDEV_SWAP); |
BDEV_SWAP); |
3425 |
|
\end{verbatim} |
3426 |
|
|
3427 |
|
Open the block device. |
3428 |
|
|
3429 |
|
\begin{verbatim} |
3430 |
/*Decrement module use count now we're safe*/ |
/*Decrement module use count now we're safe*/ |
3431 |
devfs_put_ops(de); |
devfs_put_ops(de); |
3432 |
|
\end{verbatim} |
3433 |
|
|
3434 |
|
For systems with devfs only, it decrement the usage counter of |
3435 |
|
this module. |
3436 |
|
|
3437 |
|
\begin{verbatim} |
3438 |
if (error) |
if (error) |
3439 |
goto bad_swap_2; |
goto bad_swap_2; |
3440 |
|
\end{verbatim} |
3441 |
|
|
3442 |
|
If the block device couldn't be opened, back out the changes and |
3443 |
|
return \texttt{-EINVAL} (invalid argument) error. |
3444 |
|
|
3445 |
|
\begin{verbatim} |
3446 |
set_blocksize(dev, PAGE_SIZE); |
set_blocksize(dev, PAGE_SIZE); |
3447 |
error = -ENODEV; |
error = -ENODEV; |
3448 |
if (!dev || (blk_size[MAJOR(dev)] && |
if (!dev || (blk_size[MAJOR(dev)] && |
3453 |
swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)] |
swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)] |
3454 |
>> (PAGE_SHIFT - 10); |
>> (PAGE_SHIFT - 10); |
3455 |
\end{verbatim} |
\end{verbatim} |
3456 |
|
|
3457 |
TODO |
Check if the device and block sizes are consistent, backing out |
3458 |
|
the changes and returning \texttt{-EINVAL} (invalid argument) if |
3459 |
|
they are not. Also compute the size of the swap into the |
3460 |
|
\texttt{swapfilesize} variable if the size of the block device is |
3461 |
|
defined. |
3462 |
|
|
3463 |
\begin{verbatim} |
\begin{verbatim} |
3464 |
} else if (S_ISREG(swap_inode->i_mode)) |
} else if (S_ISREG(swap_inode->i_mode)) |
3489 |
} |
} |
3490 |
\end{verbatim} |
\end{verbatim} |
3491 |
|
|
3492 |
TODO |
Make sure this device has not been activated by other swap |
3493 |
|
type. If it has already been activated, back out all the changes |
3494 |
|
and return \texttt{-EBUSY} (device or resource busy) error. |
3495 |
|
|
3496 |
\begin{verbatim} |
\begin{verbatim} |
3497 |
swap_header = (void *) __get_free_page(GFP_USER); |
swap_header = (void *) __get_free_page(GFP_USER); |
3597 |
} |
} |
3598 |
\end{verbatim} |
\end{verbatim} |
3599 |
|
|
3600 |
TODO |
The kernel has support only for subversion 1 of swap header |
3601 |
|
version 2. If any other subversion, back out the changes and |
3602 |
|
return \texttt{-EINVAL} (invalid argument) error. |
3603 |
|
|
3604 |
\begin{verbatim} |
\begin{verbatim} |
3605 |
p->lowest_bit = 1; |
p->lowest_bit = 1; |