+ if (session->ust_session) {
+ struct ltt_ust_session *usess = session->ust_session;
+
+ tot_size += ust_app_get_size_one_more_packet_per_stream(usess,
+ cur_nr_packets);
+ }
+
+ return tot_size;
+}
+
+/*
+ * Calculate the number of packets we can grab from each stream that
+ * fits within the overall snapshot max size.
+ *
+ * Returns -1 on error, 0 means infinite number of packets, else > 0 is
+ * the number of packets per stream.
+ *
+ * TODO: this approach is not perfect: we consider the worse case
+ * (packet filling the sub-buffers) as an upper bound, but we could do
+ * better if we do this calculation while we actually grab the packet
+ * content: we would know how much padding we don't actually store into
+ * the file.
+ *
+ * This algorithm is currently bounded by the number of packets per
+ * stream.
+ *
+ * Since we call this algorithm before actually grabbing the data, it's
+ * an approximation: for instance, applications could appear/disappear
+ * in between this call and actually grabbing data.
+ */
+static
+int64_t get_session_nb_packets_per_stream(struct ltt_session *session, uint64_t max_size)
+{
+ int64_t size_left;
+ uint64_t cur_nb_packets = 0;
+
+ if (!max_size) {
+ return 0; /* Infinite */
+ }
+
+ size_left = max_size;
+ for (;;) {
+ uint64_t one_more_packet_tot_size;
+
+ one_more_packet_tot_size = get_session_size_one_more_packet_per_stream(session,
+ cur_nb_packets);
+ if (!one_more_packet_tot_size) {
+ /* We are already grabbing all packets. */
+ break;
+ }
+ size_left -= one_more_packet_tot_size;
+ if (size_left < 0) {
+ break;
+ }
+ cur_nb_packets++;
+ }
+ if (!cur_nb_packets) {
+ /* Not enough room to grab one packet of each stream, error. */
+ return -1;
+ }
+ return cur_nb_packets;
+}
+
+/*
+ * Command LTTNG_SNAPSHOT_RECORD from lib lttng ctl.
+ *
+ * The wait parameter is ignored so this call always wait for the snapshot to
+ * complete before returning.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR code.
+ */
+int cmd_snapshot_record(struct ltt_session *session,
+ struct lttng_snapshot_output *output, int wait)
+{
+ int ret = LTTNG_OK;
+ unsigned int use_tmp_output = 0;
+ struct snapshot_output tmp_output;
+ unsigned int snapshot_success = 0;
+
+ assert(session);
+ assert(output);
+
+ DBG("Cmd snapshot record for session %s", session->name);
+
+ /*
+ * Permission denied to create an output if the session is not
+ * set in no output mode.
+ */
+ if (session->output_traces) {
+ ret = LTTNG_ERR_EPERM;
+ goto error;
+ }
+
+ /* The session needs to be started at least once. */
+ if (!session->has_been_started) {
+ ret = LTTNG_ERR_START_SESSION_ONCE;
+ goto error;
+ }
+
+ /* Use temporary output for the session. */
+ if (*output->ctrl_url != '\0') {
+ ret = snapshot_output_init(output->max_size, output->name,
+ output->ctrl_url, output->data_url, session->consumer,
+ &tmp_output, NULL);
+ if (ret < 0) {
+ if (ret == -ENOMEM) {
+ ret = LTTNG_ERR_NOMEM;
+ } else {
+ ret = LTTNG_ERR_INVALID;
+ }