Command to make a directory on the consumer or relay
authorJulien Desfossez <jdesfossez@efficios.com>
Mon, 11 Dec 2017 19:03:52 +0000 (14:03 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 5 Mar 2018 21:25:39 +0000 (16:25 -0500)
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 <jdesfossez@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
14 files changed:
src/bin/lttng-relayd/main.c
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/consumer.c
src/bin/lttng-sessiond/consumer.h
src/bin/lttng-sessiond/utils.c
src/bin/lttng-sessiond/utils.h
src/common/consumer/consumer.c
src/common/consumer/consumer.h
src/common/kernel-consumer/kernel-consumer.c
src/common/relayd/relayd.c
src/common/relayd/relayd.h
src/common/sessiond-comm/relayd.h
src/common/sessiond-comm/sessiond-comm.h
src/common/ust-consumer/ust-consumer.c

index cd4f058bf0243df63dd78e573e97fca202b751d3..c4c609a4f2ecf0c5d20d3960d3395e44fbdf7e51 100644 (file)
@@ -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));
index 803a88090c95d28a733f7e04614238c830980055..27acbada09627970ee2c6a46ebe301bacf4e2ae9 100644 (file)
@@ -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.
  *
index 5f551e31dd5a05d6283e0aca2cbe01ca660096b4..31f70434534cf56b3fd173242c1e5f3831e8c367 100644 (file)
@@ -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;
+}
index 24c7a273c6dab0246b128d16456b4e1e41d76868..1fe7c89b5554a250981a43907ed77bc5fbcf9e95 100644 (file)
@@ -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 */
index f77a21ddb153a5ebdd88815af3e9850e37736151..99ec7772bfcf849da5730c5aeca3e7924e870261 100644 (file)
@@ -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;
+       }
+}
index 2be72c20fc999e646a371b8c15fa3cc83ee51bb9..30c80725f1f7b5d8bd403727fc38e39000dec8de 100644 (file)
 #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 */
index 2d66048087727d6ae8fe063aeb871a36dbea8536..b449c1637875ec3d9fd480e49982975ca17ab193 100644 (file)
@@ -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);
+       }
+}
index eb9b8c4635c1c685322dccf4e439f8e59babb2a8..f5fbf326219efada17fe347b9fa3ffa6cfd46fe6 100644 (file)
@@ -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 */
index 02d042733e40687a35743cfeca0d0517ddb7f87b..5619024661d462dc56c79bacfb9fa433b66049a3 100644 (file)
@@ -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;
        }
index 4cb1c1fd339d248d028901ad4c390faa8b1f654e..c46290d1a2978f205dbf7e07d903a0d428f405fd 100644 (file)
@@ -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;
+
+}
index f090a0db63681b3b83ec451113039b3d40dd0b75..fd308d5007f3b35b4d10d81a2308d4e4aeb5d7bb 100644 (file)
@@ -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 */
index 52ca1caa15565dbbfdaa217ec7ac1b9d779646a4..74d5b1176be637601edac2e342d08a0fd56ae11f 100644 (file)
@@ -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 */
index cd5ee062230c51da3826dee0cde97864af309eec..5cd926e6f10ce8e857ecd75dc73de027d89a407b 100644 (file)
@@ -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;
 
index 3350403d9db2ef9bd639cccf48c24f852e6f76e2..d0488dbc837851ec3a23162a2595954aa2c02a87 100644 (file)
@@ -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;
        }
This page took 0.03622 seconds and 5 git commands to generate.