summaryrefslogtreecommitdiffstats
path: root/xlators/performance/quick-read
diff options
context:
space:
mode:
authorRaghavendra G <raghavendra@gluster.com>2009-09-14 13:25:25 +0000
committerAnand V. Avati <avati@dev.gluster.com>2009-09-14 23:33:08 -0700
commit80969eaf4e2ef58c051d6679fb678172b26022bb (patch)
treec7cf3b5e246e6f12fb82a0f5e4306c38277a07bf /xlators/performance/quick-read
parent62d30db76e118cb244c35b6acc15005474d77750 (diff)
backporting quick read to 2.0
Signed-off-by: Anand V. Avati <avati@dev.gluster.com> BUG: 238 (Backport quick-read to 2.0 release) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=238
Diffstat (limited to 'xlators/performance/quick-read')
-rw-r--r--xlators/performance/quick-read/Makefile.am3
-rw-r--r--xlators/performance/quick-read/src/Makefile.am14
-rw-r--r--xlators/performance/quick-read/src/quick-read.c2263
-rw-r--r--xlators/performance/quick-read/src/quick-read.h80
4 files changed, 2360 insertions, 0 deletions
diff --git a/xlators/performance/quick-read/Makefile.am b/xlators/performance/quick-read/Makefile.am
new file mode 100644
index 000000000..d471a3f92
--- /dev/null
+++ b/xlators/performance/quick-read/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = src
+
+CLEANFILES =
diff --git a/xlators/performance/quick-read/src/Makefile.am b/xlators/performance/quick-read/src/Makefile.am
new file mode 100644
index 000000000..644f27e3f
--- /dev/null
+++ b/xlators/performance/quick-read/src/Makefile.am
@@ -0,0 +1,14 @@
+xlator_LTLIBRARIES = quick-read.la
+xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/performance
+
+quick_read_la_LDFLAGS = -module -avoidversion
+
+quick_read_la_SOURCES = quick-read.c
+quick_read_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
+
+noinst_HEADERS = quick-read.h
+
+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/quick-read/src/quick-read.c b/xlators/performance/quick-read/src/quick-read.c
new file mode 100644
index 000000000..ac645dd99
--- /dev/null
+++ b/xlators/performance/quick-read/src/quick-read.c
@@ -0,0 +1,2263 @@
+/*
+ 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/>.
+*/
+
+#include "quick-read.h"
+
+int32_t
+qr_readv (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
+ off_t offset);
+
+
+static void
+qr_loc_wipe (loc_t *loc)
+{
+ if (loc == NULL) {
+ goto out;
+ }
+
+ if (loc->path) {
+ FREE (loc->path);
+ loc->path = NULL;
+ }
+
+ if (loc->inode) {
+ inode_unref (loc->inode);
+ loc->inode = NULL;
+ }
+
+ if (loc->parent) {
+ inode_unref (loc->parent);
+ loc->parent = NULL;
+ }
+
+out:
+ return;
+}
+
+
+static int32_t
+qr_loc_fill (loc_t *loc, inode_t *inode, char *path)
+{
+ int32_t ret = -1;
+ char *parent = NULL;
+
+ if ((loc == NULL) || (inode == NULL) || (path == NULL)) {
+ ret = -1;
+ errno = EINVAL;
+ goto out;
+ }
+
+ loc->inode = inode_ref (inode);
+ loc->path = strdup (path);
+ loc->ino = inode->ino;
+
+ parent = strdup (path);
+ if (parent == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ parent = dirname (parent);
+
+ loc->parent = inode_from_path (inode->table, parent);
+ if (loc->parent == NULL) {
+ ret = -1;
+ errno = EINVAL;
+ goto out;
+ }
+
+ loc->name = strrchr (loc->path, '/');
+ ret = 0;
+out:
+ if (ret == -1) {
+ qr_loc_wipe (loc);
+
+ }
+
+ if (parent) {
+ FREE (parent);
+ }
+
+ return ret;
+}
+
+
+void
+qr_resume_pending_ops (qr_fd_ctx_t *qr_fd_ctx)
+{
+ struct list_head waiting_ops;
+ call_stub_t *stub = NULL, *tmp = NULL;
+
+ if (qr_fd_ctx == NULL) {
+ goto out;
+ }
+
+ INIT_LIST_HEAD (&waiting_ops);
+
+ LOCK (&qr_fd_ctx->lock);
+ {
+ list_splice_init (&qr_fd_ctx->waiting_ops,
+ &waiting_ops);
+ }
+ UNLOCK (&qr_fd_ctx->lock);
+
+ if (!list_empty (&waiting_ops)) {
+ list_for_each_entry_safe (stub, tmp, &waiting_ops, list) {
+ list_del_init (&stub->list);
+ call_resume (stub);
+ }
+ }
+
+out:
+ return;
+}
+
+
+static void
+qr_fd_ctx_free (qr_fd_ctx_t *qr_fd_ctx)
+{
+ if (qr_fd_ctx == NULL) {
+ goto out;
+ }
+
+ assert (list_empty (&qr_fd_ctx->waiting_ops));
+
+ FREE (qr_fd_ctx->path);
+ FREE (qr_fd_ctx);
+
+out:
+ return;
+}
+
+
+int32_t
+qr_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)
+{
+ data_t *content = NULL;
+ qr_file_t *qr_file = NULL;
+ uint64_t value = 0;
+ int ret = -1;
+ qr_conf_t *conf = NULL;
+
+ if ((op_ret == -1) || (dict == NULL)) {
+ goto out;
+ }
+
+ conf = this->private;
+
+ content = dict_get (dict, GLUSTERFS_CONTENT_KEY);
+ if (content == NULL) {
+ goto out;
+ }
+
+ if (buf->st_size > conf->max_file_size) {
+ goto out;
+ }
+
+ if (S_ISDIR (buf->st_mode)) {
+ goto out;
+ }
+
+ ret = inode_ctx_get (inode, this, &value);
+ if (ret == -1) {
+ qr_file = CALLOC (1, sizeof (*qr_file));
+ if (qr_file == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ goto out;
+ }
+
+ LOCK_INIT (&qr_file->lock);
+ inode_ctx_put (inode, this, (uint64_t)(long)qr_file);
+ } else {
+ qr_file = (qr_file_t *)(long)value;
+ if (qr_file == NULL) {
+ op_ret = -1;
+ op_errno = EINVAL;
+ goto out;
+ }
+ }
+
+ LOCK (&qr_file->lock);
+ {
+ if (qr_file->xattr) {
+ dict_unref (qr_file->xattr);
+ qr_file->xattr = NULL;
+ }
+
+ qr_file->xattr = dict_ref (dict);
+ qr_file->stbuf = *buf;
+ gettimeofday (&qr_file->tv, NULL);
+ }
+ UNLOCK (&qr_file->lock);
+
+out:
+ STACK_UNWIND (frame, op_ret, op_errno, inode, buf, dict);
+ return 0;
+}
+
+
+int32_t
+qr_lookup (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xattr_req)
+{
+ qr_conf_t *conf = NULL;
+ dict_t *new_req_dict = NULL;
+ int32_t op_ret = -1, op_errno = -1;
+ data_t *content = NULL;
+ uint64_t requested_size = 0, size = 0;
+
+ conf = this->private;
+ if (conf == NULL) {
+ op_ret = -1;
+ op_errno = EINVAL;
+ goto unwind;
+ }
+
+ if ((xattr_req == NULL) && (conf->max_file_size > 0)) {
+ new_req_dict = xattr_req = dict_new ();
+ if (xattr_req == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
+ }
+
+ if (xattr_req) {
+ content = dict_get (xattr_req, GLUSTERFS_CONTENT_KEY);
+ if (content) {
+ requested_size = data_to_uint64 (content);
+ }
+ }
+
+ if (((conf->max_file_size > 0) && (content == NULL))
+ || (conf->max_file_size != requested_size)) {
+ size = (conf->max_file_size > requested_size) ?
+ conf->max_file_size : requested_size;
+
+ op_ret = dict_set (xattr_req, GLUSTERFS_CONTENT_KEY,
+ data_from_uint64 (size));
+ if (op_ret < 0) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ goto unwind;
+ }
+ }
+
+ STACK_WIND (frame, qr_lookup_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->lookup, loc, xattr_req);
+
+ if (new_req_dict) {
+ dict_unref (new_req_dict);
+ }
+
+ return 0;
+
+unwind:
+ STACK_UNWIND (frame, op_ret, op_errno, NULL, NULL, NULL);
+
+ if (new_req_dict) {
+ dict_unref (new_req_dict);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
+ int32_t op_errno, fd_t *fd)
+{
+ uint64_t value = 0;
+ int32_t ret = -1;
+ struct list_head waiting_ops;
+ qr_local_t *local = NULL;
+ qr_file_t *qr_file = NULL;
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ call_stub_t *stub = NULL, *tmp = NULL;
+ char is_open = 0;
+
+ local = frame->local;
+ if (local == NULL) {
+ op_ret = -1;
+ op_errno = EINVAL;
+ } else {
+ local->op_ret = op_ret;
+ local->op_errno = op_errno;
+ is_open = local->is_open;
+ }
+
+ INIT_LIST_HEAD (&waiting_ops);
+
+ ret = fd_ctx_get (fd, this, &value);
+ if ((ret == -1) && (op_ret != -1)) {
+ op_ret = -1;
+ op_errno = EINVAL;
+ goto out;
+ }
+
+ if (value) {
+ qr_fd_ctx = (qr_fd_ctx_t *) (long)value;
+ }
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ qr_fd_ctx->open_in_transit = 0;
+
+ if (op_ret == 0) {
+ qr_fd_ctx->opened = 1;
+ }
+ list_splice_init (&qr_fd_ctx->waiting_ops,
+ &waiting_ops);
+ }
+ UNLOCK (&qr_fd_ctx->lock);
+
+ if (local && local->is_open
+ && ((local->open_flags & O_TRUNC) == O_TRUNC)) {
+ ret = inode_ctx_get (fd->inode, this, &value);
+ if (ret == 0) {
+ qr_file = (qr_file_t *)(long) value;
+
+ if (qr_file) {
+ LOCK (&qr_file->lock);
+ {
+ dict_unref (qr_file->xattr);
+ qr_file->xattr = NULL;
+ }
+ UNLOCK (&qr_file->lock);
+ }
+ }
+ }
+
+ if (!list_empty (&waiting_ops)) {
+ list_for_each_entry_safe (stub, tmp, &waiting_ops,
+ list) {
+ list_del_init (&stub->list);
+ call_resume (stub);
+ }
+ }
+ }
+out:
+ if (is_open) {
+ STACK_UNWIND (frame, op_ret, op_errno, fd);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_open (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
+ fd_t *fd)
+{
+ qr_file_t *qr_file = NULL;
+ int32_t ret = -1;
+ uint64_t filep = 0;
+ char content_cached = 0;
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ int32_t op_ret = -1, op_errno = -1;
+ qr_local_t *local = NULL;
+ qr_conf_t *conf = NULL;
+
+ conf = this->private;
+
+ qr_fd_ctx = CALLOC (1, sizeof (*qr_fd_ctx));
+ if (qr_fd_ctx == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
+
+ LOCK_INIT (&qr_fd_ctx->lock);
+ INIT_LIST_HEAD (&qr_fd_ctx->waiting_ops);
+
+ qr_fd_ctx->path = strdup (loc->path);
+ qr_fd_ctx->flags = flags;
+
+ ret = fd_ctx_set (fd, this, (uint64_t)(long)qr_fd_ctx);
+ if (ret == -1) {
+ op_ret = -1;
+ op_errno = EINVAL;
+ goto unwind;
+ }
+
+ local = CALLOC (1, sizeof (*local));
+ if (local == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto unwind;
+ }
+
+ local->is_open = 1;
+ local->open_flags = flags;
+ frame->local = local;
+ local = NULL;
+
+ ret = inode_ctx_get (fd->inode, this, &filep);
+ if (ret == 0) {
+ qr_file = (qr_file_t *)(long) filep;
+ if (qr_file) {
+ LOCK (&qr_file->lock);
+ {
+ if (qr_file->xattr) {
+ content_cached = 1;
+ }
+ }
+ UNLOCK (&qr_file->lock);
+ }
+ }
+
+ if (content_cached && ((flags & O_DIRECTORY) == O_DIRECTORY)) {
+ op_ret = -1;
+ op_errno = ENOTDIR;
+ qr_fd_ctx = NULL;
+ goto unwind;
+ }
+
+ if (!content_cached || ((flags & O_WRONLY) == O_WRONLY)
+ || ((flags & O_TRUNC) == O_TRUNC)) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ /*
+ * we need not set this flag, since open is not yet
+ * unwounded.
+ */
+
+ qr_fd_ctx->open_in_transit = 1;
+ }
+ UNLOCK (&qr_fd_ctx->lock);
+ goto wind;
+ } else {
+ op_ret = 0;
+ op_errno = 0;
+ goto unwind;
+ }
+
+unwind:
+ if (op_ret == -1) {
+ if (qr_fd_ctx != NULL) {
+ qr_fd_ctx_free (qr_fd_ctx);
+ }
+
+ if (local != NULL) {
+ FREE (local);
+ }
+ }
+
+ STACK_UNWIND (frame, op_ret, op_errno, fd);
+ return 0;
+
+wind:
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open, loc, flags, fd);
+ return 0;
+}
+
+
+static inline char
+qr_time_elapsed (struct timeval *now, struct timeval *then)
+{
+ return now->tv_sec - then->tv_sec;
+}
+
+
+static inline char
+qr_need_validation (qr_conf_t *conf, qr_file_t *file)
+{
+ struct timeval now = {0, };
+ char need_validation = 0;
+
+ gettimeofday (&now, NULL);
+
+ if (qr_time_elapsed (&now, &file->tv) >= conf->cache_timeout)
+ need_validation = 1;
+
+ return need_validation;
+}
+
+
+static int32_t
+qr_validate_cache_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct stat *buf)
+{
+ qr_file_t *qr_file = NULL;
+ qr_local_t *local = NULL;
+ uint64_t value = 0;
+ int32_t ret = 0;
+
+ if (op_ret == -1) {
+ goto unwind;
+ }
+
+ local = frame->local;
+ if ((local == NULL) || ((local->fd) == NULL)) {
+ op_ret = -1;
+ op_errno = EINVAL;
+ goto unwind;
+ }
+
+ ret = inode_ctx_get (local->fd->inode, this, &value);
+ if (ret == -1) {
+ op_ret = -1;
+ op_errno = EINVAL;
+ goto unwind;
+ }
+
+ qr_file = (qr_file_t *)(long) value;
+ if (qr_file == NULL) {
+ op_ret = -1;
+ op_errno = EINVAL;
+ goto unwind;
+ }
+
+ LOCK (&qr_file->lock);
+ {
+ if (qr_file->stbuf.st_mtime != buf->st_mtime) {
+ dict_unref (qr_file->xattr);
+ qr_file->xattr = NULL;
+ }
+
+ gettimeofday (&qr_file->tv, NULL);
+ }
+ UNLOCK (&qr_file->lock);
+
+ frame->local = NULL;
+
+ call_resume (local->stub);
+
+ FREE (local);
+ return 0;
+
+unwind:
+ /* this is actually unwind of readv */
+ STACK_UNWIND (frame, op_ret, op_errno, NULL, -1, NULL, NULL);
+ return 0;
+}
+
+
+int32_t
+qr_validate_cache_helper (call_frame_t *frame, xlator_t *this, fd_t *fd)
+{
+ qr_local_t *local = NULL;
+ int32_t op_ret = -1, op_errno = -1;
+
+ local = frame->local;
+ if (local == NULL) {
+ op_ret = -1;
+ op_errno = EINVAL;
+ } else {
+ op_ret = local->op_ret;
+ op_errno = local->op_errno;
+ }
+
+ if (op_ret == -1) {
+ qr_validate_cache_cbk (frame, NULL, this, op_ret, op_errno,
+ NULL);
+ } else {
+ STACK_WIND (frame, qr_validate_cache_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->fstat, fd);
+ }
+
+ return 0;
+}
+
+
+int
+qr_validate_cache (call_frame_t *frame, xlator_t *this, fd_t *fd,
+ call_stub_t *stub)
+{
+ int ret = -1;
+ int flags = 0;
+ uint64_t value = 0;
+ loc_t loc = {0, };
+ char *path = NULL;
+ qr_local_t *local = NULL;
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ call_stub_t *validate_stub = NULL;
+ char need_open = 0, can_wind = 0;
+
+ local = CALLOC (1, sizeof (*local));
+ if (local == NULL) {
+ goto out;
+ }
+
+ local->fd = fd;
+ local->stub = stub;
+ frame->local = local;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long) value;
+ }
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ path = qr_fd_ctx->path;
+ flags = qr_fd_ctx->flags;
+
+ if (!(qr_fd_ctx->opened
+ || qr_fd_ctx->open_in_transit)) {
+ need_open = 1;
+ qr_fd_ctx->open_in_transit = 1;
+ }
+
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else {
+ validate_stub = fop_fstat_stub (frame,
+ qr_validate_cache_helper,
+ fd);
+ if (validate_stub == NULL) {
+ ret = -1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto unlock;
+ }
+
+ list_add_tail (&validate_stub->list,
+ &qr_fd_ctx->waiting_ops);
+ }
+ }
+ unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+
+ if (ret == -1) {
+ goto out;
+ }
+ } else {
+ can_wind = 1;
+ }
+
+ if (need_open) {
+ ret = qr_loc_fill (&loc, fd->inode, path);
+ if (ret == -1) {
+ qr_resume_pending_ops (qr_fd_ctx);
+ goto out;
+ }
+
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open,
+ &loc, flags, fd);
+
+ qr_loc_wipe (&loc);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_validate_cache_cbk,
+ FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->fstat, fd);
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+
+int32_t
+qr_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)
+{
+ STACK_UNWIND (frame, op_ret, op_errno, vector, count, stbuf, iobref);
+ return 0;
+}
+
+
+int32_t
+qr_readv_helper (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
+ off_t offset)
+{
+ STACK_WIND (frame, qr_readv_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->readv, fd, size, offset);
+ return 0;
+}
+
+
+int32_t
+qr_readv (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
+ off_t offset)
+{
+ qr_file_t *file = NULL;
+ int32_t ret = -1, op_ret = -1, op_errno = -1;
+ uint64_t value = 0;
+ int count = -1, flags = 0, i = 0;
+ char content_cached = 0, need_validation = 0;
+ char need_open = 0, can_wind = 0, need_unwind = 0;
+ struct iobuf *iobuf = NULL;
+ struct iobref *iobref = NULL;
+ struct stat stbuf = {0, };
+ data_t *content = NULL;
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ call_stub_t *stub = NULL;
+ loc_t loc = {0, };
+ qr_conf_t *conf = NULL;
+ struct iovec *vector = NULL;
+ char *path = NULL;
+ glusterfs_ctx_t *ctx = NULL;
+ off_t start = 0, end = 0;
+ size_t len = 0;
+
+ op_ret = 0;
+ conf = this->private;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long) value;
+ }
+
+ ret = inode_ctx_get (fd->inode, this, &value);
+ if (ret == 0) {
+ file = (qr_file_t *)(long)value;
+ if (file) {
+ LOCK (&file->lock);
+ {
+ if (file->xattr){
+ if (qr_need_validation (conf,file)) {
+ need_validation = 1;
+ goto unlock;
+ }
+
+ content = dict_get (file->xattr,
+ GLUSTERFS_CONTENT_KEY);
+
+ content_cached = 1;
+ if (offset > content->len) {
+ op_ret = 0;
+ end = content->len;
+ } else {
+ if ((offset + size)
+ > content->len) {
+ op_ret = content->len - offset;
+ end = content->len;
+ } else {
+ op_ret = size;
+ end = offset + size;
+ }
+ }
+
+ ctx = get_global_ctx_ptr ();
+ count = (op_ret / ctx->page_size) + 1;
+ vector = CALLOC (count,
+ sizeof (*vector));
+ if (vector == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ goto unlock;
+ }
+
+ iobref = iobref_new ();
+ if (iobref == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ goto unlock;
+ }
+
+ for (i = 0; i < count; i++) {
+ iobuf = iobuf_get (this->ctx->iobuf_pool);
+ if (iobuf == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ goto unlock;
+ }
+
+ start = offset + ctx->page_size * i;
+ if (start > end) {
+ len = 0;
+ } else {
+ len = (ctx->page_size
+ > (end - start))
+ ? (end - start)
+ : ctx->page_size;
+
+ memcpy (iobuf->ptr,
+ content->data + start,
+ len);
+ }
+
+ iobref_add (iobref, iobuf);
+ iobuf_unref (iobuf);
+
+ vector[i].iov_base = iobuf->ptr;
+ vector[i].iov_len = len;
+ }
+
+ stbuf = file->stbuf;
+ }
+ }
+ unlock:
+ UNLOCK (&file->lock);
+ }
+ }
+
+out:
+ if (content_cached || need_unwind) {
+ STACK_UNWIND (frame, op_ret, op_errno, vector, count, &stbuf,
+ iobref);
+
+ } else if (need_validation) {
+ stub = fop_readv_stub (frame, qr_readv, fd, size, offset);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ goto out;
+ }
+
+ op_ret = qr_validate_cache (frame, this, fd, stub);
+ if (op_ret == -1) {
+ need_unwind = 1;
+ op_errno = errno;
+ call_stub_destroy (stub);
+ goto out;
+ }
+ } else {
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ path = qr_fd_ctx->path;
+ flags = qr_fd_ctx->flags;
+
+ if (!(qr_fd_ctx->opened
+ || qr_fd_ctx->open_in_transit)) {
+ need_open = 1;
+ qr_fd_ctx->open_in_transit = 1;
+ }
+
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else {
+ stub = fop_readv_stub (frame,
+ qr_readv_helper,
+ fd, size,
+ offset);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto fdctx_unlock;
+ }
+
+ list_add_tail (&stub->list,
+ &qr_fd_ctx->waiting_ops);
+ }
+ }
+ fdctx_unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+
+ if (op_ret == -1) {
+ need_unwind = 1;
+ goto out;
+ }
+ } else {
+ can_wind = 1;
+ }
+
+ if (need_open) {
+ op_ret = qr_loc_fill (&loc, fd->inode, path);
+ if (op_ret == -1) {
+ qr_resume_pending_ops (qr_fd_ctx);
+ goto out;
+ }
+
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open,
+ &loc, flags, fd);
+
+ qr_loc_wipe (&loc);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_readv_cbk,
+ FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->readv, fd, size,
+ offset);
+ }
+
+ }
+
+ if (vector) {
+ FREE (vector);
+ }
+
+ if (iobref) {
+ iobref_unref (iobref);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
+ int32_t op_errno, struct stat *stbuf)
+{
+ STACK_UNWIND (frame, op_ret, op_errno, stbuf);
+ return 0;
+}
+
+
+int32_t
+qr_writev_helper (call_frame_t *frame, xlator_t *this, fd_t *fd,
+ struct iovec *vector, int32_t count, off_t off,
+ struct iobref *iobref)
+{
+ STACK_WIND (frame, qr_writev_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->writev, fd, vector, count, off,
+ iobref);
+ return 0;
+}
+
+
+int32_t
+qr_writev (call_frame_t *frame, xlator_t *this, fd_t *fd, struct iovec *vector,
+ int32_t count, off_t off, struct iobref *iobref)
+{
+ uint64_t value = 0;
+ int flags = 0;
+ call_stub_t *stub = NULL;
+ char *path = NULL;
+ loc_t loc = {0, };
+ qr_file_t *qr_file = NULL;
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ int32_t op_ret = -1, op_errno = -1, ret = -1;
+ char can_wind = 0, need_unwind = 0, need_open = 0;
+
+ ret = fd_ctx_get (fd, this, &value);
+
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long) value;
+ }
+
+ ret = inode_ctx_get (fd->inode, this, &value);
+ if (ret == 0) {
+ qr_file = (qr_file_t *)(long)value;
+ }
+
+ if (qr_file) {
+ LOCK (&qr_file->lock);
+ {
+ if (qr_file->xattr) {
+ dict_unref (qr_file->xattr);
+ qr_file->xattr = NULL;
+ }
+ }
+ UNLOCK (&qr_file->lock);
+ }
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ path = qr_fd_ctx->path;
+ flags = qr_fd_ctx->flags;
+
+ if (!(qr_fd_ctx->opened
+ || qr_fd_ctx->open_in_transit)) {
+ need_open = 1;
+ qr_fd_ctx->open_in_transit = 1;
+ }
+
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else {
+ stub = fop_writev_stub (frame, qr_writev_helper,
+ fd, vector, count, off,
+ iobref);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto unlock;
+ }
+
+ list_add_tail (&stub->list,
+ &qr_fd_ctx->waiting_ops);
+ }
+ }
+ unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+ } else {
+ can_wind = 1;
+ }
+
+out:
+ if (need_unwind) {
+ STACK_UNWIND (frame, op_ret, op_errno, NULL);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_writev_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->writev, fd, vector, count,
+ off, iobref);
+ } else if (need_open) {
+ op_ret = qr_loc_fill (&loc, fd->inode, path);
+ if (op_ret == -1) {
+ qr_resume_pending_ops (qr_fd_ctx);
+ goto out;
+ }
+
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open, &loc, flags, fd);
+
+ qr_loc_wipe (&loc);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_fstat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
+ int32_t op_errno, struct stat *buf)
+{
+ STACK_UNWIND (frame, op_ret, op_errno, buf);
+ return 0;
+}
+
+
+int32_t
+qr_fstat_helper (call_frame_t *frame, xlator_t *this, fd_t *fd)
+{
+ STACK_WIND (frame, qr_fstat_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->fstat, fd);
+ return 0;
+}
+
+
+int32_t
+qr_fstat (call_frame_t *frame, xlator_t *this, fd_t *fd)
+{
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ char need_open = 0, can_wind = 0, need_unwind = 0;
+ uint64_t value = 0;
+ int32_t ret = -1, op_ret = -1, op_errno = -1;
+ call_stub_t *stub = NULL;
+ loc_t loc = {0, };
+ char *path = NULL;
+ int flags = 0;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long) value;
+ }
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ path = qr_fd_ctx->path;
+ flags = qr_fd_ctx->flags;
+
+ if (!(qr_fd_ctx->opened
+ || qr_fd_ctx->open_in_transit)) {
+ need_open = 1;
+ qr_fd_ctx->open_in_transit = 1;
+ }
+
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else {
+ stub = fop_fstat_stub (frame, qr_fstat_helper,
+ fd);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto unlock;
+ }
+
+ list_add_tail (&stub->list,
+ &qr_fd_ctx->waiting_ops);
+ }
+ }
+ unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+ } else {
+ can_wind = 1;
+ }
+
+out:
+ if (need_unwind) {
+ STACK_UNWIND (frame, op_ret, op_errno, NULL);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_fstat_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->fstat, fd);
+ } else if (need_open) {
+ op_ret = qr_loc_fill (&loc, fd->inode, path);
+ if (op_ret == -1) {
+ qr_resume_pending_ops (qr_fd_ctx);
+ goto out;
+ }
+
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open, &loc, flags, fd);
+
+ qr_loc_wipe (&loc);
+ }
+
+ return 0;
+}
+
+
+static int32_t
+qr_fchown_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct stat *buf)
+{
+ STACK_UNWIND (frame, op_ret, op_errno, buf);
+ return 0;
+}
+
+
+int32_t
+qr_fchown_helper (call_frame_t *frame, xlator_t *this, fd_t *fd, uid_t uid,
+ gid_t gid)
+{
+ STACK_WIND (frame, qr_fchown_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->fchown, fd, uid, gid);
+ return 0;
+}
+
+
+int32_t
+qr_fchown (call_frame_t *frame, xlator_t *this, fd_t *fd, uid_t uid, gid_t gid)
+{
+ uint64_t value = 0;
+ int flags = 0;
+ call_stub_t *stub = NULL;
+ char *path = NULL;
+ loc_t loc = {0, };
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ int32_t ret = -1, op_ret = -1, op_errno = -1;
+ char need_open = 0, can_wind = 0, need_unwind = 0;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long) value;
+ }
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ path = qr_fd_ctx->path;
+ flags = qr_fd_ctx->flags;
+
+ if (!(qr_fd_ctx->opened
+ || qr_fd_ctx->open_in_transit)) {
+ need_open = 1;
+ qr_fd_ctx->open_in_transit = 1;
+ }
+
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else {
+ stub = fop_fchown_stub (frame, qr_fchown_helper,
+ fd, uid, gid);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto unlock;
+ }
+
+ list_add_tail (&stub->list,
+ &qr_fd_ctx->waiting_ops);
+ }
+ }
+ unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+ } else {
+ can_wind = 1;
+ }
+
+out:
+ if (need_unwind) {
+ STACK_UNWIND (frame, op_ret, op_errno, NULL);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_fchown_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->fchown, fd, uid, gid);
+ } else if (need_open) {
+ op_ret = qr_loc_fill (&loc, fd->inode, path);
+ if (op_ret == -1) {
+ qr_resume_pending_ops (qr_fd_ctx);
+ goto out;
+ }
+
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open, &loc, flags, fd);
+
+ qr_loc_wipe (&loc);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_fchmod_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct stat *buf)
+{
+ STACK_UNWIND (frame, op_ret, op_errno, buf);
+ return 0;
+}
+
+
+int32_t
+qr_fchmod_helper (call_frame_t *frame, xlator_t *this, fd_t *fd, mode_t mode)
+{
+ STACK_WIND(frame, qr_fchmod_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->fchmod, fd, mode);
+ return 0;
+}
+
+
+int32_t
+qr_fchmod (call_frame_t *frame, xlator_t *this, fd_t *fd, mode_t mode)
+{
+ uint64_t value = 0;
+ int flags = 0;
+ call_stub_t *stub = NULL;
+ char *path = NULL;
+ loc_t loc = {0, };
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ int32_t ret = -1, op_ret = -1, op_errno = -1;
+ char need_open = 0, can_wind = 0, need_unwind = 0;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long) value;
+ }
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ path = qr_fd_ctx->path;
+ flags = qr_fd_ctx->flags;
+ if (!(qr_fd_ctx->opened
+ || qr_fd_ctx->open_in_transit)) {
+ need_open = 1;
+ qr_fd_ctx->open_in_transit = 1;
+ }
+
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else {
+ stub = fop_fchmod_stub (frame, qr_fchmod_helper,
+ fd, mode);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto unlock;
+ }
+
+ list_add_tail (&stub->list,
+ &qr_fd_ctx->waiting_ops);
+ }
+ }
+ unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+ } else {
+ can_wind = 1;
+ }
+
+out:
+ if (need_unwind) {
+ STACK_UNWIND (frame, op_ret, op_errno, NULL);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_fchmod_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->fchmod, fd, mode);
+ } else if (need_open) {
+ op_ret = qr_loc_fill (&loc, fd->inode, path);
+ if (op_ret == -1) {
+ qr_resume_pending_ops (qr_fd_ctx);
+ goto out;
+ }
+
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open, &loc, flags, fd);
+
+ qr_loc_wipe (&loc);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_fsetxattr_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;
+}
+
+
+int32_t
+qr_fsetxattr_helper (call_frame_t *frame, xlator_t *this, fd_t *fd,
+ dict_t *dict, int32_t flags)
+{
+ STACK_WIND (frame, qr_fsetxattr_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->fsetxattr, fd, dict, flags);
+ return 0;
+}
+
+
+int32_t
+qr_fsetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *dict,
+ int32_t flags)
+{
+ uint64_t value = 0;
+ call_stub_t *stub = NULL;
+ char *path = NULL;
+ loc_t loc = {0, };
+ int open_flags = 0;
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ int32_t ret = -1, op_ret = -1, op_errno = -1;
+ char need_open = 0, can_wind = 0, need_unwind = 0;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long) value;
+ }
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ path = qr_fd_ctx->path;
+ open_flags = qr_fd_ctx->flags;
+
+ if (!(qr_fd_ctx->opened
+ || qr_fd_ctx->open_in_transit)) {
+ need_open = 1;
+ qr_fd_ctx->open_in_transit = 1;
+ }
+
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else {
+ stub = fop_fsetxattr_stub (frame,
+ qr_fsetxattr_helper,
+ fd, dict, flags);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto unlock;
+ }
+
+ list_add_tail (&stub->list,
+ &qr_fd_ctx->waiting_ops);
+ }
+ }
+ unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+ } else {
+ can_wind = 1;
+ }
+
+out:
+ if (need_unwind) {
+ STACK_UNWIND (frame, op_ret, op_errno);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_fsetxattr_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->fsetxattr, fd, dict,
+ flags);
+ } else if (need_open) {
+ op_ret = qr_loc_fill (&loc, fd->inode, path);
+ if (op_ret == -1) {
+ qr_resume_pending_ops (qr_fd_ctx);
+ goto out;
+ }
+
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open, &loc, open_flags,
+ fd);
+
+ qr_loc_wipe (&loc);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_fgetxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, dict_t *dict)
+{
+ STACK_UNWIND (frame, op_ret, op_errno, dict);
+ return 0;
+}
+
+
+int32_t
+qr_fgetxattr_helper (call_frame_t *frame, xlator_t *this, fd_t *fd,
+ const char *name)
+{
+ STACK_WIND (frame, qr_fgetxattr_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->fgetxattr, fd, name);
+ return 0;
+}
+
+
+int32_t
+qr_fgetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, const char *name)
+{
+ int flags = 0;
+ uint64_t value = 0;
+ call_stub_t *stub = NULL;
+ char *path = NULL;
+ loc_t loc = {0, };
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ int32_t ret = -1, op_ret = -1, op_errno = -1;
+ char need_open = 0, can_wind = 0, need_unwind = 0;
+
+ /*
+ * FIXME: Can quick-read use the extended attributes stored in the
+ * cache? this needs to be discussed.
+ */
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long) value;
+ }
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ path = qr_fd_ctx->path;
+ flags = qr_fd_ctx->flags;
+
+ if (!(qr_fd_ctx->opened
+ || qr_fd_ctx->open_in_transit)) {
+ need_open = 1;
+ qr_fd_ctx->open_in_transit = 1;
+ }
+
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else {
+ stub = fop_fgetxattr_stub (frame,
+ qr_fgetxattr_helper,
+ fd, name);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto unlock;
+ }
+
+ list_add_tail (&stub->list,
+ &qr_fd_ctx->waiting_ops);
+ }
+ }
+ unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+ } else {
+ can_wind = 1;
+ }
+
+out:
+ if (need_unwind) {
+ STACK_UNWIND (frame, op_ret, op_errno, NULL);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_fgetxattr_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->fgetxattr, fd, name);
+ } else if (need_open) {
+ op_ret = qr_loc_fill (&loc, fd->inode, path);
+ if (op_ret == -1) {
+ qr_resume_pending_ops (qr_fd_ctx);
+ goto out;
+ }
+
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open, &loc, flags, fd);
+
+ qr_loc_wipe (&loc);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_flush_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;
+}
+
+
+int32_t
+qr_flush_helper (call_frame_t *frame, xlator_t *this, fd_t *fd)
+{
+ STACK_WIND (frame, qr_flush_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->flush, fd);
+ return 0;
+}
+
+
+int32_t
+qr_flush (call_frame_t *frame, xlator_t *this, fd_t *fd)
+{
+ uint64_t value = 0;
+ call_stub_t *stub = NULL;
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ int32_t ret = -1, op_ret = -1, op_errno = -1;
+ char can_wind = 0, need_unwind = 0;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long)value;
+ }
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else if (qr_fd_ctx->open_in_transit) {
+ stub = fop_flush_stub (frame, qr_flush_helper,
+ fd);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto unlock;
+ }
+
+ list_add_tail (&stub->list,
+ &qr_fd_ctx->waiting_ops);
+ } else {
+ op_ret = 0;
+ need_unwind = 1;
+ }
+ }
+ unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+ } else {
+ op_ret = 0;
+ need_unwind = 1;
+ }
+
+ if (need_unwind) {
+ STACK_UNWIND (frame, op_ret, op_errno);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_flush_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->flush, fd);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_fentrylk_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;
+}
+
+int32_t
+qr_fentrylk_helper (call_frame_t *frame, xlator_t *this, const char *volume,
+ fd_t *fd, const char *basename, entrylk_cmd cmd,
+ entrylk_type type)
+{
+ STACK_WIND(frame, qr_fentrylk_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->fentrylk, volume, fd, basename,
+ cmd, type);
+ return 0;
+}
+
+
+int32_t
+qr_fentrylk (call_frame_t *frame, xlator_t *this, const char *volume, fd_t *fd,
+ const char *basename, entrylk_cmd cmd, entrylk_type type)
+{
+ int flags = 0;
+ uint64_t value = 0;
+ call_stub_t *stub = NULL;
+ char *path = NULL;
+ loc_t loc = {0, };
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ int32_t ret = -1, op_ret = -1, op_errno = -1;
+ char need_open = 0, can_wind = 0, need_unwind = 0;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long)value;
+ }
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ path = qr_fd_ctx->path;
+ flags = qr_fd_ctx->flags;
+
+ if (!(qr_fd_ctx->opened
+ || qr_fd_ctx->open_in_transit)) {
+ need_open = 1;
+ qr_fd_ctx->open_in_transit = 1;
+ }
+
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else {
+ stub = fop_fentrylk_stub (frame,
+ qr_fentrylk_helper,
+ volume, fd, basename,
+ cmd, type);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto unlock;
+ }
+
+ list_add_tail (&stub->list,
+ &qr_fd_ctx->waiting_ops);
+ }
+ }
+ unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+ } else {
+ can_wind = 1;
+ }
+
+out:
+ if (need_unwind) {
+ STACK_UNWIND (frame, op_ret, op_errno);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_fentrylk_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->fentrylk, volume, fd,
+ basename, cmd, type);
+ } else if (need_open) {
+ op_ret = qr_loc_fill (&loc, fd->inode, path);
+ if (op_ret == -1) {
+ qr_resume_pending_ops (qr_fd_ctx);
+ goto out;
+ }
+
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open, &loc, flags, fd);
+
+ qr_loc_wipe (&loc);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_finodelk_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;
+}
+
+
+int32_t
+qr_finodelk_helper (call_frame_t *frame, xlator_t *this, const char *volume,
+ fd_t *fd, int32_t cmd, struct flock *lock)
+{
+ STACK_WIND (frame, qr_finodelk_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->finodelk, volume, fd, cmd, lock);
+ return 0;
+}
+
+
+int32_t
+qr_finodelk (call_frame_t *frame, xlator_t *this, const char *volume, fd_t *fd,
+ int32_t cmd, struct flock *lock)
+{
+ int flags = 0;
+ uint64_t value = 0;
+ call_stub_t *stub = NULL;
+ char *path = NULL;
+ loc_t loc = {0, };
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ int32_t ret = -1, op_ret = -1, op_errno = -1;
+ char need_open = 0, can_wind = 0, need_unwind = 0;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long)value;
+ }
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ path = qr_fd_ctx->path;
+ flags = qr_fd_ctx->flags;
+
+ if (!(qr_fd_ctx->opened
+ || qr_fd_ctx->open_in_transit)) {
+ need_open = 1;
+ qr_fd_ctx->open_in_transit = 1;
+ }
+
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else {
+ stub = fop_finodelk_stub (frame,
+ qr_finodelk_helper,
+ volume, fd, cmd,
+ lock);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto unlock;
+ }
+
+ list_add_tail (&stub->list,
+ &qr_fd_ctx->waiting_ops);
+ }
+ }
+ unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+ } else {
+ can_wind = 1;
+ }
+
+out:
+ if (need_unwind) {
+ STACK_UNWIND (frame, op_ret, op_errno);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_finodelk_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->finodelk, volume, fd,
+ cmd, lock);
+ } else if (need_open) {
+ op_ret = qr_loc_fill (&loc, fd->inode, path);
+ if (op_ret == -1) {
+ qr_resume_pending_ops (qr_fd_ctx);
+ goto out;
+ }
+
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open, &loc, flags, fd);
+
+ qr_loc_wipe (&loc);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_fsync_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;
+}
+
+
+int32_t
+qr_fsync_helper (call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags)
+{
+ STACK_WIND (frame, qr_fsync_cbk, FIRST_CHILD (this),
+ FIRST_CHILD(this)->fops->fsync, fd, flags);
+ return 0;
+}
+
+int32_t
+qr_fsync (call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags)
+{
+ uint64_t value = 0;
+ call_stub_t *stub = NULL;
+ char *path = NULL;
+ loc_t loc = {0, };
+ int open_flags = 0;
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ int32_t ret = -1, op_ret = -1, op_errno = -1;
+ char need_open = 0, can_wind = 0, need_unwind = 0;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long)value;
+ }
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ path = qr_fd_ctx->path;
+ open_flags = qr_fd_ctx->flags;
+
+ if (!(qr_fd_ctx->opened
+ || qr_fd_ctx->open_in_transit)) {
+ need_open = 1;
+ qr_fd_ctx->open_in_transit = 1;
+ }
+
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else {
+ stub = fop_fsync_stub (frame, qr_fsync_helper,
+ fd, flags);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto unlock;
+ }
+
+ list_add_tail (&stub->list,
+ &qr_fd_ctx->waiting_ops);
+ }
+ }
+ unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+ } else {
+ can_wind = 1;
+ }
+
+out:
+ if (need_unwind) {
+ STACK_UNWIND (frame, op_ret, op_errno);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_fsync_cbk, FIRST_CHILD (this),
+ FIRST_CHILD (this)->fops->fsync, fd, flags);
+ } else if (need_open) {
+ op_ret = qr_loc_fill (&loc, fd->inode, path);
+ if (op_ret == -1) {
+ qr_resume_pending_ops (qr_fd_ctx);
+ goto out;
+ }
+
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open, &loc, open_flags,
+ fd);
+
+ qr_loc_wipe (&loc);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_ftruncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct stat *buf)
+{
+ int32_t ret = 0;
+ uint64_t value = 0;
+ qr_file_t *qr_file = NULL;
+ qr_local_t *local = NULL;
+
+ if (op_ret == -1) {
+ goto out;
+ }
+
+ local = frame->local;
+ if ((local == NULL) || (local->fd == NULL)
+ || (local->fd->inode == NULL)) {
+ op_ret = -1;
+ op_errno = EINVAL;
+ goto out;
+ }
+
+ ret = inode_ctx_get (local->fd->inode, this, &value);
+ if (ret == 0) {
+ qr_file = (qr_file_t *)(long) value;
+
+ if (qr_file) {
+ LOCK (&qr_file->lock);
+ {
+ if (qr_file->stbuf.st_size != buf->st_size) {
+ dict_unref (qr_file->xattr);
+ qr_file->xattr = NULL;
+ }
+ }
+ UNLOCK (&qr_file->lock);
+ }
+ }
+
+out:
+ STACK_UNWIND (frame, op_ret, op_errno, buf);
+ return 0;
+}
+
+
+int32_t
+qr_ftruncate_helper (call_frame_t *frame, xlator_t *this, fd_t *fd,
+ off_t offset)
+{
+ STACK_WIND (frame, qr_ftruncate_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->ftruncate, fd, offset);
+ return 0;
+}
+
+
+int32_t
+qr_ftruncate (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset)
+{
+ int flags = 0;
+ uint64_t value = 0;
+ call_stub_t *stub = NULL;
+ char *path = NULL;
+ loc_t loc = {0, };
+ qr_local_t *local = NULL;
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ int32_t ret = -1, op_ret = -1, op_errno = -1;
+ char need_open = 0, can_wind = 0, need_unwind = 0;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long)value;
+ }
+
+ local = CALLOC (1, sizeof (*local));
+ if (local == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ goto out;
+ }
+
+ local->fd = fd;
+ frame->local = local;
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ path = qr_fd_ctx->path;
+ flags = qr_fd_ctx->flags;
+
+ if (!(qr_fd_ctx->opened
+ || qr_fd_ctx->open_in_transit)) {
+ need_open = 1;
+ qr_fd_ctx->open_in_transit = 1;
+ }
+
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else {
+ stub = fop_ftruncate_stub (frame,
+ qr_ftruncate_helper,
+ fd, offset);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto unlock;
+ }
+
+ list_add_tail (&stub->list,
+ &qr_fd_ctx->waiting_ops);
+ }
+ }
+ unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+ } else {
+ can_wind = 1;
+ }
+
+out:
+ if (need_unwind) {
+ STACK_UNWIND (frame, op_ret, op_errno, NULL);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_ftruncate_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->ftruncate, fd, offset);
+ } else if (need_open) {
+ op_ret = qr_loc_fill (&loc, fd->inode, path);
+ if (op_ret == -1) {
+ qr_resume_pending_ops (qr_fd_ctx);
+ goto out;
+ }
+
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open, &loc, flags, fd);
+
+ qr_loc_wipe (&loc);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_lk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
+ int32_t op_errno, struct flock *lock)
+{
+ STACK_UNWIND (frame, op_ret, op_errno, lock);
+ return 0;
+}
+
+
+int32_t
+qr_lk_helper (call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t cmd,
+ struct flock *lock)
+{
+ STACK_WIND (frame, qr_lk_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->lk, fd, cmd, lock);
+
+ return 0;
+}
+
+
+int32_t
+qr_lk (call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t cmd,
+ struct flock *lock)
+{
+ int flags = 0;
+ uint64_t value = 0;
+ call_stub_t *stub = NULL;
+ char *path = NULL;
+ loc_t loc = {0, };
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ int32_t ret = -1, op_ret = -1, op_errno = -1;
+ char need_open = 0, can_wind = 0, need_unwind = 0;
+
+ ret = fd_ctx_get (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long)value;
+ }
+
+ if (qr_fd_ctx) {
+ LOCK (&qr_fd_ctx->lock);
+ {
+ path = qr_fd_ctx->path;
+ flags = qr_fd_ctx->flags;
+
+ if (!(qr_fd_ctx->opened
+ || qr_fd_ctx->open_in_transit)) {
+ need_open = 1;
+ qr_fd_ctx->open_in_transit = 1;
+ }
+
+ if (qr_fd_ctx->opened) {
+ can_wind = 1;
+ } else {
+ stub = fop_lk_stub (frame, qr_lk_helper, fd,
+ cmd, lock);
+ if (stub == NULL) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ need_unwind = 1;
+ qr_fd_ctx->open_in_transit = 0;
+ goto unlock;
+ }
+
+ list_add_tail (&stub->list,
+ &qr_fd_ctx->waiting_ops);
+ }
+ }
+ unlock:
+ UNLOCK (&qr_fd_ctx->lock);
+ } else {
+ can_wind = 1;
+ }
+
+out:
+ if (need_unwind) {
+ STACK_UNWIND (frame, op_ret, op_errno, NULL);
+ } else if (can_wind) {
+ STACK_WIND (frame, qr_lk_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->lk, fd, cmd, lock);
+ } else if (need_open) {
+ op_ret = qr_loc_fill (&loc, fd->inode, path);
+ if (op_ret == -1) {
+ qr_resume_pending_ops (qr_fd_ctx);
+ goto out;
+ }
+
+ STACK_WIND (frame, qr_open_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->open, &loc, flags, fd);
+
+ qr_loc_wipe (&loc);
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_release (xlator_t *this, fd_t *fd)
+{
+ qr_fd_ctx_t *qr_fd_ctx = NULL;
+ int32_t ret = 0;
+ uint64_t value = 0;
+
+ ret = fd_ctx_del (fd, this, &value);
+ if (ret == 0) {
+ qr_fd_ctx = (qr_fd_ctx_t *)(long) value;
+ if (qr_fd_ctx) {
+ qr_fd_ctx_free (qr_fd_ctx);
+ }
+ }
+
+ return 0;
+}
+
+
+int32_t
+qr_forget (xlator_t *this, inode_t *inode)
+{
+ qr_file_t *qr_file = NULL;
+ uint64_t value = 0;
+ int32_t ret = -1;
+
+ ret = inode_ctx_del (inode, this, &value);
+ if (ret == 0) {
+ qr_file = (qr_file_t *)(long) value;
+ if (qr_file) {
+ LOCK (&qr_file->lock);
+ {
+ if (qr_file->xattr) {
+ dict_unref (qr_file->xattr);
+ qr_file->xattr = NULL;
+ }
+ }
+ UNLOCK (&qr_file->lock);
+ }
+
+ FREE (qr_file);
+ }
+
+ return 0;
+}
+
+
+int32_t
+init (xlator_t *this)
+{
+ char *str = NULL;
+ int32_t ret = -1;
+ qr_conf_t *conf = NULL;
+
+ if (!this->children || this->children->next) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "FATAL: volume (%s) not configured with exactly one "
+ "child", this->name);
+ return -1;
+ }
+
+ if (!this->parents) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "dangling volume. check volfile ");
+ }
+
+ conf = CALLOC (1, sizeof (*conf));
+ if (conf == NULL) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "out of memory");
+ ret = -1;
+ goto out;
+ }
+
+ ret = dict_get_str (this->options, "max-file-size",
+ &str);
+ if (ret == 0) {
+ ret = gf_string2bytesize (str, &conf->max_file_size);
+ if (ret != 0) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "invalid number format \"%s\" of \"option "
+ "max-file-size\"",
+ str);
+ ret = -1;
+ goto out;
+ }
+ }
+
+ conf->cache_timeout = -1;
+ ret = dict_get_str (this->options, "cache-timeout", &str);
+ if (ret == 0) {
+ ret = gf_string2uint_base10 (str,
+ (unsigned int *)&conf->cache_timeout);
+ if (ret != 0) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "invalid cache-timeout value %s", str);
+ ret = -1;
+ goto out;
+ }
+ }
+
+ this->private = conf;
+out:
+ if ((ret == -1) && conf) {
+ FREE (conf);
+ }
+
+ return ret;
+}
+
+
+void
+fini (xlator_t *this)
+{
+ return;
+}
+
+
+struct xlator_fops fops = {
+ .lookup = qr_lookup,
+ .open = qr_open,
+ .readv = qr_readv,
+ .writev = qr_writev,
+ .fstat = qr_fstat,
+ .fchown = qr_fchown,
+ .fchmod = qr_fchmod,
+ .fsetxattr = qr_fsetxattr,
+ .fgetxattr = qr_fgetxattr,
+ .flush = qr_flush,
+ .fentrylk = qr_fentrylk,
+ .finodelk = qr_finodelk,
+ .fsync = qr_fsync,
+ .ftruncate = qr_ftruncate,
+ .lk = qr_lk,
+};
+
+
+struct xlator_mops mops = {
+};
+
+
+struct xlator_cbks cbks = {
+ .forget = qr_forget,
+ .release = qr_release,
+};
+
+struct volume_options options[] = {
+ { .key = {"cache-timeout"},
+ .type = GF_OPTION_TYPE_INT,
+ .min = 1,
+ .max = 60
+ },
+ { .key = {"max-file-size"},
+ .type = GF_OPTION_TYPE_SIZET,
+ .min = 0,
+ .max = 1 * GF_UNIT_MB
+ },
+};
diff --git a/xlators/performance/quick-read/src/quick-read.h b/xlators/performance/quick-read/src/quick-read.h
new file mode 100644
index 000000000..c49ab167b
--- /dev/null
+++ b/xlators/performance/quick-read/src/quick-read.h
@@ -0,0 +1,80 @@
+/*
+ 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 __QUICK_READ_H
+#define __QUICK_READ_H
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "glusterfs.h"
+#include "logging.h"
+#include "dict.h"
+#include "xlator.h"
+#include "list.h"
+#include "compat.h"
+#include "compat-errno.h"
+#include "common-utils.h"
+#include "call-stub.h"
+#include "defaults.h"
+#include <libgen.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define GLUSTERFS_CONTENT_KEY "glusterfs.content"
+
+struct qr_fd_ctx {
+ char opened;
+ char open_in_transit;
+ char *path;
+ int flags;
+ struct list_head waiting_ops;
+ gf_lock_t lock;
+};
+typedef struct qr_fd_ctx qr_fd_ctx_t;
+
+struct qr_local {
+ char is_open;
+ fd_t *fd;
+ int open_flags;
+ int32_t op_ret;
+ int32_t op_errno;
+ call_stub_t *stub;
+};
+typedef struct qr_local qr_local_t;
+
+struct qr_file {
+ dict_t *xattr;
+ struct stat stbuf;
+ struct timeval tv;
+ gf_lock_t lock;
+};
+typedef struct qr_file qr_file_t;
+
+struct qr_conf {
+ uint64_t max_file_size;
+ int32_t cache_timeout;
+};
+typedef struct qr_conf qr_conf_t;
+
+#endif /* #ifndef __QUICK_READ_H */