/[lkdp]/lkdp/mm/swapping.tex
ViewVC logotype

Diff of /lkdp/mm/swapping.tex

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.14 by rcastro, Wed Jul 31 20:27:59 2002 UTC revision 1.15 by rcastro, Thu Aug 1 19:52:51 2002 UTC
# Line 234  flush_cache_page(vma, address); Line 234  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       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))
# Line 2162  return retval; Line 2165  return retval;
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;
# Line 2171  int retval = 0; Line 2177  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))
# Line 2188  case 1: Line 2224  case 1:
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;
# Line 2204  swp_entry_t entry; Line 2246  swp_entry_t entry;
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);
# Line 2229  if (p->swap_map[SWP_OFFSET(entry)] == 1) Line 2305  if (p->swap_map[SWP_OFFSET(entry)] == 1)
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);
# Line 2238  if (retval) { Line 2321  if (retval) {
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}\\
# Line 2245  return retval; Line 2332  return retval;
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! */
# Line 2271  if (page) { Line 2387  if (page) {
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}\\
# Line 2300  if (likely(pte_to_swp_entry(pte).val != Line 2421  if (likely(pte_to_swp_entry(pte).val !=
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);
# Line 2372  do { Line 2498  do {
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.    
# Line 2434  do { Line 2558  do {
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
# Line 2469  do { Line 2591  do {
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()}
# Line 2840  if (reset_overflow) { Line 2960  if (reset_overflow) {
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: }
# Line 2864  int err; Line 2982  int err;
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);
# Line 2977  if (p->swap_device) Line 3097  if (p->swap_device)
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();
# Line 2999  err = 0; Line 3119  err = 0;
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:
# Line 3009  path_release(&nd); Line 3129  path_release(&nd);
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}\\
# Line 3171  if (!capable(CAP_SYS_ADMIN)) Line 3292  if (!capable(CAP_SYS_ADMIN))
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();
# Line 3267  if (S_ISBLK(swap_inode->i_mode)) { Line 3390  if (S_ISBLK(swap_inode->i_mode)) {
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)] &&
# Line 3297  if (S_ISBLK(swap_inode->i_mode)) { Line 3453  if (S_ISBLK(swap_inode->i_mode)) {
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))
# Line 3329  for (i = 0 ; i < nr_swapfiles ; i++) { Line 3489  for (i = 0 ; i < nr_swapfiles ; i++) {
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);
# Line 3435  case 2: Line 3597  case 2:
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;

Legend:
Removed from v.1.14  
changed lines
  Added in v.1.15

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26