2 #include <linux/module.h>
4 #include <linux/pagemap.h>
5 #include <linux/highmem.h>
6 #include <linux/ceph/pagelist.h>
8 static void ceph_pagelist_unmap_tail(struct ceph_pagelist
*pl
)
10 if (pl
->mapped_tail
) {
11 struct page
*page
= list_entry(pl
->head
.prev
, struct page
, lru
);
13 pl
->mapped_tail
= NULL
;
17 int ceph_pagelist_release(struct ceph_pagelist
*pl
)
19 ceph_pagelist_unmap_tail(pl
);
20 while (!list_empty(&pl
->head
)) {
21 struct page
*page
= list_first_entry(&pl
->head
, struct page
,
26 ceph_pagelist_free_reserve(pl
);
29 EXPORT_SYMBOL(ceph_pagelist_release
);
31 static int ceph_pagelist_addpage(struct ceph_pagelist
*pl
)
35 if (!pl
->num_pages_free
) {
36 page
= __page_cache_alloc(GFP_NOFS
);
38 page
= list_first_entry(&pl
->free_list
, struct page
, lru
);
44 pl
->room
+= PAGE_SIZE
;
45 ceph_pagelist_unmap_tail(pl
);
46 list_add_tail(&page
->lru
, &pl
->head
);
47 pl
->mapped_tail
= kmap(page
);
51 int ceph_pagelist_append(struct ceph_pagelist
*pl
, const void *buf
, size_t len
)
53 while (pl
->room
< len
) {
54 size_t bit
= pl
->room
;
57 memcpy(pl
->mapped_tail
+ (pl
->length
& ~PAGE_CACHE_MASK
),
63 ret
= ceph_pagelist_addpage(pl
);
68 memcpy(pl
->mapped_tail
+ (pl
->length
& ~PAGE_CACHE_MASK
), buf
, len
);
73 EXPORT_SYMBOL(ceph_pagelist_append
);
76 * Allocate enough pages for a pagelist to append the given amount
77 * of data without without allocating.
78 * Returns: 0 on success, -ENOMEM on error.
80 int ceph_pagelist_reserve(struct ceph_pagelist
*pl
, size_t space
)
82 if (space
<= pl
->room
)
85 space
= (space
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
; /* conv to num pages */
87 while (space
> pl
->num_pages_free
) {
88 struct page
*page
= __page_cache_alloc(GFP_NOFS
);
91 list_add_tail(&page
->lru
, &pl
->free_list
);
96 EXPORT_SYMBOL(ceph_pagelist_reserve
);
99 * Free any pages that have been preallocated.
101 int ceph_pagelist_free_reserve(struct ceph_pagelist
*pl
)
103 while (!list_empty(&pl
->free_list
)) {
104 struct page
*page
= list_first_entry(&pl
->free_list
,
106 list_del(&page
->lru
);
108 --pl
->num_pages_free
;
110 BUG_ON(pl
->num_pages_free
);
113 EXPORT_SYMBOL(ceph_pagelist_free_reserve
);
116 * Create a truncation point.
118 void ceph_pagelist_set_cursor(struct ceph_pagelist
*pl
,
119 struct ceph_pagelist_cursor
*c
)
122 c
->page_lru
= pl
->head
.prev
;
125 EXPORT_SYMBOL(ceph_pagelist_set_cursor
);
128 * Truncate a pagelist to the given point. Move extra pages to reserve.
130 * Returns: 0 on success,
131 * -EINVAL if the pagelist doesn't match the trunc point pagelist
133 int ceph_pagelist_truncate(struct ceph_pagelist
*pl
,
134 struct ceph_pagelist_cursor
*c
)
140 ceph_pagelist_unmap_tail(pl
);
141 while (pl
->head
.prev
!= c
->page_lru
) {
142 page
= list_entry(pl
->head
.prev
, struct page
, lru
);
143 list_del(&page
->lru
); /* remove from pagelist */
144 list_add_tail(&page
->lru
, &pl
->free_list
); /* add to reserve */
145 ++pl
->num_pages_free
;
148 if (!list_empty(&pl
->head
)) {
149 page
= list_entry(pl
->head
.prev
, struct page
, lru
);
150 pl
->mapped_tail
= kmap(page
);
154 EXPORT_SYMBOL(ceph_pagelist_truncate
);