#include <urcu/list.h>
#include <urcu/rculfhash.h>
-#include <sys/stat.h>
-#include <sys/types.h>
#include <fcntl.h>
-#include <stdbool.h>
-#include <pthread.h>
#include <inttypes.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
-#include "common/macros.h"
-#include "common/error.h"
#include "common/defaults.h"
-#include "common/hashtable/utils.h"
+#include "common/error.h"
#include "common/hashtable/hashtable.h"
+#include "common/hashtable/utils.h"
+#include "common/macros.h"
#include "fd-tracker.h"
+#include "inode.h"
/* Tracker lock must be taken by the user. */
-#define TRACKED_COUNT(tracker) \
- (tracker->count.suspendable.active + \
- tracker->count.suspendable.suspended + \
- tracker->count.unsuspendable)
+#define TRACKED_COUNT(tracker) \
+ (tracker->count.suspendable.active + \
+ tracker->count.suspendable.suspended + \
+ tracker->count.unsuspendable)
/* Tracker lock must be taken by the user. */
-#define ACTIVE_COUNT(tracker) \
- (tracker->count.suspendable.active + \
- tracker->count.unsuspendable)
+#define ACTIVE_COUNT(tracker) \
+ (tracker->count.suspendable.active + tracker->count.unsuspendable)
/* Tracker lock must be taken by the user. */
-#define SUSPENDED_COUNT(tracker) \
- (tracker->count.suspendable.suspended)
+#define SUSPENDED_COUNT(tracker) (tracker->count.suspendable.suspended)
/* Tracker lock must be taken by the user. */
-#define SUSPENDABLE_COUNT(tracker) \
- (tracker->count.suspendable.active + \
- tracker->count.suspendable.suspended)
+#define SUSPENDABLE_COUNT(tracker) \
+ (tracker->count.suspendable.active + \
+ tracker->count.suspendable.suspended)
/* Tracker lock must be taken by the user. */
-#define UNSUSPENDABLE_COUNT(tracker) \
- (tracker->count.unsuspendable)
+#define UNSUSPENDABLE_COUNT(tracker) (tracker->count.unsuspendable)
struct fd_tracker {
pthread_mutex_t lock;
struct {
- struct {
+ struct {
unsigned int active;
unsigned int suspended;
} suspendable;
struct cds_list_head active_handles;
struct cds_list_head suspended_handles;
struct cds_lfht *unsuspendable_fds;
+ struct lttng_inode_registry *inode_registry;
};
struct open_properties {
- char *path;
int flags;
struct {
bool is_set;
*/
struct fd_tracker *tracker;
struct open_properties properties;
+ struct lttng_inode *inode;
int fd;
/* inode number of the file at the time of the handle's creation. */
uint64_t ino;
static int match_fd(struct cds_lfht_node *node, const void *key);
static void unsuspendable_fd_destroy(struct unsuspendable_fd *entry);
-static struct unsuspendable_fd *unsuspendable_fd_create(const char *name,
- int fd);
-static int open_from_properties(struct open_properties *properties);
+static struct unsuspendable_fd *unsuspendable_fd_create(
+ const char *name, int fd);
+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 fd_tracker_track(struct fd_tracker *tracker,
- struct fs_handle *handle);
-static void fd_tracker_untrack(struct fd_tracker *tracker,
- struct fs_handle *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);
+static void fd_tracker_track(
+ struct fd_tracker *tracker, struct fs_handle *handle);
+static void fd_tracker_untrack(
+ struct fd_tracker *tracker, struct fs_handle *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);
/* Match function of the tracker's unsuspendable_fds hash table. */
-static
-int match_fd(struct cds_lfht_node *node, const void *key)
+static int match_fd(struct cds_lfht_node *node, const void *key)
{
- struct unsuspendable_fd *entry =
- caa_container_of(node, struct unsuspendable_fd, tracker_node);
+ struct unsuspendable_fd *entry = caa_container_of(
+ node, struct unsuspendable_fd, tracker_node);
- return hash_match_key_ulong((void *) (unsigned long) entry->fd,
- (void *) key);
+ return hash_match_key_ulong(
+ (void *) (unsigned long) entry->fd, (void *) key);
}
-static
-void delete_unsuspendable_fd(struct rcu_head *head)
+static void delete_unsuspendable_fd(struct rcu_head *head)
{
- struct unsuspendable_fd *fd = caa_container_of(head,
- struct unsuspendable_fd, rcu_head);
+ struct unsuspendable_fd *fd = caa_container_of(
+ head, struct unsuspendable_fd, rcu_head);
free(fd->name);
free(fd);
}
-static
-void unsuspendable_fd_destroy(struct unsuspendable_fd *entry)
+static void unsuspendable_fd_destroy(struct unsuspendable_fd *entry)
{
if (!entry) {
return;
call_rcu(&entry->rcu_head, delete_unsuspendable_fd);
}
-static
-struct unsuspendable_fd *unsuspendable_fd_create(const char *name, int fd)
+static struct unsuspendable_fd *unsuspendable_fd_create(
+ const char *name, int fd)
{
- struct unsuspendable_fd *entry =
- zmalloc(sizeof(*entry));
+ struct unsuspendable_fd *entry = zmalloc(sizeof(*entry));
if (!entry) {
goto error;
return NULL;
}
-static
-void fs_handle_log(struct fs_handle *handle)
+static void fs_handle_log(struct fs_handle *handle)
{
+ const char *path;
+
pthread_mutex_lock(&handle->lock);
+ path = lttng_inode_get_path(handle->inode);
+
if (handle->fd >= 0) {
- DBG_NO_LOC(" %s [active, fd %d%s]",
- handle->properties.path,
- handle->fd,
+ DBG_NO_LOC(" %s [active, fd %d%s]", path, handle->fd,
handle->in_use ? ", in use" : "");
} else {
- DBG_NO_LOC(" %s [suspended]", handle->properties.path);
+ DBG_NO_LOC(" %s [suspended]", path);
}
pthread_mutex_unlock(&handle->lock);
}
-static
-int fs_handle_suspend(struct fs_handle *handle)
+/* Tracker lock must be held by the caller. */
+static int fs_handle_suspend(struct fs_handle *handle)
{
int ret = 0;
struct stat fs_stat;
+ const char *path;
pthread_mutex_lock(&handle->lock);
+ path = lttng_inode_get_path(handle->inode);
assert(handle->fd >= 0);
if (handle->in_use) {
/* This handle can't be suspended as it is currently in use. */
goto end;
}
- ret = stat(handle->properties.path, &fs_stat);
+ ret = stat(path, &fs_stat);
if (ret) {
- PERROR("Filesystem handle to %s cannot be suspended as stat() failed",
- handle->properties.path);
+ PERROR("Filesystem handle to %s cannot be suspended as stat() failed",
+ path);
ret = -errno;
goto end;
}
if (fs_stat.st_ino != handle->ino) {
/* Don't suspend as the handle would not be restorable. */
WARN("Filesystem handle to %s cannot be suspended as its inode changed",
- handle->properties.path);
+ path);
ret = -ENOENT;
goto end;
}
- handle->offset = lseek(handle->fd, 0, SEEK_CUR);
+ handle->offset = lseek(handle->fd, 0, SEEK_CUR);
if (handle->offset == -1) {
WARN("Filesystem handle to %s cannot be suspended as lseek() failed to sample its current position",
- handle->properties.path);
+ path);
ret = -errno;
goto end;
}
ret = close(handle->fd);
if (ret) {
- PERROR("Filesystem handle to %s cannot be suspended as close() failed",
- handle->properties.path);
+ PERROR("Filesystem handle to %s cannot be suspended as close() failed",
+ path);
ret = -errno;
goto end;
}
DBG("Suspended filesystem handle to %s (fd %i) at position %" PRId64,
- handle->properties.path, handle->fd, handle->offset);
+ path, handle->fd, handle->offset);
handle->fd = -1;
end:
if (ret) {
}
/* Caller must hold the tracker and handle's locks. */
-static
-int fs_handle_restore(struct fs_handle *handle)
+static int fs_handle_restore(struct fs_handle *handle)
{
int ret, fd = -1;
+ const char *path = lttng_inode_get_path(handle->inode);
assert(handle->fd == -1);
- ret = open_from_properties(&handle->properties);
+ assert(path);
+ ret = open_from_properties(path, &handle->properties);
if (ret < 0) {
- PERROR("Failed to restore filesystem handle to %s, open() failed",
- handle->properties.path);
+ PERROR("Failed to restore filesystem handle to %s, open() failed",
+ path);
ret = -errno;
goto end;
}
ret = lseek(fd, handle->offset, SEEK_SET);
if (ret < 0) {
- PERROR("Failed to restore filesystem handle to %s, lseek() failed",
- handle->properties.path);
+ PERROR("Failed to restore filesystem handle to %s, lseek() failed",
+ path);
ret = -errno;
goto end;
}
DBG("Restored filesystem handle to %s (fd %i) at position %" PRId64,
- handle->properties.path, fd, handle->offset);
+ path, fd, handle->offset);
ret = 0;
handle->fd = fd;
fd = -1;
return ret;
}
-static
-int open_from_properties(struct open_properties *properties)
+static int open_from_properties(
+ const char *path, struct open_properties *properties)
{
int ret;
* thus it is ignored here.
*/
if ((properties->flags & O_CREAT) && properties->mode.is_set) {
- ret = open(properties->path, properties->flags,
- properties->mode.value);
+ ret = open(path, properties->flags, properties->mode.value);
} else {
- ret = open(properties->path, properties->flags);
+ ret = open(path, properties->flags);
}
/*
* Some flags should not be used beyond the initial open() of a
tracker->capacity = capacity;
tracker->unsuspendable_fds = cds_lfht_new(DEFAULT_HT_SIZE, 1, 0,
CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
+ if (!tracker->unsuspendable_fds) {
+ ERR("Failed to create fd-tracker's unsuspendable_fds hash table");
+ goto error;
+ }
+ tracker->inode_registry = lttng_inode_registry_create();
+ if (!tracker->inode_registry) {
+ ERR("Failed to create fd-tracker's inode registry");
+ goto error;
+ }
DBG("File descriptor tracker created with a limit of %u simultaneously-opened FDs",
capacity);
end:
return tracker;
+error:
+ fd_tracker_destroy(tracker);
+ return NULL;
}
void fd_tracker_log(struct fd_tracker *tracker)
DBG_NO_LOC(" capacity: %u", tracker->capacity);
DBG_NO_LOC(" Tracked suspendable file descriptors");
- cds_list_for_each_entry(handle, &tracker->active_handles,
- handles_list_node) {
+ cds_list_for_each_entry (
+ handle, &tracker->active_handles, handles_list_node) {
fs_handle_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);
}
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",
+ DBG_NO_LOC(" %s [active, fd %d]",
+ unsuspendable_fd->name ?: "Unnamed",
unsuspendable_fd->fd);
}
rcu_read_unlock();
}
pthread_mutex_unlock(&tracker->lock);
- ret = cds_lfht_destroy(tracker->unsuspendable_fds, NULL);
- assert(!ret);
+ if (tracker->unsuspendable_fds) {
+ ret = cds_lfht_destroy(tracker->unsuspendable_fds, NULL);
+ assert(!ret);
+ }
+
+ lttng_inode_registry_destroy(tracker->inode_registry);
pthread_mutex_destroy(&tracker->lock);
free(tracker);
end:
}
struct fs_handle *fd_tracker_open_fs_handle(struct fd_tracker *tracker,
- const char *path, int flags, mode_t *mode)
+ const char *path,
+ int flags,
+ mode_t *mode)
{
int ret;
struct fs_handle *handle = NULL;
struct stat fd_stat;
struct open_properties properties = {
- .path = strdup(path),
.flags = flags,
.mode.is_set = !!mode,
.mode.value = mode ? *mode : 0,
};
- if (!properties.path) {
- goto end;
- }
-
pthread_mutex_lock(&tracker->lock);
if (ACTIVE_COUNT(tracker) == tracker->capacity) {
if (tracker->count.suspendable.active > 0) {
ret = fd_tracker_suspend_handles(tracker, 1);
if (ret) {
- goto error_destroy;
+ goto end;
}
} else {
/*
* There are not enough active suspendable file
- * descriptors to open a new fd and still accomodate the
- * tracker's capacity.
+ * descriptors to open a new fd and still accommodate
+ * the tracker's capacity.
*/
WARN("Cannot open file system handle, too many unsuspendable file descriptors are opened (%u)",
tracker->count.unsuspendable);
- ret = -EMFILE;
- goto error_destroy;
+ goto end;
}
}
if (!handle) {
goto end;
}
+ handle->tracker = tracker;
ret = pthread_mutex_init(&handle->lock, NULL);
if (ret) {
PERROR("Failed to initialize handle mutex while creating fs handle");
- free(handle);
- goto end;
+ goto error_mutex_init;
}
- handle->fd = open_from_properties(&properties);
+ handle->fd = open_from_properties(path, &properties);
if (handle->fd < 0) {
PERROR("Failed to open fs handle to %s, open() returned", path);
- ret = -errno;
- goto error_destroy;
+ goto error;
}
handle->properties = properties;
- properties.path = NULL;
+
+ handle->inode = lttng_inode_registry_get_inode(
+ tracker->inode_registry, handle->fd, path);
+ if (!handle->inode) {
+ ERR("Failed to get lttng_inode corresponding to file %s", path);
+ goto error;
+ }
if (fstat(handle->fd, &fd_stat)) {
PERROR("Failed to retrieve file descriptor inode while creating fs handle, fstat() returned");
- ret = -errno;
- goto error_destroy;
+ goto error;
}
handle->ino = fd_stat.st_ino;
fd_tracker_track(tracker, handle);
- handle->tracker = tracker;
- pthread_mutex_unlock(&tracker->lock);
end:
- free(properties.path);
- return handle;
-error_destroy:
pthread_mutex_unlock(&tracker->lock);
- (void) fs_handle_close(handle);
+ return handle;
+error:
+ if (handle->inode) {
+ lttng_inode_put(handle->inode);
+ }
+ pthread_mutex_destroy(&handle->lock);
+error_mutex_init:
+ free(handle);
handle = NULL;
goto end;
}
/* Caller must hold the tracker's lock. */
-static
-int fd_tracker_suspend_handles(struct fd_tracker *tracker,
- unsigned int count)
+static int fd_tracker_suspend_handles(
+ struct fd_tracker *tracker, unsigned int count)
{
unsigned int left_to_close = count;
struct fs_handle *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;
}
int fd_tracker_open_unsuspendable_fd(struct fd_tracker *tracker,
- int *out_fds, const char **names, unsigned int fd_count,
- fd_open_cb open, void *user_data)
+ int *out_fds,
+ const char **names,
+ unsigned int fd_count,
+ fd_open_cb open,
+ void *user_data)
{
int ret, user_ret, i, fds_to_suspend;
unsigned int active_fds;
pthread_mutex_lock(&tracker->lock);
active_fds = ACTIVE_COUNT(tracker);
- fds_to_suspend = (int) active_fds + (int) fd_count - (int) tracker->capacity;
+ fds_to_suspend = (int) active_fds + (int) fd_count -
+ (int) tracker->capacity;
if (fds_to_suspend > 0) {
if (fds_to_suspend <= tracker->count.suspendable.active) {
- ret = fd_tracker_suspend_handles(tracker, fds_to_suspend);
+ ret = fd_tracker_suspend_handles(
+ tracker, fds_to_suspend);
if (ret) {
goto end;
}
* of unsuspendable fds.
*/
for (i = 0; i < fd_count; i++) {
- struct unsuspendable_fd *entry =
- unsuspendable_fd_create(names ? names[i] : NULL,
- out_fds[i]);
+ struct unsuspendable_fd *entry = unsuspendable_fd_create(
+ names ? names[i] : NULL, out_fds[i]);
if (!entry) {
ret = -1;
struct cds_lfht_node *node;
struct unsuspendable_fd *entry = entries[i];
- node = cds_lfht_add_unique(
- tracker->unsuspendable_fds,
- hash_key_ulong((void *) (unsigned long) out_fds[i],
+ node = cds_lfht_add_unique(tracker->unsuspendable_fds,
+ hash_key_ulong((void *) (unsigned long)
+ out_fds[i],
seed.value),
- match_fd,
- (void *) (unsigned long) out_fds[i],
+ match_fd, (void *) (unsigned long) out_fds[i],
&entry->tracker_node);
if (node != &entry->tracker_node) {
}
int fd_tracker_close_unsuspendable_fd(struct fd_tracker *tracker,
- int *fds_in, unsigned int fd_count, fd_close_cb close,
+ int *fds_in,
+ unsigned int fd_count,
+ fd_close_cb close,
void *user_data)
{
int i, ret, user_ret;
cds_lfht_lookup(tracker->unsuspendable_fds,
hash_key_ulong((void *) (unsigned long) fds[i],
seed.value),
- match_fd,
- (void *) (unsigned long) fds[i],
+ match_fd, (void *) (unsigned long) fds[i],
&iter);
node = cds_lfht_iter_get_node(&iter);
if (!node) {
ret = -EINVAL;
goto end;
}
- entry = caa_container_of(node,
- struct unsuspendable_fd,
- tracker_node);
+ entry = caa_container_of(
+ node, struct unsuspendable_fd, tracker_node);
cds_lfht_del(tracker->unsuspendable_fds, node);
unsuspendable_fd_destroy(entry);
}
/* Caller must have taken the tracker's and handle's locks. */
-static
-void fd_tracker_track(struct fd_tracker *tracker, struct fs_handle *handle)
+static void fd_tracker_track(
+ struct fd_tracker *tracker, struct fs_handle *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)
+static void fd_tracker_untrack(
+ struct fd_tracker *tracker, struct fs_handle *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)
+static int fd_tracker_restore_handle(
+ struct fd_tracker *tracker, struct fs_handle *handle)
{
int ret;
pthread_mutex_unlock(&handle->lock);
}
+int fs_handle_unlink(struct fs_handle *handle)
+{
+ int ret;
+
+ pthread_mutex_lock(&handle->tracker->lock);
+ pthread_mutex_lock(&handle->lock);
+ ret = lttng_inode_defer_unlink(handle->inode);
+ pthread_mutex_unlock(&handle->lock);
+ pthread_mutex_unlock(&handle->tracker->lock);
+ return ret;
+}
+
int fs_handle_close(struct fs_handle *handle)
{
int ret = 0;
+ const char *path = NULL;
if (!handle) {
ret = -EINVAL;
pthread_mutex_lock(&handle->tracker->lock);
pthread_mutex_lock(&handle->lock);
+ if (handle->inode) {
+ path = lttng_inode_get_path(handle->inode);
+ }
fd_tracker_untrack(handle->tracker, handle);
if (handle->fd >= 0) {
/*
*/
if (close(handle->fd)) {
PERROR("Failed to close the file descritptor (%d) of fs handle to %s, close() returned",
- handle->fd, handle->properties.path);
+ handle->fd, path ? path : "Unknown");
}
handle->fd = -1;
}
+ if (handle->inode) {
+ lttng_inode_put(handle->inode);
+ }
pthread_mutex_unlock(&handle->lock);
pthread_mutex_destroy(&handle->lock);
pthread_mutex_unlock(&handle->tracker->lock);
- free(handle->properties.path);
free(handle);
end:
return ret;