relayd: track directory handles through the fd-tracker
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 30 Jan 2020 16:45:07 +0000 (11:45 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 31 Jan 2020 21:14:34 +0000 (16:14 -0500)
Track directory handles through the fd-tracker as unsuspendable
file descriptors. New fd-tracker utils are introduced to wrap
the creation and registration of the file descriptors to the
fd-tracker.

Note that file descriptors only need to be tracked when the
dirfd-backed implementation of the directory handles is used.

Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I754af1943f5d6f02a6219d48c8fc4b8106de1c13

src/bin/lttng-relayd/session.c
src/common/compat/directory-handle.c
src/common/compat/directory-handle.h
src/common/fd-tracker/fd-tracker.c
src/common/fd-tracker/inode.c
src/common/fd-tracker/inode.h
src/common/fd-tracker/utils.c
src/common/fd-tracker/utils.h
src/common/trace-chunk.c

index 3dcb1cd3367183f854c8b63b1daefd5a2360831f..daae9a55ba1d5308427a101f16e2416e9f4d46bb 100644 (file)
@@ -9,11 +9,11 @@
 
 #define _LGPL_SOURCE
 #include <common/common.h>
-#include <common/uuid.h>
+#include <common/compat/path.h>
+#include <common/fd-tracker/utils.h>
 #include <common/time.h>
 #include <common/utils.h>
 #include <common/uuid.h>
-#include <common/compat/path.h>
 #include <urcu/rculist.h>
 
 #include <sys/stat.h>
@@ -196,7 +196,7 @@ static struct lttng_directory_handle *session_create_output_directory_handle(
                goto end;
        }
 
-       handle = lttng_directory_handle_create(full_session_path);
+       handle = fd_tracker_create_directory_handle(the_fd_tracker, full_session_path);
 end:
        pthread_mutex_unlock(&session->lock);
        free(full_session_path);
index eb1cd926e6e2df0979d041a21532a7a6b141b050..f0139be29bced2a8f566d64dc0b77b49c93a3cca 100644 (file)
@@ -181,6 +181,10 @@ void lttng_directory_handle_release(struct urcu_ref *ref)
        struct lttng_directory_handle *handle =
                        container_of(ref, struct lttng_directory_handle, ref);
 
+       if (handle->destroy_cb) {
+               handle->destroy_cb(handle, handle->destroy_cb_data);
+       }
+
        if (handle->dirfd == AT_FDCWD || handle->dirfd == -1) {
                goto end;
        }
index 35e91f71c03c72b44129b618220acc0d9cdc9014..574a09d743776e831d04fe9ef24f07e4790be32d 100644 (file)
@@ -26,10 +26,18 @@ enum lttng_directory_handle_rmdir_recursive_flags {
  * or a directory file descriptors, depending on the platform's capabilities.
  */
 #ifdef COMPAT_DIRFD
+
+struct lttng_directory_handle;
+
+typedef void (*lttng_directory_handle_destroy_cb)(
+               struct lttng_directory_handle *handle, void *data);
+
 struct lttng_directory_handle {
        struct urcu_ref ref;
        ino_t directory_inode;
        int dirfd;
+       lttng_directory_handle_destroy_cb destroy_cb;
+       void *destroy_cb_data;
 };
 
 static inline
index 417859abe889e0e8b94eabe88dd9fd0d00376f9c..188abfb6d2792f4f3f2eb9d899e6fb62d784f522 100644 (file)
@@ -210,7 +210,7 @@ static void fs_handle_tracked_log(struct fs_handle_tracked *handle)
        const char *path;
 
        pthread_mutex_lock(&handle->lock);
-       lttng_inode_get_location(handle->inode, NULL, &path);
+       lttng_inode_borrow_location(handle->inode, NULL, &path);
 
        if (handle->fd >= 0) {
                DBG_NO_LOC("    %s [active, fd %d%s]", path, handle->fd,
@@ -230,7 +230,8 @@ static int fs_handle_tracked_suspend(struct fs_handle_tracked *handle)
        const struct lttng_directory_handle *node_directory_handle;
 
        pthread_mutex_lock(&handle->lock);
-       lttng_inode_get_location(handle->inode, &node_directory_handle, &path);
+       lttng_inode_borrow_location(
+                       handle->inode, &node_directory_handle, &path);
        assert(handle->fd >= 0);
        if (handle->in_use) {
                /* This handle can't be suspended as it is currently in use. */
@@ -288,7 +289,8 @@ static int fs_handle_tracked_restore(struct fs_handle_tracked *handle)
        const char *path;
        const struct lttng_directory_handle *node_directory_handle;
 
-       lttng_inode_get_location(handle->inode, &node_directory_handle, &path);
+       lttng_inode_borrow_location(
+                       handle->inode, &node_directory_handle, &path);
 
        assert(handle->fd == -1);
        assert(path);
@@ -882,6 +884,7 @@ static int fs_handle_tracked_close(struct fs_handle *_handle)
        const char *path = NULL;
        struct fs_handle_tracked *handle =
                        container_of(_handle, struct fs_handle_tracked, parent);
+       struct lttng_directory_handle *inode_directory_handle = NULL;
 
        if (!handle) {
                ret = -EINVAL;
@@ -891,7 +894,29 @@ static int fs_handle_tracked_close(struct fs_handle *_handle)
        pthread_mutex_lock(&handle->tracker->lock);
        pthread_mutex_lock(&handle->lock);
        if (handle->inode) {
-               lttng_inode_get_location(handle->inode, NULL, &path);
+               lttng_inode_borrow_location(handle->inode, NULL, &path);
+               /*
+                * Here a reference to the inode's directory handle is acquired
+                * to prevent the last reference to it from being released while
+                * the tracker's lock is taken.
+                *
+                * If this wasn't done, the directory handle could attempt to
+                * close its underlying directory file descriptor, which would
+                * attempt to lock the tracker's lock, resulting in a deadlock.
+                *
+                * Since a new reference to the directory handle is taken within
+                * the scope of this function, it is not possible for the last
+                * reference to the inode's location directory handle to be
+                * released during the call to lttng_inode_put().
+                *
+                * We wait until the tracker's lock is released to release the
+                * reference. Hence, the call to the tracker is delayed just
+                * enough to not attempt to recursively acquire the tracker's
+                * lock twice.
+                */
+               inode_directory_handle =
+                               lttng_inode_get_location_directory_handle(
+                                               handle->inode);
        }
        fd_tracker_untrack(handle->tracker, handle);
        if (handle->fd >= 0) {
@@ -912,6 +937,7 @@ static int fs_handle_tracked_close(struct fs_handle *_handle)
        pthread_mutex_destroy(&handle->lock);
        pthread_mutex_unlock(&handle->tracker->lock);
        free(handle);
+       lttng_directory_handle_put(inode_directory_handle);
 end:
        return ret;
 }
index 0e1ebc6ff5dc51b2fe93ea7208c13ac17f5136c6..727f6141aba4d78de12bf77ec3f688ef6c8bf92f 100644 (file)
@@ -280,7 +280,19 @@ void lttng_inode_put(struct lttng_inode *inode)
        urcu_ref_put(&inode->ref, lttng_inode_release);
 }
 
-void lttng_inode_get_location(struct lttng_inode *inode,
+struct lttng_directory_handle *lttng_inode_get_location_directory_handle(
+               struct lttng_inode *inode)
+{
+       if (inode->location.directory_handle) {
+               const bool reference_acquired = lttng_directory_handle_get(
+                               inode->location.directory_handle);
+
+               assert(reference_acquired);
+       }
+       return inode->location.directory_handle;
+}
+
+void lttng_inode_borrow_location(struct lttng_inode *inode,
                const struct lttng_directory_handle **out_directory_handle,
                const char **out_path)
 {
index d69f354ea7d12c78c147a61b5c9b31b5b77f20ea..7e95c0726efc9057f67b8457569067f0118c0770 100644 (file)
@@ -14,6 +14,7 @@
 struct lttng_inode;
 struct lttng_inode_registry;
 struct lttng_unlinked_file_directory;
+struct lttng_directory_handle;
 
 /*
  * The unlinked file pool is protected by the fd-tracker's lock.
@@ -41,10 +42,14 @@ struct lttng_inode *lttng_inode_registry_get_inode(
 
 void lttng_inode_registry_destroy(struct lttng_inode_registry *registry);
 
-void lttng_inode_get_location(struct lttng_inode *inode,
+void lttng_inode_borrow_location(struct lttng_inode *inode,
                const struct lttng_directory_handle **out_directory_handle,
                const char **out_path);
 
+/* Returns a new reference to the inode's location directory handle. */
+struct lttng_directory_handle *lttng_inode_get_location_directory_handle(
+               struct lttng_inode *inode);
+
 int lttng_inode_rename(struct lttng_inode *inode,
                struct lttng_directory_handle *old_directory_handle,
                const char *old_path,
index 1f71fd49623eda113386fc1dd8ed7471cf318234..fe2cdcc4ed4f84f1c629e27c630964d25d10f377 100644 (file)
@@ -5,29 +5,35 @@
  *
  */
 
+#include <common/error.h>
 #include <common/fd-tracker/utils.h>
 #include <common/utils.h>
+#include <lttng/constant.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
-static int open_pipe_cloexec(void *data, int *fds)
+static
+int open_pipe_cloexec(void *data, int *fds)
 {
        return utils_create_pipe_cloexec(fds);
 }
 
-static int close_pipe(void *data, int *pipe)
+static
+int close_pipe(void *data, int *pipe)
 {
        utils_close_pipe(pipe);
        pipe[0] = pipe[1] = -1;
        return 0;
 }
 
+LTTNG_HIDDEN
 int fd_tracker_util_close_fd(void *unused, int *fd)
 {
        return close(*fd);
 }
 
+LTTNG_HIDDEN
 int fd_tracker_util_pipe_open_cloexec(
                struct fd_tracker *tracker, const char *name, int *pipe)
 {
@@ -53,8 +59,134 @@ end:
        return ret;
 }
 
+LTTNG_HIDDEN
 int fd_tracker_util_pipe_close(struct fd_tracker *tracker, int *pipe)
 {
        return fd_tracker_close_unsuspendable_fd(
                        tracker, pipe, 2, close_pipe, NULL);
 }
+
+struct open_directory_handle_args {
+       const struct lttng_directory_handle *in_handle;
+       struct lttng_directory_handle *ret_handle;
+       const char *path;
+};
+
+static
+int open_directory_handle(void *_args, int *out_fds)
+{
+       int ret = 0;
+       struct open_directory_handle_args *args = _args;
+       struct lttng_directory_handle *new_handle = NULL;
+
+       new_handle = args->in_handle ?
+                       lttng_directory_handle_create_from_handle(
+                               args->path, args->in_handle) :
+                       lttng_directory_handle_create(args->path);
+       if (!new_handle) {
+               ret = -errno;
+               goto end;
+       }
+
+       args->ret_handle = new_handle;
+
+       /*
+        * Reserved to indicate that the handle does not use a handle; there is
+        * nothing to track. We want to indicate an error to the fd-tracker so
+        * that it doesn't attempt to track the file descriptor, but also want
+        * the caller to retrieve the newly-created handle.
+        *
+        * Calling this a hack is a fair assessment.
+        */
+       if (!lttng_directory_handle_uses_fd(new_handle)) {
+               ret = ENOTSUP;
+       } else {
+#ifdef COMPAT_DIRFD
+               *out_fds = new_handle->dirfd;
+#else
+               abort();
+#endif
+
+       }
+end:
+       return ret;
+}
+
+#ifdef COMPAT_DIRFD
+static
+int fd_close(void *unused, int *in_fds)
+{
+       const int ret = close(in_fds[0]);
+
+       in_fds[0] = -1;
+       return ret;
+}
+
+static
+void directory_handle_destroy(
+               struct lttng_directory_handle *handle, void *data)
+{
+       struct fd_tracker *tracker = data;
+       const int ret = fd_tracker_close_unsuspendable_fd(
+                       tracker, &handle->dirfd, 1, fd_close, NULL);
+
+       if (ret) {
+               ERR("Failed to untrack directory handle file descriptor");
+       }
+}
+#endif
+
+LTTNG_HIDDEN
+struct lttng_directory_handle *fd_tracker_create_directory_handle(
+               struct fd_tracker *tracker, const char *path)
+{
+       return fd_tracker_create_directory_handle_from_handle(
+                       tracker, NULL, path);
+}
+
+LTTNG_HIDDEN
+struct lttng_directory_handle *fd_tracker_create_directory_handle_from_handle(
+               struct fd_tracker *tracker,
+               struct lttng_directory_handle *in_handle,
+               const char *path)
+{
+       int ret;
+       int dirfd = -1;
+       char *handle_name = NULL;
+       char cwd_path[LTTNG_PATH_MAX] = "working directory";
+       struct lttng_directory_handle *new_handle = NULL;
+       struct open_directory_handle_args open_args = {
+               .in_handle = in_handle,
+               .path = path,
+       };
+
+       if (!path) {
+               if (!getcwd(cwd_path, sizeof(cwd_path))) {
+                       PERROR("Failed to get current working directory to name directory handle");
+                       goto end;
+               }
+       }
+
+       ret = asprintf(&handle_name, "Directory handle to %s",
+                       path ? path : cwd_path);
+       if (ret < 0) {
+               PERROR("Failed to format directory handle name");
+               goto end;
+       }
+
+       ret = fd_tracker_open_unsuspendable_fd(tracker, &dirfd,
+                       (const char **) &handle_name, 1, open_directory_handle,
+                       &open_args);
+       if (ret && ret != ENOTSUP) {
+               ERR("Failed to open directory handle to %s through the fd tracker", path ? path : cwd_path);
+       }
+       new_handle = open_args.ret_handle;
+
+#ifdef COMPAT_DIRFD
+       new_handle->destroy_cb = directory_handle_destroy;
+       new_handle->destroy_cb_data = tracker;
+#endif
+end:
+       free(handle_name);
+       return new_handle;
+}
index 617ee49bb0dae5f8c580e7d301f7ab9c2258138b..202c4a1b846f47d0dd434daa32daccd0020ff0bc 100644 (file)
@@ -8,7 +8,9 @@
 #ifndef FD_TRACKER_UTILS_H
 #define FD_TRACKER_UTILS_H
 
+#include <common/compat/directory-handle.h>
 #include <common/fd-tracker/fd-tracker.h>
+#include <common/macros.h>
 
 struct lttng_poll_event;
 
@@ -16,24 +18,39 @@ struct lttng_poll_event;
  * Utility implementing a close_fd callback which receives one file descriptor
  * and closes it, returning close()'s return value.
  */
+LTTNG_HIDDEN
 int fd_tracker_util_close_fd(void *, int *fd);
 
 /*
  * Create a pipe and track its underlying fds.
  */
+LTTNG_HIDDEN
 int fd_tracker_util_pipe_open_cloexec(
                struct fd_tracker *tracker, const char *name, int *pipe);
+LTTNG_HIDDEN
 int fd_tracker_util_pipe_close(struct fd_tracker *tracker, int *pipe);
 
 /*
  * Create a poll event and track its underlying fd, if applicable.
  */
+LTTNG_HIDDEN
 int fd_tracker_util_poll_create(struct fd_tracker *tracker,
                const char *name,
                struct lttng_poll_event *events,
                int size,
                int flags);
+LTTNG_HIDDEN
 int fd_tracker_util_poll_clean(
                struct fd_tracker *tracker, struct lttng_poll_event *events);
 
+LTTNG_HIDDEN
+struct lttng_directory_handle *fd_tracker_create_directory_handle(
+               struct fd_tracker *tracker, const char *path);
+
+LTTNG_HIDDEN
+struct lttng_directory_handle *fd_tracker_create_directory_handle_from_handle(
+               struct fd_tracker *tracker,
+               struct lttng_directory_handle *handle,
+               const char *path);
+
 #endif /* FD_TRACKER_UTILS_H */
index f846712526085e8fb807cd871771bdc7c4c28029..63bfb6c523add6a4058d3867a39581274cb55374 100644 (file)
@@ -11,6 +11,7 @@
 #include <common/dynamic-array.h>
 #include <common/error.h>
 #include <common/fd-tracker/fd-tracker.h>
+#include <common/fd-tracker/utils.h>
 #include <common/fs-handle-internal.h>
 #include <common/hashtable/hashtable.h>
 #include <common/hashtable/utils.h>
@@ -781,9 +782,14 @@ enum lttng_trace_chunk_status lttng_trace_chunk_rename_path_no_lock(
                        status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
                        goto end;
                }
-               rename_directory = lttng_directory_handle_create_from_handle(
-                               path,
-                               chunk->session_output_directory);
+               rename_directory = chunk->fd_tracker ?
+                               fd_tracker_create_directory_handle_from_handle(
+                                               chunk->fd_tracker,
+                                               chunk->session_output_directory,
+                                               path) :
+                               lttng_directory_handle_create_from_handle(
+                                               path,
+                                               chunk->session_output_directory);
                if (!rename_directory) {
                        ERR("Failed to get handle to trace chunk rename directory");
                        status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
@@ -1039,9 +1045,14 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_as_owner(
                        goto end;
                }
                chunk_directory_handle =
-                               lttng_directory_handle_create_from_handle(
-                                       chunk->path,
-                                       session_output_directory);
+                               chunk->fd_tracker ?
+                                       fd_tracker_create_directory_handle_from_handle(
+                                                       chunk->fd_tracker,
+                                                       session_output_directory,
+                                                       chunk->path) :
+                                       lttng_directory_handle_create_from_handle(
+                                                       chunk->path,
+                                                       session_output_directory);
                if (!chunk_directory_handle) {
                        /* The function already logs on all error paths. */
                        status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
@@ -1572,9 +1583,14 @@ int lttng_trace_chunk_move_to_completed_post_release(
                goto end;
        }
 
-       archived_chunks_directory = lttng_directory_handle_create_from_handle(
-                       DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY,
-                       trace_chunk->session_output_directory);
+       archived_chunks_directory = trace_chunk->fd_tracker ?
+                       fd_tracker_create_directory_handle_from_handle(
+                                       trace_chunk->fd_tracker,
+                                       trace_chunk->session_output_directory,
+                                       DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY) :
+                       lttng_directory_handle_create_from_handle(
+                                       DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY,
+                                       trace_chunk->session_output_directory);
        if (!archived_chunks_directory) {
                PERROR("Failed to get handle to archived trace chunks directory");
                ret = -1;
This page took 0.032709 seconds and 4 git commands to generate.