*/
#define _GNU_SOURCE
+#define _LGPL_SOURCE
#include <errno.h>
#include <inttypes.h>
#include <pthread.h>
#include "ust-ctl.h"
#include "utils.h"
+static
+int ust_app_flush_app_session(struct ust_app *app, struct ust_app_session *ua_sess);
+
/* Next available channel key. Access under next_channel_key_lock. */
static uint64_t _next_channel_key;
static pthread_mutex_t next_channel_key_lock = PTHREAD_MUTEX_INITIALIZER;
ua_sess->handle = -1;
ua_sess->channels = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+ ua_sess->metadata_attr.type = LTTNG_UST_CHAN_METADATA;
pthread_mutex_init(&ua_sess->lock, NULL);
return ua_sess;
}
/* If event not enabled, disable it on the tracer */
- if (ua_event->enabled == 0) {
- ret = disable_ust_event(app, ua_sess, ua_event);
+ if (ua_event->enabled) {
+ /*
+ * We now need to explicitly enable the event, since it
+ * is now disabled at creation.
+ */
+ ret = enable_ust_event(app, ua_sess, ua_event);
if (ret < 0) {
/*
- * If we hit an EPERM, something is wrong with our disable call. If
+ * If we hit an EPERM, something is wrong with our enable call. If
* we get an EEXIST, there is a problem on the tracer side since we
* just created it.
*/
}
lttng_ht_node_init_ulong(&ua_ctx->node,
(unsigned long) ua_ctx->ctx.ctx);
- lttng_ht_add_unique_ulong(ua_chan->ctx, &ua_ctx->node);
+ lttng_ht_add_ulong(ua_chan->ctx, &ua_ctx->node);
cds_list_add_tail(&ua_ctx->list, &ua_chan->ctx_list);
}
ua_sess->consumer = usess->consumer;
ua_sess->output_traces = usess->output_traces;
ua_sess->live_timer_interval = usess->live_timer_interval;
+ copy_channel_attr_to_ustctl(&ua_sess->metadata_attr,
+ &usess->metadata_attr);
switch (ua_sess->buffer_type) {
case LTTNG_BUFFER_PER_PID:
if (ret < 0) {
goto error;
}
- buffer_reg_pid_add(reg_pid);
} else {
goto end;
}
app->byte_order, app->version.major,
app->version.minor);
if (ret < 0) {
+ /*
+ * reg_pid->registry->reg.ust is NULL upon error, so we need to
+ * destroy the buffer registry, because it is always expected
+ * that if the buffer registry can be found, its ust registry is
+ * non-NULL.
+ */
+ buffer_reg_pid_destroy(reg_pid);
goto error;
}
+ buffer_reg_pid_add(reg_pid);
+
DBG3("UST app buffer registry per PID created successfully");
end:
if (ret < 0) {
goto error;
}
- buffer_reg_uid_add(reg_uid);
} else {
goto end;
}
app->byte_order, app->version.major,
app->version.minor);
if (ret < 0) {
+ /*
+ * reg_uid->registry->reg.ust is NULL upon error, so we need to
+ * destroy the buffer registry, because it is always expected
+ * that if the buffer registry can be found, its ust registry is
+ * non-NULL.
+ */
+ buffer_reg_uid_destroy(reg_uid, NULL);
goto error;
}
/* Add node to teardown list of the session. */
cds_list_add(®_uid->lnode, &usess->buffer_reg_uid_list);
- DBG3("UST app buffer registry per UID created successfully");
+ buffer_reg_uid_add(reg_uid);
+ DBG3("UST app buffer registry per UID created successfully");
end:
if (regp) {
*regp = reg_uid;
/* Init local registry. */
ret = setup_buffer_reg_pid(ua_sess, app, NULL);
if (ret < 0) {
+ delete_ust_app_session(-1, ua_sess, app);
goto error;
}
break;
/* Look for a global registry. If none exists, create one. */
ret = setup_buffer_reg_uid(usess, app, NULL);
if (ret < 0) {
+ delete_ust_app_session(-1, ua_sess, app);
goto error;
}
break;
return ret;
}
+/*
+ * Match function for a hash table lookup of ust_app_ctx.
+ *
+ * It matches an ust app context based on the context type and, in the case
+ * of perf counters, their name.
+ */
+static int ht_match_ust_app_ctx(struct cds_lfht_node *node, const void *_key)
+{
+ struct ust_app_ctx *ctx;
+ const struct lttng_ust_context *key;
+
+ assert(node);
+ assert(_key);
+
+ ctx = caa_container_of(node, struct ust_app_ctx, node.node);
+ key = _key;
+
+ /* Context type */
+ if (ctx->ctx.ctx != key->ctx) {
+ goto no_match;
+ }
+
+ /* Check the name in the case of perf thread counters. */
+ if (key->ctx == LTTNG_UST_CONTEXT_PERF_THREAD_COUNTER) {
+ if (strncmp(key->u.perf_counter.name,
+ ctx->ctx.u.perf_counter.name,
+ sizeof(key->u.perf_counter.name))) {
+ goto no_match;
+ }
+ }
+
+ /* Match. */
+ return 1;
+
+no_match:
+ return 0;
+}
+
+/*
+ * Lookup for an ust app context from an lttng_ust_context.
+ *
+ * Must be called while holding RCU read side lock.
+ * Return an ust_app_ctx object or NULL on error.
+ */
+static
+struct ust_app_ctx *find_ust_app_context(struct lttng_ht *ht,
+ struct lttng_ust_context *uctx)
+{
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_ulong *node;
+ struct ust_app_ctx *app_ctx = NULL;
+
+ assert(uctx);
+ assert(ht);
+
+ /* Lookup using the lttng_ust_context_type and a custom match fct. */
+ cds_lfht_lookup(ht->ht, ht->hash_fct((void *) uctx->ctx, lttng_ht_seed),
+ ht_match_ust_app_ctx, uctx, &iter.iter);
+ node = lttng_ht_iter_get_node_ulong(&iter);
+ if (!node) {
+ goto end;
+ }
+
+ app_ctx = caa_container_of(node, struct ust_app_ctx, node);
+
+end:
+ return app_ctx;
+}
+
/*
* Create a context for the channel on the tracer.
*
struct ust_app *app)
{
int ret = 0;
- struct lttng_ht_iter iter;
- struct lttng_ht_node_ulong *node;
struct ust_app_ctx *ua_ctx;
DBG2("UST app adding context to channel %s", ua_chan->name);
- lttng_ht_lookup(ua_chan->ctx, (void *)((unsigned long)uctx->ctx), &iter);
- node = lttng_ht_iter_get_node_ulong(&iter);
- if (node != NULL) {
+ ua_ctx = find_ust_app_context(ua_chan->ctx, uctx);
+ if (ua_ctx) {
ret = -EEXIST;
goto error;
}
}
lttng_ht_node_init_ulong(&ua_ctx->node, (unsigned long) ua_ctx->ctx.ctx);
- lttng_ht_add_unique_ulong(ua_chan->ctx, &ua_ctx->node);
+ lttng_ht_add_ulong(ua_chan->ctx, &ua_ctx->node);
cds_list_add_tail(&ua_ctx->list, &ua_chan->ctx_list);
ret = create_ust_channel_context(ua_chan, ua_ctx, app);
/* Create the buffer registry channel object. */
ret = create_buffer_reg_channel(reg_uid->registry, ua_chan, ®_chan);
if (ret < 0) {
+ ERR("Error creating the UST channel \"%s\" registry instance",
+ ua_chan->name);
goto error;
}
assert(reg_chan);
ret = do_consumer_create_channel(usess, ua_sess, ua_chan,
app->bits_per_long, reg_uid->registry->reg.ust);
if (ret < 0) {
+ ERR("Error creating UST channel \"%s\" on the consumer daemon",
+ ua_chan->name);
+
/*
* Let's remove the previously created buffer registry channel so
* it's not visible anymore in the session registry.
*/
ret = setup_buffer_reg_channel(reg_uid->registry, ua_chan, reg_chan);
if (ret < 0) {
+ ERR("Error setting up UST channel \"%s\"",
+ ua_chan->name);
goto error;
}
/* Send buffers to the application. */
ret = send_channel_uid_to_ust(reg_chan, app, ua_sess, ua_chan);
if (ret < 0) {
+ /*
+ * Don't report error to the console, since it may be
+ * caused by application concurrently exiting.
+ */
goto error;
}
/* Create and add a new channel registry to session. */
ret = ust_registry_channel_add(registry, ua_chan->key);
if (ret < 0) {
+ ERR("Error creating the UST channel \"%s\" registry instance",
+ ua_chan->name);
goto error;
}
ret = do_consumer_create_channel(usess, ua_sess, ua_chan,
app->bits_per_long, registry);
if (ret < 0) {
+ ERR("Error creating UST channel \"%s\" on the consumer daemon",
+ ua_chan->name);
goto error;
}
ret = send_channel_pid_to_ust(app, ua_sess, ua_chan);
if (ret < 0) {
+ /*
+ * Don't report error to the console, since it may be
+ * caused by application concurrently exiting.
+ */
goto error;
}
* Called with UST app session lock held and RCU read side lock.
*/
static int create_ust_app_metadata(struct ust_app_session *ua_sess,
- struct ust_app *app, struct consumer_output *consumer,
- struct ustctl_consumer_channel_attr *attr)
+ struct ust_app *app, struct consumer_output *consumer)
{
int ret = 0;
struct ust_app_channel *metadata;
goto error;
}
- if (!attr) {
- /* Set default attributes for metadata. */
- metadata->attr.overwrite = DEFAULT_CHANNEL_OVERWRITE;
- metadata->attr.subbuf_size = default_get_metadata_subbuf_size();
- metadata->attr.num_subbuf = DEFAULT_METADATA_SUBBUF_NUM;
- metadata->attr.switch_timer_interval = DEFAULT_METADATA_SWITCH_TIMER;
- metadata->attr.read_timer_interval = DEFAULT_METADATA_READ_TIMER;
- metadata->attr.output = LTTNG_UST_MMAP;
- metadata->attr.type = LTTNG_UST_CHAN_METADATA;
- } else {
- memcpy(&metadata->attr, attr, sizeof(metadata->attr));
- metadata->attr.output = LTTNG_UST_MMAP;
- metadata->attr.type = LTTNG_UST_CHAN_METADATA;
- }
+ memcpy(&metadata->attr, &ua_sess->metadata_attr, sizeof(metadata->attr));
/* Need one fd for the channel. */
ret = lttng_fd_get(LTTNG_FD_APPS, 1);
ret = ustctl_tracer_version(app->sock, &app->version);
if (ret < 0) {
if (ret != -LTTNG_UST_ERR_EXITING && ret != -EPIPE) {
- ERR("UST app %d verson failed with ret %d", app->sock, ret);
+ ERR("UST app %d version failed with ret %d", app->sock, ret);
} else {
- DBG3("UST app %d verion failed. Application is dead", app->sock);
+ DBG3("UST app %d version failed. Application is dead", app->sock);
}
}
{
struct ust_app *lta;
struct lttng_ht_node_ulong *node;
+ struct lttng_ht_iter ust_app_sock_iter;
struct lttng_ht_iter iter;
struct ust_app_session *ua_sess;
int ret;
rcu_read_lock();
/* Get the node reference for a call_rcu */
- lttng_ht_lookup(ust_app_ht_by_sock, (void *)((unsigned long) sock), &iter);
- node = lttng_ht_iter_get_node_ulong(&iter);
+ lttng_ht_lookup(ust_app_ht_by_sock, (void *)((unsigned long) sock), &ust_app_sock_iter);
+ node = lttng_ht_iter_get_node_ulong(&ust_app_sock_iter);
assert(node);
lta = caa_container_of(node, struct ust_app, sock_n);
DBG("PID %d unregistering with sock %d", lta->pid, sock);
- /* Remove application from PID hash table */
- ret = lttng_ht_del(ust_app_ht_by_sock, &iter);
- assert(!ret);
-
/*
- * Remove application from notify hash table. The thread handling the
- * notify socket could have deleted the node so ignore on error because
- * either way it's valid. The close of that socket is handled by the other
- * thread.
+ * Perform "push metadata" and flush all application streams
+ * before removing app from hash tables, ensuring proper
+ * behavior of data_pending check.
+ * Remove sessions so they are not visible during deletion.
*/
- iter.iter.node = <a->notify_sock_n.node;
- (void) lttng_ht_del(ust_app_ht_by_notify_sock, &iter);
-
- /*
- * Ignore return value since the node might have been removed before by an
- * add replace during app registration because the PID can be reassigned by
- * the OS.
- */
- iter.iter.node = <a->pid_n.node;
- ret = lttng_ht_del(ust_app_ht, &iter);
- if (ret) {
- DBG3("Unregister app by PID %d failed. This can happen on pid reuse",
- lta->pid);
- }
-
- /* Remove sessions so they are not visible during deletion.*/
cds_lfht_for_each_entry(lta->sessions->ht, &iter.iter, ua_sess,
node.node) {
struct ust_registry_session *registry;
continue;
}
+ (void) ust_app_flush_app_session(lta, ua_sess);
+
/*
* Add session to list for teardown. This is safe since at this point we
* are the only one using this list.
(void) close_metadata(registry, ua_sess->consumer);
}
}
-
cds_list_add(&ua_sess->teardown_node, <a->teardown_head);
+
pthread_mutex_unlock(&ua_sess->lock);
}
+ /* Remove application from PID hash table */
+ ret = lttng_ht_del(ust_app_ht_by_sock, &ust_app_sock_iter);
+ assert(!ret);
+
+ /*
+ * Remove application from notify hash table. The thread handling the
+ * notify socket could have deleted the node so ignore on error because
+ * either way it's valid. The close of that socket is handled by the other
+ * thread.
+ */
+ iter.iter.node = <a->notify_sock_n.node;
+ (void) lttng_ht_del(ust_app_ht_by_notify_sock, &iter);
+
+ /*
+ * Ignore return value since the node might have been removed before by an
+ * add replace during app registration because the PID can be reassigned by
+ * the OS.
+ */
+ iter.iter.node = <a->pid_n.node;
+ ret = lttng_ht_del(ust_app_ht, &iter);
+ if (ret) {
+ DBG3("Unregister app by PID %d failed. This can happen on pid reuse",
+ lta->pid);
+ }
+
/* Free memory */
call_rcu(<a->pid_n.head, delete_ust_app_rcu);
rcu_read_lock();
- cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
- ret = lttng_ht_del(ust_app_ht, &iter);
- assert(!ret);
- call_rcu(&app->pid_n.head, delete_ust_app_rcu);
+ if (ust_app_ht) {
+ cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+ ret = lttng_ht_del(ust_app_ht, &iter);
+ assert(!ret);
+ call_rcu(&app->pid_n.head, delete_ust_app_rcu);
+ }
}
/* Cleanup socket hash table */
- cds_lfht_for_each_entry(ust_app_ht_by_sock->ht, &iter.iter, app,
- sock_n.node) {
- ret = lttng_ht_del(ust_app_ht_by_sock, &iter);
- assert(!ret);
+ if (ust_app_ht_by_sock) {
+ cds_lfht_for_each_entry(ust_app_ht_by_sock->ht, &iter.iter, app,
+ sock_n.node) {
+ ret = lttng_ht_del(ust_app_ht_by_sock, &iter);
+ assert(!ret);
+ }
}
/* Cleanup notify socket hash table */
- cds_lfht_for_each_entry(ust_app_ht_by_notify_sock->ht, &iter.iter, app,
- notify_sock_n.node) {
- ret = lttng_ht_del(ust_app_ht_by_notify_sock, &iter);
- assert(!ret);
+ if (ust_app_ht_by_notify_sock) {
+ cds_lfht_for_each_entry(ust_app_ht_by_notify_sock->ht, &iter.iter, app,
+ notify_sock_n.node) {
+ ret = lttng_ht_del(ust_app_ht_by_notify_sock, &iter);
+ assert(!ret);
+ }
}
rcu_read_unlock();
/* Destroy is done only when the ht is empty */
- ht_cleanup_push(ust_app_ht);
- ht_cleanup_push(ust_app_ht_by_sock);
- ht_cleanup_push(ust_app_ht_by_notify_sock);
+ if (ust_app_ht) {
+ ht_cleanup_push(ust_app_ht);
+ }
+ if (ust_app_ht_by_sock) {
+ ht_cleanup_push(ust_app_ht_by_sock);
+ }
+ if (ust_app_ht_by_notify_sock) {
+ ht_cleanup_push(ust_app_ht_by_notify_sock);
+ }
}
/*
* Init UST app hash table.
*/
-void ust_app_ht_alloc(void)
+int ust_app_ht_alloc(void)
{
ust_app_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+ if (!ust_app_ht) {
+ return -1;
+ }
ust_app_ht_by_sock = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+ if (!ust_app_ht_by_sock) {
+ return -1;
+ }
ust_app_ht_by_notify_sock = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+ if (!ust_app_ht_by_notify_sock) {
+ return -1;
+ }
+ return 0;
}
/*
pthread_mutex_lock(&ua_sess->lock);
if (!strncmp(uchan->name, DEFAULT_METADATA_NAME,
sizeof(uchan->name))) {
- struct ustctl_consumer_channel_attr attr;
- copy_channel_attr_to_ustctl(&attr, &uchan->attr);
- ret = create_ust_app_metadata(ua_sess, app, usess->consumer,
- &attr);
+ copy_channel_attr_to_ustctl(&ua_sess->metadata_attr, &uchan->attr);
+ ret = 0;
} else {
/* Create channel onto application. We don't need the chan ref. */
ret = create_ust_app_channel(ua_sess, uchan, app,
* Create the metadata for the application. This returns gracefully if a
* metadata was already set for the session.
*/
- ret = create_ust_app_metadata(ua_sess, app, usess->consumer, NULL);
+ ret = create_ust_app_metadata(ua_sess, app, usess->consumer);
if (ret < 0) {
goto error_unlock;
}
return -1;
}
-/*
- * Flush buffers for a specific UST session and app.
- */
static
-int ust_app_flush_trace(struct ltt_ust_session *usess, struct ust_app *app)
+int ust_app_flush_app_session(struct ust_app *app,
+ struct ust_app_session *ua_sess)
{
- int ret = 0;
+ int ret, retval = 0;
struct lttng_ht_iter iter;
- struct ust_app_session *ua_sess;
struct ust_app_channel *ua_chan;
+ struct consumer_socket *socket;
- DBG("Flushing buffers for ust app pid %d", app->pid);
+ DBG("Flushing app session buffers for ust app pid %d", app->pid);
rcu_read_lock();
if (!app->compatible) {
- goto end_no_session;
- }
-
- ua_sess = lookup_session_by_app(usess, app);
- if (ua_sess == NULL) {
- goto end_no_session;
+ goto end_not_compatible;
}
pthread_mutex_lock(&ua_sess->lock);
health_code_update();
/* Flushing buffers */
+ socket = consumer_find_socket_by_bitness(app->bits_per_long,
+ ua_sess->consumer);
cds_lfht_for_each_entry(ua_sess->channels->ht, &iter.iter, ua_chan,
node.node) {
health_code_update();
assert(ua_chan->is_sent);
- ret = ustctl_sock_flush_buffer(app->sock, ua_chan->obj);
- if (ret < 0) {
- if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
- ERR("UST app PID %d channel %s flush failed with ret %d",
- app->pid, ua_chan->name, ret);
- } else {
- DBG3("UST app failed to flush %s. Application is dead.",
- ua_chan->name);
- /*
- * This is normal behavior, an application can die during the
- * creation process. Don't report an error so the execution can
- * continue normally.
- */
- }
- /* Continuing flushing all buffers */
+ ret = consumer_flush_channel(socket, ua_chan->key);
+ if (ret) {
+ ERR("Error flushing consumer channel");
+ retval = -1;
continue;
}
}
health_code_update();
pthread_mutex_unlock(&ua_sess->lock);
+end_not_compatible:
+ rcu_read_unlock();
+ health_code_update();
+ return retval;
+}
+
+/*
+ * Flush buffers for a specific UST session and app.
+ */
+static
+int ust_app_flush_session(struct ust_app *app, struct ltt_ust_session *usess)
+
+{
+ int ret;
+ struct ust_app_session *ua_sess;
+
+ DBG("Flushing session buffers for ust app pid %d", app->pid);
+
+ rcu_read_lock();
+
+ ua_sess = lookup_session_by_app(usess, app);
+ if (ua_sess == NULL) {
+ ret = -1;
+ goto end_no_session;
+ }
+ ret = ust_app_flush_app_session(app, ua_sess);
+
end_no_session:
rcu_read_unlock();
health_code_update();
- return 0;
+ return ret;
}
/*
}
case LTTNG_BUFFER_PER_PID:
cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
- ret = ust_app_flush_trace(usess, app);
+ ret = ust_app_flush_session(app, usess);
if (ret < 0) {
/* Continue to next apps even on error */
continue;
*/
cds_lfht_for_each_entry(ua_sess->channels->ht, &iter.iter, ua_chan,
node.node) {
- /*
- * For a metadata channel, handle it differently.
- */
- if (!strncmp(ua_chan->name, DEFAULT_METADATA_NAME,
- sizeof(ua_chan->name))) {
- ret = create_ust_app_metadata(ua_sess, app, usess->consumer,
- &ua_chan->attr);
- if (ret < 0) {
- goto error_unlock;
- }
- /* Remove it from the hash table and continue!. */
- ret = lttng_ht_del(ua_sess->channels, &iter);
- assert(!ret);
- delete_ust_app_channel(-1, ua_chan, app);
- continue;
- } else {
- ret = do_create_channel(app, usess, ua_sess, ua_chan);
- if (ret < 0) {
- /*
- * Stop everything. On error, the application failed, no more
- * file descriptor are available or ENOMEM so stopping here is
- * the only thing we can do for now.
- */
- goto error_unlock;
- }
+ ret = do_create_channel(app, usess, ua_sess, ua_chan);
+ if (ret < 0) {
+ /*
+ * Stop everything. On error, the application failed, no more
+ * file descriptor are available or ENOMEM so stopping here is
+ * the only thing we can do for now.
+ */
+ goto error_unlock;
}
/*
pthread_mutex_unlock(&ua_sess->lock);
- if (usess->start_trace) {
+ if (usess->active) {
ret = ust_app_start_trace(usess, app);
if (ret < 0) {
goto error;
* Return 0 on success or else a negative value.
*/
int ust_app_snapshot_record(struct ltt_ust_session *usess,
- struct snapshot_output *output, int wait, unsigned int nb_streams)
+ struct snapshot_output *output, int wait, uint64_t max_stream_size)
{
int ret = 0;
unsigned int snapshot_done = 0;
struct lttng_ht_iter iter;
struct ust_app *app;
char pathname[PATH_MAX];
- uint64_t max_stream_size = 0;
assert(usess);
assert(output);
rcu_read_lock();
- /*
- * Compute the maximum size of a single stream if a max size is asked by
- * the caller.
- */
- if (output->max_size > 0 && nb_streams > 0) {
- max_stream_size = output->max_size / nb_streams;
- }
-
switch (usess->buffer_type) {
case LTTNG_BUFFER_PER_UID:
{
/* Add the UST default trace dir to path. */
cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter,
reg_chan, node.node) {
-
- /*
- * Make sure the maximum stream size is not lower than the
- * subbuffer size or else it's an error since we won't be able to
- * snapshot anything.
- */
- if (max_stream_size &&
- reg_chan->subbuf_size > max_stream_size) {
- ret = -EINVAL;
- DBG3("UST app snapshot record maximum stream size %" PRIu64
- " is smaller than subbuffer size of %zu",
- max_stream_size, reg_chan->subbuf_size);
- goto error;
- }
- ret = consumer_snapshot_channel(socket, reg_chan->consumer_key, output, 0,
- usess->uid, usess->gid, pathname, wait,
+ ret = consumer_snapshot_channel(socket, reg_chan->consumer_key,
+ output, 0, usess->uid, usess->gid, pathname, wait,
max_stream_size);
if (ret < 0) {
goto error;
}
}
- ret = consumer_snapshot_channel(socket, reg->registry->reg.ust->metadata_key, output,
- 1, usess->uid, usess->gid, pathname, wait,
- max_stream_size);
+ ret = consumer_snapshot_channel(socket,
+ reg->registry->reg.ust->metadata_key, output, 1,
+ usess->uid, usess->gid, pathname, wait, max_stream_size);
if (ret < 0) {
goto error;
}
cds_lfht_for_each_entry(ua_sess->channels->ht, &chan_iter.iter,
ua_chan, node.node) {
- /*
- * Make sure the maximum stream size is not lower than the
- * subbuffer size or else it's an error since we won't be able to
- * snapshot anything.
- */
- if (max_stream_size &&
- ua_chan->attr.subbuf_size > max_stream_size) {
- ret = -EINVAL;
- DBG3("UST app snapshot record maximum stream size %" PRIu64
- " is smaller than subbuffer size of %" PRIu64,
- max_stream_size, ua_chan->attr.subbuf_size);
- goto error;
- }
-
- ret = consumer_snapshot_channel(socket, ua_chan->key, output, 0,
- ua_sess->euid, ua_sess->egid, pathname, wait,
+ ret = consumer_snapshot_channel(socket, ua_chan->key, output,
+ 0, ua_sess->euid, ua_sess->egid, pathname, wait,
max_stream_size);
if (ret < 0) {
goto error;
cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) {
struct buffer_reg_channel *reg_chan;
+ rcu_read_lock();
cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter,
reg_chan, node.node) {
ret += reg_chan->stream_count;
}
+ rcu_read_unlock();
}
break;
}