#include <sys/stat.h>
#include <sys/types.h>
-#include "common/defaults.h"
-#include "common/error.h"
-#include "common/hashtable/hashtable.h"
-#include "common/hashtable/utils.h"
-#include "common/macros.h"
+#include <common/defaults.h>
+#include <common/error.h>
+#include <common/hashtable/hashtable.h>
+#include <common/hashtable/utils.h>
+#include <common/macros.h>
+#include <common/fs-handle-internal.h>
#include "fd-tracker.h"
#include "inode.h"
};
/*
- * A fs_handle is not ref-counted. Therefore, it is assumed that a
+ * A fs_handle_tracked is not ref-counted. Therefore, it is assumed that a
* handle is never in-use while it is being reclaimed. It can be
* shared by multiple threads, but external synchronization is required
* to ensure it is not still being used when it is reclaimed (close method).
*
* The fs_handle lock always nests _within_ the tracker's lock.
*/
-struct fs_handle {
+struct fs_handle_tracked {
+ struct fs_handle parent;
pthread_mutex_t lock;
/*
* Weak reference to the tracker. All fs_handles are assumed to have
static int open_from_properties(
const char *path, struct open_properties *properties);
-static void fs_handle_log(struct fs_handle *handle);
-static int fs_handle_suspend(struct fs_handle *handle);
-static int fs_handle_restore(struct fs_handle *handle);
+static void fs_handle_tracked_log(struct fs_handle_tracked *handle);
+static int fs_handle_tracked_suspend(struct fs_handle_tracked *handle);
+static int fs_handle_tracked_restore(struct fs_handle_tracked *handle);
+static int fs_handle_tracked_get_fd(struct fs_handle *_handle);
+static void fs_handle_tracked_put_fd(struct fs_handle *_handle);
+static int fs_handle_tracked_unlink(struct fs_handle *_handle);
+static int fs_handle_tracked_close(struct fs_handle *_handle);
static void fd_tracker_track(
- struct fd_tracker *tracker, struct fs_handle *handle);
+ struct fd_tracker *tracker, struct fs_handle_tracked *handle);
static void fd_tracker_untrack(
- struct fd_tracker *tracker, struct fs_handle *handle);
+ struct fd_tracker *tracker, struct fs_handle_tracked *handle);
static int fd_tracker_suspend_handles(
struct fd_tracker *tracker, unsigned int count);
static int fd_tracker_restore_handle(
- struct fd_tracker *tracker, struct fs_handle *handle);
+ struct fd_tracker *tracker, struct fs_handle_tracked *handle);
+
+static const struct fs_handle fs_handle_tracked_callbacks = {
+ .get_fd = fs_handle_tracked_get_fd,
+ .put_fd = fs_handle_tracked_put_fd,
+ .unlink = fs_handle_tracked_unlink,
+ .close = fs_handle_tracked_close,
+};
/* Match function of the tracker's unsuspendable_fds hash table. */
static int match_fd(struct cds_lfht_node *node, const void *key)
return NULL;
}
-static void fs_handle_log(struct fs_handle *handle)
+static void fs_handle_tracked_log(struct fs_handle_tracked *handle)
{
const char *path;
}
/* Tracker lock must be held by the caller. */
-static int fs_handle_suspend(struct fs_handle *handle)
+static int fs_handle_tracked_suspend(struct fs_handle_tracked *handle)
{
int ret = 0;
struct stat fs_stat;
}
/* Caller must hold the tracker and handle's locks. */
-static int fs_handle_restore(struct fs_handle *handle)
+static int fs_handle_tracked_restore(struct fs_handle_tracked *handle)
{
int ret, fd = -1;
const char *path = lttng_inode_get_path(handle->inode);
void fd_tracker_log(struct fd_tracker *tracker)
{
- struct fs_handle *handle;
+ struct fs_handle_tracked *handle;
struct unsuspendable_fd *unsuspendable_fd;
struct cds_lfht_iter iter;
DBG_NO_LOC(" capacity: %u", tracker->capacity);
DBG_NO_LOC(" Tracked suspendable file descriptors");
- cds_list_for_each_entry (
+ cds_list_for_each_entry(
handle, &tracker->active_handles, handles_list_node) {
- fs_handle_log(handle);
+ fs_handle_tracked_log(handle);
}
- cds_list_for_each_entry (handle, &tracker->suspended_handles,
+ cds_list_for_each_entry(handle, &tracker->suspended_handles,
handles_list_node) {
- fs_handle_log(handle);
+ fs_handle_tracked_log(handle);
}
if (!SUSPENDABLE_COUNT(tracker)) {
DBG_NO_LOC(" None");
DBG_NO_LOC(" Tracked unsuspendable file descriptors");
rcu_read_lock();
- cds_lfht_for_each_entry (tracker->unsuspendable_fds, &iter,
+ cds_lfht_for_each_entry(tracker->unsuspendable_fds, &iter,
unsuspendable_fd, tracker_node) {
DBG_NO_LOC(" %s [active, fd %d]",
unsuspendable_fd->name ?: "Unnamed",
mode_t *mode)
{
int ret;
- struct fs_handle *handle = NULL;
+ struct fs_handle_tracked *handle = NULL;
struct stat fd_stat;
struct open_properties properties = {
.flags = flags,
if (!handle) {
goto end;
}
+ handle->parent = fs_handle_tracked_callbacks;
handle->tracker = tracker;
ret = pthread_mutex_init(&handle->lock, NULL);
fd_tracker_track(tracker, handle);
end:
pthread_mutex_unlock(&tracker->lock);
- return handle;
+ return handle ? &handle->parent : NULL;
error:
if (handle->inode) {
lttng_inode_put(handle->inode);
struct fd_tracker *tracker, unsigned int count)
{
unsigned int left_to_close = count;
- struct fs_handle *handle, *tmp;
+ struct fs_handle_tracked *handle, *tmp;
- cds_list_for_each_entry_safe (handle, tmp, &tracker->active_handles,
+ cds_list_for_each_entry_safe(handle, tmp, &tracker->active_handles,
handles_list_node) {
int ret;
fd_tracker_untrack(tracker, handle);
- ret = fs_handle_suspend(handle);
+ ret = fs_handle_tracked_suspend(handle);
fd_tracker_track(tracker, handle);
if (!ret) {
left_to_close--;
/* Caller must have taken the tracker's and handle's locks. */
static void fd_tracker_track(
- struct fd_tracker *tracker, struct fs_handle *handle)
+ struct fd_tracker *tracker, struct fs_handle_tracked *handle)
{
if (handle->fd >= 0) {
tracker->count.suspendable.active++;
/* Caller must have taken the tracker's and handle's locks. */
static void fd_tracker_untrack(
- struct fd_tracker *tracker, struct fs_handle *handle)
+ struct fd_tracker *tracker, struct fs_handle_tracked *handle)
{
if (handle->fd >= 0) {
tracker->count.suspendable.active--;
/* Caller must have taken the tracker's and handle's locks. */
static int fd_tracker_restore_handle(
- struct fd_tracker *tracker, struct fs_handle *handle)
+ struct fd_tracker *tracker, struct fs_handle_tracked *handle)
{
int ret;
goto end;
}
}
- ret = fs_handle_restore(handle);
+ ret = fs_handle_tracked_restore(handle);
end:
fd_tracker_track(tracker, handle);
return ret ? ret : handle->fd;
}
-int fs_handle_get_fd(struct fs_handle *handle)
+static int fs_handle_tracked_get_fd(struct fs_handle *_handle)
{
int ret;
+ struct fs_handle_tracked *handle =
+ container_of(_handle, struct fs_handle_tracked, parent);
/*
* TODO This should be optimized as it is a fairly hot path.
return ret;
}
-void fs_handle_put_fd(struct fs_handle *handle)
+static void fs_handle_tracked_put_fd(struct fs_handle *_handle)
{
+ struct fs_handle_tracked *handle =
+ container_of(_handle, struct fs_handle_tracked, parent);
+
pthread_mutex_lock(&handle->lock);
handle->in_use = false;
pthread_mutex_unlock(&handle->lock);
}
-int fs_handle_unlink(struct fs_handle *handle)
+static int fs_handle_tracked_unlink(struct fs_handle *_handle)
{
int ret;
+ struct fs_handle_tracked *handle =
+ container_of(_handle, struct fs_handle_tracked, parent);
pthread_mutex_lock(&handle->tracker->lock);
pthread_mutex_lock(&handle->lock);
return ret;
}
-int fs_handle_close(struct fs_handle *handle)
+static int fs_handle_tracked_close(struct fs_handle *_handle)
{
int ret = 0;
const char *path = NULL;
+ struct fs_handle_tracked *handle =
+ container_of(_handle, struct fs_handle_tracked, parent);
if (!handle) {
ret = -EINVAL;
--- /dev/null
+/*
+ * Copyright (C) 2020 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FS_HANDLE_H
+#define FS_HANDLE_H
+
+#include <common/macros.h>
+
+struct fs_handle;
+
+/*
+ * Marks the handle as the most recently used and marks the 'fd' as
+ * "in-use". This prevents the tracker from recycling the underlying
+ * file descriptor while it is actively being used by a thread.
+ *
+ * Don't forget that the tracker may be initiating an fd 'suspension'
+ * from another thread as the need to free an fd slot may arise from any
+ * thread within the daemon.
+ *
+ * Note that a restorable fd should never be held for longer than
+ * strictly necessary (e.g. the duration of a syscall()).
+ *
+ * Returns the fd on success, otherwise a negative value may be returned
+ * if the restoration of the fd failed.
+ */
+LTTNG_HIDDEN
+int fs_handle_get_fd(struct fs_handle *handle);
+
+/*
+ * Used by the caller to signal that it is no longer using the underlying fd and
+ * that it may be safely suspended.
+ */
+LTTNG_HIDDEN
+void fs_handle_put_fd(struct fs_handle *handle);
+
+/*
+ * Unlink the file associated to an fs_handle. Note that the unlink
+ * operation will not be performed immediately. It will only be performed
+ * once all references to the underlying file (through other fs_handle objects)
+ * have been released.
+ *
+ * However, note that the file will be renamed so as to provide the observable
+ * effect of an unlink(), that is removing a name from the filesystem.
+ *
+ * Returns 0 on success, otherwise a negative value will be returned
+ * if the operation failed.
+ */
+LTTNG_HIDDEN
+int fs_handle_unlink(struct fs_handle *handle);
+
+/*
+ * Frees the handle and discards the underlying fd.
+ */
+LTTNG_HIDDEN
+int fs_handle_close(struct fs_handle *handle);
+
+#endif /* FS_HANDLE_H */