A while cycle is used to scan the list of memory regions built in the first phase, starting with the memory region descriptor that free points to.
In each iteration, the mpnt local variable points to the descriptor of a memory region in the list. The map_count field of the current->mm memory descriptor is decremented (since the region has been removed in the first phase from the list of regions owned by the process) and a check is made (by means of two question-mark conditional expressions) to determine whether the mpnt region must be eliminated or simply downsized:
current->mm->map_count--; st = addr < mpnt->vm_start end = addr+len; end = end > mpnt->vm_end ?
The st and end local variables delimit the linear address interval in the mpnt memory region that should be deleted; the size local variable specifies the length of the interval.
Next, do_munmap( ) releases the page frames allocated for the pages included in the interval from st to end:
The zap_page_range( ) function deallocates the page frames included in the interval from st to end and updates the corresponding Page Table entries. The function invokes in nested fashion the zap_pmd_range( ) and zap_pte_range( ) functions for scanning the Page Tables; the latter function clears the Page Table entries and frees the corresponding page frames (or slot in a swap area; see Chapter 14). While doing this, zap_pte_range( ) also invalidates the TLB entries corresponding to the interval from st to end.
The last action performed in each iteration of the do_munmap( ) loop is to check whether a downsized version of the mpnt memory region must be reinserted in the list of regions of current:
extra = unmap_fixup(mm, mpnt, st, size, extra); The unmap_fixup( ) function considers four possible cases:
1. The memory region has been totally canceled. It returns the address of the previously allocated memory region object (see Step 4 in the earlier section Section 18.104.22.168), which can be released by invoking kmem_cache_free( ).
2. Only the lower part of the memory region has been removed:
(mpnt->vm_start < st) && (mpnt->vm_end == end)
In this case, it updates the vm_end field of mnpt, invokes _ _insert_vm_struct( ) to insert the downsized region in the list of regions belonging to the process, and returns the address of the previously allocated memory region object.
3. Only the upper part of the memory region has been removed:
(mpnt->vm_start == st) && (mpnt->vm_end > end)
In this case, it updates the vm_start field of mnpt, invokes__insert_vm_struct( ) to insert the downsized region in the list of regions belonging to the process, and returns the address of the previously allocated memory object.
4. The linear address interval is in the middle of the memory region:
(mpnt->vm_start < st) && (mpnt->vm_end > end)
It updates the vm_start and vm_end fields of mnpt and of the previously allocated extra memory region object so that they refer to the linear address intervals, respectively, from mpnt->vm_start to st and from end to mpnt->vm_end. Then it invokes _ _insert_vm_struct( ) twice to insert the two regions in the list of regions belonging to the process and in the red-black tree, and returns null, thus preserving the memory region object previously allocated.
This terminates the description of what must be done in a single iteration of the second-phase loop
After handling all the memory region descriptors in the list built during the first phase, do_munmap ) checks if the additional extra memory descriptor has been used. If the address returned by unmap_fixup( ) is null, the descriptor has been used; otherwise, do_munmap( ) invokes kmem_cache_free( ) to release it. Finally, do_munmap( ) invokes the free_pgtables( ) function: it again scans the Page Table entries corresponding to the linear address interval just removed and reclaims the page frames that store unused Page Tables.
I [email protected] RuBoard
As stated previously, the Linux Page Fault exception handler must distinguish exceptions caused by programming errors from those caused by a reference to a page that legitimately belongs to the process address space but simply hasn't been allocated yet.
The memory region descriptors allow the exception handler to perform its job quite efficiently. The do_page_fault( ) function, which is the Page Fault interrupt service routine for the 80 x 86 architecture, compares the linear address that caused the Page Fault against the memory regions of the current process; it can thus determine the proper way to handle the exception according to the scheme that is illustrated in Figure 8-4.
Was this article helpful?