pagelist.c revision 3d14c5d2b6e15c21d8e5467dc62d33127c23a644
1 2#include <linux/module.h> 3#include <linux/gfp.h> 4#include <linux/pagemap.h> 5#include <linux/highmem.h> 6#include <linux/ceph/pagelist.h> 7 8static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl) 9{ 10 struct page *page = list_entry(pl->head.prev, struct page, 11 lru); 12 kunmap(page); 13} 14 15int ceph_pagelist_release(struct ceph_pagelist *pl) 16{ 17 if (pl->mapped_tail) 18 ceph_pagelist_unmap_tail(pl); 19 20 while (!list_empty(&pl->head)) { 21 struct page *page = list_first_entry(&pl->head, struct page, 22 lru); 23 list_del(&page->lru); 24 __free_page(page); 25 } 26 return 0; 27} 28EXPORT_SYMBOL(ceph_pagelist_release); 29 30static int ceph_pagelist_addpage(struct ceph_pagelist *pl) 31{ 32 struct page *page = __page_cache_alloc(GFP_NOFS); 33 if (!page) 34 return -ENOMEM; 35 pl->room += PAGE_SIZE; 36 list_add_tail(&page->lru, &pl->head); 37 if (pl->mapped_tail) 38 ceph_pagelist_unmap_tail(pl); 39 pl->mapped_tail = kmap(page); 40 return 0; 41} 42 43int ceph_pagelist_append(struct ceph_pagelist *pl, const void *buf, size_t len) 44{ 45 while (pl->room < len) { 46 size_t bit = pl->room; 47 int ret; 48 49 memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK), 50 buf, bit); 51 pl->length += bit; 52 pl->room -= bit; 53 buf += bit; 54 len -= bit; 55 ret = ceph_pagelist_addpage(pl); 56 if (ret) 57 return ret; 58 } 59 60 memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK), buf, len); 61 pl->length += len; 62 pl->room -= len; 63 return 0; 64} 65EXPORT_SYMBOL(ceph_pagelist_append); 66