mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
ceph: add pagelist_reserve, pagelist_truncate, pagelist_set_cursor
These facilitate preallocation of pages so that we can encode into the pagelist in an atomic context. Signed-off-by: Greg Farnum <gregf@hq.newdream.net> Signed-off-by: Sage Weil <sage@newdream.net>
This commit is contained in:
parent
18a38193ef
commit
ac0b74d8a1
2 changed files with 118 additions and 9 deletions
|
@ -8,6 +8,14 @@ struct ceph_pagelist {
|
|||
void *mapped_tail;
|
||||
size_t length;
|
||||
size_t room;
|
||||
struct list_head free_list;
|
||||
size_t num_pages_free;
|
||||
};
|
||||
|
||||
struct ceph_pagelist_cursor {
|
||||
struct ceph_pagelist *pl; /* pagelist, for error checking */
|
||||
struct list_head *page_lru; /* page in list */
|
||||
size_t room; /* room remaining to reset to */
|
||||
};
|
||||
|
||||
static inline void ceph_pagelist_init(struct ceph_pagelist *pl)
|
||||
|
@ -16,11 +24,24 @@ static inline void ceph_pagelist_init(struct ceph_pagelist *pl)
|
|||
pl->mapped_tail = NULL;
|
||||
pl->length = 0;
|
||||
pl->room = 0;
|
||||
INIT_LIST_HEAD(&pl->free_list);
|
||||
pl->num_pages_free = 0;
|
||||
}
|
||||
|
||||
extern int ceph_pagelist_release(struct ceph_pagelist *pl);
|
||||
|
||||
extern int ceph_pagelist_append(struct ceph_pagelist *pl, const void *d, size_t l);
|
||||
|
||||
extern int ceph_pagelist_reserve(struct ceph_pagelist *pl, size_t space);
|
||||
|
||||
extern int ceph_pagelist_free_reserve(struct ceph_pagelist *pl);
|
||||
|
||||
extern void ceph_pagelist_set_cursor(struct ceph_pagelist *pl,
|
||||
struct ceph_pagelist_cursor *c);
|
||||
|
||||
extern int ceph_pagelist_truncate(struct ceph_pagelist *pl,
|
||||
struct ceph_pagelist_cursor *c);
|
||||
|
||||
static inline int ceph_pagelist_encode_64(struct ceph_pagelist *pl, u64 v)
|
||||
{
|
||||
__le64 ev = cpu_to_le64(v);
|
||||
|
|
|
@ -7,35 +7,42 @@
|
|||
|
||||
static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl)
|
||||
{
|
||||
struct page *page = list_entry(pl->head.prev, struct page,
|
||||
lru);
|
||||
kunmap(page);
|
||||
if (pl->mapped_tail) {
|
||||
struct page *page = list_entry(pl->head.prev, struct page, lru);
|
||||
kunmap(page);
|
||||
pl->mapped_tail = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ceph_pagelist_release(struct ceph_pagelist *pl)
|
||||
{
|
||||
if (pl->mapped_tail)
|
||||
ceph_pagelist_unmap_tail(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;
|
||||
}
|
||||
EXPORT_SYMBOL(ceph_pagelist_release);
|
||||
|
||||
static int ceph_pagelist_addpage(struct ceph_pagelist *pl)
|
||||
{
|
||||
struct page *page = __page_cache_alloc(GFP_NOFS);
|
||||
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);
|
||||
}
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
pl->room += PAGE_SIZE;
|
||||
ceph_pagelist_unmap_tail(pl);
|
||||
list_add_tail(&page->lru, &pl->head);
|
||||
if (pl->mapped_tail)
|
||||
ceph_pagelist_unmap_tail(pl);
|
||||
pl->mapped_tail = kmap(page);
|
||||
return 0;
|
||||
}
|
||||
|
@ -63,3 +70,84 @@ int ceph_pagelist_append(struct ceph_pagelist *pl, const void *buf, size_t len)
|
|||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ceph_pagelist_append);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
|
Loading…
Reference in a new issue