Blame view
net/ceph/pagelist.c
3.62 KB
58bb3b374 ceph: support cep... |
1 |
|
3d14c5d2b ceph: factor out ... |
2 |
#include <linux/module.h> |
5a0e3ad6a include cleanup: ... |
3 |
#include <linux/gfp.h> |
58bb3b374 ceph: support cep... |
4 5 |
#include <linux/pagemap.h> #include <linux/highmem.h> |
3d14c5d2b ceph: factor out ... |
6 |
#include <linux/ceph/pagelist.h> |
58bb3b374 ceph: support cep... |
7 |
|
3d4401d9d ceph: fix pagelis... |
8 9 |
static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl) { |
ac0b74d8a ceph: add pagelis... |
10 11 12 13 14 |
if (pl->mapped_tail) { struct page *page = list_entry(pl->head.prev, struct page, lru); kunmap(page); pl->mapped_tail = NULL; } |
3d4401d9d ceph: fix pagelis... |
15 |
} |
58bb3b374 ceph: support cep... |
16 17 |
int ceph_pagelist_release(struct ceph_pagelist *pl) { |
ac0b74d8a ceph: add pagelis... |
18 |
ceph_pagelist_unmap_tail(pl); |
58bb3b374 ceph: support cep... |
19 20 21 22 23 24 |
while (!list_empty(&pl->head)) { struct page *page = list_first_entry(&pl->head, struct page, lru); list_del(&page->lru); __free_page(page); } |
ac0b74d8a ceph: add pagelis... |
25 |
ceph_pagelist_free_reserve(pl); |
58bb3b374 ceph: support cep... |
26 27 |
return 0; } |
3d14c5d2b ceph: factor out ... |
28 |
EXPORT_SYMBOL(ceph_pagelist_release); |
58bb3b374 ceph: support cep... |
29 30 31 |
static int ceph_pagelist_addpage(struct ceph_pagelist *pl) { |
ac0b74d8a ceph: add pagelis... |
32 33 34 35 36 37 38 |
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); |
240634e9b ceph: fix num_pag... |
39 |
--pl->num_pages_free; |
ac0b74d8a ceph: add pagelis... |
40 |
} |
58bb3b374 ceph: support cep... |
41 42 43 |
if (!page) return -ENOMEM; pl->room += PAGE_SIZE; |
ac0b74d8a ceph: add pagelis... |
44 |
ceph_pagelist_unmap_tail(pl); |
58bb3b374 ceph: support cep... |
45 |
list_add_tail(&page->lru, &pl->head); |
58bb3b374 ceph: support cep... |
46 47 48 |
pl->mapped_tail = kmap(page); return 0; } |
68b4476b0 ceph: messenger a... |
49 |
int ceph_pagelist_append(struct ceph_pagelist *pl, const void *buf, size_t len) |
58bb3b374 ceph: support cep... |
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
{ while (pl->room < len) { size_t bit = pl->room; int ret; memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK), buf, bit); pl->length += bit; pl->room -= bit; buf += bit; len -= bit; ret = ceph_pagelist_addpage(pl); if (ret) return ret; } memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK), buf, len); pl->length += len; pl->room -= len; return 0; } |
3d14c5d2b ceph: factor out ... |
71 |
EXPORT_SYMBOL(ceph_pagelist_append); |
ac0b74d8a ceph: add pagelis... |
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
/** * Allocate enough pages for a pagelist to append the given amount * of data without without allocating. * Returns: 0 on success, -ENOMEM on error. */ int ceph_pagelist_reserve(struct ceph_pagelist *pl, size_t space) { if (space <= pl->room) return 0; space -= pl->room; space = (space + PAGE_SIZE - 1) >> PAGE_SHIFT; /* conv to num pages */ while (space > pl->num_pages_free) { struct page *page = __page_cache_alloc(GFP_NOFS); if (!page) return -ENOMEM; list_add_tail(&page->lru, &pl->free_list); ++pl->num_pages_free; } return 0; } EXPORT_SYMBOL(ceph_pagelist_reserve); /** * Free any pages that have been preallocated. */ int ceph_pagelist_free_reserve(struct ceph_pagelist *pl) { while (!list_empty(&pl->free_list)) { struct page *page = list_first_entry(&pl->free_list, struct page, lru); list_del(&page->lru); __free_page(page); --pl->num_pages_free; } BUG_ON(pl->num_pages_free); return 0; } EXPORT_SYMBOL(ceph_pagelist_free_reserve); /** * Create a truncation point. */ void ceph_pagelist_set_cursor(struct ceph_pagelist *pl, struct ceph_pagelist_cursor *c) { c->pl = pl; c->page_lru = pl->head.prev; c->room = pl->room; } EXPORT_SYMBOL(ceph_pagelist_set_cursor); /** * 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); } return 0; } EXPORT_SYMBOL(ceph_pagelist_truncate); |