summaryrefslogtreecommitdiffstats
path: root/xlators/nfs/server/src/nfs-generics.c
diff options
context:
space:
mode:
authorShehjar Tikoo <shehjart@gluster.com>2010-03-31 07:27:03 +0000
committerAnand V. Avati <avati@dev.gluster.com>2010-03-31 07:44:02 -0700
commitc4fd1cf7325972d8ff64ef3a2bea70edcf4f1085 (patch)
treeb91c42227b2881eb8b77d39aca3d8348966bc052 /xlators/nfs/server/src/nfs-generics.c
parent8b2949db0d56bdf5842abcb72437cc7dccd884df (diff)
nfs: Add generic nfs translator
Signed-off-by: Shehjar Tikoo <shehjart@gluster.com> Signed-off-by: Anand V. Avati <avati@dev.gluster.com> BUG: 399 (NFS translator with Mount v3 and NFS v3 support) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=399
Diffstat (limited to 'xlators/nfs/server/src/nfs-generics.c')
-rw-r--r--xlators/nfs/server/src/nfs-generics.c1067
1 files changed, 1067 insertions, 0 deletions
diff --git a/xlators/nfs/server/src/nfs-generics.c b/xlators/nfs/server/src/nfs-generics.c
new file mode 100644
index 00000000000..f83a7c86814
--- /dev/null
+++ b/xlators/nfs/server/src/nfs-generics.c
@@ -0,0 +1,1067 @@
+/*
+ Copyright (c) 2010 Gluster, Inc. <http://www.gluster.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 "string.h"
+
+#include "inode.h"
+#include "nfs.h"
+#include "nfs-fops.h"
+#include "nfs-inodes.h"
+#include "nfs-generics.h"
+#include "xlator.h"
+
+
+int
+nfs_fstat (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, fop_stat_cbk_t cbk,
+ void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!fd) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_fstat (xl, nfu, fd, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_stat (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, fop_stat_cbk_t cbk,
+ void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_stat (xl, nfu, pathloc, cbk, local);
+
+ return ret;
+}
+
+
+
+int
+nfs_readdirp (xlator_t *xl, nfs_user_t *nfu, fd_t *dirfd, size_t bufsize,
+ off_t offset, fop_readdir_cbk_t cbk, void *local)
+{
+ if ((!xl) || (!dirfd) || (!nfu))
+ return -EFAULT;
+
+ return nfs_fop_readdirp (xl, nfu, dirfd, bufsize, offset, cbk,
+ local);
+}
+
+
+
+int
+nfs_lookup (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_lookup_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_lookup (xl, nfu, pathloc, cbk, local);
+ return ret;
+}
+
+int
+nfs_create (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int flags,
+ mode_t mode, fop_create_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_create (xl, nfu, pathloc, flags, mode, cbk,local);
+ return ret;
+}
+
+
+int
+nfs_flush (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, fop_flush_cbk_t cbk,
+ void *local)
+{
+ return nfs_fop_flush (xl, nfu, fd, cbk, local);
+}
+
+
+
+int
+nfs_mkdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, mode_t mode,
+ fop_mkdir_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_mkdir (xl, nfu, pathloc, mode, cbk, local);
+ return ret;
+}
+
+
+
+int
+nfs_truncate (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, off_t offset,
+ fop_truncate_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_truncate (xl, nfu, pathloc, offset, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_read (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, size_t size,
+ off_t offset, fop_readv_cbk_t cbk, void *local)
+{
+ return nfs_fop_read (xl, nfu, fd, size, offset, cbk, local);
+}
+
+
+int
+nfs_fsync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, int32_t datasync,
+ fop_fsync_cbk_t cbk, void *local)
+{
+ return nfs_fop_fsync (xl, nfu, fd, datasync, cbk, local);
+}
+
+
+int
+nfs_write (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, struct iobuf *srciob,
+ struct iovec *vector, int32_t count, off_t offset,
+ fop_writev_cbk_t cbk, void *local)
+{
+ return nfs_fop_write (xl, nfu, fd, srciob, vector, count, offset, cbk,
+ local);
+}
+
+
+int
+nfs_open (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int32_t flags,
+ fop_open_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_open (xl, nfu, pathloc, flags, GF_OPEN_NOWB, cbk,
+ local);
+ return ret;
+}
+
+
+int
+nfs_rename (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc, loc_t *newloc,
+ fop_rename_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!oldloc) || (!newloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_rename (xl, nfu, oldloc, newloc, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_link (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc, loc_t *newloc,
+ fop_link_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!oldloc) || (!newloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_link (xl, nfu, oldloc, newloc, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_unlink (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_unlink_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_unlink (xl, nfu, pathloc, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_rmdir (xlator_t *xl, nfs_user_t *nfu, loc_t *path, fop_rmdir_cbk_t cbk,
+ void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!path) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_rmdir (xl, nfu, path, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_mknod (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, mode_t mode,
+ dev_t dev, fop_mknod_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_mknod (xl, nfu, pathloc, mode, dev, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_readlink (xlator_t *xl, nfs_user_t *nfu, loc_t *linkloc,
+ fop_readlink_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!linkloc) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_readlink (xl, nfu, linkloc, NFS_PATH_MAX, cbk, local);
+ return ret;
+}
+
+
+
+int
+nfs_symlink (xlator_t *xl, nfs_user_t *nfu, char *target, loc_t *linkloc,
+ fop_symlink_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!linkloc) || (!target) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_symlink (xl, nfu, target, linkloc, cbk, local);
+ return ret;
+}
+
+
+
+int
+nfs_setattr (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ struct iatt *buf, int32_t valid, fop_setattr_cbk_t cbk,
+ void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_setattr (xl, nfu, pathloc, buf, valid, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_statfs (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_statfs_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_statfs (xl, nfu, pathloc, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_open_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, fd_t *fd)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (!sf)
+ return -1;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync open failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync open done");
+
+ sf->replystub = fop_open_cbk_stub (frame, NULL, op_ret, op_errno, fd);
+
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+call_stub_t *
+nfs_open_sync (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int32_t flags)
+{
+ nfs_syncfop_t *sf = NULL;
+ call_stub_t *reply = NULL;
+ int ret = -1;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed");
+ goto err;
+ }
+
+ ret = nfs_open (xl, nfu, pathloc, flags, nfs_open_sync_cbk, sf);
+ if (ret < 0)
+ goto err;
+
+ reply = nfs_syncfop_wait (sf);
+
+err:
+ if (ret < 0)
+ FREE (sf);
+
+ return reply;
+}
+
+
+
+int
+nfs_fdctx_alloc (fd_t *fd, xlator_t *xl)
+{
+ nfs_fdctx_t *fdctx = NULL;
+ int ret = -EFAULT;
+
+ if ((!fd) || (!xl))
+ return ret;
+
+ fdctx = CALLOC (1, sizeof (*fdctx));
+ if (!fdctx) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Memory allocation failure");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ pthread_mutex_init (&fdctx->lock, NULL);
+
+ ret = fd_ctx_set (fd, xl, (uint64_t)fdctx);
+ if (ret == -1) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to set fd context");
+ ret = -EFAULT;
+ goto free_ctx;
+ }
+
+ ret = 0;
+
+free_ctx:
+ if (ret < 0)
+ FREE (fdctx);
+
+err:
+ return ret;
+}
+
+
+void
+nfs_fdctx_del (fd_t *fd, xlator_t *xl)
+{
+ nfs_fdctx_t *fdctx = NULL;
+ uint64_t ctxaddr = 0;
+ int ret = -1;
+
+ if ((!fd) || (!xl))
+ return;
+
+ ret = fd_ctx_del (fd, xl, &ctxaddr);
+ if (ret == -1)
+ goto err;
+
+ fdctx = (nfs_fdctx_t *)ctxaddr;
+ FREE (fdctx);
+
+err:
+ return;
+}
+
+
+nfs_fdctx_t *
+nfs_fdctx_get (fd_t *fd, xlator_t *xl)
+{
+ nfs_fdctx_t *fdctx = NULL;
+ int ret = -1;
+ uint64_t ctxptr = 0;
+
+ if ((!fd) || (!xl))
+ return NULL;
+
+ ret = fd_ctx_get (fd, xl, &ctxptr);
+ if (ret == -1) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to get fd context");
+ goto err;
+ }
+
+ fdctx = (nfs_fdctx_t *)ctxptr;
+err:
+ return fdctx;
+}
+
+
+int
+nfs_dir_fdctx_init (fd_t *dirfd, xlator_t *xl, xlator_t *fopxl, size_t bufsize)
+{
+ int ret = -EFAULT;
+ nfs_fdctx_t *fdctx = NULL;
+
+ if ((!dirfd) || (!xl))
+ return ret;
+
+ ret = nfs_fdctx_alloc (dirfd, xl);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to alloc dir fd context");
+ goto err;
+ }
+
+ fdctx = nfs_fdctx_get (dirfd, xl);
+ if (!fdctx) {
+ ret = -EFAULT;
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to get dir fd context");
+ goto err;
+ }
+
+ fdctx->dcache = CALLOC (1, sizeof (struct nfs_direntcache));
+ if (!fdctx->dcache) {
+ ret = -ENOMEM;
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to allocate dirent"
+ " cache");
+ goto free_ctx;
+ }
+
+ INIT_LIST_HEAD (&fdctx->dcache->entries.list);
+ fdctx->dirent_bufsize = bufsize;
+ fdctx->dirvol = fopxl;
+
+ ret = 0;
+
+free_ctx:
+ if (ret < 0)
+ nfs_fdctx_del (dirfd, xl);
+err:
+ return ret;
+}
+
+
+
+
+/* Dirent caching code copied from libglusterfsclient.
+ * Please duplicate enhancements and bug fixes there too.
+ */
+void
+nfs_dcache_invalidate (xlator_t *nfsx, fd_t *fd)
+{
+ nfs_fdctx_t *fd_ctx = NULL;
+
+ if (!fd)
+ return;
+
+ fd_ctx = nfs_fdctx_get (fd, nfsx);
+ if (!fd_ctx) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "No fd context present");
+ return;
+ }
+
+ if (!fd_ctx->dcache) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "No dirent cache present");
+ return;
+ }
+
+ if (!list_empty (&fd_ctx->dcache->entries.list)) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Freeing dirents");
+ gf_dirent_free (&fd_ctx->dcache->entries);
+ }
+
+ INIT_LIST_HEAD (&fd_ctx->dcache->entries.list);
+
+ fd_ctx->dcache->next = NULL;
+ fd_ctx->dcache->prev_off = 0;
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache invalidated");
+
+ return;
+}
+
+/* Dirent caching code copied from libglusterfsclient.
+ * Please duplicate enhancements and bug fixes there too.
+ */
+/* The first entry in the entries is always a placeholder
+ * or the list head. The real entries begin from entries->next.
+ */
+int
+nfs_dcache_update (xlator_t *nfsx, fd_t *fd, gf_dirent_t *entries)
+{
+ nfs_fdctx_t *fdctx = NULL;
+ int ret = -EFAULT;
+
+ if ((!fd) || (!entries))
+ return ret;
+
+ fdctx = nfs_fdctx_get (fd, nfsx);
+ if (!fdctx) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "No fd context present");
+ return ret;
+ }
+
+ /* dcache is not enabled. */
+ if (!fdctx->dcache) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "No dirent cache present");
+ return ret;
+ }
+
+ /* If we're updating, we must begin with invalidating any previous
+ * entries.
+ */
+ nfs_dcache_invalidate (nfsx, fd);
+
+ fdctx->dcache->next = entries->next;
+ /* We still need to store a pointer to the head
+ * so we start free'ing from the head when invalidation
+ * is required.
+ *
+ * Need to delink the entries from the list
+ * given to us by an underlying translators. Most translators will
+ * free this list after this call so we must preserve the dirents in
+ * order to cache them.
+ */
+ list_splice_init (&entries->list, &fdctx->dcache->entries.list);
+ ret = 0;
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache updated");
+
+ return ret;
+}
+
+/* Dirent caching code copied from libglusterfsclient.
+ * Please duplicate enhancements and bug fixes there too.
+ */
+int
+nfs_dcache_readdir (xlator_t *nfsx, fd_t *fd, gf_dirent_t *dirp, off_t *offset)
+{
+ nfs_fdctx_t *fdctx = NULL;
+ int cachevalid = 0;
+
+ if ((!fd) || (!dirp) || (!offset))
+ return 0;
+
+ fdctx = nfs_fdctx_get (fd, nfsx);
+ if (!fdctx) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "No fd context present");
+ goto out;
+ }
+
+ if (!fdctx->dcache) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "No dirent cache present");
+ goto out;
+ }
+
+ /* We've either run out of entries in the cache
+ * or the cache is empty.
+ */
+ if (!fdctx->dcache->next) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache is empty");
+ goto out;
+ }
+
+ /* The dirent list is created as a circular linked list
+ * so this check is needed to ensure, we dont start
+ * reading old entries again.
+ * If we're reached this situation, the cache is exhausted
+ * and we'll need to pre-fetch more entries to continue serving.
+ */
+ if (fdctx->dcache->next == &fdctx->dcache->entries) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache was exhausted");
+ goto out;
+ }
+
+ /* During sequential reading we generally expect that the offset
+ * requested is the same as the offset we served in the previous call
+ * to readdir. But, seekdir, rewinddir and libgf_dcache_invalidate
+ * require special handling because seekdir/rewinddir change the offset
+ * in the fd_ctx and libgf_dcache_invalidate changes the prev_off.
+ */
+ if (*offset != fdctx->dcache->prev_off) {
+ /* For all cases of the if branch above, we know that the
+ * cache is now invalid except for the case below. It handles
+ * the case where the two offset values above are different
+ * but different because the previous readdir block was
+ * exhausted, resulting in a prev_off being set to 0 in
+ * libgf_dcache_invalidate, while the requested offset is non
+ * zero because that is what we returned for the last dirent
+ * of the previous readdir block.
+ */
+ if ((*offset != 0) && (fdctx->dcache->prev_off == 0)) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache was"
+ " exhausted");
+ cachevalid = 1;
+ } else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache is"
+ " invalid");
+ } else {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache is valid");
+ cachevalid = 1;
+ }
+
+ if (!cachevalid)
+ goto out;
+
+ dirp->d_ino = fdctx->dcache->next->d_ino;
+ strncpy (dirp->d_name, fdctx->dcache->next->d_name,
+ fdctx->dcache->next->d_len + 1);
+ dirp->d_len = fdctx->dcache->next->d_len;
+ dirp->d_stat = fdctx->dcache->next->d_stat;
+// nfs_map_dev (fdctx->dirvol, &dirp->d_stat.st_dev);
+
+ *offset = fdctx->dcache->next->d_off;
+ dirp->d_off = *offset;
+ fdctx->dcache->prev_off = fdctx->dcache->next->d_off;
+ fdctx->dcache->next = fdctx->dcache->next->next;
+
+out:
+ return cachevalid;
+}
+
+int
+__nfs_readdir_sync (xlator_t *nfsx, xlator_t *fopxl, nfs_user_t *nfu,
+ fd_t *dirfd, off_t *offset, gf_dirent_t *entry,
+ size_t bufsize)
+{
+ int ret = -1;
+ call_stub_t *reply = NULL;
+
+ if ((!fopxl) || (!dirfd) || (!entry))
+ return ret;
+
+ ret = nfs_dcache_readdir (nfsx, dirfd, entry, offset);
+ if (ret) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent served from cache");
+ ret = 0;
+ goto err;
+ }
+
+ reply = nfs_fop_readdirp_sync (fopxl, nfu, dirfd, *offset,bufsize);
+ if (!reply) {
+ ret = -1;
+ gf_log (GF_NFS, GF_LOG_ERROR, "Sync readdir failed");
+ goto err;
+ }
+
+ if (reply->args.readdir_cbk.op_ret <= 0) {
+ ret = -1;
+ goto err;
+ }
+
+ ret = nfs_dcache_update (nfsx, dirfd, &reply->args.readdir_cbk.entries);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to update dirent cache");
+ goto err;
+ }
+
+ ret = nfs_dcache_readdir (nfsx, dirfd, entry, offset);
+ if (ret) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent served from cache,"
+ " after updating from server");
+ ret = 0;
+ } else {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent still not served from"
+ " cache, even after updating from server");
+ ret = -1;
+ }
+
+err:
+ if (reply)
+ call_stub_destroy (reply);
+ return ret;
+}
+
+
+
+int
+nfs_readdir_sync (xlator_t *nfsx, xlator_t *fopxl, nfs_user_t *nfu,
+ fd_t *dirfd, gf_dirent_t *entry)
+{
+ int ret = -EFAULT;
+ nfs_fdctx_t *fdctx = NULL;
+
+ if ((!nfsx) || (!fopxl) || (!dirfd) || (!entry) || (!nfu))
+ return ret;
+
+ fdctx = nfs_fdctx_get (dirfd, nfsx);
+ if (!fdctx) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "No fd context present");
+ goto err;
+ }
+
+ pthread_mutex_lock (&fdctx->lock);
+ {
+ ret = __nfs_readdir_sync (nfsx, fopxl, nfu, dirfd,
+ &fdctx->offset, entry,
+ fdctx->dirent_bufsize);
+ }
+ pthread_mutex_unlock (&fdctx->lock);
+
+ if (ret < 0)
+ gf_log (GF_NFS, GF_LOG_ERROR, "Sync readdir failed: %s",
+ strerror (-ret));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Entry read: %s: len %d, ino %"
+ PRIu64", igen: %"PRIu64, entry->d_name, entry->d_len,
+ entry->d_ino, entry->d_stat.ia_dev);
+
+err:
+ return ret;
+}
+
+
+int32_t
+nfs_flush_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (!sf)
+ return -1;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync open failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync open done");
+
+ sf->replystub = fop_flush_cbk_stub (frame, NULL, op_ret, op_errno);
+
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+call_stub_t *
+nfs_flush_sync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd)
+{
+ nfs_syncfop_t *sf = NULL;
+ call_stub_t *reply = NULL;
+ int ret = -1;
+
+ if ((!xl) || (!fd) || (!nfu))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed");
+ goto err;
+ }
+
+ ret = nfs_flush (xl, nfu, fd, nfs_flush_sync_cbk, sf);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Sync flush failed: %s",
+ strerror (-ret));
+ goto err;
+ }
+
+ reply = nfs_syncfop_wait (sf);
+
+err:
+ if (ret < 0)
+ FREE (sf);
+
+ return reply;
+}
+
+
+int32_t
+nfs_writev_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
+ struct iatt *postbuf)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (!sf)
+ return -1;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync write failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync write done");
+
+ sf->replystub = fop_writev_cbk_stub (frame, NULL, op_ret, op_errno,
+ prebuf, postbuf);
+
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+
+call_stub_t *
+nfs_write_sync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, struct iobuf *srciob,
+ struct iovec *vec, int count, off_t offset)
+{
+ nfs_syncfop_t *sf = NULL;
+ call_stub_t *reply = NULL;
+ int ret = -1;
+
+ if ((!xl) || (!fd) || (!vec) || (!nfu) || (!srciob))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed");
+ goto err;
+ }
+
+ ret = nfs_write (xl, nfu, fd, srciob, vec, count, offset,
+ nfs_writev_sync_cbk, sf);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Sync flush failed: %s",
+ strerror (-ret));
+ goto err;
+ }
+
+ reply = nfs_syncfop_wait (sf);
+
+err:
+ if (ret < 0)
+ FREE (sf);
+
+ return reply;
+}
+
+
+
+int32_t
+nfs_fsync_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
+ struct iatt *postbuf)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (!sf)
+ return -1;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync fsync failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync fsync done");
+
+ sf->replystub = fop_fsync_cbk_stub (frame, NULL, op_ret, op_errno,
+ prebuf, postbuf);
+
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+
+call_stub_t *
+nfs_fsync_sync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, int32_t datasync)
+{
+ nfs_syncfop_t *sf = NULL;
+ call_stub_t *reply = NULL;
+ int ret = -1;
+
+ if ((!xl) || (!fd) || (!nfu))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed");
+ goto err;
+ }
+
+ ret = nfs_fsync (xl, nfu, fd, datasync, nfs_fsync_sync_cbk, sf);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Sync fsync failed: %s",
+ strerror (-ret));
+ goto err;
+ }
+
+ reply = nfs_syncfop_wait (sf);
+
+err:
+ if (ret < 0)
+ FREE (sf);
+
+ return reply;
+}
+
+int32_t
+nfs_read_sync_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 iatt *buf, struct iobref *iobref)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (!sf)
+ return -1;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync read failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync read done");
+
+ sf->replystub = fop_readv_cbk_stub (frame, NULL, op_ret, op_errno,
+ vector, count, buf, iobref);
+
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+
+call_stub_t *
+nfs_read_sync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, size_t size,
+ off_t offset)
+{
+ nfs_syncfop_t *sf = NULL;
+ call_stub_t *reply = NULL;
+ int ret = -1;
+
+ if ((!xl) || (!fd) || (!nfu))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed");
+ goto err;
+ }
+
+ ret = nfs_read (xl, nfu, fd, size, offset, nfs_read_sync_cbk, sf);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Sync read failed: %s",
+ strerror (-ret));
+ goto err;
+ }
+
+ reply = nfs_syncfop_wait (sf);
+
+err:
+ if (ret < 0)
+ FREE (sf);
+
+ return reply;
+}
+
+
+int32_t
+nfs_opendir_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, fd_t *fd)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (!sf)
+ return -1;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync opendir failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync opendir done");
+
+ sf->replystub = fop_opendir_cbk_stub (frame, NULL, op_ret, op_errno,fd);
+
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+call_stub_t *
+nfs_opendir_sync (xlator_t *nfsx, xlator_t *fopxl, nfs_user_t *nfu,
+ loc_t *pathloc, size_t bufsize)
+{
+ int ret = -EFAULT;
+ call_stub_t *reply = NULL;
+ nfs_syncfop_t *sf = NULL;
+ fd_t *dirfd = NULL;
+
+ if ((!nfsx) || (!fopxl) || (!pathloc) || (!nfu))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = nfs_inode_opendir (fopxl, nfu, pathloc, nfs_opendir_sync_cbk, sf);
+ if (ret < 0)
+ goto err;
+
+ reply = nfs_syncfop_wait (sf);
+ if (!reply) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ dirfd = reply->args.opendir_cbk.fd;
+ ret = nfs_dir_fdctx_init (dirfd, nfsx, fopxl, bufsize);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "fd context allocation failed");
+ goto err;
+ }
+
+ ret = 0;
+
+err:
+ if (ret < 0)
+ FREE (sf);
+
+ return reply;
+}
+
+
+int
+nfs_opendir (xlator_t *fopxl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_opendir_cbk_t cbk, void *local)
+{
+ if ((!fopxl) || (!pathloc) || (!nfu))
+ return -EFAULT;
+
+ return nfs_inode_opendir (fopxl, nfu, pathloc, cbk, local);
+}