title: Linux kernel page freeing
body: <p>I'm building my own memory pool as a Linux kernel module. I modified page frame allocation function so that user level processes get page frames from my memory pool. This works fine. Then I tried to modify the page freeing function in order to reclaim page frames when they are freed by processes. But whenever I enabled page reclaiming, I couldn't start any program, with "segmentation fault" message printed in console.</p>
  
  <p>I'm using <code>alloc_page(__GFP_HIGHMEM | __GFP_MOVABLE | __GFP_ZERO)</code> to create my memory pool, which goes into per-cpu page frame cache, so every page I get has a usage counter (page->_count) set to 1.</p>
  
  <p>For page freeing, I inserted a few lines in <code>free_pcppages_bulk()</code>, which is called when per-cpu page frame cache wants to flush some free pages back to Buddy system:</p>
  
  <pre><code>static void free_pcppages_bulk(struct zone *zone, int count, 
      struct per_cpu_pages *pcp)
  {
  int migratetype = 0;
  int batch_free = 0;
  int to_free = count;
  
  spin_lock(&amp;zone-&gt;lock);
  zone_clear_flag(zone, ZONE_ALL_UNRECLAIMABLE);
  zone-&gt;pages_scanned = 0;
  
  while (to_free) {
      struct page *page;
      struct list_head *list;
  
      /*
       * Remove pages from lists in a round-robin fashion. A
       * batch_free count is maintained that is incremented when an
       * empty list is encountered.  This is so more pages are freed
       * off fuller lists instead of spinning excessively around empty
       * lists
       */
      do {
          batch_free++;
          if (++migratetype == MIGRATE_PCPTYPES)
              migratetype = 0;
          list = &amp;pcp-&gt;lists[migratetype];
      } while (list_empty(list));
  
      do {
          page = list_entry(list-&gt;prev, struct page, lru);
          /* must delete as __free_one_page list manipulates */
          list_del(&amp;page-&gt;lru);
          /* MIGRATE_MOVABLE list may include MIGRATE_RESERVEs */
  
          /* --ADDED BY ME-- */
          if(colored_free != NULL) { /* if my memory pool is created */
              if(!colored_free(page, zone)) { /* if it fails, free page to Buddy system */
                  __free_one_page(page, zone, 0, page_private(page));
              }
          }
          else {
              __free_one_page(page, zone, 0, page_private(page));
          }
  
          trace_mm_page_pcpu_drain(page, 0, page_private(page));
      } while (--to_free &amp;&amp; --batch_free &amp;&amp; !list_empty(list));
  }
  __mod_zone_page_state(zone, NR_FREE_PAGES, count);
  spin_unlock(&amp;zone-&gt;lock);
  }
  </code></pre>
  
  <p>In <code>colored_free()</code>, I simply insert the page descriptor in a page free list. Since the page usage counter is set to 0 when it's going to be freed to Buddy system, I reset it to 1 to restore the initial page state when my memory pool is created.</p>
  
  <p>Any suggestion on this? Or is there a better way to free page frames to my memory pool instead of Buddy system?</p>