diff options
Diffstat (limited to 'assoc_buf.h')
-rw-r--r-- | assoc_buf.h | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/assoc_buf.h b/assoc_buf.h new file mode 100644 index 0000000..e9e7fbc --- /dev/null +++ b/assoc_buf.h @@ -0,0 +1,72 @@ +#include <linux/slab.h> +#include <linux/kernel.h> + +struct asbuf { + unsigned long ino; + char *buf; + size_t alloc; +}; + + +ssize_t asbuf_free_alloc(struct asbuf *buf, size_t size) { + char *mem; + + mem = kmalloc(size, GFP_KERNEL); + if (!mem) + return -ENOMEM; + + if (buf->alloc) + kfree(buf->buf); + + buf->buf = mem; + buf->alloc = size; + return 0; +} + +void asbuf_free(struct asbuf *buf) { + kfree(buf->buf); +} + +ssize_t asbuf_to_user(struct asbuf *buf, + char __user *user_buf, + size_t len, + loff_t *offset) { + + size_t chars_left, request; + ssize_t uncopied, copied; + + if (!buf->alloc) + return -EINVAL; + + if (*offset > buf->alloc) + return -EINVAL; + + chars_left = buf->alloc - *offset; + request = min(len, chars_left); + + printk(KERN_INFO "buf: %p\t alloc: %zu\t request: %zu\n", buf, buf->alloc, request); + + uncopied = copy_to_user(user_buf, buf->buf + *offset, request); + copied = request - uncopied; + + *offset += copied; + return copied; +} + +ssize_t asbuf_from_user(struct asbuf *buf, + const char __user *user_buf, + size_t len, + loff_t *offset) { + ssize_t rc = 0; + size_t uncopied, copied; + rc = asbuf_free_alloc(buf, len); + if (rc != 0) + return rc; + + uncopied = copy_from_user(buf->buf, user_buf, len); + copied = len - uncopied; + + *offset = 0; + + return copied; +} |