This lets callers specify a region of memory to read from or write to with an array of page/offset/len tuples. There have been specific requests to do this from servers which want to do O_DIRECT from the kernel. (knfsd?) This could also be used by places which currently hold a kmap() and call fop->write. ecryptfs_write_lower_page_segment() is one such caller. --- fs/rwmem.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/rwmem.h | 16 ++++++++++++ 2 files changed, 82 insertions(+), 0 deletions(-) diff --git a/fs/rwmem.c b/fs/rwmem.c index 0433ba4..c87e8a4 100644 --- a/fs/rwmem.c +++ b/fs/rwmem.c @@ -90,3 +90,69 @@ struct rwmem_ops rwmem_iovec_ops = { .seg_bytes = rwmem_iovec_seg_bytes, .get_seg_pages = rwmem_iovec_get_seg_pages, }; + +void rwmem_pages_init(struct rwmem *rwm) +{ + struct rwmem_pages *rwp = container_of(rwm, struct rwmem_pages, rwmem); + struct pgol *pgol; + unsigned long i; + + rwm->total_bytes = 0; + rwm->nr_pages = rwm->nr_segs; + rwm->boundary_bits = 0; + + for (i = 0; i < rwm->nr_segs; i++) { + pgol = &rwp->pgol[i]; + + rwm->total_bytes += pgol->len; + rwm->boundary_bits |= pgol->offset | pgol->len; + } +} + +/* + * Returns the offset of the start of a segment within its first page. + */ +unsigned long rwmem_pages_seg_page_offset(struct rwmem *rwm, unsigned long i) +{ + struct rwmem_pages *rwp = container_of(rwm, struct rwmem_pages, rwmem); + BUG_ON(i >= rwm->nr_segs); + return rwp->pgol[i].offset; +} + +/* + * Returns the total bytes in the given segment. + */ +unsigned long rwmem_pages_seg_bytes(struct rwmem *rwm, unsigned long i) +{ + struct rwmem_pages *rwp = container_of(rwm, struct rwmem_pages, rwmem); + BUG_ON(i >= rwm->nr_segs); + return rwp->pgol[i].len; +} + +/* + * For now each page is its own seg. + */ +int rwmem_pages_get_seg_pages(struct rwmem *rwm, unsigned long i, + unsigned long *cursor, struct page **pages, + unsigned long max_pages, int write) +{ + struct rwmem_pages *rwp = container_of(rwm, struct rwmem_pages, rwmem); + int ret = 0; + + BUG_ON(i >= rwm->nr_segs); + BUG_ON(*cursor != 0); + + if (max_pages) { + pages[0] = rwp->pgol[i].page; + get_page(pages[0]); + ret = 1; + } + return ret; +} + +struct rwmem_ops rwmem_pages_ops = { + .init = rwmem_pages_init, + .seg_page_offset = rwmem_pages_seg_page_offset, + .seg_bytes = rwmem_pages_seg_bytes, + .get_seg_pages = rwmem_pages_get_seg_pages, +}; diff --git a/include/linux/rwmem.h b/include/linux/rwmem.h index 666f9f4..47019f0 100644 --- a/include/linux/rwmem.h +++ b/include/linux/rwmem.h @@ -26,4 +26,20 @@ struct rwmem_iovec { }; struct rwmem_ops rwmem_iovec_ops; +/* + * How many times do we need this in subsystems before we make a universal + * struct? (bio_vec, skb_frag_struct, pipe_buffer) + */ +struct pgol { + struct page *page; + unsigned int offset; + unsigned int len; +}; + +struct rwmem_pages { + struct rwmem rwmem; + struct pgol *pgol; +}; +struct rwmem_ops rwmem_pages_ops; + #endif -- 1.5.2.2 - To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html