summaryrefslogtreecommitdiffstats
path: root/xlators/performance
diff options
context:
space:
mode:
authorRaghavendra G <raghavendra@gluster.com>2009-09-10 07:41:14 +0000
committerAnand V. Avati <avati@dev.gluster.com>2009-09-13 22:10:38 -0700
commit62d30db76e118cb244c35b6acc15005474d77750 (patch)
tree6a8eac18e3c1d9d81c624a97b11d19ee3a1388fa /xlators/performance
parentdd149ca8e7757e6e935c6481be8fd4fee9d13790 (diff)
backport stat-prefetch from 2.1
Signed-off-by: Anand V. Avati <avati@dev.gluster.com> BUG: 257 (Backport stat-prefetch to 2.0) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=257
Diffstat (limited to 'xlators/performance')
-rw-r--r--xlators/performance/Makefile.am2
-rw-r--r--xlators/performance/stat-prefetch/src/Makefile.am11
-rw-r--r--xlators/performance/stat-prefetch/src/stat-prefetch.c2078
-rw-r--r--xlators/performance/stat-prefetch/src/stat-prefetch.h57
4 files changed, 1763 insertions, 385 deletions
diff --git a/xlators/performance/Makefile.am b/xlators/performance/Makefile.am
index f7504bbe8f3..5caa59f327f 100644
--- a/xlators/performance/Makefile.am
+++ b/xlators/performance/Makefile.am
@@ -1,3 +1,3 @@
-SUBDIRS = write-behind read-ahead io-threads io-cache symlink-cache
+SUBDIRS = write-behind read-ahead io-threads io-cache symlink-cache stat-prefetch
CLEANFILES =
diff --git a/xlators/performance/stat-prefetch/src/Makefile.am b/xlators/performance/stat-prefetch/src/Makefile.am
index e52f2df48fd..b16c133a1ab 100644
--- a/xlators/performance/stat-prefetch/src/Makefile.am
+++ b/xlators/performance/stat-prefetch/src/Makefile.am
@@ -1,11 +1,14 @@
-xlator_PROGRAMS = stat-prefetch.so
+xlator_LTLIBRARIES = stat-prefetch.la
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/performance
-stat_prefetch_so_SOURCES = stat-prefetch.c
+stat_prefetch_la_LDFLAGS = -module -avoidversion
+stat_prefetch_la_SOURCES = stat-prefetch.c
noinst_HEADERS = stat-prefetch.h
-AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall \
- -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles
+stat_prefetch_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
+
+AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS)\
+ -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles $(GF_CFLAGS)
CLEANFILES =
diff --git a/xlators/performance/stat-prefetch/src/stat-prefetch.c b/xlators/performance/stat-prefetch/src/stat-prefetch.c
index c6bf1e684cf..57bed9a52a7 100644
--- a/xlators/performance/stat-prefetch/src/stat-prefetch.c
+++ b/xlators/performance/stat-prefetch/src/stat-prefetch.c
@@ -1,508 +1,1838 @@
/*
- Copyright (c) 2006-2009 Z RESEARCH, Inc. <http://www.zresearch.com>
- This file is part of GlusterFS.
-
- GlusterFS is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- GlusterFS 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
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see
- <http://www.gnu.org/licenses/>.
+ Copyright (c) 2009-2010 Z RESEARCH, Inc. <http://www.zresearch.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
*/
-#ifndef _CONFIG_H
-#define _CONFIG_H
-#include "config.h"
-#endif
-
-#include "glusterfs.h"
#include "stat-prefetch.h"
-#include "dict.h"
-#include "xlator.h"
-#include <sys/time.h>
-
-struct sp_cache {
- struct sp_cache *next;
- struct sp_cache *prev;
- pid_t pid;
- long long tv_time;
- char *dirname;
- dir_entry_t entries;
- int32_t count;
- pthread_mutex_t lock;
-};
+#include "locking.h"
+#include "inode.h"
+#include <libgen.h>
+
-static void
-stat_prefetch_cache_flush (struct sp_cache *cache, int32_t force)
+sp_cache_t *
+sp_cache_init (void)
{
- struct sp_cache *trav;
- struct timeval tv;
- long long tv_time;
+ sp_cache_t *cache = NULL;
- gettimeofday (&tv, NULL);
- tv_time = (tv.tv_usec + (tv.tv_sec * 1000000));
+ cache = CALLOC (1, sizeof (*cache));
+ if (cache) {
+ INIT_LIST_HEAD (&cache->entries.list);
+ LOCK_INIT (&cache->lock);
+ }
- pthread_mutex_lock (&cache->lock);
+ return cache;
+}
- trav = cache->next;
- while (trav != cache) {
- struct sp_cache *next = trav->next;
- {
- if (tv_time > trav->tv_time || force) {
- gf_log ("stat-prefetch",
- GF_LOG_DEBUG,
- "flush on: %s",
- trav->dirname);
- dir_entry_t *entries;
+
+void
+sp_local_free (sp_local_t *local)
+{
+ if (local) {
+ loc_wipe (&local->loc);
+ FREE (local);
+ }
+}
- trav->prev->next = trav->next;
- trav->next->prev = trav->prev;
- entries = trav->entries.next;
+int32_t
+sp_cache_remove_entry (sp_cache_t *cache, char *name, char remove_all)
+{
+ int32_t ret = -1;
+ gf_dirent_t *entry = NULL, *tmp = NULL;
+
+ if ((cache == NULL) || ((name == NULL) && !remove_all)) {
+ goto out;
+ }
+
+ LOCK (&cache->lock);
+ {
+ list_for_each_entry_safe (entry, tmp, &cache->entries.list,
+ list) {
+ if (remove_all || (!strcmp (name, entry->d_name))) {
+ list_del_init (&entry->list);
+ FREE (entry);
+ ret = 0;
+
+ if (!remove_all) {
+ break;
+ }
+ }
+ }
+ }
+ UNLOCK (&cache->lock);
+
+out:
+ return ret;
+}
+
- while (entries) {
- dir_entry_t *nextentry = entries->next;
- {
- free (entries->name);
- free (entries);
- }
- entries = nextentry;
- }
- free (trav->dirname);
- free (trav);
- }
- }
- trav = next;
- }
+int32_t
+sp_cache_get_entry (sp_cache_t *cache, char *name, gf_dirent_t *entry)
+{
+ int32_t ret = -1;
+ gf_dirent_t *tmp = NULL;
+
+ if ((cache == NULL) || (name == NULL) || (entry == NULL)) {
+ goto out;
+ }
+
+ LOCK (&cache->lock);
+ {
+ list_for_each_entry (tmp, &cache->entries.list, list) {
+ if (!strcmp (name, tmp->d_name)) {
+ memcpy (entry, tmp, sizeof (*entry));
+ ret = 0;
+ break;
+ }
+ }
+
+ }
+ UNLOCK (&cache->lock);
+
+out:
+ return ret;
+}
+
- pthread_mutex_unlock (&cache->lock);
+void
+sp_cache_free (sp_cache_t *cache)
+{
+ sp_cache_remove_entry (cache, NULL, 1);
+ FREE (cache);
}
-static int32_t
-stat_prefetch_cache_fill (struct sp_cache *cache,
- pid_t pid,
- char *dirname,
- dir_entry_t *entries)
-{
- struct sp_cache *trav;
- struct timeval tv;
-
- pthread_mutex_unlock (&cache->lock);
- trav = cache->next;
- while (trav != cache) {
- // if (trav->pid == pid && !strcmp (trav->dirname, dirname)) {
- if (!strcmp (trav->dirname, dirname)) {
- break;
- }
- trav = trav->next;
- }
-
- if (trav == cache) {
- trav = CALLOC (1, sizeof (*trav));
- ERR_ABORT (trav);
- trav->pid = pid;
- trav->dirname = dirname;
-
- trav->prev = cache->prev;
- trav->next = cache;
- trav->next->prev = trav;
- trav->prev->next = trav;
- } else {
- free (dirname);
- }
-
- while (trav->entries.next) {
- dir_entry_t *tmp = trav->entries.next;
-
- trav->entries.next = trav->entries.next->next;
- free (tmp->name);
- free (tmp);
- }
- trav->entries.next = entries->next;
- entries->next = NULL;
-
- gettimeofday (&tv, NULL);
- trav->tv_time = (tv.tv_usec + (tv.tv_sec * 1000000)) + cache->tv_time;
-
- pthread_mutex_unlock (&cache->lock);
- return 0;
+
+sp_cache_t *
+sp_get_cache_fd (xlator_t *this, fd_t *fd)
+{
+ sp_cache_t *cache = NULL;
+ uint64_t value = 0;
+ int32_t ret = -1;
+ sp_fd_ctx_t *fd_ctx = NULL;
+
+ if (fd == NULL) {
+ goto out;
+ }
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == -1) {
+ goto out;
+ }
+
+ fd_ctx = (void *)(long) value;
+
+ LOCK (&fd_ctx->lock);
+ {
+ cache = fd_ctx->cache;
+ }
+ UNLOCK (&fd_ctx->lock);
+out:
+ return cache;
+}
+
+
+void
+sp_fd_ctx_free (sp_fd_ctx_t *fd_ctx)
+{
+ if (fd_ctx == NULL) {
+ goto out;
+ }
+
+ if (fd_ctx->parent_inode) {
+ inode_unref (fd_ctx->parent_inode);
+ fd_ctx->parent_inode = NULL;
+ }
+
+ if (fd_ctx->name) {
+ FREE (fd_ctx->name);
+ fd_ctx->name = NULL;
+ }
+
+ if (fd_ctx->cache) {
+ sp_cache_free (fd_ctx->cache);
+ }
+
+ FREE (fd_ctx);
+out:
+ return;
+}
+
+
+inline sp_fd_ctx_t *
+sp_fd_ctx_init (void)
+{
+ sp_fd_ctx_t *fd_ctx = NULL;
+
+ fd_ctx = CALLOC (1, sizeof (*fd_ctx));
+ if (fd_ctx) {
+ LOCK_INIT (&fd_ctx->lock);
+ }
+
+ return fd_ctx;
}
+
+sp_fd_ctx_t *
+sp_fd_ctx_new (xlator_t *this, inode_t *parent, char *name, sp_cache_t *cache)
+{
+ sp_fd_ctx_t *fd_ctx = NULL;
+
+ fd_ctx = sp_fd_ctx_init ();
+ if (fd_ctx == NULL) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto out;
+ }
+
+ if (parent) {
+ fd_ctx->parent_inode = inode_ref (parent);
+ }
+
+ if (name) {
+ fd_ctx->name = strdup (name);
+ if (fd_ctx->name == NULL) {
+ sp_fd_ctx_free (fd_ctx);
+ fd_ctx = NULL;
+ }
+ }
+
+ fd_ctx->cache = cache;
+
+out:
+ return fd_ctx;
+}
+
+
+sp_cache_t *
+sp_del_cache_fd (xlator_t *this, fd_t *fd)
+{
+ sp_cache_t *cache = NULL;
+ uint64_t value = 0;
+ int32_t ret = -1;
+ sp_fd_ctx_t *fd_ctx = NULL;
+
+ if (fd == NULL) {
+ goto out;
+ }
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == -1) {
+ goto out;
+ }
+
+ fd_ctx = (void *)(long) value;
+
+ LOCK (&fd_ctx->lock);
+ {
+ cache = fd_ctx->cache;
+ fd_ctx->cache = NULL;
+ }
+ UNLOCK (&fd_ctx->lock);
+
+out:
+ return cache;
+}
+
+
+sp_cache_t *
+sp_get_cache_inode (xlator_t *this, inode_t *inode, int32_t pid)
+{
+ fd_t *fd = NULL;
+ sp_cache_t *cache = NULL;
+
+ if (inode == NULL) {
+ goto out;
+ }
+
+ fd = fd_lookup (inode, pid);
+ if (fd == NULL) {
+ goto out;
+ }
+
+ cache = sp_get_cache_fd (this, fd);
+out:
+ return cache;
+}
+
+
+inline int32_t
+sp_put_cache (xlator_t *this, fd_t *fd, sp_cache_t *cache)
+{
+ sp_fd_ctx_t *fd_ctx = NULL;
+ int32_t ret = -1;
+ uint64_t value = 0;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (!ret) {
+ fd_ctx = (void *)(long)value;
+ } else {
+ fd_ctx = sp_fd_ctx_init ();
+ if (fd_ctx == NULL) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ ret = -1;
+ goto out;
+ }
+
+ ret = fd_ctx_set (fd, this, (long)(void *)fd_ctx);
+ if (ret == -1) {
+ sp_fd_ctx_free (fd_ctx);
+ goto out;
+ }
+ }
+
+ LOCK (&fd_ctx->lock);
+ {
+ if (fd_ctx->cache) {
+ sp_cache_free (fd_ctx->cache);
+ }
+
+ fd_ctx->cache = cache;
+ }
+ UNLOCK (&fd_ctx->lock);
+
+out:
+ return ret;
+}
+
+
+int32_t
+sp_cache_add_entries (sp_cache_t *cache, gf_dirent_t *entries)
+{
+ gf_dirent_t copy;
+ gf_dirent_t *entry = NULL, *new = NULL;
+ int32_t ret = -1;
+ uint64_t expected_offset = 0;
+
+ memset (&copy, 0, sizeof (copy));
+ INIT_LIST_HEAD (&copy.list);
+
+ LOCK (&cache->lock);
+ {
+ list_for_each_entry (entry, &entries->list, list) {
+ new = gf_dirent_for_name (entry->d_name);
+ if (new == NULL) {
+ gf_dirent_free (&copy);
+ goto unlock;
+ }
+
+ new->d_ino = entry->d_ino;
+ new->d_off = entry->d_off;
+ new->d_len = entry->d_len;
+ new->d_type = entry->d_type;
+ new->d_stat = entry->d_stat;
+
+ list_add_tail (&new->list, &copy.list);
+
+ expected_offset = new->d_off;
+ }
+
+ /*
+ * splice entries in cache to copy, so that we have a list in
+ * ascending order of offsets
+ */
+ list_splice_init (&cache->entries.list, &copy.list);
+
+ /* splice back the copy into cache */
+ list_splice_init (&copy.list, &cache->entries.list);
+
+ cache->expected_offset = expected_offset;
+
+ ret = 0;
+ }
+unlock:
+ UNLOCK (&cache->lock);
+
+ return ret;
+}
+
+
+int32_t
+sp_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct stat *buf, dict_t *dict)
+{
+ struct stat *stbuf = NULL;
+ int32_t ret = -1;
+
+ if (op_ret == -1) {
+ goto out;
+ }
+
+ if (S_ISDIR (buf->st_mode)) {
+ stbuf = CALLOC (1, sizeof (*stbuf));
+ if (stbuf == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto out;
+ }
+
+ memcpy (stbuf, buf, sizeof (*stbuf));
+ ret = inode_ctx_put (inode, this, (long)stbuf);
+ if (ret == -1) {
+ op_ret = -1;
+
+ /* FIXME: EINVAL is not correct */
+ op_errno = EINVAL;
+ FREE (stbuf);
+ goto out;
+ }
+ }
+
+out:
+ SP_STACK_UNWIND (frame, op_ret, op_errno, inode, buf, dict);
+ return 0;
+}
+
+
+int32_t
+sp_lookup_behind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct stat *buf, dict_t *dict)
+{
+ sp_local_t *local = NULL;
+ sp_cache_t *cache = NULL;
+
+ local = frame->local;
+ if (local == NULL) {
+ goto out;
+ }
+
+ if ((op_ret == -1) && (op_errno = ENOENT)) {
+ cache = sp_get_cache_inode (this, local->loc.parent,
+ frame->root->pid);
+
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)local->loc.name,
+ 0);
+ }
+ }
+
+out:
+ SP_STACK_DESTROY (frame);
+ return 0;
+}
+
+
+int32_t
+sp_get_ancestors (char *path, char **parent, char **grand_parent)
+{
+ int32_t ret = -1, i = 0;
+ char *cpy = NULL;
+
+ if (!path || !parent || !grand_parent) {
+ ret = 0;
+ goto out;
+ }
+
+ for (i = 0; i < 2; i++) {
+ if (!strcmp (path, "/")) {
+ break;
+ }
+
+ cpy = strdup (path);
+ if (cpy == NULL) {
+ goto out;
+ }
+
+ path = dirname (cpy);
+ switch (i)
+ {
+ case 0:
+ *parent = path;
+ break;
+ case 1:
+ *grand_parent = path;
+ break;
+ }
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+
+int32_t
+sp_cache_remove_parent_entry (call_frame_t *frame, xlator_t *this, char *path)
+{
+ char *parent = NULL, *grand_parent = NULL, *cpy = NULL;
+ inode_t *inode_gp = NULL;
+ sp_cache_t *cache_gp = NULL;
+ int32_t ret = -1;
+
+ ret = sp_get_ancestors (path, &parent, &grand_parent);
+ if (ret == -1) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto out;
+ }
+
+ if (grand_parent && strcmp (grand_parent, "/")) {
+ inode_gp = inode_from_path (frame->root->frames.this->itable,
+ grand_parent);
+ if (inode_gp) {
+ cache_gp = sp_get_cache_inode (this, inode_gp,
+ frame->root->pid);
+ if (cache_gp) {
+ cpy = strdup (parent);
+ GF_VALIDATE_OR_GOTO_WITH_ERROR (this->name,
+ cpy, out,
+ ENOMEM);
+ path = basename (cpy);
+ sp_cache_remove_entry (cache_gp, path, 0);
+ FREE (cpy);
+ }
+ inode_unref (inode_gp);
+ }
+ }
+
+ ret = 0;
+out:
+ if (parent) {
+ FREE (parent);
+ }
+
+ if (grand_parent) {
+ FREE (grand_parent);
+ }
+
+ return ret;
+}
+
+
+int32_t
+sp_lookup (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xattr_req)
+{
+ sp_local_t *local = NULL;
+ gf_dirent_t dirent;
+ int32_t ret = -1, op_ret = -1, op_errno = EINVAL;
+ sp_cache_t *cache = NULL;
+ struct stat *postparent = NULL, *buf = NULL;
+ uint64_t value = 0;
+ call_frame_t *wind_frame = NULL;
+ char lookup_behind = 0;
+
+ if (loc == NULL) {
+ goto unwind;
+ }
+
+ if (xattr_req || (loc->parent == NULL) || (loc->name == NULL)) {
+ goto wind;
+ }
+
+ memset (&dirent, 0, sizeof (dirent));
+ cache = sp_get_cache_inode (this, loc->parent, frame->root->pid);
+ if (cache) {
+ ret = sp_cache_get_entry (cache, (char *)loc->name, &dirent);
+ if (ret == 0) {
+ ret = inode_ctx_get (loc->parent, this, &value);
+ if (ret == 0) {
+ postparent = (void *)(long)value;
+ buf = &dirent.d_stat;
+ op_ret = 0;
+ op_errno = 0;
+ lookup_behind = 1;
+ }
+ }
+ }
+
+wind:
+ if (lookup_behind) {
+ wind_frame = copy_frame (frame);
+ if (wind_frame == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
+
+ local = CALLOC (1, sizeof (*local));
+ if (local == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ STACK_DESTROY (wind_frame->root);
+ goto unwind;
+ }
+
+ loc_copy (&local->loc, loc);
+ wind_frame->local = local;
+ STACK_WIND (wind_frame, sp_lookup_behind_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->lookup, loc, xattr_req);
+ } else {
+ STACK_WIND (frame, sp_lookup_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->lookup, loc, xattr_req);
+
+ return 0;
+ }
+
+unwind:
+ SP_STACK_UNWIND (frame, op_ret, op_errno, loc->inode, buf, postparent,
+ NULL);
+ return 0;
+
+}
+
+
+int32_t
+sp_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, gf_dirent_t *entries)
+{
+ sp_local_t *local = NULL;
+ sp_cache_t *cache = NULL;
+ fd_t *fd = NULL;
+ int32_t ret = 0;
+
+ local = frame->local;
+ if (local == NULL) {
+ goto out;
+ }
+
+ fd = local->fd;
+
+ cache = sp_get_cache_fd (this, fd);
+ if (cache == NULL) {
+ cache = sp_cache_init ();
+ if (cache == NULL) {
+ goto out;
+ }
+
+ ret = sp_put_cache (this, fd, cache);
+ if (ret == -1) {
+ sp_cache_free (cache);
+ goto out;
+ }
+ }
+
+ sp_cache_add_entries (cache, entries);
+
+out:
+ SP_STACK_UNWIND (frame, op_ret, op_errno, entries);
+ return 0;
+}
+
+
+int32_t
+sp_readdir (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
+ off_t off)
+{
+ sp_cache_t *cache = NULL;
+ sp_local_t *local = NULL;
+ char *path = NULL;
+ int32_t ret = -1;
+
+ cache = sp_get_cache_fd (this, fd);
+ if (cache) {
+ if (off != cache->expected_offset) {
+ cache = sp_del_cache_fd (this, fd);
+ if (cache) {
+ sp_cache_free (cache);
+ }
+ }
+ }
+
+ ret = inode_path (fd->inode, NULL, &path);
+ if (ret == -1) {
+ goto unwind;
+ }
+
+ ret = sp_cache_remove_parent_entry (frame, this, path);
+ if (ret < 0) {
+ errno = -ret;
+ goto unwind;
+ }
+
+ local = CALLOC (1, sizeof (*local));
+ if (local) {
+ local->fd = fd;
+ frame->local = local;
+ }
+
+ STACK_WIND (frame, sp_readdir_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->readdir, fd, size, off);
+
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
+}
+
+
+int32_t
+sp_stbuf_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
+ int32_t op_errno, struct stat *buf)
+{
+ SP_STACK_UNWIND (frame, op_ret, op_errno, buf);
+ return 0;
+}
+
+
+int32_t
+sp_chmod (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode)
+{
+ sp_cache_t *cache = NULL;
+
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
+
+ cache = sp_get_cache_inode (this, loc->parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)loc->name, 0);
+ }
+
+ STACK_WIND (frame, sp_stbuf_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->chmod, loc, mode);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
+}
+
+
+int32_t
+sp_fd_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
+ int32_t op_errno, fd_t *fd)
+{
+ sp_local_t *local = NULL;
+ sp_fd_ctx_t *fd_ctx = NULL;
+
+ if (op_ret == -1) {
+ goto out;
+ }
+
+ local = frame->local;
+ GF_VALIDATE_OR_GOTO_WITH_ERROR (this->name, local, out, EINVAL);
+
+ fd_ctx = sp_fd_ctx_new (this, local->loc.parent,
+ (char *)local->loc.name, NULL);
+ GF_VALIDATE_OR_GOTO_WITH_ERROR (this->name, fd_ctx, out, ENOMEM);
+
+ op_ret = fd_ctx_set (fd, this, (long)(void *)fd_ctx);
+ if (op_ret == -1) {
+ sp_fd_ctx_free (fd_ctx);
+ op_errno = ENOMEM;
+ }
+
+out:
+ SP_STACK_UNWIND (frame, op_ret, op_errno, fd);
+ return 0;
+}
+
+
+int32_t
+sp_open (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
+ fd_t *fd)
+{
+ sp_local_t *local = NULL;
+ int32_t ret = -1;
+
+ local = CALLOC (1, sizeof (*local));
+ GF_VALIDATE_OR_GOTO_WITH_ERROR (this->name, local, unwind, ENOMEM);
+
+ frame->local = local;
+
+ ret = loc_copy (&local->loc, loc);
+ if (ret == -1) {
+ goto unwind;
+ }
+
+ STACK_WIND (frame, sp_fd_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open, loc, flags, fd);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, fd);
+ return 0;
+}
+
+
static int32_t
-stat_prefetch_cache_lookup (struct sp_cache *cache,
- pid_t pid,
- const char *path,
- struct stat *buf)
-{
- struct sp_cache *trav;
- char *dirname = strdup (path);
- char *filename = strrchr (dirname, '/');
- dir_entry_t *entries;
- dir_entry_t *prev = NULL;
+sp_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, fd_t *fd, inode_t *inode,
+ struct stat *buf)
+{
+ sp_local_t *local = NULL;
+ sp_fd_ctx_t *fd_ctx = NULL;
- *filename = '\0';
- filename ++;
+ if (op_ret == -1) {
+ goto out;
+ }
- pthread_mutex_lock (&cache->lock);
- trav = cache->next;
- while (trav != cache) {
- // if ((trav->pid == pid) && !strcmp (dirname, trav->dirname))
- if (!strcmp (dirname, trav->dirname))
- break;
- trav = trav->next;
- }
- if (trav == cache) {
- free (dirname);
- pthread_mutex_unlock (&cache->lock);
- return -1;
- }
-
- entries = trav->entries.next;
- prev = &trav->entries;
- while (entries) {
- if (!strcmp (entries->name, filename))
- break;
- prev = entries;
- entries = entries->next;
- }
- if (!entries) {
- free (dirname);
- pthread_mutex_unlock (&cache->lock);
- return -1;
- }
+ local = frame->local;
+ GF_VALIDATE_OR_GOTO_WITH_ERROR (this->name, local, out, EINVAL);
- *buf = entries->buf;
- prev->next = entries->next;
- free (entries->name);
- free (entries);
- free (dirname);
+ fd_ctx = sp_fd_ctx_new (this, local->loc.parent,
+ (char *)local->loc.name, NULL);
+ GF_VALIDATE_OR_GOTO_WITH_ERROR (this->name, fd_ctx, out, ENOMEM);
- pthread_mutex_unlock (&cache->lock);
+ op_ret = fd_ctx_set (fd, this, (long)(void *)fd_ctx);
+ if (op_ret == -1) {
+ sp_fd_ctx_free (fd_ctx);
+ op_errno = ENOMEM;
+ }
- return 0;
+out:
+ SP_STACK_UNWIND (frame, op_ret, op_errno, fd, inode, buf);
+ return 0;
}
-
+
int32_t
-stat_prefetch_readdir_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno,
- dir_entry_t *entries,
- int32_t count)
+sp_create (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
+ mode_t mode, fd_t *fd)
{
- char *path = frame->local;
- pid_t pid = frame->root->pid;
- frame->local = NULL;
+ sp_local_t *local = NULL;
+ int32_t ret = -1;
+
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->path, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->inode, unwind);
+
+ ret = sp_cache_remove_parent_entry (frame, this, (char *)loc->path);
+ if (ret == -1) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
+
+ local = CALLOC (1, sizeof (*local));
+ GF_VALIDATE_OR_GOTO_WITH_ERROR (this->name, local, unwind, ENOMEM);
- STACK_UNWIND (frame, op_ret, op_errno, entries, count);
+ frame->local = local;
- if (op_ret == 0)
- stat_prefetch_cache_fill (this->private,
- pid,
- path,
- entries);
- else
- free (path);
+ ret = loc_copy (&local->loc, loc);
+ if (ret == -1) {
+ goto unwind;
+ }
- return 0;
+ STACK_WIND (frame, sp_create_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->create, loc, flags, mode, fd);
+
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, fd);
+ return 0;
}
+
int32_t
-stat_prefetch_readdir (call_frame_t *frame,
- xlator_t *this,
- const char *path)
+sp_opendir (call_frame_t *frame, xlator_t *this, loc_t *loc, fd_t *fd)
{
- stat_prefetch_cache_flush (this->private, 0);
+ sp_local_t *local = NULL;
+ int32_t ret = -1;
+
+ local = CALLOC (1, sizeof (*local));
+ GF_VALIDATE_OR_GOTO_WITH_ERROR (this->name, local, unwind, ENOMEM);
- frame->local = strdup (path);
- STACK_WIND (frame,
- stat_prefetch_readdir_cbk,
- FIRST_CHILD(this),
- FIRST_CHILD(this)->fops->readdir,
- path);
- return 0;
+ frame->local = local;
+
+ ret = loc_copy (&local->loc, loc);
+ if (ret == -1) {
+ goto unwind;
+ }
+
+ STACK_WIND (frame, sp_fd_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->opendir, loc, fd);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, fd);
+ return 0;
}
int32_t
-stat_prefetch_getattr_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno,
- struct stat *buf)
+sp_new_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct stat *buf)
{
- STACK_UNWIND (frame, op_ret, op_errno, buf);
- return 0;
+ STACK_UNWIND (frame, op_ret, op_errno, inode, buf);
+ return 0;
}
+
int32_t
-stat_prefetch_getattr (call_frame_t *frame,
- struct xlator *this,
- const char *path)
+sp_mkdir (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode)
{
- struct stat buf;
- pid_t pid = frame->root->pid;
- stat_prefetch_cache_flush (this->private, 0);
+ int32_t ret = 0;
- if (stat_prefetch_cache_lookup (this->private,
- pid,
- path,
- &buf) == 0) {
- STACK_UNWIND (frame, 0, 0, &buf);
- return 0;
- }
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->path, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->inode, unwind);
- STACK_WIND (frame,
- stat_prefetch_getattr_cbk,
- FIRST_CHILD(this),
- FIRST_CHILD(this)->fops->getattr,
- path);
+ ret = sp_cache_remove_parent_entry (frame, this, (char *)loc->path);
+ if (ret == -1) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
- return 0;
+ STACK_WIND (frame, sp_new_entry_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->mkdir, loc, mode);
+
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, loc->inode, NULL);
+ return 0;
}
int32_t
-stat_prefetch_unlink_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno)
+sp_mknod (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
+ dev_t rdev)
{
- STACK_UNWIND (frame, op_ret, op_errno);
- return 0;
+ int32_t ret = 0;
+
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->path, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->inode, unwind);
+
+ ret = sp_cache_remove_parent_entry (frame, this, (char *)loc->path);
+ if (ret == -1) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
+
+ STACK_WIND (frame, sp_new_entry_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->mknod, loc, mode, rdev);
+
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, loc->inode, NULL);
+ return 0;
+}
+
+
+int32_t
+sp_symlink (call_frame_t *frame, xlator_t *this, const char *linkpath,
+ loc_t *loc)
+{
+ int32_t ret = 0;
+
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->path, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->inode, unwind);
+
+ ret = sp_cache_remove_parent_entry (frame, this, (char *)loc->path);
+ if (ret == -1) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
+
+ STACK_WIND (frame, sp_new_entry_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->symlink, linkpath, loc);
+
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, loc->inode, NULL);
+ return 0;
}
+
int32_t
-stat_prefetch_unlink (call_frame_t *frame,
- struct xlator *this,
- const char *path)
+sp_link (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc)
{
- stat_prefetch_cache_flush (this->private, 1);
+ int32_t ret = 0;
- STACK_WIND (frame,
- stat_prefetch_unlink_cbk,
- FIRST_CHILD(this),
- FIRST_CHILD(this)->fops->unlink,
- path);
+ GF_VALIDATE_OR_GOTO (this->name, newloc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, newloc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, newloc->path, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, newloc->name, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, newloc->inode, unwind);
- return 0;
+ ret = sp_cache_remove_parent_entry (frame, this, (char *)newloc->path);
+ if (ret == -1) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
+
+ STACK_WIND (frame, sp_new_entry_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->link, oldloc, newloc);
+
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, oldloc->inode, NULL);
+ return 0;
}
int32_t
-stat_prefetch_chmod_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno,
- struct stat *buf)
+sp_fchmod (call_frame_t *frame, xlator_t *this, fd_t *fd, mode_t mode)
{
- STACK_UNWIND (frame, op_ret, op_errno, buf);
- return 0;
+ sp_fd_ctx_t *fd_ctx = NULL;
+ sp_cache_t *cache = NULL;
+ uint64_t value = 0;
+ int32_t ret = 0;
+ inode_t *parent = NULL;
+ char *name = NULL;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == -1) {
+ errno = EINVAL;
+ goto unwind;
+ }
+
+ fd_ctx = (void *)(long)value;
+ name = fd_ctx->name;
+ parent = fd_ctx->parent_inode;
+
+ cache = sp_get_cache_inode (this, parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, name, 0);
+ }
+
+ STACK_WIND (frame, sp_stbuf_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->fchmod, fd, mode);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
}
+
int32_t
-stat_prefetch_chmod (call_frame_t *frame,
- struct xlator *this,
- const char *path,
- mode_t mode)
+sp_chown (call_frame_t *frame, xlator_t *this, loc_t *loc, uid_t uid, gid_t gid)
{
- stat_prefetch_cache_flush (this->private, 1);
+ sp_cache_t *cache = NULL;
- STACK_WIND (frame,
- stat_prefetch_chmod_cbk,
- FIRST_CHILD(this),
- FIRST_CHILD(this)->fops->chmod,
- path,
- mode);
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
- return 0;
+ cache = sp_get_cache_inode (this, loc->parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)loc->name, 0);
+ }
+
+ STACK_WIND (frame, sp_stbuf_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->chown, loc, uid, gid);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
}
int32_t
-stat_prefetch_chown_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno,
- struct stat *buf)
+sp_fchown (call_frame_t *frame, xlator_t *this, fd_t *fd, uid_t uid, gid_t gid)
{
- STACK_UNWIND (frame, op_ret, op_errno, buf);
- return 0;
+ sp_fd_ctx_t *fd_ctx = NULL;
+ sp_cache_t *cache = NULL;
+ uint64_t value = 0;
+ int32_t ret = 0;
+ inode_t *parent = NULL;
+ char *name = NULL;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == -1) {
+ errno = EINVAL;
+ goto unwind;
+ }
+
+ fd_ctx = (void *)(long)value;
+ name = fd_ctx->name;
+ parent = fd_ctx->parent_inode;
+
+ cache = sp_get_cache_inode (this, parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, name, 0);
+ }
+
+ STACK_WIND (frame, sp_stbuf_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->fchown, fd, uid, gid);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
}
+
int32_t
-stat_prefetch_chown (call_frame_t *frame,
- struct xlator *this,
- const char *path,
- uid_t uid,
- gid_t gid)
+sp_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset)
{
- stat_prefetch_cache_flush (this->private, 1);
+ sp_cache_t *cache = NULL;
+
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
+
+ cache = sp_get_cache_inode (this, loc->parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)loc->name, 0);
+ }
- STACK_WIND (frame,
- stat_prefetch_chown_cbk,
- FIRST_CHILD(this),
- FIRST_CHILD(this)->fops->chown,
- path,
- uid,
- gid);
+ STACK_WIND (frame, sp_stbuf_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->truncate, loc, offset);
+ return 0;
- return 0;
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
}
int32_t
-stat_prefetch_utimes_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno,
- struct stat *buf)
+sp_ftruncate (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset)
{
- STACK_UNWIND (frame, op_ret, op_errno, buf);
- return 0;
+ sp_fd_ctx_t *fd_ctx = NULL;
+ sp_cache_t *cache = NULL;
+ uint64_t value = 0;
+ int32_t ret = 0;
+ inode_t *parent = NULL;
+ char *name = NULL;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == -1) {
+ errno = EINVAL;
+ goto unwind;
+ }
+
+ fd_ctx = (void *)(long)value;
+ name = fd_ctx->name;
+ parent = fd_ctx->parent_inode;
+
+ cache = sp_get_cache_inode (this, parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, name, 0);
+ }
+
+ STACK_WIND (frame, sp_stbuf_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->ftruncate, fd, offset);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
}
+
int32_t
-stat_prefetch_utimes (call_frame_t *frame,
- struct xlator *this,
- const char *path,
- struct timespec *tvp)
+sp_utimens (call_frame_t *frame, xlator_t *this, loc_t *loc,
+ struct timespec tv[2])
{
- stat_prefetch_cache_flush (this->private, 1);
+ sp_cache_t *cache = NULL;
+
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
- STACK_WIND (frame,
- stat_prefetch_utimes_cbk,
- FIRST_CHILD(this),
- FIRST_CHILD(this)->fops->utimes,
- path,
- tvp);
+ cache = sp_get_cache_inode (this, loc->parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)loc->name, 0);
+ }
- return 0;
+ STACK_WIND (frame, sp_stbuf_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->utimens, loc, tv);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
}
int32_t
-stat_prefetch_truncate_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno,
- struct stat *buf)
+sp_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, const char *path)
{
- STACK_UNWIND (frame, op_ret, op_errno, buf);
- return 0;
+ SP_STACK_UNWIND (frame, op_ret, op_errno, path);
+ return 0;
}
+
int32_t
-stat_prefetch_truncate (call_frame_t *frame,
- struct xlator *this,
- const char *path,
- off_t offset)
+sp_readlink (call_frame_t *frame, xlator_t *this, loc_t *loc, size_t size)
{
- stat_prefetch_cache_flush (this->private, 1);
+ sp_cache_t *cache = NULL;
- STACK_WIND (frame,
- stat_prefetch_truncate_cbk,
- FIRST_CHILD(this),
- FIRST_CHILD(this)->fops->truncate,
- path,
- offset);
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
- return 0;
+ cache = sp_get_cache_inode (this, loc->parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)loc->name, 0);
+ }
+
+ STACK_WIND (frame, sp_readlink_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->readlink, loc, size);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
}
int32_t
-stat_prefetch_rename_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno)
+sp_err_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno)
{
- STACK_UNWIND (frame, op_ret, op_errno);
- return 0;
+ SP_STACK_UNWIND (frame, op_ret, op_errno);
+ return 0;
}
+
int32_t
-stat_prefetch_rename (call_frame_t *frame,
- struct xlator *this,
- const char *oldpath,
- const char *newpath)
+sp_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc)
{
- stat_prefetch_cache_flush (this->private, 1);
+ sp_cache_t *cache = NULL;
+ int32_t ret = 0;
+
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
+
+ cache = sp_get_cache_inode (this, loc->parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)loc->name, 0);
+ }
+
+ ret = sp_cache_remove_parent_entry (frame, this, (char *)loc->path);
+ if (ret == -1) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
+
+ STACK_WIND (frame, sp_err_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->unlink, loc);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno);
+ return 0;
+}
- STACK_WIND (frame,
- stat_prefetch_rename_cbk,
- FIRST_CHILD(this),
- FIRST_CHILD(this)->fops->rename,
- oldpath,
- newpath);
- return 0;
+void
+sp_remove_caches_from_all_fds_opened (xlator_t *this, inode_t *inode)
+{
+ fd_t *fd = NULL;
+ sp_cache_t *cache = NULL;
+
+ LOCK (&inode->lock);
+ {
+ list_for_each_entry (fd, &inode->fd_list, inode_list) {
+ cache = sp_get_cache_fd (this, fd);
+ if (cache) {
+ sp_cache_remove_entry (cache, NULL, 1);
+ }
+ }
+ }
+ UNLOCK (&inode->lock);
}
+
-int32_t
-init (struct xlator *this)
+int32_t
+sp_rmdir (call_frame_t *frame, xlator_t *this, loc_t *loc)
+{
+ sp_cache_t *cache = NULL;
+ int32_t ret = -1;
+
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->path, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->inode, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+
+ sp_remove_caches_from_all_fds_opened (this, loc->inode);
+
+ cache = sp_get_cache_inode (this, loc->parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)loc->name, 0);
+ }
+
+ ret = sp_cache_remove_parent_entry (frame, this, (char *)loc->path);
+ if (ret == -1) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
+
+ STACK_WIND (frame, sp_err_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->rmdir, loc);
+ return 0;
+
+unwind:
+ STACK_UNWIND (frame, -1, errno);
+ return 0;
+}
+
+
+int32_t
+sp_readv_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
+ int32_t op_errno, struct iovec *vector, int32_t count,
+ struct stat *stbuf, struct iobref *iobref)
+{
+ SP_STACK_UNWIND (frame, op_ret, op_errno, vector, count, stbuf, iobref);
+ return 0;
+}
+
+
+int32_t
+sp_readv (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
+ off_t offset)
+{
+ sp_fd_ctx_t *fd_ctx = NULL;
+ sp_cache_t *cache = NULL;
+ uint64_t value = 0;
+ int32_t ret = 0;
+ inode_t *parent = NULL;
+ char *name = NULL;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == -1) {
+ errno = EINVAL;
+ goto unwind;
+ }
+
+ fd_ctx = (void *)(long)value;
+ name = fd_ctx->name;
+ parent = fd_ctx->parent_inode;
+
+ cache = sp_get_cache_inode (this, parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, name, 0);
+ }
+
+ STACK_WIND (frame, sp_readv_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->readv, fd, size, offset);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL, -1, NULL, NULL);
+ return 0;
+}
+
+
+int32_t
+sp_writev (call_frame_t *frame, xlator_t *this, fd_t *fd, struct iovec *vector,
+ int32_t count, off_t off, struct iobref *iobref)
+{
+ sp_fd_ctx_t *fd_ctx = NULL;
+ sp_cache_t *cache = NULL;
+ uint64_t value = 0;
+ int32_t ret = 0;
+ inode_t *parent = NULL;
+ char *name = NULL;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == -1) {
+ errno = EINVAL;
+ goto unwind;
+ }
+
+ fd_ctx = (void *)(long)value;
+ name = fd_ctx->name;
+ parent = fd_ctx->parent_inode;
+
+ cache = sp_get_cache_inode (this, parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, name, 0);
+ }
+
+ STACK_WIND (frame, sp_stbuf_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->writev, fd, vector, count, off,
+ iobref);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
+}
+
+
+int32_t
+sp_fsync (call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags)
+{
+ sp_fd_ctx_t *fd_ctx = NULL;
+ sp_cache_t *cache = NULL;
+ uint64_t value = 0;
+ int32_t ret = 0;
+ inode_t *parent = NULL;
+ char *name = NULL;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == -1) {
+ errno = EINVAL;
+ goto unwind;
+ }
+
+ fd_ctx = (void *)(long)value;
+ name = fd_ctx->name;
+ parent = fd_ctx->parent_inode;
+
+ cache = sp_get_cache_inode (this, parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, name, 0);
+ }
+
+ STACK_WIND (frame, sp_err_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->fsync, fd, flags);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno);
+ return 0;
+}
+
+
+int32_t
+sp_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc,loc_t *newloc)
+{
+ sp_cache_t *cache = NULL;
+ int32_t ret = -1;
+
+ GF_VALIDATE_OR_GOTO (this->name, oldloc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, oldloc->path, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, oldloc->name, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, oldloc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, oldloc->inode, unwind);
+
+ GF_VALIDATE_OR_GOTO (this->name, newloc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, newloc->path, unwind);
+
+ cache = sp_get_cache_inode (this, oldloc->parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)oldloc->name, 0);
+ }
+
+ cache = sp_get_cache_inode (this, newloc->parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)newloc->name, 0);
+ }
+
+ ret = sp_cache_remove_parent_entry (frame, this, (char *)oldloc->path);
+ if (ret == -1) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
+
+ ret = sp_cache_remove_parent_entry (frame, this, (char *)newloc->path);
+ if (ret == -1) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
+
+ if (S_ISDIR (oldloc->inode->st_mode)) {
+ sp_remove_caches_from_all_fds_opened (this, oldloc->inode);
+ }
+
+ STACK_WIND (frame, sp_stbuf_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->rename, oldloc, newloc);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
+}
+
+
+int32_t
+sp_setxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict,
+ int32_t flags)
+{
+ sp_cache_t *cache = NULL;
+
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
+
+ cache = sp_get_cache_inode (this, loc->parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)loc->name, 0);
+ }
+
+ STACK_WIND (frame, sp_err_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->setxattr, loc, dict, flags);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno);
+ return 0;
+}
+
+
+int32_t
+sp_removexattr (call_frame_t *frame, xlator_t *this, loc_t *loc,
+ const char *name)
+{
+ sp_cache_t *cache = NULL;
+
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
+
+ cache = sp_get_cache_inode (this, loc->parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)loc->name, 0);
+ }
+
+ STACK_WIND (frame, sp_err_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->removexattr, loc, name);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno);
+ return 0;
+}
+
+
+int32_t
+sp_setdents (call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags,
+ dir_entry_t *entries, int32_t count)
+{
+ sp_fd_ctx_t *fd_ctx = NULL;
+ sp_cache_t *cache = NULL;
+ uint64_t value = 0;
+ int32_t ret = 0;
+ inode_t *parent = NULL;
+ char *name = NULL;
+ dir_entry_t *trav = NULL;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == -1) {
+ errno = EINVAL;
+ goto unwind;
+ }
+
+ fd_ctx = (void *)(long)value;
+ name = fd_ctx->name;
+ parent = fd_ctx->parent_inode;
+
+ cache = sp_get_cache_inode (this, parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, name, 0);
+ }
+
+ cache = sp_get_cache_fd (this, fd);
+ if (cache) {
+ for (trav = entries->next; trav; trav = trav->next) {
+ sp_cache_remove_entry (cache, trav->name, 0);
+ }
+ }
+
+ STACK_WIND (frame, sp_err_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->setdents, fd, flags, entries,
+ count);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno);
+ return 0;
+}
+
+
+int32_t
+sp_getdents_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, dir_entry_t *entries,
+ int32_t count)
+{
+ dir_entry_t *trav = NULL;
+ sp_local_t *local = NULL;
+ sp_cache_t *cache = NULL;
+
+ if (op_ret == -1) {
+ goto out;
+ }
+
+ local = frame->local;
+ if ((local == NULL) || (local->fd == NULL)) {
+ op_ret = -1;
+ op_errno = EINVAL;
+ goto out;
+ }
+
+ cache = sp_get_cache_fd (this, local->fd);
+ if (cache) {
+ for (trav = entries->next; trav; trav = trav->next) {
+ if (S_ISLNK (trav->buf.st_mode)) {
+ sp_cache_remove_entry (cache, trav->name, 0);
+ }
+ }
+ }
+
+out:
+ SP_STACK_UNWIND (frame, op_ret, op_errno, entries, count);
+ return 0;
+}
+
+
+int32_t
+sp_getdents (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
+ off_t offset, int32_t flags)
+{
+ sp_fd_ctx_t *fd_ctx = NULL;
+ sp_cache_t *cache = NULL;
+ uint64_t value = 0;
+ int32_t ret = 0;
+ inode_t *parent = NULL;
+ char *name = NULL;
+ sp_local_t *local = NULL;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == -1) {
+ errno = EINVAL;
+ goto unwind;
+ }
+
+ fd_ctx = (void *)(long)value;
+ name = fd_ctx->name;
+ parent = fd_ctx->parent_inode;
+
+ cache = sp_get_cache_inode (this, parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, name, 0);
+ }
+
+ local = CALLOC (1, sizeof (*local));
+ if (local == NULL) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
+
+ local->fd = fd;
+ frame->local = local;
+
+ STACK_WIND (frame, sp_getdents_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->getdents, fd, size, offset, flags);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL, -1);
+ return 0;
+}
+
+
+int32_t
+sp_checksum_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, uint8_t *file_checksum,
+ uint8_t *dir_checksum)
+{
+ SP_STACK_UNWIND (frame, op_ret, op_errno, file_checksum, dir_checksum);
+ return 0;
+}
+
+
+int32_t
+sp_checksum (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flag)
+{
+ sp_cache_t *cache = NULL;
+
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
+
+ cache = sp_get_cache_inode (this, loc->parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)loc->name, 0);
+ }
+
+ STACK_WIND (frame, sp_checksum_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->checksum, loc, flag);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
+}
+
+
+int32_t
+sp_xattrop_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, dict_t *dict)
+{
+ SP_STACK_UNWIND (frame, op_ret, op_errno, dict);
+ return 0;
+}
+
+
+int32_t
+sp_xattrop (call_frame_t *frame, xlator_t *this, loc_t *loc,
+ gf_xattrop_flags_t flags, dict_t *dict)
{
- struct sp_cache *cache;
- dict_t *options = this->options;
+ sp_cache_t *cache = NULL;
- if (!this->children || this->children->next) {
- gf_log ("stat-prefetch",
- GF_LOG_ERROR,
- "FATAL: translator %s does not have exactly one child node",
- this->name);
- return -1;
- }
+ GF_VALIDATE_OR_GOTO (this->name, loc, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->parent, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind);
- cache = (void *) CALLOC (1, sizeof (*cache));
- ERR_ABORT (cache);
- cache->next = cache->prev = cache;
+ cache = sp_get_cache_inode (this, loc->parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, (char *)loc->name, 0);
+ }
- cache->tv_time = 1 * 1000000;
+ STACK_WIND (frame, sp_xattrop_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->xattrop, loc, flags, dict);
+ return 0;
- if (dict_get (options, "cache-seconds")) {
- cache->tv_time = (data_to_int64 (dict_get (options, "cache-seconds")) *
- 1000000);
- }
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
+}
- pthread_mutex_init (&cache->lock, NULL);
- this->private = cache;
- return 0;
+int32_t
+sp_fxattrop (call_frame_t *frame, xlator_t *this, fd_t *fd,
+ gf_xattrop_flags_t flags, dict_t *dict)
+{
+ sp_fd_ctx_t *fd_ctx = NULL;
+ sp_cache_t *cache = NULL;
+ uint64_t value = 0;
+ int32_t ret = 0;
+ inode_t *parent = NULL;
+ char *name = NULL;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == -1) {
+ errno = EINVAL;
+ goto unwind;
+ }
+
+ fd_ctx = (void *)(long)value;
+ name = fd_ctx->name;
+ parent = fd_ctx->parent_inode;
+
+ cache = sp_get_cache_inode (this, parent, frame->root->pid);
+ if (cache) {
+ sp_cache_remove_entry (cache, name, 0);
+ }
+
+ STACK_WIND (frame, sp_xattrop_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->fxattrop, fd, flags, dict);
+ return 0;
+
+unwind:
+ SP_STACK_UNWIND (frame, -1, errno, NULL);
+ return 0;
+}
+
+
+int32_t
+sp_forget (xlator_t *this, inode_t *inode)
+{
+ struct stat *buf = NULL;
+ uint64_t value = 0;
+
+ inode_ctx_del (inode, this, &value);
+
+ if (value) {
+ buf = (void *)(long)value;
+ FREE (buf);
+ }
+
+ return 0;
+}
+
+
+int32_t
+sp_release (xlator_t *this, fd_t *fd)
+{
+ sp_fd_ctx_t *fd_ctx = NULL;
+ uint64_t value = 0;
+ int32_t ret = 0;
+
+ ret = fd_ctx_del (fd, this, &value);
+ if (!ret) {
+ fd_ctx = (void *)(long) value;
+ sp_fd_ctx_free (fd_ctx);
+ }
+
+ return 0;
+}
+
+
+
+int32_t
+init (xlator_t *this)
+{
+ int32_t ret = -1;
+ if (!this->children || this->children->next) {
+ gf_log ("stat-prefetch",
+ GF_LOG_ERROR,
+ "FATAL: translator %s does not have exactly one child "
+ "node", this->name);
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
}
void
-fini (struct xlator *this)
+fini (xlator_t *this)
{
- return;
+ return;
}
struct xlator_fops fops = {
- .getattr = stat_prefetch_getattr,
- .readdir = stat_prefetch_readdir,
- .unlink = stat_prefetch_unlink,
- .chmod = stat_prefetch_chmod,
- .chown = stat_prefetch_chown,
- .rename = stat_prefetch_rename,
- .utimes = stat_prefetch_utimes,
- .truncate = stat_prefetch_truncate,
+ .lookup = sp_lookup,
+ .readdir = sp_readdir,
+ .chmod = sp_chmod,
+ .open = sp_open,
+ .create = sp_create,
+ .opendir = sp_opendir,
+ .mkdir = sp_mkdir,
+ .mknod = sp_mknod,
+ .symlink = sp_symlink,
+ .link = sp_link,
+ .fchmod = sp_fchmod,
+ .chown = sp_chown,
+ .fchown = sp_fchown,
+ .truncate = sp_truncate,
+ .ftruncate = sp_ftruncate,
+ .utimens = sp_utimens,
+ .readlink = sp_readlink,
+ .unlink = sp_unlink,
+ .rmdir = sp_rmdir,
+ .readv = sp_readv,
+ .writev = sp_writev,
+ .fsync = sp_fsync,
+ .rename = sp_rename,
+ .setxattr = sp_setxattr,
+ .removexattr = sp_removexattr,
+ .setdents = sp_setdents,
+ .getdents = sp_getdents,
+ .checksum = sp_checksum,
+ .xattrop = sp_xattrop,
+ .fxattrop = sp_fxattrop,
};
struct xlator_mops mops = {
};
+
+struct xlator_cbks cbks = {
+ .forget = sp_forget,
+ .release = sp_release,
+ .releasedir = sp_release
+};
diff --git a/xlators/performance/stat-prefetch/src/stat-prefetch.h b/xlators/performance/stat-prefetch/src/stat-prefetch.h
index ef82952b0c7..05c5d436184 100644
--- a/xlators/performance/stat-prefetch/src/stat-prefetch.h
+++ b/xlators/performance/stat-prefetch/src/stat-prefetch.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2006-2009 Z RESEARCH, Inc. <http://www.zresearch.com>
+ Copyright (c) 2009-2010 Z RESEARCH, Inc. <http://www.zresearch.com>
This file is part of GlusterFS.
GlusterFS is free software; you can redistribute it and/or modify
@@ -17,16 +17,61 @@
<http://www.gnu.org/licenses/>.
*/
-#ifndef _STAT_PREFETCH_H_
-#define _STAT_PREFETCH_H_
+#ifndef _STAT_PREFETCH_H
+#define _STAT_PREFETCH_H
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
-#include <stdio.h>
-#include <sys/time.h>
+#include "glusterfs.h"
+#include "dict.h"
#include "xlator.h"
-#endif /* _STAT_PREFETCH_H_ */
+struct sp_cache {
+ gf_dirent_t entries; /* Head of list of cached dirents */
+ uint64_t expected_offset; /* Offset where the next read will
+ * happen.
+ */
+ gf_lock_t lock;
+};
+typedef struct sp_cache sp_cache_t;
+
+struct sp_fd_ctx {
+ sp_cache_t *cache;
+ inode_t *parent_inode; /*
+ * inode corresponding to dirname (path)
+ */
+ char *name; /*
+ * basename of path on which this fd is
+ * opened
+ */
+ gf_lock_t lock;
+};
+typedef struct sp_fd_ctx sp_fd_ctx_t;
+
+struct sp_local {
+ loc_t loc;
+ fd_t *fd;
+};
+typedef struct sp_local sp_local_t;
+
+
+void sp_local_free (sp_local_t *local);
+
+#define SP_STACK_UNWIND(frame, params ...) do { \
+ sp_local_t *__local = frame->local; \
+ frame->local = NULL; \
+ STACK_UNWIND (frame, params); \
+ sp_local_free (__local); \
+} while (0)
+
+#define SP_STACK_DESTROY(frame) do { \
+ sp_local_t *__local = frame->local; \
+ frame->local = NULL; \
+ STACK_DESTROY (frame->root); \
+ sp_local_free (__local); \
+} while (0)
+
+#endif /* #ifndef _STAT_PREFETCH_H */