title: How to get a struct page from any address in the Linux kernel
body: <p>I have existing code that takes a list of <code>struct page *</code> and builds a descriptor table to share memory with a device. The upper layer of that code currently expects a buffer allocated with <code>vmalloc</code> or from user space, and uses <a href="http://lxr.linux.no/#linux+v2.6.26/mm/vmalloc.c#L174" rel="noreferrer"><code>vmalloc_to_page</code></a> to obtain the corresponding <code>struct page *</code>.</p>
  
  <p>Now the upper layer needs to cope with all kinds of memory, not just memory obtained through <code>vmalloc</code>. This could be a buffer obtained with <code>kmalloc</code>, a pointer inside the stack of a kernel thread, or other cases that I'm not aware of. The only guarantee I have is that the caller of this upper layer must ensure that the memory buffer in question is mapped in kernel space at that point (i.e. it is valid to access <code>buffer[i]</code> for all <code>0&lt;=i&lt;size</code> at this point). <strong>How do I obtain a <code>struct page*</code> corresponding to an arbitrary pointer?</strong></p>
  
  <p>Putting it in pseudo-code, I have this:</p>
  
  <pre><code>lower_layer(struct page*);
  upper_layer(void *buffer, size_t size) {
      for (addr = buffer &amp; PAGE_MASK; addr &lt;= buffer + size; addr += PAGE_SIZE) {
          struct page *pg = vmalloc_to_page(addr);
          lower_layer(pg);
      }
  }
  </code></pre>
  
  <p>and I now need to change <code>upper_layer</code> to cope with any valid buffer (without changing <code>lower_layer</code>).</p>
  
  <p>I've found <a href="http://lxr.linux.no/#linux+v2.6.26/include/asm-arm/memory.h#L225" rel="noreferrer"><code>virt_to_page</code></a>, which <a href="http://lwn.net/images/pdf/LDD3/ch15.pdf" rel="noreferrer"><em>Linux Device Drivers</em></a> indicates operates on “a logical address, [not] memory from <code>vmalloc</code> or high memory”. Furthermore, <a href="http://lxr.linux.no/#linux+v2.6.26/include/linux/mm.h#L261" rel="noreferrer"><code>is_vmalloc_addr</code></a> tests whether an address comes from <code>vmalloc</code>, and <a href="http://lxr.linux.no/#linux+v2.6.26/include/asm-arm/memory.h#L226" rel="noreferrer"><code>virt_addr_valid</code></a> tests if an address is a valid virtual address (fodder for <code>virt_to_page</code>; this includes <code>kmalloc(GFP_KERNEL)</code> and kernel stacks). What about other cases: global buffers, high memory (it'll come one day, though I can ignore it for now), possibly other kinds that I'm not aware of? So I could reformulate my question as:</p>
  
  <ol>
  <li>What are <em>all</em> the kinds of memory zones in the kernel?</li>
  <li>How do I tell them apart?</li>
  <li>How do I obtain page mapping information for each of them?</li>
  </ol>
  
  <p>If it matters, the code is running on ARM (with an MMU), and the kernel version is at least 2.6.26.</p>