68b4476b0b
Allow the messenger to send/receive data in a bio. This is added so that we wouldn't need to copy the data into pages or some other buffer when doing IO for an rbd block device. We can now have trailing variable sized data for osd ops. Also osd ops encoding is more modular. Signed-off-by: Yehuda Sadeh <yehuda@hq.newdream.net> Signed-off-by: Sage Weil <sage@newdream.net>
64 lines
1.3 KiB
C
64 lines
1.3 KiB
C
|
|
#include <linux/gfp.h>
|
|
#include <linux/pagemap.h>
|
|
#include <linux/highmem.h>
|
|
|
|
#include "pagelist.h"
|
|
|
|
static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl)
|
|
{
|
|
struct page *page = list_entry(pl->head.prev, struct page,
|
|
lru);
|
|
kunmap(page);
|
|
}
|
|
|
|
int ceph_pagelist_release(struct ceph_pagelist *pl)
|
|
{
|
|
if (pl->mapped_tail)
|
|
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);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int ceph_pagelist_addpage(struct ceph_pagelist *pl)
|
|
{
|
|
struct page *page = __page_cache_alloc(GFP_NOFS);
|
|
if (!page)
|
|
return -ENOMEM;
|
|
pl->room += PAGE_SIZE;
|
|
list_add_tail(&page->lru, &pl->head);
|
|
if (pl->mapped_tail)
|
|
ceph_pagelist_unmap_tail(pl);
|
|
pl->mapped_tail = kmap(page);
|
|
return 0;
|
|
}
|
|
|
|
int ceph_pagelist_append(struct ceph_pagelist *pl, const void *buf, size_t len)
|
|
{
|
|
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;
|
|
}
|