Mercurial > hvf > hvf-old
changeset 533:a332c4f679c7
cp/fs: added a generic variable length record in-memory spool file code
Note: There's still no way to get a saved record.
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Tue, 26 Apr 2011 14:01:31 -0400 |
parents | c9988df57ecf |
children | e323b4a731d4 |
files | cp/fs/Makefile cp/fs/spool.c cp/include/spool.h |
diffstat | 3 files changed, 186 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/cp/fs/Makefile Tue Apr 26 14:00:24 2011 -0400 +++ b/cp/fs/Makefile Tue Apr 26 14:01:31 2011 -0400 @@ -1,1 +1,1 @@ -objs-fs := bdev.o edf.o bcache.o +objs-fs := bdev.o edf.o bcache.o spool.o
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/fs/spool.c Tue Apr 26 14:01:31 2011 -0400 @@ -0,0 +1,146 @@ +/* + * (C) Copyright 2007-2011 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <spool.h> +#include <buddy.h> +#include <slab.h> + +static LOCK_CLASS(spool_file_lc); + +struct spool_file *alloc_spool() +{ + struct spool_file *f; + + f = malloc(sizeof(struct spool_file), ZONE_NORMAL); + if (!f) + return ERR_PTR(-ENOMEM); + + mutex_init(&f->lock, &spool_file_lc); + INIT_LIST_HEAD(&f->list); + f->recs = 0; + f->pages = 0; + f->frecoff = 0; + f->lrecoff = 0; + + return f; +} + +void free_spool(struct spool_file *f) +{ + free(f); +} + +int spool_append_rec(struct spool_file *f, u8 *buf, u16 len) +{ + struct list_head new_pages; + struct spool_page *spage, *tmp; + struct spool_rec *rec; + struct page *page; + int npages; + int loff; + int copied; + u32 left; + u32 rlen; + int ret; + + INIT_LIST_HEAD(&new_pages); + npages = 0; + + BUG_ON(sizeof(struct spool_rec) != 2); + + mutex_lock(&f->lock); + + left = SPOOL_DATA_SIZE - f->lrecoff; + rlen = len + sizeof(struct spool_rec); + copied = 0; + + /* try to fill up the last page */ + if (f->pages && left) { + spage = list_last_entry(&f->list, struct spool_page, list); + rec = (struct spool_rec*) (spage->data + f->lrecoff); + + switch(left) { + case 1: + spage->data[f->lrecoff] = len >> 8; + copied = 1; + loff = SPOOL_DATA_SIZE; + break; + case 2: + rec->len = len; + copied = 2; + loff = SPOOL_DATA_SIZE; + break; + default: + rec->len = len; + memcpy(rec->data, buf, min_t(u32, len, left-2)); + copied = 2 + min_t(u32, len, left-2); + loff = f->lrecoff + copied; + break; + } + } + + BUG_ON(rlen < copied); + + /* we need to allocate space */ + while (rlen != copied) { + page = alloc_pages(0, ZONE_NORMAL); + if (!page) { + ret = -ENOMEM; + goto err; + } + + spage = page_to_addr(page); + + INIT_LIST_HEAD(&spage->list); + list_add_tail(&spage->list, &new_pages); + npages++; + + rec = (struct spool_rec*) spage->data; + left = SPOOL_DATA_SIZE; + + switch(copied) { + case 0: + /* nothing was copied */ + rec->len = len; + memcpy(rec->data, buf, min_t(u32, len, left-2)); + loff = 2 + min_t(u32, len, left-2); + break; + case 1: + /* half of the length was copied */ + spage->data[0] = len & 0xff; + rec = (struct spool_rec*) (spage->data - 1); + memcpy(rec->data, buf, min_t(u32, len, left-1)); + loff = 1 + min_t(u32, len, left-1); + break; + default: + /* the length and maybe some data were copied */ + memcpy(spage, buf-copied+2, min(rlen-copied, left)); + loff = min(rlen-copied, left); + break; + } + + copied += loff; + } + + list_splice_tail(&new_pages, &f->list); + + f->pages += npages; + f->recs++; + f->lrecoff = loff; + + mutex_unlock(&f->lock); + return 0; + +err: + mutex_unlock(&f->lock); + + list_for_each_entry_safe(spage, tmp, &new_pages, list) + free_pages(spage, 0); + + return ret; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/spool.h Tue Apr 26 14:01:31 2011 -0400 @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2007-2011 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __SPOOL_H +#define __SPOOL_H + +#include <list.h> +#include <mutex.h> + +struct spool_rec { + u16 len; + u8 data[0]; +}; + +#define SPOOL_DATA_SIZE (PAGE_SIZE - sizeof(struct list_head)) +struct spool_page { + struct list_head list; + u8 data[SPOOL_DATA_SIZE]; +}; + +struct spool_file { + mutex_t lock; + struct list_head list; + u64 recs; + u64 pages; + u16 frecoff; /* start of the first record, + offset into first page's data */ + u16 lrecoff; /* end of the last record, + offset into last page's data */ +}; + +extern struct spool_file *alloc_spool(); +extern void free_spool(struct spool_file *f); + +#endif