X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Flib%2Fringbuffer%2Fring_buffer_backend.c;h=cbc931df04b2682a29b02f3afa8e5cd60318474b;hb=e5f1eb9a2a0f516b32966aad52be990b093f24ad;hp=eaf8f1157b0beeffeb43c46d7ede709b8de4c2bb;hpb=e20c0fec4a2e120143f2e71c63d9fcd664af55a4;p=lttng-modules.git diff --git a/src/lib/ringbuffer/ring_buffer_backend.c b/src/lib/ringbuffer/ring_buffer_backend.c index eaf8f115..cbc931df 100644 --- a/src/lib/ringbuffer/ring_buffer_backend.c +++ b/src/lib/ringbuffer/ring_buffer_backend.c @@ -653,26 +653,20 @@ EXPORT_SYMBOL_GPL(_lib_ring_buffer_memset); * @offset : offset within the buffer * @src : source address * @len : length to write - * @pagecpy : page size copied so far * @pad : character to use for padding */ void _lib_ring_buffer_strcpy(struct lttng_kernel_ring_buffer_backend *bufb, - size_t offset, const char *src, size_t len, - size_t pagecpy, int pad) + size_t offset, const char *src, size_t len, int pad) { struct channel_backend *chanb = &bufb->chan->backend; const struct lttng_kernel_ring_buffer_config *config = &chanb->config; - size_t sbidx, index; + size_t sbidx, index, bytes_left_in_page; struct lttng_kernel_ring_buffer_backend_pages *rpages; unsigned long sb_bindex, id; - int src_terminated = 0; + bool src_terminated = false; CHAN_WARN_ON(chanb, !len); - offset += pagecpy; do { - len -= pagecpy; - if (!src_terminated) - src += pagecpy; sbidx = offset >> chanb->subbuf_size_order; index = (offset & (chanb->subbuf_size - 1)) >> PAGE_SHIFT; @@ -682,7 +676,7 @@ void _lib_ring_buffer_strcpy(struct lttng_kernel_ring_buffer_backend *bufb, */ CHAN_WARN_ON(chanb, offset >= chanb->buf_size); - pagecpy = min_t(size_t, len, PAGE_SIZE - (offset & ~PAGE_MASK)); + bytes_left_in_page = min_t(size_t, len, PAGE_SIZE - (offset & ~PAGE_MASK)); id = bufb->buf_wsb[sbidx].id; sb_bindex = subbuffer_id_get_index(config, id); rpages = bufb->array[sb_bindex]; @@ -692,8 +686,8 @@ void _lib_ring_buffer_strcpy(struct lttng_kernel_ring_buffer_backend *bufb, if (likely(!src_terminated)) { size_t count, to_copy; - to_copy = pagecpy; - if (pagecpy == len) + to_copy = bytes_left_in_page; + if (bytes_left_in_page == len) to_copy--; /* Final '\0' */ count = lib_ring_buffer_do_strcpy(config, rpages->p[index].virt @@ -705,7 +699,7 @@ void _lib_ring_buffer_strcpy(struct lttng_kernel_ring_buffer_backend *bufb, size_t pad_len = to_copy - count; /* Next pages will have padding */ - src_terminated = 1; + src_terminated = true; lib_ring_buffer_do_memset(rpages->p[index].virt + (offset & ~PAGE_MASK), pad, pad_len); @@ -714,21 +708,104 @@ void _lib_ring_buffer_strcpy(struct lttng_kernel_ring_buffer_backend *bufb, } else { size_t pad_len; - pad_len = pagecpy; - if (pagecpy == len) + pad_len = bytes_left_in_page; + if (bytes_left_in_page == len) pad_len--; /* Final '\0' */ lib_ring_buffer_do_memset(rpages->p[index].virt + (offset & ~PAGE_MASK), pad, pad_len); offset += pad_len; } - } while (unlikely(len != pagecpy)); + len -= bytes_left_in_page; + if (!src_terminated) + src += bytes_left_in_page; + } while (unlikely(len)); + /* Ending '\0' */ lib_ring_buffer_do_memset(rpages->p[index].virt + (offset & ~PAGE_MASK), '\0', 1); } EXPORT_SYMBOL_GPL(_lib_ring_buffer_strcpy); +/** + * _lib_ring_buffer_pstrcpy - write to a buffer backend P-string + * @bufb : buffer backend + * @src : source pointer to copy from + * @len : length of data to copy + * @pad : character to use for padding + * + * This function copies up to @len bytes of data from a source pointer + * to a Pascal String into the buffer backend. If a terminating '\0' + * character is found in @src before @len characters are copied, pad the + * buffer with @pad characters (e.g. '\0'). + * + * The length of the pascal strings in the ring buffer is explicit: it + * is either the array or sequence length. + */ +void _lib_ring_buffer_pstrcpy(struct lttng_kernel_ring_buffer_backend *bufb, + size_t offset, const char *src, size_t len, int pad) +{ + struct channel_backend *chanb = &bufb->chan->backend; + const struct lttng_kernel_ring_buffer_config *config = &chanb->config; + size_t sbidx, index, bytes_left_in_page; + struct lttng_kernel_ring_buffer_backend_pages *rpages; + unsigned long sb_bindex, id; + bool src_terminated = false; + + CHAN_WARN_ON(chanb, !len); + do { + sbidx = offset >> chanb->subbuf_size_order; + index = (offset & (chanb->subbuf_size - 1)) >> PAGE_SHIFT; + + /* + * Underlying layer should never ask for writes across + * subbuffers. + */ + CHAN_WARN_ON(chanb, offset >= chanb->buf_size); + + bytes_left_in_page = min_t(size_t, len, PAGE_SIZE - (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(chanb, config->mode == RING_BUFFER_OVERWRITE + && subbuffer_id_is_noref(config, id)); + + if (likely(!src_terminated)) { + size_t count, to_copy; + + to_copy = bytes_left_in_page; + count = lib_ring_buffer_do_strcpy(config, + rpages->p[index].virt + + (offset & ~PAGE_MASK), + src, to_copy); + offset += count; + /* Padding */ + if (unlikely(count < to_copy)) { + size_t pad_len = to_copy - count; + + /* Next pages will have padding */ + src_terminated = true; + lib_ring_buffer_do_memset(rpages->p[index].virt + + (offset & ~PAGE_MASK), + pad, pad_len); + offset += pad_len; + } + } else { + size_t pad_len; + + pad_len = bytes_left_in_page; + lib_ring_buffer_do_memset(rpages->p[index].virt + + (offset & ~PAGE_MASK), + pad, pad_len); + offset += pad_len; + } + len -= bytes_left_in_page; + if (!src_terminated) + src += bytes_left_in_page; + } while (unlikely(len)); +} +EXPORT_SYMBOL_GPL(_lib_ring_buffer_pstrcpy); + /** * lib_ring_buffer_copy_from_user_inatomic - write user data to a ring_buffer buffer. * @bufb : buffer backend @@ -790,7 +867,6 @@ EXPORT_SYMBOL_GPL(_lib_ring_buffer_copy_from_user_inatomic); * @offset : offset within the buffer * @src : source address * @len : length to write - * @pagecpy : page size copied so far * @pad : character to use for padding * * This function deals with userspace pointers, it should never be called @@ -798,21 +874,16 @@ EXPORT_SYMBOL_GPL(_lib_ring_buffer_copy_from_user_inatomic); * previously. */ void _lib_ring_buffer_strcpy_from_user_inatomic(struct lttng_kernel_ring_buffer_backend *bufb, - size_t offset, const char __user *src, size_t len, - size_t pagecpy, int pad) + size_t offset, const char __user *src, size_t len, int pad) { struct channel_backend *chanb = &bufb->chan->backend; const struct lttng_kernel_ring_buffer_config *config = &chanb->config; - size_t sbidx, index; + size_t sbidx, index, bytes_left_in_page; struct lttng_kernel_ring_buffer_backend_pages *rpages; unsigned long sb_bindex, id; - int src_terminated = 0; + bool src_terminated = false; - offset += pagecpy; do { - len -= pagecpy; - if (!src_terminated) - src += pagecpy; sbidx = offset >> chanb->subbuf_size_order; index = (offset & (chanb->subbuf_size - 1)) >> PAGE_SHIFT; @@ -822,7 +893,7 @@ void _lib_ring_buffer_strcpy_from_user_inatomic(struct lttng_kernel_ring_buffer_ */ CHAN_WARN_ON(chanb, offset >= chanb->buf_size); - pagecpy = min_t(size_t, len, PAGE_SIZE - (offset & ~PAGE_MASK)); + bytes_left_in_page = min_t(size_t, len, PAGE_SIZE - (offset & ~PAGE_MASK)); id = bufb->buf_wsb[sbidx].id; sb_bindex = subbuffer_id_get_index(config, id); rpages = bufb->array[sb_bindex]; @@ -832,8 +903,8 @@ void _lib_ring_buffer_strcpy_from_user_inatomic(struct lttng_kernel_ring_buffer_ if (likely(!src_terminated)) { size_t count, to_copy; - to_copy = pagecpy; - if (pagecpy == len) + to_copy = bytes_left_in_page; + if (bytes_left_in_page == len) to_copy--; /* Final '\0' */ count = lib_ring_buffer_do_strcpy_from_user_inatomic(config, rpages->p[index].virt @@ -845,7 +916,7 @@ void _lib_ring_buffer_strcpy_from_user_inatomic(struct lttng_kernel_ring_buffer_ size_t pad_len = to_copy - count; /* Next pages will have padding */ - src_terminated = 1; + src_terminated = true; lib_ring_buffer_do_memset(rpages->p[index].virt + (offset & ~PAGE_MASK), pad, pad_len); @@ -854,21 +925,108 @@ void _lib_ring_buffer_strcpy_from_user_inatomic(struct lttng_kernel_ring_buffer_ } else { size_t pad_len; - pad_len = pagecpy; - if (pagecpy == len) + pad_len = bytes_left_in_page; + if (bytes_left_in_page == len) pad_len--; /* Final '\0' */ lib_ring_buffer_do_memset(rpages->p[index].virt + (offset & ~PAGE_MASK), pad, pad_len); offset += pad_len; } - } while (unlikely(len != pagecpy)); + len -= bytes_left_in_page; + if (!src_terminated) + src += bytes_left_in_page; + } while (unlikely(len)); + /* Ending '\0' */ lib_ring_buffer_do_memset(rpages->p[index].virt + (offset & ~PAGE_MASK), '\0', 1); } EXPORT_SYMBOL_GPL(_lib_ring_buffer_strcpy_from_user_inatomic); +/** + * _lib_ring_buffer_pstrcpy_from_user_inatomic - write userspace string to a buffer backend P-string + * @bufb : buffer backend + * @src : source pointer to copy from + * @len : length of data to copy + * @pad : character to use for padding + * + * This function copies up to @len bytes of data from a source pointer + * to a Pascal String into the buffer backend. If a terminating '\0' + * character is found in @src before @len characters are copied, pad the + * buffer with @pad characters (e.g. '\0'). + * + * The length of the pascal strings in the ring buffer is explicit: it + * is either the array or sequence length. + * + * This function deals with userspace pointers, it should never be called + * directly without having the src pointer checked with access_ok() + * previously. + */ +void _lib_ring_buffer_pstrcpy_from_user_inatomic(struct lttng_kernel_ring_buffer_backend *bufb, + size_t offset, const char __user *src, size_t len, int pad) +{ + struct channel_backend *chanb = &bufb->chan->backend; + const struct lttng_kernel_ring_buffer_config *config = &chanb->config; + size_t sbidx, index, bytes_left_in_page; + struct lttng_kernel_ring_buffer_backend_pages *rpages; + unsigned long sb_bindex, id; + bool src_terminated = false; + + CHAN_WARN_ON(chanb, !len); + do { + sbidx = offset >> chanb->subbuf_size_order; + index = (offset & (chanb->subbuf_size - 1)) >> PAGE_SHIFT; + + /* + * Underlying layer should never ask for writes across + * subbuffers. + */ + CHAN_WARN_ON(chanb, offset >= chanb->buf_size); + + bytes_left_in_page = min_t(size_t, len, PAGE_SIZE - (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(chanb, config->mode == RING_BUFFER_OVERWRITE + && subbuffer_id_is_noref(config, id)); + + if (likely(!src_terminated)) { + size_t count, to_copy; + + to_copy = bytes_left_in_page; + count = lib_ring_buffer_do_strcpy_from_user_inatomic(config, + rpages->p[index].virt + + (offset & ~PAGE_MASK), + src, to_copy); + offset += count; + /* Padding */ + if (unlikely(count < to_copy)) { + size_t pad_len = to_copy - count; + + /* Next pages will have padding */ + src_terminated = true; + lib_ring_buffer_do_memset(rpages->p[index].virt + + (offset & ~PAGE_MASK), + pad, pad_len); + offset += pad_len; + } + } else { + size_t pad_len; + + pad_len = bytes_left_in_page; + lib_ring_buffer_do_memset(rpages->p[index].virt + + (offset & ~PAGE_MASK), + pad, pad_len); + offset += pad_len; + } + len -= bytes_left_in_page; + if (!src_terminated) + src += bytes_left_in_page; + } while (unlikely(len)); +} +EXPORT_SYMBOL_GPL(_lib_ring_buffer_pstrcpy_from_user_inatomic); + /** * lib_ring_buffer_read - read data from ring_buffer_buffer. * @bufb : buffer backend