X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Fcommon%2Ffd-tracker%2Ffd-tracker.c;h=2cf26f723234a382ae1355468af8a130dc5b61ce;hb=f5a2cd657eb3a81a8788438d796e906148a1b3b1;hp=0331f56d0ac2cb2935e0ed9964cd19ae1f398cec;hpb=0ad3c26c35b54c48c152af0ce409750d8958c5b1;p=deliverable%2Flttng-tools.git diff --git a/src/common/fd-tracker/fd-tracker.c b/src/common/fd-tracker/fd-tracker.c index 0331f56d0..2cf26f723 100644 --- a/src/common/fd-tracker/fd-tracker.c +++ b/src/common/fd-tracker/fd-tracker.c @@ -15,7 +15,6 @@ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #include #include #include @@ -34,6 +33,7 @@ #include "common/hashtable/hashtable.h" #include "fd-tracker.h" +#include "inode.h" /* Tracker lock must be taken by the user. */ #define TRACKED_COUNT(tracker) \ @@ -85,10 +85,10 @@ struct fd_tracker { 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; @@ -113,6 +113,7 @@ struct fs_handle { */ 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; @@ -130,6 +131,7 @@ struct unsuspendable_fd { int fd; char *name; struct cds_lfht_node tracker_node; + struct rcu_head rcu_head; }; static struct { @@ -144,7 +146,8 @@ 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 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); @@ -170,14 +173,23 @@ int match_fd(struct cds_lfht_node *node, const void *key) (void *) key); } +static +void delete_unsuspendable_fd(struct rcu_head *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) { if (!entry) { return; } - free(entry->name); - free(entry); + call_rcu(&entry->rcu_head, delete_unsuspendable_fd); } static @@ -206,25 +218,32 @@ error: 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, + 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); } +/* 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. */ @@ -232,10 +251,10 @@ int fs_handle_suspend(struct fs_handle *handle) 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); + path); ret = -errno; goto end; } @@ -243,7 +262,7 @@ int fs_handle_suspend(struct fs_handle *handle) 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; } @@ -251,7 +270,7 @@ int fs_handle_suspend(struct fs_handle *handle) 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; } @@ -259,12 +278,12 @@ int fs_handle_suspend(struct fs_handle *handle) ret = close(handle->fd); if (ret) { PERROR("Filesystem handle to %s cannot be suspended as close() failed", - handle->properties.path); + 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) { @@ -279,12 +298,15 @@ 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); + path); ret = -errno; goto end; } @@ -293,12 +315,12 @@ int fs_handle_restore(struct fs_handle *handle) ret = lseek(fd, handle->offset, SEEK_SET); if (ret < 0) { PERROR("Failed to restore filesystem handle to %s, lseek() failed", - handle->properties.path); + 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; @@ -310,7 +332,7 @@ end: } static -int open_from_properties(struct open_properties *properties) +int open_from_properties(const char *path, struct open_properties *properties) { int ret; @@ -321,10 +343,10 @@ int open_from_properties(struct open_properties *properties) * thus it is ignored here. */ if ((properties->flags & O_CREAT) && properties->mode.is_set) { - ret = open(properties->path, properties->flags, + 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 @@ -365,8 +387,22 @@ struct fd_tracker *fd_tracker_create(unsigned int capacity) 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) @@ -435,8 +471,12 @@ int fd_tracker_destroy(struct fd_tracker *tracker) } 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: @@ -450,33 +490,27 @@ struct fs_handle *fd_tracker_open_fs_handle(struct fd_tracker *tracker, 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; } } @@ -484,45 +518,47 @@ struct fs_handle *fd_tracker_open_fs_handle(struct fd_tracker *tracker, 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; } - /* - * Clear the create flag from the open flags as it would make no sense - * to use it when restoring a fs handle. - */ - properties.flags &= ~O_CREAT; 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; } @@ -752,6 +788,17 @@ int fs_handle_get_fd(struct fs_handle *handle) { int ret; + /* + * TODO This should be optimized as it is a fairly hot path. + * The fd-tracker's lock should only be taken when a fs_handle is + * restored (slow path). On the fast path (fs_handle is active), + * the only effect on the fd_tracker is marking the handle as the + * most recently used. Currently, it is done by a call to the + * track/untrack helpers, but it should be done atomically. + * + * Note that the lock's nesting order must still be respected here. + * The handle's lock nests inside the tracker's lock. + */ pthread_mutex_lock(&handle->tracker->lock); pthread_mutex_lock(&handle->lock); assert(!handle->in_use); @@ -784,9 +831,22 @@ void fs_handle_put_fd(struct fs_handle *handle) 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; @@ -795,22 +855,26 @@ int fs_handle_close(struct fs_handle *handle) 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) { + assert(!handle->in_use); /* * The return value of close() is not propagated as there * isn't much the user can do about it. */ 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; } + 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;