LWN.net Logo

Another reason for kmap_atomic()

Another reason for kmap_atomic()

Posted Nov 19, 2004 19:55 UTC (Fri) by giraffedata (subscriber, #1954)
Parent article: On not getting burned by kmap_atomic()

The article misses the real purpose of kmap_atomic(), which is evident in its name. kmap() can sleep, waiting for a virtual address range to be available. Some callers aren't able to sleep where they call kmap().

kmap_atomic() uses reserve pools of virtual address ranges (page table entries) so that it is always atomic (or fails immediately if the reserve pool is empty). The reason there are multiple pools (chosen by kmap's second argument) is to avoid deadlock. The kmap() succeeding is sometimes a prerequisite to page table entries getting freed up.

Example: Someone does a kmap. System needs to swap out a high memory page to free up a page table entry for the kmap. The swap device can't access high memory, so the device driver has to copy the page to a low memory page "bounce buffer". To do that, it has to kmap both pages. The one reserved bounce buffer PTE slot keeps this from causing a deadlock.

Since these kmappers are always using the same small set of page table entries, it makes an ideal place for a performance improvement with per-cpu page table entries.


(Log in to post comments)

Another reason for kmap_atomic()

Posted Feb 22, 2007 8:50 UTC (Thu) by pbreuer (guest, #43542) [Link]

Are you SURE kmap can sleep? This is said also by Rubini in LDD (http://www.xml.com/ldd/chapter/book/ch13.html "kmap returns a kernel virtual address for any page in the system. For low-memory pages, it just returns the logical address of the page; for high-memory pages, kmapcreates a special mapping. Mappings created with kmap should always be freed with kunmap; a limited number of such mappings is available, so it is better not to hold on to them for too long. kmap calls are additive, so if two or more functions both call kmap on the same page the right thing happens. Note also that kmap can sleep if no mappings are available.").

However, I see no way it can. In kernel 2.6.17, for example, in highmem.h

static inline void *kmap(struct page *page) { return page_address(page); }

and page_address() is defined in mm.h:

#define page_address(page) ((page)->virtual)

or

#define page_address(page) \
__va( (((page) - page_zone(page)->zone_mem_map) << PAGE_SHIFT) \
+ page_zone(page)->zone_start_paddr)

OK, so you think page_zone() might sleep? No. That's also in mm.h:

static inline zone_t *page_zone(struct page *page)
{
return zone_table[page->flags >> ZONE_SHIFT];
}

so I don't see a sleep.

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds