void lib_ring_buffer_backend_reset(struct lttng_ust_lib_ring_buffer_backend *bufb, struct lttng_ust_shm_handle *handle) { struct channel_backend *chanb; const struct lttng_ust_lib_ring_buffer_config *config; unsigned long num_subbuf_alloc; unsigned int i; chanb = &shmp(handle, bufb->chan)->backend; if (!chanb) abort(); config = &chanb->config; num_subbuf_alloc = chanb->num_subbuf; if (chanb->extra_reader_sb) num_subbuf_alloc++; for (i = 0; i < chanb->num_subbuf; i++) { struct lttng_ust_lib_ring_buffer_backend_subbuffer *sb; sb = shmp_index(handle, bufb->buf_wsb, i); if (!sb) abort(); sb->id = subbuffer_id(config, 0, 1, i); } if (chanb->extra_reader_sb) bufb->buf_rsb.id = subbuffer_id(config, 0, 1, num_subbuf_alloc - 1); else bufb->buf_rsb.id = subbuffer_id(config, 0, 1, 0); for (i = 0; i < num_subbuf_alloc; i++) { struct lttng_ust_lib_ring_buffer_backend_pages_shmp *sbp; struct lttng_ust_lib_ring_buffer_backend_pages *pages; sbp = shmp_index(handle, bufb->array, i); if (!sbp) abort(); pages = shmp(handle, sbp->shmp); if (!pages) abort(); /* Don't reset mmap_offset */ v_set(config, &pages->records_commit, 0); v_set(config, &pages->records_unread, 0); pages->data_size = 0; /* Don't reset backend page and virt addresses */ } /* Don't reset num_pages_per_subbuf, cpu, allocated */ v_set(config, &bufb->records_read, 0); }
void *ustctl_get_mmap_base(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf) { if (!handle || !buf) return NULL; return shmp(handle, buf->backend.memory_map); }
void ustctl_unmap_channel(struct lttng_ust_shm_handle *handle) { struct channel *chan; assert(handle); chan = shmp(handle, handle->chan); channel_destroy(chan, handle, 1); }
static void unmap_channel(struct lttng_ust_shm_handle *handle) { struct channel *chan; chan = shmp(handle, handle->chan); /* unmap channel */ channel_destroy(chan, handle, 1); }
void *ustctl_get_mmap_base(struct ustctl_consumer_stream *stream) { struct lttng_ust_lib_ring_buffer *buf; struct ustctl_consumer_channel *consumer_chan; if (!stream) return NULL; buf = stream->buf; consumer_chan = stream->chan; return shmp(consumer_chan->chan->handle, buf->backend.memory_map); }
/* returns the offset of the subbuffer belonging to the mmap reader. */ int ustctl_get_mmap_read_offset(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf, unsigned long *off) { struct channel *chan = handle->shadow_chan; unsigned long sb_bindex; if (!handle || !buf || !off) return -EINVAL; if (chan->backend.config.output != RING_BUFFER_MMAP) return -EINVAL; sb_bindex = subbuffer_id_get_index(&chan->backend.config, buf->backend.buf_rsb.id); *off = shmp(handle, shmp_index(handle, buf->backend.array, sb_bindex)->shmp)->mmap_offset; return 0; }
static struct lttng_ust_client_lib_ring_buffer_client_cb *get_client_cb( struct lttng_ust_lib_ring_buffer *buf, struct lttng_ust_shm_handle *handle) { struct channel *chan; const struct lttng_ust_lib_ring_buffer_config *config; struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb; chan = shmp(handle, buf->backend.chan); config = &chan->backend.config; if (!config->cb_ptr) return NULL; client_cb = caa_container_of(config->cb_ptr, struct lttng_ust_client_lib_ring_buffer_client_cb, parent); return client_cb; }
static struct lttng_ust_shm_handle *map_channel(struct lttng_ust_object_data *chan_data, struct lttng_ust_object_data *stream_datas, int nr_check) { struct lttng_ust_shm_handle *handle; struct channel *chan; int k, ret; /* map metadata channel */ handle = channel_handle_create(chan_data->shm_fd, chan_data->wait_fd, chan_data->memory_map_size); if (!handle) { printf("create handle error\n"); return NULL; } chan_data->shm_fd = -1; chan_data->wait_fd = -1; chan = shmp(handle, handle->chan); for (k = 0; k < nr_check; k++) { struct lttng_ust_object_data *stream_data = &stream_datas[k]; if (!stream_data->handle) break; /* map stream */ ret = channel_handle_add_stream(handle, stream_data->shm_fd, stream_data->wait_fd, stream_data->memory_map_size); if (ret) { printf("add stream error\n"); goto error_destroy; } stream_data->shm_fd = -1; stream_data->wait_fd = -1; } return handle; error_destroy: channel_destroy(chan, handle, 1); return NULL; }
/* returns the offset of the subbuffer belonging to the mmap reader. */ int ustctl_get_mmap_read_offset(struct ustctl_consumer_stream *stream, unsigned long *off) { struct channel *chan; unsigned long sb_bindex; struct lttng_ust_lib_ring_buffer *buf; struct ustctl_consumer_channel *consumer_chan; if (!stream) return -EINVAL; buf = stream->buf; consumer_chan = stream->chan; chan = consumer_chan->chan->chan; if (chan->backend.config.output != RING_BUFFER_MMAP) return -EINVAL; sb_bindex = subbuffer_id_get_index(&chan->backend.config, buf->backend.buf_rsb.id); *off = shmp(consumer_chan->chan->handle, shmp_index(consumer_chan->chan->handle, buf->backend.array, sb_bindex)->shmp)->mmap_offset; return 0; }
static int consume_stream(struct lttng_ust_shm_handle *handle, int cpu, char *outfile) { struct channel *chan; struct lttng_ust_lib_ring_buffer *buf; int outfd, ret; int *shm_fd, *wait_fd; uint64_t *memory_map_size; chan = shmp(handle, handle->chan); /* open stream */ buf = channel_get_ring_buffer(&chan->backend.config, chan, cpu, handle, &shm_fd, &wait_fd, &memory_map_size); if (!buf) return -ENOENT; ret = lib_ring_buffer_open_read(buf, handle, 1); if (ret) { return -1; } /* copy */ outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (outfd < 0) { perror("open output"); return -1; } printf("Waiting for buffer data for %s\n", outfile); for (;;) { unsigned long read_size; unsigned long copy_size; char *ptr; ret = lib_ring_buffer_get_next_subbuf(buf, handle); printf("get next ret %d\n", ret); if (ret == -ENODATA) break; if (ret == -EAGAIN) { sleep(1); continue; } if (ret) { printf("Error %d in lib_ring_buffer_get_next_subbuf\n", ret); return -1; } read_size = lib_ring_buffer_get_read_data_size( &chan->backend.config, buf, handle); read_size = PAGE_ALIGN(read_size); ptr = lib_ring_buffer_read_offset_address( &buf->backend, 0, handle); printf("WRITE: copy %lu bytes\n", read_size); copy_size = write(outfd, ptr, read_size); if (copy_size < read_size) { printf("write issue: copied %lu, expected %lu\n", copy_size, read_size); } lib_ring_buffer_put_next_subbuf(buf, handle); } ret = close(outfd); if (ret) { perror("close"); return -1; } /* close stream */ lib_ring_buffer_release_read(buf, handle, 1); return 0; }
/** * lib_ring_buffer_backend_allocate - allocate a channel buffer * @config: ring buffer instance configuration * @buf: the buffer struct * @size: total size of the buffer * @num_subbuf: number of subbuffers * @extra_reader_sb: need extra subbuffer for reader */ static int lib_ring_buffer_backend_allocate(const struct lttng_ust_lib_ring_buffer_config *config, struct lttng_ust_lib_ring_buffer_backend *bufb, size_t size, size_t num_subbuf, int extra_reader_sb, struct lttng_ust_shm_handle *handle, struct shm_object *shmobj) { struct channel_backend *chanb; unsigned long subbuf_size, mmap_offset = 0; unsigned long num_subbuf_alloc; unsigned long i; long page_size; chanb = &shmp(handle, bufb->chan)->backend; if (!chanb) return -EINVAL; subbuf_size = chanb->subbuf_size; num_subbuf_alloc = num_subbuf; if (extra_reader_sb) num_subbuf_alloc++; page_size = sysconf(_SC_PAGE_SIZE); if (page_size <= 0) { goto page_size_error; } align_shm(shmobj, __alignof__(struct lttng_ust_lib_ring_buffer_backend_pages_shmp)); set_shmp(bufb->array, zalloc_shm(shmobj, sizeof(struct lttng_ust_lib_ring_buffer_backend_pages_shmp) * num_subbuf_alloc)); if (caa_unlikely(!shmp(handle, bufb->array))) goto array_error; /* * This is the largest element (the buffer pages) which needs to * be aligned on page size. */ align_shm(shmobj, page_size); set_shmp(bufb->memory_map, zalloc_shm(shmobj, subbuf_size * num_subbuf_alloc)); if (caa_unlikely(!shmp(handle, bufb->memory_map))) goto memory_map_error; /* Allocate backend pages array elements */ for (i = 0; i < num_subbuf_alloc; i++) { align_shm(shmobj, __alignof__(struct lttng_ust_lib_ring_buffer_backend_pages)); set_shmp(shmp_index(handle, bufb->array, i)->shmp, zalloc_shm(shmobj, sizeof(struct lttng_ust_lib_ring_buffer_backend_pages))); if (!shmp(handle, shmp_index(handle, bufb->array, i)->shmp)) goto free_array; } /* Allocate write-side subbuffer table */ align_shm(shmobj, __alignof__(struct lttng_ust_lib_ring_buffer_backend_subbuffer)); set_shmp(bufb->buf_wsb, zalloc_shm(shmobj, sizeof(struct lttng_ust_lib_ring_buffer_backend_subbuffer) * num_subbuf)); if (caa_unlikely(!shmp(handle, bufb->buf_wsb))) goto free_array; for (i = 0; i < num_subbuf; i++) { struct lttng_ust_lib_ring_buffer_backend_subbuffer *sb; sb = shmp_index(handle, bufb->buf_wsb, i); if (!sb) goto free_array; sb->id = subbuffer_id(config, 0, 1, i); } /* Assign read-side subbuffer table */ if (extra_reader_sb) bufb->buf_rsb.id = subbuffer_id(config, 0, 1, num_subbuf_alloc - 1); else bufb->buf_rsb.id = subbuffer_id(config, 0, 1, 0); /* Allocate subbuffer packet counter table */ align_shm(shmobj, __alignof__(struct lttng_ust_lib_ring_buffer_backend_subbuffer)); set_shmp(bufb->buf_cnt, zalloc_shm(shmobj, sizeof(struct lttng_ust_lib_ring_buffer_backend_counts) * num_subbuf)); if (caa_unlikely(!shmp(handle, bufb->buf_cnt))) goto free_wsb; /* Assign pages to page index */ for (i = 0; i < num_subbuf_alloc; i++) { struct lttng_ust_lib_ring_buffer_backend_pages_shmp *sbp; struct lttng_ust_lib_ring_buffer_backend_pages *pages; struct shm_ref ref; ref.index = bufb->memory_map._ref.index; ref.offset = bufb->memory_map._ref.offset; ref.offset += i * subbuf_size; sbp = shmp_index(handle, bufb->array, i); if (!sbp) goto free_array; pages = shmp(handle, sbp->shmp); if (!pages) goto free_array; set_shmp(pages->p, ref); if (config->output == RING_BUFFER_MMAP) { pages->mmap_offset = mmap_offset; mmap_offset += subbuf_size; } } return 0; free_wsb: /* bufb->buf_wsb will be freed by shm teardown */ free_array: /* bufb->array[i] will be freed by shm teardown */ memory_map_error: /* bufb->array will be freed by shm teardown */ array_error: page_size_error: return -ENOMEM; }
/** * channel_backend_init - initialize a channel backend * @chanb: channel backend * @name: channel name * @config: client ring buffer configuration * @parent: dentry of parent directory, %NULL for root directory * @subbuf_size: size of sub-buffers (> page size, power of 2) * @num_subbuf: number of sub-buffers (power of 2) * @lttng_ust_shm_handle: shared memory handle * @stream_fds: stream file descriptors. * * Returns channel pointer if successful, %NULL otherwise. * * Creates per-cpu channel buffers using the sizes and attributes * specified. The created channel buffer files will be named * name_0...name_N-1. File permissions will be %S_IRUSR. * * Called with CPU hotplug disabled. */ int channel_backend_init(struct channel_backend *chanb, const char *name, const struct lttng_ust_lib_ring_buffer_config *config, size_t subbuf_size, size_t num_subbuf, struct lttng_ust_shm_handle *handle, const int *stream_fds) { struct channel *chan = caa_container_of(chanb, struct channel, backend); unsigned int i; int ret; size_t shmsize = 0, num_subbuf_alloc; long page_size; if (!name) return -EPERM; page_size = sysconf(_SC_PAGE_SIZE); if (page_size <= 0) { return -ENOMEM; } /* Check that the subbuffer size is larger than a page. */ if (subbuf_size < page_size) return -EINVAL; /* * Make sure the number of subbuffers and subbuffer size are * power of 2, and nonzero. */ if (!subbuf_size || (subbuf_size & (subbuf_size - 1))) return -EINVAL; if (!num_subbuf || (num_subbuf & (num_subbuf - 1))) return -EINVAL; /* * Overwrite mode buffers require at least 2 subbuffers per * buffer. */ if (config->mode == RING_BUFFER_OVERWRITE && num_subbuf < 2) return -EINVAL; ret = subbuffer_id_check_index(config, num_subbuf); if (ret) return ret; chanb->buf_size = num_subbuf * subbuf_size; chanb->subbuf_size = subbuf_size; chanb->buf_size_order = get_count_order(chanb->buf_size); chanb->subbuf_size_order = get_count_order(subbuf_size); chanb->num_subbuf_order = get_count_order(num_subbuf); chanb->extra_reader_sb = (config->mode == RING_BUFFER_OVERWRITE) ? 1 : 0; chanb->num_subbuf = num_subbuf; strncpy(chanb->name, name, NAME_MAX); chanb->name[NAME_MAX - 1] = '\0'; memcpy(&chanb->config, config, sizeof(*config)); /* Per-cpu buffer size: control (prior to backend) */ shmsize = offset_align(shmsize, __alignof__(struct lttng_ust_lib_ring_buffer)); shmsize += sizeof(struct lttng_ust_lib_ring_buffer); /* Per-cpu buffer size: backend */ /* num_subbuf + 1 is the worse case */ num_subbuf_alloc = num_subbuf + 1; shmsize += offset_align(shmsize, __alignof__(struct lttng_ust_lib_ring_buffer_backend_pages_shmp)); shmsize += sizeof(struct lttng_ust_lib_ring_buffer_backend_pages_shmp) * num_subbuf_alloc; shmsize += offset_align(shmsize, page_size); shmsize += subbuf_size * num_subbuf_alloc; shmsize += offset_align(shmsize, __alignof__(struct lttng_ust_lib_ring_buffer_backend_pages)); shmsize += sizeof(struct lttng_ust_lib_ring_buffer_backend_pages) * num_subbuf_alloc; shmsize += offset_align(shmsize, __alignof__(struct lttng_ust_lib_ring_buffer_backend_subbuffer)); shmsize += sizeof(struct lttng_ust_lib_ring_buffer_backend_subbuffer) * num_subbuf; /* Per-cpu buffer size: control (after backend) */ shmsize += offset_align(shmsize, __alignof__(struct commit_counters_hot)); shmsize += sizeof(struct commit_counters_hot) * num_subbuf; shmsize += offset_align(shmsize, __alignof__(struct commit_counters_cold)); shmsize += sizeof(struct commit_counters_cold) * num_subbuf; if (config->alloc == RING_BUFFER_ALLOC_PER_CPU) { struct lttng_ust_lib_ring_buffer *buf; /* * We need to allocate for all possible cpus. */ for_each_possible_cpu(i) { struct shm_object *shmobj; shmobj = shm_object_table_alloc(handle->table, shmsize, SHM_OBJECT_SHM, stream_fds[i]); if (!shmobj) goto end; align_shm(shmobj, __alignof__(struct lttng_ust_lib_ring_buffer)); set_shmp(chanb->buf[i].shmp, zalloc_shm(shmobj, sizeof(struct lttng_ust_lib_ring_buffer))); buf = shmp(handle, chanb->buf[i].shmp); if (!buf) goto end; set_shmp(buf->self, chanb->buf[i].shmp._ref); ret = lib_ring_buffer_create(buf, chanb, i, handle, shmobj); if (ret) goto free_bufs; /* cpu hotplug locked */ } } else {
/* Map channel shm into process memory */ struct lttng_ust_shm_handle *ustctl_map_channel(struct lttng_ust_object_data *chan_data) { struct lttng_ust_shm_handle *handle; struct channel *chan; size_t chan_size; struct lttng_ust_lib_ring_buffer_config *config; int ret; if (!chan_data) return NULL; handle = channel_handle_create(chan_data->shm_fd, chan_data->wait_fd, chan_data->memory_map_size); if (!handle) { ERR("create handle error"); return NULL; } /* * Set to -1, and then close the shm fd, and set the handle shm * fd to -1 too. We don't need the shm fds after they have been * mapped. * The wait_fd is set to -1 in chan_data because it is now owned * by the handle. */ chan_data->shm_fd = -1; chan_data->wait_fd = -1; /* chan is object 0. This is hardcoded. */ if (handle->table->objects[0].shm_fd >= 0) { ret = close(handle->table->objects[0].shm_fd); if (ret) { perror("Error closing shm_fd"); } handle->table->objects[0].shm_fd = -1; } /* * TODO: add consistency checks to be resilient if the * application try to feed us with incoherent channel structure * values. */ chan = shmp(handle, handle->chan); /* chan is object 0. This is hardcoded. */ chan_size = handle->table->objects[0].allocated_len; handle->shadow_chan = malloc(chan_size); if (!handle->shadow_chan) { channel_destroy(chan, handle, 1); return NULL; } memcpy(handle->shadow_chan, chan, chan_size); /* * The callback pointers in the producer are invalid in the * consumer. We need to look them up here. */ config = &handle->shadow_chan->backend.config; switch (config->client_type) { case LTTNG_CLIENT_METADATA: memcpy(&config->cb, lttng_client_callbacks_metadata, sizeof(config->cb)); break; case LTTNG_CLIENT_DISCARD: memcpy(&config->cb, lttng_client_callbacks_discard, sizeof(config->cb)); break; case LTTNG_CLIENT_OVERWRITE: memcpy(&config->cb, lttng_client_callbacks_overwrite, sizeof(config->cb)); break; default: ERR("Unknown client type %d", config->client_type); channel_destroy(chan, handle, 1); return NULL; } /* Replace the object table pointer. */ ret = munmap(handle->table->objects[0].memory_map, handle->table->objects[0].memory_map_size); if (ret) { perror("munmap"); assert(0); } handle->table->objects[0].memory_map = (char *) handle->shadow_chan; handle->table->objects[0].is_shadow = 1; return handle; }