Blame view
net/ceph/pagelist.c
3.65 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
3d14c5d2b ceph: factor out ... |
2 |
#include <linux/module.h> |
5a0e3ad6a include cleanup: ... |
3 |
#include <linux/gfp.h> |
e4339d28f libceph: referenc... |
4 |
#include <linux/slab.h> |
58bb3b374 ceph: support cep... |
5 6 |
#include <linux/pagemap.h> #include <linux/highmem.h> |
3d14c5d2b ceph: factor out ... |
7 |
#include <linux/ceph/pagelist.h> |
58bb3b374 ceph: support cep... |
8 |
|
3d4401d9d ceph: fix pagelis... |
9 10 |
static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl) { |
ac0b74d8a ceph: add pagelis... |
11 12 13 14 15 |
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... |
16 |
} |
e4339d28f libceph: referenc... |
17 |
void ceph_pagelist_release(struct ceph_pagelist *pl) |
58bb3b374 ceph: support cep... |
18 |
{ |
0e1a5ee65 libceph: convert ... |
19 |
if (!refcount_dec_and_test(&pl->refcnt)) |
e4339d28f libceph: referenc... |
20 |
return; |
ac0b74d8a ceph: add pagelis... |
21 |
ceph_pagelist_unmap_tail(pl); |
58bb3b374 ceph: support cep... |
22 23 24 25 26 27 |
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... |
28 |
ceph_pagelist_free_reserve(pl); |
e4339d28f libceph: referenc... |
29 |
kfree(pl); |
58bb3b374 ceph: support cep... |
30 |
} |
3d14c5d2b ceph: factor out ... |
31 |
EXPORT_SYMBOL(ceph_pagelist_release); |
58bb3b374 ceph: support cep... |
32 33 34 |
static int ceph_pagelist_addpage(struct ceph_pagelist *pl) { |
ac0b74d8a ceph: add pagelis... |
35 36 37 38 39 40 41 |
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... |
42 |
--pl->num_pages_free; |
ac0b74d8a ceph: add pagelis... |
43 |
} |
58bb3b374 ceph: support cep... |
44 45 46 |
if (!page) return -ENOMEM; pl->room += PAGE_SIZE; |
ac0b74d8a ceph: add pagelis... |
47 |
ceph_pagelist_unmap_tail(pl); |
58bb3b374 ceph: support cep... |
48 |
list_add_tail(&page->lru, &pl->head); |
58bb3b374 ceph: support cep... |
49 50 51 |
pl->mapped_tail = kmap(page); return 0; } |
68b4476b0 ceph: messenger a... |
52 |
int ceph_pagelist_append(struct ceph_pagelist *pl, const void *buf, size_t len) |
58bb3b374 ceph: support cep... |
53 54 55 56 |
{ while (pl->room < len) { size_t bit = pl->room; int ret; |
09cbfeaf1 mm, fs: get rid o... |
57 |
memcpy(pl->mapped_tail + (pl->length & ~PAGE_MASK), |
58bb3b374 ceph: support cep... |
58 59 60 61 62 63 64 65 66 |
buf, bit); pl->length += bit; pl->room -= bit; buf += bit; len -= bit; ret = ceph_pagelist_addpage(pl); if (ret) return ret; } |
09cbfeaf1 mm, fs: get rid o... |
67 |
memcpy(pl->mapped_tail + (pl->length & ~PAGE_MASK), buf, len); |
58bb3b374 ceph: support cep... |
68 69 70 71 |
pl->length += len; pl->room -= len; return 0; } |
3d14c5d2b ceph: factor out ... |
72 |
EXPORT_SYMBOL(ceph_pagelist_append); |
ac0b74d8a ceph: add pagelis... |
73 |
|
ae86b9e38 net: Fix non-kern... |
74 |
/* Allocate enough pages for a pagelist to append the given amount |
ac0b74d8a ceph: add pagelis... |
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
* 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); |
ae86b9e38 net: Fix non-kern... |
95 |
/* Free any pages that have been preallocated. */ |
ac0b74d8a ceph: add pagelis... |
96 97 98 99 100 101 102 103 104 105 106 107 108 |
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); |
ae86b9e38 net: Fix non-kern... |
109 |
/* Create a truncation point. */ |
ac0b74d8a ceph: add pagelis... |
110 111 112 113 114 115 116 117 |
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); |
ae86b9e38 net: Fix non-kern... |
118 |
/* Truncate a pagelist to the given point. Move extra pages to reserve. |
ac0b74d8a ceph: add pagelis... |
119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
* 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); |
cc4829e59 ceph: use list_mo... |
133 134 |
/* move from pagelist to reserve */ list_move_tail(&page->lru, &pl->free_list); |
ac0b74d8a ceph: add pagelis... |
135 136 137 138 139 140 141 142 143 144 |
++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); |