When any kernel routine wants memory it ends up calling get_free_page(). This is at a lower level than kmalloc() (in fact kmalloc() uses get_free_page() when it needs more memory).
get_free_page() takes one parameter, a priority. Possible values are GFP_BUFFER, GFP_KERNEL, and GFP_ATOMIC. It takes a page off of the free_page_list, updates mem_map, zeroes the page and returns the physical address of the page (note that kmalloc() returns a physical address. The logic of the mm depends on the identity map between logical and physical addresses).
That itself is simple enough. The problem, of course, is that the free_page_list may be empty. If you did not request an atomic operation, at this stage, you enter into the realm of page stealing which we'll go into in a moment. As a last resort (and for atomic requests) a page is torn off from the secondary_page_list (as you may have guessed, when pages are freed, the secondary_page_list gets filled up first).
The actual manipulation of the page_lists and mem_map occurs in this mysterious macro called REMOVE_FROM_MEM_QUEUE() which you probably never want to look into. Suffice it to say that interrupts are disabled. [I think that this should be explained here. It is not that hard...]
Now back to the page stealing bit. get_free_page() calls try_to_free_page() which repeatedly calls shrink_buffers() and swap_out() in that order until it is successful in freeing a page. The priority is increased on each successive iteration so that these two routines run through their page stealing loops more often.
Here's one run through swap_out():
try_to_swap_out() scans the page tables of all user processes and enforces the stealing policy:
Of these actions, 6 and 7 will stop the process as they result in the actual freeing of a physical page. Action 5 results in one of the processes losing an unshared clean page that was not accessed recently (decrement Q->rss) which is not all that bad, but the cumulative effects of a few iterations can slow down a process considerably. At present, there are 6 iterations, so a page shared by 6 processes can get stolen if it is clean.
Page table entries are updated and the TLB invalidated. [Wonder about the latter. It seems unnecessary since accessed pages aren't offed and there is a walk through many page tables between iterations ...may be in case an interrupt came along and wanted the most recently axed page?]
The actual work of freeing the page is done by free_page(), the complement of get_free_page(). It ignores RESERVED pages, updates mem_map, then frees the page and updates the page_lists if it is unmapped. For swapping (in 6 above), write_swap_page() gets called and does nothing remarkable from the memory management perspective.
The details of shrink_buffers() would take us too far afield. Essentially it looks for free buffers, then writes out dirty buffers, then goes at busy buffers and calls free_page() when its able to free all the buffers on a page.
Note that page directories and page tables along with RESERVED pages do not get swapped, stolen or aged. They are mapped in the process page directory through reserved page tables. They are freed only on exit from the process.