int ceph_pagelist_release(struct ceph_pagelist *pl) { ceph_pagelist_unmap_tail(pl); while (!list_empty(&pl->head)) { struct page *page = list_first_entry(&pl->head, struct page, lru); list_del(&page->lru); __free_page(page); } ceph_pagelist_free_reserve(pl); return 0; }
void ceph_pagelist_release(struct ceph_pagelist *pl) { if (!refcount_dec_and_test(&pl->refcnt)) return; ceph_pagelist_unmap_tail(pl); while (!list_empty(&pl->head)) { struct page *page = list_first_entry(&pl->head, struct page, lru); list_del(&page->lru); __free_page(page); } ceph_pagelist_free_reserve(pl); kfree(pl); }
static int ceph_pagelist_addpage(struct ceph_pagelist *pl) { struct page *page; if (!pl->num_pages_free) { page = __page_cache_alloc(GFP_NOFS); } else { page = list_first_entry(&pl->free_list, struct page, lru); list_del(&page->lru); --pl->num_pages_free; } if (!page) return -ENOMEM; pl->room += PAGE_SIZE; ceph_pagelist_unmap_tail(pl); list_add_tail(&page->lru, &pl->head); pl->mapped_tail = kmap(page); return 0; }
/** * Truncate a pagelist to the given point. Move extra pages to reserve. * This won't sleep. * Returns: 0 on success, * -EINVAL if the pagelist doesn't match the trunc point pagelist */ int ceph_pagelist_truncate(struct ceph_pagelist *pl, struct ceph_pagelist_cursor *c) { struct page *page; if (pl != c->pl) return -EINVAL; ceph_pagelist_unmap_tail(pl); while (pl->head.prev != c->page_lru) { page = list_entry(pl->head.prev, struct page, lru); list_del(&page->lru); /* remove from pagelist */ list_add_tail(&page->lru, &pl->free_list); /* add to reserve */ ++pl->num_pages_free; } pl->room = c->room; if (!list_empty(&pl->head)) { page = list_entry(pl->head.prev, struct page, lru); pl->mapped_tail = kmap(page); }