diff options
| -rw-r--r-- | configure.ac | 2 | ||||
| -rwxr-xr-x | tests/performance/open-behind.t | 45 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volgen.c | 1 | ||||
| -rw-r--r-- | xlators/performance/Makefile.am | 2 | ||||
| -rw-r--r-- | xlators/performance/open-behind/Makefile.am | 1 | ||||
| -rw-r--r-- | xlators/performance/open-behind/src/Makefile.am | 15 | ||||
| -rw-r--r-- | xlators/performance/open-behind/src/open-behind-mem-types.h | 21 | ||||
| -rw-r--r-- | xlators/performance/open-behind/src/open-behind.c | 920 | 
8 files changed, 1006 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index 3f87a46a086..a2d49beb304 100644 --- a/configure.ac +++ b/configure.ac @@ -73,6 +73,8 @@ AC_CONFIG_FILES([Makefile  		xlators/performance/symlink-cache/src/Makefile  		xlators/performance/quick-read/Makefile  		xlators/performance/quick-read/src/Makefile +		xlators/performance/open-behind/Makefile +		xlators/performance/open-behind/src/Makefile                  xlators/performance/md-cache/Makefile                  xlators/performance/md-cache/src/Makefile  		xlators/debug/Makefile diff --git a/tests/performance/open-behind.t b/tests/performance/open-behind.t new file mode 100755 index 00000000000..2524ce9e276 --- /dev/null +++ b/tests/performance/open-behind.t @@ -0,0 +1,45 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 $H0:$B0/${V0}{1,2}; + +TEST $CLI volume start $V0; + +## Mount FUSE +TEST glusterfs -s $H0 --volfile-id $V0 $M0; + +TEST glusterfs -s $H0 --volfile-id $V0 $M1; + +D0="hello-this-is-a-test-message0"; +F0="test-file0"; + +function write_to() +{ +    local file="$1"; +    local data="$2"; + +    echo "$data" > "$file"; +} + + +TEST write_to "$M0/$F0" "$D0"; +EXPECT "$D0" cat $M1/$F0; + +TEST $CLI volume set $V0 performance.open-behind off; + +D1="hello-this-is-a-test-message1"; +F1="test-file1"; + +TEST write_to "$M0/$F1" "$D1"; +EXPECT "$D1" cat $M1/$F1; + +EXPECT "$D0" cat $M1/$F0; + +cleanup; diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index 01dbd8c79f2..f89cd3a4988 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -201,6 +201,7 @@ static struct volopt_map_entry glusterd_volopt_map[] = {          {"performance.read-ahead",               "performance/read-ahead",    "!perf", "on", NO_DOC, 0, 1},          {"performance.io-cache",                 "performance/io-cache",      "!perf", "on", NO_DOC, 0, 1},          {"performance.quick-read",               "performance/quick-read",    "!perf", "on", NO_DOC, 0, 1}, +        {"performance.open-behind",              "performance/open-behind",   "!perf", "on", NO_DOC, 0, 2},          {"performance.stat-prefetch",            "performance/md-cache",      "!perf", "on", NO_DOC, 0, 1},          {"performance.client-io-threads",        "performance/io-threads",    "!perf", "off", NO_DOC, 0, 1}, diff --git a/xlators/performance/Makefile.am b/xlators/performance/Makefile.am index eb94d8d6a1c..f99e11829db 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 quick-read md-cache +SUBDIRS = write-behind read-ahead io-threads io-cache symlink-cache quick-read md-cache open-behind  CLEANFILES =  diff --git a/xlators/performance/open-behind/Makefile.am b/xlators/performance/open-behind/Makefile.am new file mode 100644 index 00000000000..af437a64d6d --- /dev/null +++ b/xlators/performance/open-behind/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/xlators/performance/open-behind/src/Makefile.am b/xlators/performance/open-behind/src/Makefile.am new file mode 100644 index 00000000000..e7630ceffc3 --- /dev/null +++ b/xlators/performance/open-behind/src/Makefile.am @@ -0,0 +1,15 @@ +xlator_LTLIBRARIES = open-behind.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/performance + +open_behind_la_LDFLAGS = -module -avoidversion + +open_behind_la_SOURCES = open-behind.c +open_behind_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + +noinst_HEADERS = open-behind-mem-types.h + +AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src + +AM_CFLAGS = -Wall $(GF_CFLAGS) + +CLEANFILES = diff --git a/xlators/performance/open-behind/src/open-behind-mem-types.h b/xlators/performance/open-behind/src/open-behind-mem-types.h new file mode 100644 index 00000000000..1e94296f424 --- /dev/null +++ b/xlators/performance/open-behind/src/open-behind-mem-types.h @@ -0,0 +1,21 @@ +/* +  Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> +  This file is part of GlusterFS. + +  This file is licensed to you under your choice of the GNU Lesser +  General Public License, version 3 or any later version (LGPLv3 or +  later), or the GNU General Public License, version 2 (GPLv2), in all +  cases as published by the Free Software Foundation. +*/ + +#ifndef __OB_MEM_TYPES_H__ +#define __OB_MEM_TYPES_H__ + +#include "mem-types.h" + +enum gf_ob_mem_types_ { +        gf_ob_mt_fd_t   = gf_common_mt_end + 1, +	gf_ob_mt_conf_t, +        gf_ob_mt_end +}; +#endif diff --git a/xlators/performance/open-behind/src/open-behind.c b/xlators/performance/open-behind/src/open-behind.c new file mode 100644 index 00000000000..e6791973489 --- /dev/null +++ b/xlators/performance/open-behind/src/open-behind.c @@ -0,0 +1,920 @@ +/* +  Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> +  This file is part of GlusterFS. + +  This file is licensed to you under your choice of the GNU Lesser +  General Public License, version 3 or any later version (LGPLv3 or +  later), or the GNU General Public License, version 2 (GPLv2), in all +  cases as published by the Free Software Foundation. +*/ + +#include "open-behind-mem-types.h" +#include "xlator.h" +#include "statedump.h" +#include "call-stub.h" +#include "defaults.h" + +typedef struct ob_conf { +	gf_boolean_t  use_anonymous_fd; /* use anonymous FDs wherever safe +					   e.g - fstat() readv() + +					   whereas for fops like writev(), lk(), +					   the fd is important for side effects +					   like mandatory locks +					*/ +	gf_boolean_t  lazy_open; /* delay backend open as much as possible */ +} ob_conf_t; + + +typedef struct ob_fd { +	call_frame_t     *open_frame; +	loc_t             loc; +	dict_t           *xdata; +	int               flags; +	struct list_head  list; +} ob_fd_t; + + +ob_fd_t * +__ob_fd_ctx_get (xlator_t *this, fd_t *fd) +{ +	uint64_t    value = 0; +	int         ret = -1; +	ob_fd_t    *ob_fd = NULL; + +	ret = __fd_ctx_get (fd, this, &value); +	if (ret) +		return NULL; + +	ob_fd = (void *) ((long) value); + +	return ob_fd; +} + + +ob_fd_t * +ob_fd_ctx_get (xlator_t *this, fd_t *fd) +{ +	ob_fd_t  *ob_fd = NULL; + +	LOCK (&fd->lock); +	{ +		ob_fd = __ob_fd_ctx_get (this, fd); +	} +	UNLOCK (&fd->lock); + +	return ob_fd; +} + + +int +__ob_fd_ctx_set (xlator_t *this, fd_t *fd, ob_fd_t *ob_fd) +{ +	uint64_t    value = 0; +	int         ret = -1; + +	value = (long) ((void *) ob_fd); + +	ret = __fd_ctx_set (fd, this, value); + +	return ret; +} + + +int +ob_fd_ctx_set (xlator_t *this, fd_t *fd, ob_fd_t *ob_fd) +{ +	int ret = -1; + +	LOCK (&fd->lock); +	{ +		ret = __ob_fd_ctx_set (this, fd, ob_fd); +	} +	UNLOCK (&fd->lock); + +	return ret; +} + + +ob_fd_t * +ob_fd_new (void) +{ +	ob_fd_t  *ob_fd = NULL; + +	ob_fd = GF_CALLOC (1, sizeof (*ob_fd), gf_ob_mt_fd_t); + +	INIT_LIST_HEAD (&ob_fd->list); + +	return ob_fd; +} + + +void +ob_fd_free (ob_fd_t *ob_fd) +{ +	loc_wipe (&ob_fd->loc); + +	if (ob_fd->xdata) +		dict_unref (ob_fd->xdata); + +	if (ob_fd->open_frame) +		STACK_DESTROY (ob_fd->open_frame->root); + +	GF_FREE (ob_fd); +} + + +int +ob_wake_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +	     int op_ret, int op_errno, fd_t *fd_ret, dict_t *xdata) +{ +	fd_t              *fd = NULL; +	struct list_head   list; +	ob_fd_t           *ob_fd = NULL; +	call_stub_t       *stub = NULL, *tmp = NULL; + +	fd = frame->local; +	frame->local = NULL; + +	LOCK (&fd->lock); +	{ +		ob_fd = __ob_fd_ctx_get (this, fd); + +		__fd_ctx_del (fd, this, NULL); +	} +	UNLOCK (&fd->lock); + +	INIT_LIST_HEAD (&list); + +	list_splice_init (&ob_fd->list, &list); + +	list_for_each_entry_safe (stub, tmp, &list, list) { +		list_del_init (&stub->list); + +		call_resume (stub); +	} + +	ob_fd_free (ob_fd); + +	fd_unref (fd); + +	STACK_DESTROY (frame->root); + +	return 0; +} + + +int +ob_fd_wake (xlator_t *this, fd_t *fd) +{ +	call_frame_t *frame = NULL; +	ob_fd_t      *ob_fd = NULL; + +	LOCK (&fd->lock); +	{ +		ob_fd = __ob_fd_ctx_get (this, fd); +		if (!ob_fd) +			goto unlock; + +		frame = ob_fd->open_frame; +		ob_fd->open_frame = NULL; +	} +unlock: +	UNLOCK (&fd->lock); + +	if (frame) { +		frame->local = fd_ref (fd); + +		STACK_WIND (frame, ob_wake_cbk, FIRST_CHILD (this), +			    FIRST_CHILD (this)->fops->open, +			    &ob_fd->loc, ob_fd->flags, fd, ob_fd->xdata); +	} + +	return 0; +} + + +int +open_and_resume (xlator_t *this, fd_t *fd, call_stub_t *stub) +{ +	ob_fd_t  *ob_fd = NULL; + +	if (!fd) +		goto nofd; + +	LOCK (&fd->lock); +	{ +		ob_fd = __ob_fd_ctx_get (this, fd); +		if (!ob_fd) +			goto unlock; + +		list_add_tail (&stub->list, &ob_fd->list); +	} +unlock: +	UNLOCK (&fd->lock); + +nofd: +	if (ob_fd) +		ob_fd_wake (this, fd); +	else +		call_resume (stub); + +	return 0; +} + + +int +ob_open_behind (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, +		fd_t *fd, dict_t *xdata) +{ +	ob_fd_t    *ob_fd = NULL; +	int         ret = -1; +	ob_conf_t  *conf = NULL; + + +	conf = this->private; + +	if (flags & O_TRUNC) { +		STACK_WIND (frame, default_open_cbk, +			    FIRST_CHILD (this), FIRST_CHILD (this)->fops->open, +			    loc, flags, fd, xdata); +		return 0; +	} + +	ob_fd = ob_fd_new (); +	if (!ob_fd) +		goto enomem; + +	ob_fd->open_frame = copy_frame (frame); +	if (!ob_fd->open_frame) +		goto enomem; +	ret = loc_copy (&ob_fd->loc, loc); +	if (ret) +		goto enomem; + +	ob_fd->flags = flags; +	if (xdata) +		ob_fd->xdata = dict_ref (xdata); + +	ret = ob_fd_ctx_set (this, fd, ob_fd); +	if (ret) +		goto enomem; + +	fd_ref (fd); + +	STACK_UNWIND_STRICT (open, frame, 0, 0, fd, xdata); + +	if (!conf->lazy_open) +		ob_fd_wake (this, fd); + +	fd_unref (fd); + +	return 0; +enomem: +	if (ob_fd) { +		if (ob_fd->open_frame) +			STACK_DESTROY (ob_fd->open_frame->root); +		loc_wipe (&ob_fd->loc); +		if (ob_fd->xdata) +			dict_unref (ob_fd->xdata); +		GF_FREE (ob_fd); +	} + +	return -1; +} + + +int +ob_open (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, +	 fd_t *fd, dict_t *xdata) +{ +	fd_t         *old_fd = NULL; +	int           ret = -1; +	int           op_errno = 0; +	call_stub_t  *stub = NULL; + +	old_fd = fd_lookup (fd->inode, 0); +	if (old_fd) { +		/* open-behind only when this is the first FD */ +		stub = fop_open_stub (frame, default_open_resume, +				      loc, flags, fd, xdata); +		if (!stub) { +			op_errno = ENOMEM; +			fd_unref (old_fd); +			goto err; +		} + +		open_and_resume (this, old_fd, stub); + +		fd_unref (old_fd); + +		return 0; +	} + +	ret = ob_open_behind (frame, this, loc, flags, fd, xdata); +	if (ret) { +		op_errno = ENOMEM; +		goto err; +	} + +	return 0; +err: +	gf_log (this->name, GF_LOG_ERROR, "%s: %s", loc->path, +		strerror (op_errno)); + +	STACK_UNWIND_STRICT (open, frame, -1, op_errno, 0, 0); + +	return 0; +} + + +fd_t * +ob_get_wind_fd (xlator_t *this, fd_t *fd) +{ +	ob_conf_t  *conf = NULL; +	ob_fd_t    *ob_fd = NULL; + +	conf = this->private; + +	ob_fd = ob_fd_ctx_get (this, fd); + +	if (ob_fd && conf->use_anonymous_fd) +		return fd_anonymous (fd->inode); + +	return fd_ref (fd); +} + + +int +ob_readv (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, +	  off_t offset, uint32_t flags, dict_t *xdata) +{ +	call_stub_t  *stub = NULL; +	fd_t         *wind_fd = NULL; + +	wind_fd = ob_get_wind_fd (this, fd); + +	stub = fop_readv_stub (frame, default_readv_resume, wind_fd, +			       size, offset, flags, xdata); +	fd_unref (wind_fd); + +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (readv, frame, -1, ENOMEM, 0, 0, 0, 0, 0); + +	return 0; +} + + +int +ob_writev (call_frame_t *frame, xlator_t *this, fd_t *fd, struct iovec *iov, +	   int count, off_t offset, uint32_t flags, struct iobref *iobref, +	   dict_t *xdata) +{ +	call_stub_t  *stub = NULL; + +	stub = fop_writev_stub (frame, default_writev_resume, fd, iov, count, +				offset, flags, iobref, xdata); +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (writev, frame, -1, ENOMEM, 0, 0, 0); + +	return 0; +} + + +int +ob_fstat (call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata) +{ +	call_stub_t  *stub = NULL; +	fd_t         *wind_fd = NULL; + +	wind_fd = ob_get_wind_fd (this, fd); + +	stub = fop_fstat_stub (frame, default_fstat_resume, wind_fd, xdata); + +	fd_unref (wind_fd); + +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (fstat, frame, -1, ENOMEM, 0, 0); + +	return 0; +} + + +int +ob_flush (call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata) +{ +	call_stub_t   *stub = NULL; +	ob_fd_t       *ob_fd = NULL; +	gf_boolean_t   unwind = _gf_false; + +	LOCK (&fd->lock); +	{ +		ob_fd = __ob_fd_ctx_get (this, fd); +		if (ob_fd && ob_fd->open_frame) +			/* if open() was never wound to backend, +			   no need to wind flush() either. +			*/ +			unwind = _gf_true; +	} +	UNLOCK (&fd->lock); + +	if (unwind) +		goto unwind; + +	stub = fop_flush_stub (frame, default_flush_resume, fd, xdata); +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (flush, frame, -1, ENOMEM, 0); + +	return 0; + +unwind: +	STACK_UNWIND_STRICT (flush, frame, 0, 0, 0); + +	return 0; +} + + +int +ob_fsync (call_frame_t *frame, xlator_t *this, fd_t *fd, int flag, +	  dict_t *xdata) +{ +	call_stub_t  *stub = NULL; + +	stub = fop_fsync_stub (frame, default_fsync_resume, fd, flag, xdata); +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (fsync, frame, -1, ENOMEM, 0, 0, 0); + +	return 0; +} + + +int +ob_lk (call_frame_t *frame, xlator_t *this, fd_t *fd, int cmd, +       struct gf_flock *flock, dict_t *xdata) +{ +	call_stub_t  *stub = NULL; + +	stub = fop_lk_stub (frame, default_lk_resume, fd, cmd, flock, xdata); +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (lk, frame, -1, ENOMEM, 0, 0); + +	return 0; +} + +int +ob_ftruncate (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +	      dict_t *xdata) +{ +	call_stub_t  *stub = NULL; + +	stub = fop_ftruncate_stub (frame, default_ftruncate_resume, fd, offset, +				   xdata); +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (ftruncate, frame, -1, ENOMEM, 0, 0, 0); + +	return 0; +} + + +int +ob_fsetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xattr, +	      int flags, dict_t *xdata) +{ +	call_stub_t  *stub = NULL; + +	stub = fop_fsetxattr_stub (frame, default_fsetxattr_resume, fd, xattr, +				   flags, xdata); +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (fsetxattr, frame, -1, ENOMEM, 0); + +	return 0; +} + + +int +ob_fgetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, const char *name, +	      dict_t *xdata) +{ +	call_stub_t  *stub = NULL; + +	stub = fop_fgetxattr_stub (frame, default_fgetxattr_resume, fd, name, +				   xdata); +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (fgetxattr, frame, -1, ENOMEM, 0, 0); + +	return 0; +} + + +int +ob_fremovexattr (call_frame_t *frame, xlator_t *this, fd_t *fd, +		 const char *name, dict_t *xdata) +{ +	call_stub_t  *stub = NULL; + +	stub = fop_fremovexattr_stub (frame, default_fremovexattr_resume, fd, +				      name, xdata); +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (fremovexattr, frame, -1, ENOMEM, 0); + +	return 0; +} + + +int +ob_finodelk (call_frame_t *frame, xlator_t *this, const char *volume, fd_t *fd, +	     int cmd, struct gf_flock *flock, dict_t *xdata) +{ +	call_stub_t  *stub = NULL; + +	stub = fop_finodelk_stub (frame, default_finodelk_resume, volume, fd, +				  cmd, flock, xdata); +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (finodelk, frame, -1, ENOMEM, 0); + +	return 0; +} + + +int +ob_fentrylk (call_frame_t *frame, xlator_t *this, const char *volume, fd_t *fd, +	     const char *basename, entrylk_cmd cmd, entrylk_type type, +	     dict_t *xdata) +{ +	call_stub_t  *stub = NULL; + +	stub = fop_fentrylk_stub (frame, default_fentrylk_resume, volume, fd, +				  basename, cmd, type, xdata); +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (fentrylk, frame, -1, ENOMEM, 0); + +	return 0; +} + + +int +ob_fxattrop (call_frame_t *frame, xlator_t *this, fd_t *fd, +	     gf_xattrop_flags_t optype, dict_t *xattr, dict_t *xdata) +{ +	call_stub_t  *stub = NULL; + +	stub = fop_fxattrop_stub (frame, default_fxattrop_resume, fd, optype, +				  xattr, xdata); +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (fxattrop, frame, -1, ENOMEM, 0, 0); + +	return 0; +} + + +int +ob_fsetattr (call_frame_t *frame, xlator_t *this, fd_t *fd, +	     struct iatt *iatt, int valid, dict_t *xdata) +{ +	call_stub_t  *stub = NULL; + +	stub = fop_fsetattr_stub (frame, default_fsetattr_resume, fd, +				  iatt, valid, xdata); +	if (!stub) +		goto err; + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (fsetattr, frame, -1, ENOMEM, 0, 0, 0); + +	return 0; +} + + +int +ob_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int xflags, +	   dict_t *xdata) +{ +	fd_t         *fd = NULL; +	call_stub_t  *stub = NULL; + +	stub = fop_unlink_stub (frame, default_unlink_resume, loc, +				xflags, xdata); +	if (!stub) +		goto err; + +	fd = fd_lookup (loc->inode, 0); + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (unlink, frame, -1, ENOMEM, 0, 0, 0); + +	return 0; +} + + +int +ob_rename (call_frame_t *frame, xlator_t *this, loc_t *src, loc_t *dst, +	   dict_t *xdata) +{ +	fd_t         *fd = NULL; +	call_stub_t  *stub = NULL; + +	stub = fop_rename_stub (frame, default_rename_resume, src, dst, xdata); +	if (!stub) +		goto err; + +	if (dst->inode) +		fd = fd_lookup (dst->inode, 0); + +	open_and_resume (this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT (rename, frame, -1, ENOMEM, 0, 0, 0, 0, 0, 0); + +	return 0; +} + + +int +ob_release (xlator_t *this, fd_t *fd) +{ +	ob_fd_t *ob_fd = NULL; + +	ob_fd = ob_fd_ctx_get (this, fd); + +	ob_fd_free (ob_fd); + +	return 0; +} + + +int +ob_priv_dump (xlator_t *this) +{ +        ob_conf_t        *conf       = NULL; +        char              key_prefix[GF_DUMP_MAX_BUF_LEN]; + +        conf = this->private; + +        if (!conf) +                return -1; + +        gf_proc_dump_build_key (key_prefix, "xlator.performance.open-behind", +                                "priv"); + +        gf_proc_dump_add_section (key_prefix); + +        gf_proc_dump_write ("use_anonymous_fd", "%d", conf->use_anonymous_fd); + +        gf_proc_dump_write ("lazy_open", "%d", conf->lazy_open); + +        return 0; +} + + +int +ob_fdctx_dump (xlator_t *this, fd_t *fd) +{ +	ob_fd_t   *ob_fd = NULL; +        char       key_prefix[GF_DUMP_MAX_BUF_LEN] = {0, }; +	int        ret = 0; + +	ret = TRY_LOCK (&fd->lock); +	if (ret) +		return 0; + +	ob_fd = __ob_fd_ctx_get (this, fd); +	if (!ob_fd) { +		UNLOCK (&fd->lock); +		return 0; +	} + +        gf_proc_dump_build_key (key_prefix, "xlator.performance.open-behind", +                                "file"); +        gf_proc_dump_add_section (key_prefix); + +        gf_proc_dump_write ("fd", "%p", fd); + +        gf_proc_dump_write ("open_frame", "%p", ob_fd->open_frame); + +        gf_proc_dump_write ("open_frame.root.unique", "%p", +			    ob_fd->open_frame->root->unique); + +	gf_proc_dump_write ("loc.path", "%s", ob_fd->loc.path); + +	gf_proc_dump_write ("loc.ino", "%s", uuid_utoa (ob_fd->loc.gfid)); + +        gf_proc_dump_write ("flags", "%p", ob_fd->open_frame); + +	UNLOCK (&fd->lock); + +	return 0; +} + + +int +mem_acct_init (xlator_t *this) +{ +        int     ret = -1; + +        ret = xlator_mem_acct_init (this, gf_ob_mt_end + 1); + +        if (ret) +                gf_log (this->name, GF_LOG_ERROR, "Memory accounting failed"); + +        return ret; +} + + +int +reconfigure (xlator_t *this, dict_t *options) +{ +        ob_conf_t  *conf = NULL; +	int         ret = -1; + +        conf = this->private; + +        GF_OPTION_RECONF ("use-anonymous-fd", conf->use_anonymous_fd, options, +			  bool, out); + +        GF_OPTION_RECONF ("lazy-open", conf->lazy_open, options, bool, out); + +        ret = 0; +out: +        return ret; +} + + +int +init (xlator_t *this) +{ +        ob_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 = GF_CALLOC (1, sizeof (*conf), gf_ob_mt_conf_t); +        if (!conf) +                goto err; + +        GF_OPTION_INIT ("use-anonymous-fd", conf->use_anonymous_fd, bool, err); + +        GF_OPTION_INIT ("lazy-open", conf->lazy_open, bool, err); + +        this->private = conf; + +	return 0; +err: +	if (conf) +                GF_FREE (conf); + +        return -1; +} + + +void +fini (xlator_t *this) +{ +        ob_conf_t *conf = NULL; + +        conf = this->private; + +        GF_FREE (conf); + +	return; +} + + +struct xlator_fops fops = { +        .open        = ob_open, +        .readv       = ob_readv, +        .writev      = ob_writev, +	.flush       = ob_flush, +	.fsync       = ob_fsync, +	.fstat       = ob_fstat, +	.ftruncate   = ob_ftruncate, +	.fsetxattr   = ob_fsetxattr, +	.fgetxattr   = ob_fgetxattr, +	.fremovexattr = ob_fremovexattr, +	.finodelk    = ob_finodelk, +	.fentrylk    = ob_fentrylk, +	.fxattrop    = ob_fxattrop, +	.fsetattr    = ob_fsetattr, +	.unlink      = ob_unlink, +	.rename      = ob_rename, +	.lk          = ob_lk, +}; + +struct xlator_cbks cbks = { +        .release  = ob_release, +}; + +struct xlator_dumpops dumpops = { +	.priv    = ob_priv_dump, +	.fdctx   = ob_fdctx_dump, +}; + + +struct volume_options options[] = { +        { .key  = {"use-anonymous-fd"}, +          .type = GF_OPTION_TYPE_BOOL, +          .default_value = "yes", +	  .description = "For read operations, use anonymous FD when " +	  "original FD is open-behind and not yet opened in the backend.", +        }, +        { .key  = {"lazy-open"}, +          .type = GF_OPTION_TYPE_BOOL, +          .default_value = "yes", +	  .description = "Perform open in the backend only when a necessary " +	  "FOP arrives (e.g writev on the FD, unlink of the file). When option " +	  "is disabled, perform backend open right after unwinding open().", +        }, + +};  | 
