From a1ae2ea59428174575b7328b1062a6248d636b72 Mon Sep 17 00:00:00 2001 From: Julien Desfossez Date: Mon, 11 Dec 2017 14:03:52 -0500 Subject: [PATCH] Command to make a directory on the consumer or relay MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This new command allows the session daemon to create a directory in the session folder (local or remote), this gives more control over the directory creation which is currently lazy (when the first stream is created). Signed-off-by: Julien Desfossez Signed-off-by: Jérémie Galarneau --- src/bin/lttng-relayd/main.c | 115 +++++++++++++++++++ src/bin/lttng-sessiond/cmd.c | 107 +++++++++++++++++ src/bin/lttng-sessiond/consumer.c | 45 ++++++++ src/bin/lttng-sessiond/consumer.h | 4 + src/bin/lttng-sessiond/utils.c | 19 +++ src/bin/lttng-sessiond/utils.h | 2 + src/common/consumer/consumer.c | 48 ++++++++ src/common/consumer/consumer.h | 3 + src/common/kernel-consumer/kernel-consumer.c | 23 ++++ src/common/relayd/relayd.c | 58 ++++++++++ src/common/relayd/relayd.h | 1 + src/common/sessiond-comm/relayd.h | 6 + src/common/sessiond-comm/sessiond-comm.h | 9 ++ src/common/ust-consumer/ust-consumer.c | 23 ++++ 14 files changed, 463 insertions(+) diff --git a/src/bin/lttng-relayd/main.c b/src/bin/lttng-relayd/main.c index cd4f058bf..c4c609a4f 100644 --- a/src/bin/lttng-relayd/main.c +++ b/src/bin/lttng-relayd/main.c @@ -2122,6 +2122,118 @@ end_no_session: return ret; } +/* + * relay_mkdir: Create a folder on the disk. + */ +static int relay_mkdir(struct lttcomm_relayd_hdr *recv_hdr, + struct relay_connection *conn) +{ + int ret; + ssize_t network_ret; + struct relay_session *session = conn->session; + struct lttcomm_relayd_mkdir path_info_header; + struct lttcomm_relayd_mkdir *path_info = NULL; + struct lttcomm_relayd_generic_reply reply; + char *path = NULL; + + if (!session || !conn->version_check_done) { + ERR("Trying to rename before version check"); + ret = -1; + goto end_no_session; + } + + if (session->major == 2 && session->minor < 11) { + /* + * This client is not supposed to use this command since + * it predates its introduction. + */ + ERR("relay_mkdir command is unsupported before LTTng 2.11"); + ret = -1; + goto end_no_session; + } + + network_ret = conn->sock->ops->recvmsg(conn->sock, &path_info_header, + sizeof(path_info_header), 0); + if (network_ret < (ssize_t) sizeof(path_info_header)) { + if (network_ret == 0) { + /* Orderly shutdown. Not necessary to print an error. */ + DBG("Socket %d did an orderly shutdown", conn->sock->fd); + } else { + ERR("Reception of mkdir command argument length failed with ret = %zi, expected %zu", + network_ret, sizeof(path_info_header)); + } + ret = -1; + goto end_no_session; + } + + path_info_header.length = be32toh(path_info_header.length); + + /* Ensure that it fits in local path length. */ + if (path_info_header.length >= LTTNG_PATH_MAX) { + ret = -ENAMETOOLONG; + ERR("Path name argument of mkdir command (%" PRIu32 " bytes) exceeds the maximal length allowed (%d bytes)", + path_info_header.length, LTTNG_PATH_MAX); + goto end; + } + + path_info = zmalloc(sizeof(path_info_header) + path_info_header.length); + if (!path_info) { + PERROR("zmalloc of mkdir command path"); + ret = -1; + goto end; + } + + network_ret = conn->sock->ops->recvmsg(conn->sock, path_info->path, + path_info_header.length, 0); + if (network_ret < (ssize_t) path_info_header.length) { + if (network_ret == 0) { + /* Orderly shutdown. Not necessary to print an error. */ + DBG("Socket %d did an orderly shutdown", conn->sock->fd); + } else { + ERR("Reception of mkdir path argument failed with ret = %zi, expected %" PRIu32, + network_ret, path_info_header.length); + } + ret = -1; + goto end_no_session; + } + + path = create_output_path(path_info->path); + if (!path) { + ERR("Failed to create output path"); + ret = -1; + goto end; + } + + ret = utils_mkdir_recursive(path, S_IRWXU | S_IRWXG, -1, -1); + if (ret < 0) { + ERR("relay creating output directory"); + goto end; + } + + ret = 0; + +end: + memset(&reply, 0, sizeof(reply)); + if (ret < 0) { + reply.ret_code = htobe32(LTTNG_ERR_UNK); + } else { + reply.ret_code = htobe32(LTTNG_OK); + } + network_ret = conn->sock->ops->sendmsg(conn->sock, &reply, + sizeof(struct lttcomm_relayd_generic_reply), 0); + if (network_ret < (ssize_t) sizeof(struct lttcomm_relayd_generic_reply)) { + ERR("Failed to send mkdir command status code with ret = %zi, expected %zu", + network_ret, + sizeof(struct lttcomm_relayd_generic_reply)); + ret = -1; + } + +end_no_session: + free(path); + free(path_info); + return ret; +} + /* * Process the commands received on the control socket */ @@ -2170,6 +2282,9 @@ static int relay_process_control(struct lttcomm_relayd_hdr *recv_hdr, case RELAYD_RESET_METADATA: ret = relay_reset_metadata(recv_hdr, conn); break; + case RELAYD_MKDIR: + ret = relay_mkdir(recv_hdr, conn); + break; case RELAYD_UPDATE_SYNC_INFO: default: ERR("Received unknown command (%u)", be32toh(recv_hdr->cmd)); diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index 803a88090..27acbada0 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -2373,6 +2373,113 @@ error: return -ret; } +static +int domain_mkdir(const struct consumer_output *output, + const struct ltt_session *session, + uid_t uid, gid_t gid) +{ + struct consumer_socket *socket; + struct lttng_ht_iter iter; + int ret; + char *path = NULL; + + if (!output || !output->socks) { + ERR("No consumer output found"); + ret = -1; + goto end; + } + + path = zmalloc(LTTNG_PATH_MAX * sizeof(char)); + if (!path) { + ERR("Cannot allocate mkdir path"); + ret = -1; + goto end; + } + + ret = snprintf(path, LTTNG_PATH_MAX, "%s%s%s", + session_get_base_path(session), + output->chunk_path, output->subdir); + if (ret < 0 || ret >= LTTNG_PATH_MAX) { + ERR("Format path"); + ret = -1; + goto end; + } + + DBG("Domain mkdir %s for session %" PRIu64, path, session->id); + rcu_read_lock(); + /* + * We have to iterate to find a socket, but we only need to send the + * rename command to one consumer, so we break after the first one. + */ + cds_lfht_for_each_entry(output->socks->ht, &iter.iter, socket, node.node) { + pthread_mutex_lock(socket->lock); + ret = consumer_mkdir(socket, session->id, output, path, uid, gid); + pthread_mutex_unlock(socket->lock); + if (ret) { + ERR("Consumer mkdir"); + ret = -1; + goto end_unlock; + } + break; + } + + ret = 0; + +end_unlock: + rcu_read_unlock(); +end: + free(path); + return ret; +} + +static +int session_mkdir(const struct ltt_session *session) +{ + int ret; + struct consumer_output *output; + uid_t uid; + gid_t gid; + + /* + * Unsupported feature in lttng-relayd before 2.11, not an error since it + * is only needed for session rotation and the user will get an error + * on rotate. + */ + if (session->consumer->type == CONSUMER_DST_NET && + session->consumer->relay_major_version == 2 && + session->consumer->relay_minor_version < 11) { + ret = 0; + goto end; + } + + if (session->kernel_session) { + output = session->kernel_session->consumer; + uid = session->kernel_session->uid; + gid = session->kernel_session->gid; + ret = domain_mkdir(output, session, uid, gid); + if (ret) { + ERR("Mkdir kernel"); + goto end; + } + } + + if (session->ust_session) { + output = session->ust_session->consumer; + uid = session->ust_session->uid; + gid = session->ust_session->gid; + ret = domain_mkdir(output, session, uid, gid); + if (ret) { + ERR("Mkdir UST"); + goto end; + } + } + + ret = 0; + +end: + return ret; +} + /* * Command LTTNG_START_TRACE processed by the client thread. * diff --git a/src/bin/lttng-sessiond/consumer.c b/src/bin/lttng-sessiond/consumer.c index 5f551e31d..31f704345 100644 --- a/src/bin/lttng-sessiond/consumer.c +++ b/src/bin/lttng-sessiond/consumer.c @@ -1579,3 +1579,48 @@ end: rcu_read_unlock(); return ret; } + +/* + * Ask the consumer to create a directory. + * + * Called with the consumer socket lock held. + */ +int consumer_mkdir(struct consumer_socket *socket, uint64_t session_id, + const struct consumer_output *output, const char *path, + uid_t uid, gid_t gid) +{ + int ret; + struct lttcomm_consumer_msg msg; + + assert(socket); + + DBG("Consumer mkdir %s in session %" PRIu64, path, session_id); + + memset(&msg, 0, sizeof(msg)); + msg.cmd_type = LTTNG_CONSUMER_MKDIR; + msg.u.mkdir.session_id = session_id; + msg.u.mkdir.uid = uid; + msg.u.mkdir.gid = gid; + ret = snprintf(msg.u.mkdir.path, sizeof(msg.u.mkdir.path), "%s", path); + if (ret < 0 || ret >= sizeof(msg.u.mkdir.path)) { + ERR("Format path"); + ret = -1; + goto error; + } + + if (output->type == CONSUMER_DST_NET) { + msg.u.mkdir.relayd_id = output->net_seq_index; + } else { + msg.u.mkdir.relayd_id = (uint64_t) -1ULL; + } + + health_code_update(); + ret = consumer_send_msg(socket, &msg); + if (ret < 0) { + goto error; + } + +error: + health_code_update(); + return ret; +} diff --git a/src/bin/lttng-sessiond/consumer.h b/src/bin/lttng-sessiond/consumer.h index 24c7a273c..1fe7c89b5 100644 --- a/src/bin/lttng-sessiond/consumer.h +++ b/src/bin/lttng-sessiond/consumer.h @@ -315,4 +315,8 @@ int consumer_snapshot_channel(struct consumer_socket *socket, uint64_t key, struct snapshot_output *output, int metadata, uid_t uid, gid_t gid, const char *session_path, int wait, uint64_t nb_packets_per_stream); +int consumer_mkdir(struct consumer_socket *socket, uint64_t session_id, + const struct consumer_output *output, const char *path, + uid_t uid, gid_t gid); + #endif /* _CONSUMER_H */ diff --git a/src/bin/lttng-sessiond/utils.c b/src/bin/lttng-sessiond/utils.c index f77a21ddb..99ec7772b 100644 --- a/src/bin/lttng-sessiond/utils.c +++ b/src/bin/lttng-sessiond/utils.c @@ -95,3 +95,22 @@ int loglevels_match(int a_loglevel_type, int a_loglevel_value, return match; } + +const char *session_get_base_path(const struct ltt_session *session) +{ + struct consumer_output *consumer; + + if (session->kernel_session) { + consumer = session->kernel_session->consumer; + } else if (session->ust_session) { + consumer = session->ust_session->consumer; + } else { + abort(); + } + + if (session->net_handle > 0) { + return consumer->dst.net.base_dir; + } else { + return consumer->dst.session_root_path; + } +} diff --git a/src/bin/lttng-sessiond/utils.h b/src/bin/lttng-sessiond/utils.h index 2be72c20f..30c80725f 100644 --- a/src/bin/lttng-sessiond/utils.h +++ b/src/bin/lttng-sessiond/utils.h @@ -19,11 +19,13 @@ #define _LTT_UTILS_H struct lttng_ht; +struct ltt_session; const char *get_home_dir(void); int notify_thread_pipe(int wpipe); void ht_cleanup_push(struct lttng_ht *ht); int loglevels_match(int a_loglevel_type, int a_loglevel_value, int b_loglevel_type, int b_loglevel_value, int loglevel_all_type); +const char *session_get_base_path(const struct ltt_session *session); #endif /* _LTT_UTILS_H */ diff --git a/src/common/consumer/consumer.c b/src/common/consumer/consumer.c index 2d6604808..b449c1637 100644 --- a/src/common/consumer/consumer.c +++ b/src/common/consumer/consumer.c @@ -3783,3 +3783,51 @@ unsigned long consumer_get_consume_start_pos(unsigned long consumed_pos, } return start_pos; } + +static +int mkdir_local(const char *path, uid_t uid, gid_t gid) +{ + int ret; + + ret = utils_mkdir_recursive(path, S_IRWXU | S_IRWXG, uid, gid); + if (ret < 0) { + /* utils_mkdir_recursive logs an error. */ + goto end; + } + + ret = 0; +end: + return ret; +} + +static +int mkdir_relay(const char *path, uint64_t relayd_id) +{ + int ret; + struct consumer_relayd_sock_pair *relayd; + + relayd = consumer_find_relayd(relayd_id); + if (!relayd) { + ERR("Failed to find relayd"); + ret = -1; + goto end; + } + + pthread_mutex_lock(&relayd->ctrl_sock_mutex); + ret = relayd_mkdir(&relayd->control_sock, path); + pthread_mutex_unlock(&relayd->ctrl_sock_mutex); + +end: + return ret; + +} + +int lttng_consumer_mkdir(const char *path, uid_t uid, gid_t gid, + uint64_t relayd_id) +{ + if (relayd_id != -1ULL) { + return mkdir_relay(path, relayd_id); + } else { + return mkdir_local(path, uid, gid); + } +} diff --git a/src/common/consumer/consumer.h b/src/common/consumer/consumer.h index eb9b8c463..f5fbf3262 100644 --- a/src/common/consumer/consumer.h +++ b/src/common/consumer/consumer.h @@ -62,6 +62,7 @@ enum lttng_consumer_command { LTTNG_CONSUMER_LOST_PACKETS, LTTNG_CONSUMER_CLEAR_QUIESCENT_CHANNEL, LTTNG_CONSUMER_SET_CHANNEL_MONITOR_PIPE, + LTTNG_CONSUMER_MKDIR, }; /* State of each fd in consumer */ @@ -759,5 +760,7 @@ void consumer_del_stream_for_data(struct lttng_consumer_stream *stream); void consumer_add_metadata_stream(struct lttng_consumer_stream *stream); void consumer_del_stream_for_metadata(struct lttng_consumer_stream *stream); int consumer_create_index_file(struct lttng_consumer_stream *stream); +int lttng_consumer_mkdir(const char *path, uid_t uid, gid_t gid, + uint64_t relayd_id); #endif /* LIB_CONSUMER_H */ diff --git a/src/common/kernel-consumer/kernel-consumer.c b/src/common/kernel-consumer/kernel-consumer.c index 02d042733..561902466 100644 --- a/src/common/kernel-consumer/kernel-consumer.c +++ b/src/common/kernel-consumer/kernel-consumer.c @@ -1072,6 +1072,29 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, } break; } + case LTTNG_CONSUMER_MKDIR: + { + DBG("Consumer mkdir %s in session %" PRIu64, + msg.u.mkdir.path, + msg.u.mkdir.session_id); + ret = lttng_consumer_mkdir(msg.u.mkdir.path, + msg.u.mkdir.uid, + msg.u.mkdir.gid, + msg.u.mkdir.relayd_id); + if (ret < 0) { + ERR("consumer mkdir failed"); + ret_code = LTTCOMM_CONSUMERD_CHAN_NOT_FOUND; + } + + health_code_update(); + + ret = consumer_send_status_msg(sock, ret_code); + if (ret < 0) { + /* Somehow, the session daemon is not responding anymore. */ + goto end_nosignal; + } + break; + } default: goto end_nosignal; } diff --git a/src/common/relayd/relayd.c b/src/common/relayd/relayd.c index 4cb1c1fd3..c46290d1a 100644 --- a/src/common/relayd/relayd.c +++ b/src/common/relayd/relayd.c @@ -941,3 +941,61 @@ int relayd_reset_metadata(struct lttcomm_relayd_sock *rsock, error: return ret; } + +int relayd_mkdir(struct lttcomm_relayd_sock *rsock, const char *path) +{ + int ret; + struct lttcomm_relayd_mkdir *msg; + struct lttcomm_relayd_generic_reply reply; + size_t len; + + /* Code flow error. Safety net. */ + assert(rsock); + + DBG("Relayd mkdir path %s", path); + + len = strlen(path) + 1; + msg = zmalloc(sizeof(msg->length) + len); + if (!msg) { + PERROR("Alloc mkdir msg"); + ret = -1; + goto error; + } + msg->length = htobe32((uint32_t) len); + + if (lttng_strncpy(msg->path, path, len)) { + ret = -1; + goto error; + } + + /* Send command */ + ret = send_command(rsock, RELAYD_MKDIR, (void *) msg, + sizeof(msg->length) + len, 0); + if (ret < 0) { + goto error; + } + + /* Receive response */ + ret = recv_reply(rsock, (void *) &reply, sizeof(reply)); + if (ret < 0) { + goto error; + } + + reply.ret_code = be32toh(reply.ret_code); + + /* Return session id or negative ret code. */ + if (reply.ret_code != LTTNG_OK) { + ret = -1; + ERR("Relayd mkdir replied error %d", reply.ret_code); + } else { + /* Success */ + ret = 0; + } + + DBG("Relayd mkdir completed successfully"); + +error: + free(msg); + return ret; + +} diff --git a/src/common/relayd/relayd.h b/src/common/relayd/relayd.h index f090a0db6..fd308d500 100644 --- a/src/common/relayd/relayd.h +++ b/src/common/relayd/relayd.h @@ -51,5 +51,6 @@ int relayd_send_index(struct lttcomm_relayd_sock *rsock, uint64_t net_seq_num); int relayd_reset_metadata(struct lttcomm_relayd_sock *rsock, uint64_t stream_id, uint64_t version); +int relayd_mkdir(struct lttcomm_relayd_sock *rsock, const char *path); #endif /* _RELAYD_H */ diff --git a/src/common/sessiond-comm/relayd.h b/src/common/sessiond-comm/relayd.h index 52ca1caa1..74d5b1176 100644 --- a/src/common/sessiond-comm/relayd.h +++ b/src/common/sessiond-comm/relayd.h @@ -195,4 +195,10 @@ struct lttcomm_relayd_reset_metadata { uint64_t version; } LTTNG_PACKED; +struct lttcomm_relayd_mkdir { + /* Includes trailing NULL */ + uint32_t length; + char path[]; +} LTTNG_PACKED; + #endif /* _RELAYD_COMM */ diff --git a/src/common/sessiond-comm/sessiond-comm.h b/src/common/sessiond-comm/sessiond-comm.h index cd5ee0622..5cd926e6f 100644 --- a/src/common/sessiond-comm/sessiond-comm.h +++ b/src/common/sessiond-comm/sessiond-comm.h @@ -123,6 +123,8 @@ enum lttcomm_relayd_command { RELAYD_STREAMS_SENT = 16, /* Ask the relay to reset the metadata trace file (2.8+) */ RELAYD_RESET_METADATA = 17, + /* Create a folder on the relayd FS (2.11+) */ + RELAYD_MKDIR = 21, }; /* @@ -534,6 +536,13 @@ struct lttcomm_consumer_msg { struct { uint64_t session_id; } LTTNG_PACKED regenerate_metadata; + struct { + char path[LTTNG_PATH_MAX]; + uint64_t relayd_id; /* Relayd id if apply. */ + uint64_t session_id; + uint32_t uid; + uint32_t gid; + } LTTNG_PACKED mkdir; } u; } LTTNG_PACKED; diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c index 3350403d9..d0488dbc8 100644 --- a/src/common/ust-consumer/ust-consumer.c +++ b/src/common/ust-consumer/ust-consumer.c @@ -1917,6 +1917,29 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, } goto end_msg_sessiond; } + case LTTNG_CONSUMER_MKDIR: + { + DBG("Consumer mkdir %s in session %" PRIu64, + msg.u.mkdir.path, + msg.u.mkdir.session_id); + ret = lttng_consumer_mkdir(msg.u.mkdir.path, + msg.u.mkdir.uid, + msg.u.mkdir.gid, + msg.u.mkdir.relayd_id); + if (ret < 0) { + ERR("consumer mkdir failed"); + ret_code = LTTCOMM_CONSUMERD_CHAN_NOT_FOUND; + } + + health_code_update(); + + ret = consumer_send_status_msg(sock, ret_code); + if (ret < 0) { + /* Somehow, the session daemon is not responding anymore. */ + goto end_nosignal; + } + break; + } default: break; } -- 2.34.1