X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=lib%2Fringbuffer%2Fbackend.h;h=2ce6ce9cd752508484123d4997d0f18481913b85;hb=886d51a3d7ed5fa6b41d7f19b3e14ae6c535a44c;hp=47bc1798334188a2c31c2c89e71c12ad81e4b42e;hpb=f3bc08c50e1b302bceea699027d889fd6d9af525;p=lttng-modules.git diff --git a/lib/ringbuffer/backend.h b/lib/ringbuffer/backend.h index 47bc1798..2ce6ce9c 100644 --- a/lib/ringbuffer/backend.h +++ b/lib/ringbuffer/backend.h @@ -1,14 +1,26 @@ -#ifndef _LINUX_RING_BUFFER_BACKEND_H -#define _LINUX_RING_BUFFER_BACKEND_H +#ifndef _LIB_RING_BUFFER_BACKEND_H +#define _LIB_RING_BUFFER_BACKEND_H /* - * linux/ringbuffer/backend.h - * - * Copyright (C) 2008-2010 - Mathieu Desnoyers + * lib/ringbuffer/backend.h * * Ring buffer backend (API). * - * Dual LGPL v2.1/GPL v2 license. + * Copyright (C) 2010-2012 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Credits to Steven Rostedt for proposing to use an extra-subbuffer owned by * the reader in flight recorder mode. @@ -103,6 +115,115 @@ void lib_ring_buffer_write(const struct lib_ring_buffer_config *config, ctx->buf_offset += len; } +/** + * lib_ring_buffer_memset - write len bytes of c to a buffer backend + * @config : ring buffer instance configuration + * @bufb : ring buffer backend + * @offset : offset within the buffer + * @c : the byte to copy + * @len : number of bytes to copy + * + * This function writes "len" bytes of "c" to a buffer backend, at a specific + * offset. This is more or less a buffer backend-specific memset() operation. + * Calls the slow path (_ring_buffer_memset) if write is crossing a page + * boundary. + */ +static inline +void lib_ring_buffer_memset(const struct lib_ring_buffer_config *config, + struct lib_ring_buffer_ctx *ctx, int c, size_t len) +{ + + struct lib_ring_buffer_backend *bufb = &ctx->buf->backend; + struct channel_backend *chanb = &ctx->chan->backend; + size_t sbidx, index; + size_t offset = ctx->buf_offset; + ssize_t pagecpy; + struct lib_ring_buffer_backend_pages *rpages; + unsigned long sb_bindex, id; + + offset &= chanb->buf_size - 1; + sbidx = offset >> chanb->subbuf_size_order; + index = (offset & (chanb->subbuf_size - 1)) >> PAGE_SHIFT; + pagecpy = min_t(size_t, len, (-offset) & ~PAGE_MASK); + id = bufb->buf_wsb[sbidx].id; + sb_bindex = subbuffer_id_get_index(config, id); + rpages = bufb->array[sb_bindex]; + CHAN_WARN_ON(ctx->chan, + config->mode == RING_BUFFER_OVERWRITE + && subbuffer_id_is_noref(config, id)); + if (likely(pagecpy == len)) + lib_ring_buffer_do_memset(rpages->p[index].virt + + (offset & ~PAGE_MASK), + c, len); + else + _lib_ring_buffer_memset(bufb, offset, c, len, 0); + ctx->buf_offset += len; +} + +/** + * lib_ring_buffer_copy_from_user - write userspace data to a buffer backend + * @config : ring buffer instance configuration + * @ctx: ring buffer context. (input arguments only) + * @src : userspace source pointer to copy from + * @len : length of data to copy + * + * This function copies "len" bytes of data from a userspace pointer to a + * buffer backend, at the current context offset. This is more or less a buffer + * backend-specific memcpy() operation. Calls the slow path + * (_ring_buffer_write_from_user) if copy is crossing a page boundary. + */ +static inline +void lib_ring_buffer_copy_from_user(const struct lib_ring_buffer_config *config, + struct lib_ring_buffer_ctx *ctx, + const void __user *src, size_t len) +{ + struct lib_ring_buffer_backend *bufb = &ctx->buf->backend; + struct channel_backend *chanb = &ctx->chan->backend; + size_t sbidx, index; + size_t offset = ctx->buf_offset; + ssize_t pagecpy; + struct lib_ring_buffer_backend_pages *rpages; + unsigned long sb_bindex, id; + unsigned long ret; + + offset &= chanb->buf_size - 1; + sbidx = offset >> chanb->subbuf_size_order; + index = (offset & (chanb->subbuf_size - 1)) >> PAGE_SHIFT; + pagecpy = min_t(size_t, len, (-offset) & ~PAGE_MASK); + id = bufb->buf_wsb[sbidx].id; + sb_bindex = subbuffer_id_get_index(config, id); + rpages = bufb->array[sb_bindex]; + CHAN_WARN_ON(ctx->chan, + config->mode == RING_BUFFER_OVERWRITE + && subbuffer_id_is_noref(config, id)); + + if (unlikely(!access_ok(VERIFY_READ, src, len))) + goto fill_buffer; + + if (likely(pagecpy == len)) { + ret = lib_ring_buffer_do_copy_from_user( + rpages->p[index].virt + (offset & ~PAGE_MASK), + src, len); + if (unlikely(ret > 0)) { + len -= (pagecpy - ret); + offset += (pagecpy - ret); + goto fill_buffer; + } + } else { + _lib_ring_buffer_copy_from_user(bufb, offset, src, len, 0); + } + ctx->buf_offset += len; + + return; + +fill_buffer: + /* + * In the error path we call the slow path version to avoid + * the pollution of static inline code. + */ + _lib_ring_buffer_memset(bufb, offset, 0, len, 0); +} + /* * This accessor counts the number of unread records in a buffer. * It only provides a consistent value if no reads not writes are performed @@ -138,4 +259,4 @@ ssize_t lib_ring_buffer_file_splice_read(struct file *in, loff_t *ppos, size_t len, unsigned int flags); loff_t lib_ring_buffer_no_llseek(struct file *file, loff_t offset, int origin); -#endif /* _LINUX_RING_BUFFER_BACKEND_H */ +#endif /* _LIB_RING_BUFFER_BACKEND_H */