code/cow_brd.c
static struct page *brd_insert_page(struct brd_device *brd, sector_t sector)
{
  pgoff_t idx;
  struct page *page;
  gfp_t gfp_flags;
  void *dst, *parent_src = NULL;
  struct page *parent_page = NULL;

  page = brd_lookup_page(brd, sector);
  if (page)
    return page;

  /*
   * Must use NOIO because we don't want to recurse back into the
   * block or filesystem layers from page reclaim.
   *
   * Cannot support XIP and highmem, because our ->direct_access
   * routine for XIP must return memory that is always addressable.
   * If XIP was reworked to use pfns and kmap throughout, this
   * restriction might be able to be lifted.
   */
  gfp_flags = GFP_NOIO | __GFP_ZERO;
#ifndef CONFIG_BLK_DEV_XIP
  gfp_flags |= __GFP_HIGHMEM;
#endif
  page = alloc_page(gfp_flags);
  if (!page)
    return NULL;

  if (radix_tree_preload(GFP_NOIO)) {
    __free_page(page);
    return NULL;
  }

  spin_lock(&brd->brd_lock);
  idx = sector >> PAGE_SECTORS_SHIFT;
  page->index = idx;
  if (radix_tree_insert(&brd->brd_pages, idx, page)) {
    __free_page(page);
    page = radix_tree_lookup(&brd->brd_pages, idx);
    BUG_ON(!page);
    BUG_ON(page->index != idx);
  }
  spin_unlock(&brd->brd_lock);

  radix_tree_preload_end();

  // Copy over the data in the parent's page to the snapshot page if the parent
  // has a page in this sector address.
  if (brd->parent_brd) {
    parent_page = brd_lookup_page(brd->parent_brd, sector);
    // This page may not have originally existed in the parent.
    if (parent_page) {
      // Map both the parent and snapshot pages so that the kernel can access
      // those addresses. The snapshot page and the parent page both already
      // reside in radix trees, so even when we unmap the pages, the data and
      // the page itself will still remain.
      dst = kmap_atomic(page);
      parent_src = kmap_atomic(parent_page);
      memcpy(dst, parent_src, PAGE_SIZE);
      kunmap_atomic(parent_src);
      kunmap_atomic(dst);
    }
  }

  return page;
}
/*
 * Look up and return a brd's page for a given sector.
 * If one does not exist, allocate an empty page, and insert that. Then
 * return it.
 */
Look up and return a brd's page for a given sector.
If one does not exist, allocate an empty page, and insert that. Then
return it.
Look up and return a brd ' s page for a given sector . If one does not exist allocate an empty page and insert that . Then return it .
static struct page *brd_insert_page(struct brd_device *brd, sector_t sector)
{
  pgoff_t idx;
  struct page *page;
  gfp_t gfp_flags;
  void *dst, *parent_src = NULL;
  struct page *parent_page = NULL;
  page = brd_lookup_page(brd, sector);
  if (page)
    return page;
  gfp_flags = GFP_NOIO | __GFP_ZERO;
#ifndef CONFIG_BLK_DEV_XIP
  gfp_flags |= __GFP_HIGHMEM;
#endif
  page = alloc_page(gfp_flags);
  if (!page)
    return NULL;
  if (radix_tree_preload(GFP_NOIO)) {
    __free_page(page);
    return NULL;
  }
  spin_lock(&brd->brd_lock);
  idx = sector >> PAGE_SECTORS_SHIFT;
  page->index = idx;
  if (radix_tree_insert(&brd->brd_pages, idx, page)) {
    __free_page(page);
    page = radix_tree_lookup(&brd->brd_pages, idx);
    BUG_ON(!page);
    BUG_ON(page->index != idx);
  }
  spin_unlock(&brd->brd_lock);
  radix_tree_preload_end();
  if (brd->parent_brd) {
    parent_page = brd_lookup_page(brd->parent_brd, sector);
    if (parent_page) {
      dst = kmap_atomic(page);
      parent_src = kmap_atomic(parent_page);
      memcpy(dst, parent_src, PAGE_SIZE);
      kunmap_atomic(parent_src);
      kunmap_atomic(dst);
    }
  }
  return page;
}
static struct page * brd_insert_page ( struct brd_device * brd , sector_t sector ) { pgoff_t idx ; struct page * page ; gfp_t gfp_flags ; void * dst , * parent_src = NULL ; struct page * parent_page = NULL ; page = brd_lookup_page ( brd , sector ) ; if ( page ) return page ; gfp_flags = GFP_NOIO | __GFP_ZERO ; #ifndef CONFIG_BLK_DEV_XIP gfp_flags |= __GFP_HIGHMEM ; #endif page = alloc_page ( gfp_flags ) ; if ( ! page ) return NULL ; if ( radix_tree_preload ( GFP_NOIO ) ) { __free_page ( page ) ; return NULL ; } spin_lock ( & brd -> brd_lock ) ; idx = sector >> PAGE_SECTORS_SHIFT ; page -> index = idx ; if ( radix_tree_insert ( & brd -> brd_pages , idx , page ) ) { __free_page ( page ) ; page = radix_tree_lookup ( & brd -> brd_pages , idx ) ; BUG_ON ( ! page ) ; BUG_ON ( page -> index != idx ) ; } spin_unlock ( & brd -> brd_lock ) ; radix_tree_preload_end ( ) ; if ( brd -> parent_brd ) { parent_page = brd_lookup_page ( brd -> parent_brd , sector ) ; if ( parent_page ) { dst = kmap_atomic ( page ) ; parent_src = kmap_atomic ( parent_page ) ; memcpy ( dst , parent_src , PAGE_SIZE ) ; kunmap_atomic ( parent_src ) ; kunmap_atomic ( dst ) ; } } return page ; }
Look up and return a brd's page for a given sector.
Look up and return a brd ' s page for a given sector .
/*
   * Must use NOIO because we don't want to recurse back into the
   * block or filesystem layers from page reclaim.
   *
   * Cannot support XIP and highmem, because our ->direct_access
   * routine for XIP must return memory that is always addressable.
   * If XIP was reworked to use pfns and kmap throughout, this
   * restriction might be able to be lifted.
   */ // Copy over the data in the parent's page to the snapshot page if the parent // has a page in this sector address. // This page may not have originally existed in the parent. // Map both the parent and snapshot pages so that the kernel can access // those addresses. The snapshot page and the parent page both already // reside in radix trees, so even when we unmap the pages, the data and // the page itself will still remain.