diff options
author | Amar Tumballi <amar@gluster.com> | 2010-06-21 04:24:40 +0000 |
---|---|---|
committer | Anand V. Avati <avati@dev.gluster.com> | 2010-06-21 20:21:05 -0700 |
commit | b9b8734a9496ccf5f8ed5527dc7714930a59948b (patch) | |
tree | ffcf9187c315b30e23cfa7f68f1d360e246d94c2 /xlators/protocol/legacy/server | |
parent | 2a5fada7546032e1fc1b106ddd40e42cc45349e1 (diff) |
renamed xlator/protocol to xlator/protocol/legacy
Signed-off-by: Amar Tumballi <amar@gluster.com>
Signed-off-by: Raghavendra G <raghavendra@gluster.com>
Signed-off-by: Anand V. Avati <avati@dev.gluster.com>
BUG: 875 (Implement a new protocol to provide proper backward/forward compatibility)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=875
Diffstat (limited to 'xlators/protocol/legacy/server')
-rw-r--r-- | xlators/protocol/legacy/server/Makefile.am | 3 | ||||
-rw-r--r-- | xlators/protocol/legacy/server/src/Makefile.am | 22 | ||||
-rw-r--r-- | xlators/protocol/legacy/server/src/server-helpers.c | 925 | ||||
-rw-r--r-- | xlators/protocol/legacy/server/src/server-helpers.h | 72 | ||||
-rw-r--r-- | xlators/protocol/legacy/server/src/server-mem-types.h | 39 | ||||
-rw-r--r-- | xlators/protocol/legacy/server/src/server-protocol.c | 6577 | ||||
-rw-r--r-- | xlators/protocol/legacy/server/src/server-protocol.h | 198 | ||||
-rw-r--r-- | xlators/protocol/legacy/server/src/server-resolve.c | 656 |
8 files changed, 8492 insertions, 0 deletions
diff --git a/xlators/protocol/legacy/server/Makefile.am b/xlators/protocol/legacy/server/Makefile.am new file mode 100644 index 00000000000..d471a3f9243 --- /dev/null +++ b/xlators/protocol/legacy/server/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +CLEANFILES = diff --git a/xlators/protocol/legacy/server/src/Makefile.am b/xlators/protocol/legacy/server/src/Makefile.am new file mode 100644 index 00000000000..87d3042c534 --- /dev/null +++ b/xlators/protocol/legacy/server/src/Makefile.am @@ -0,0 +1,22 @@ + +xlator_LTLIBRARIES = server.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/protocol + +server_la_LDFLAGS = -module -avoidversion + +server_la_SOURCES = server-protocol.c server-resolve.c server-helpers.c +server_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \ + $(top_builddir)/xlators/protocol/legacy/lib/src/libgfproto.la \ + $(top_builddir)/xlators/protocol/lib/src/libgfproto1.la + +noinst_HEADERS = server-protocol.h server-helpers.h server-mem-types.h + +AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS) \ + -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles \ + -I$(top_srcdir)/contrib/md5/ \ + -DDATADIR=\"$(localstatedir)\" -DCONFDIR=\"$(sysconfdir)/glusterfs\" \ + $(GF_CFLAGS) -I$(top_srcdir)/xlators/protocol/legacy/lib/src \ + -I$(top_srcdir)/xlators/protocol/lib/src + +CLEANFILES = + diff --git a/xlators/protocol/legacy/server/src/server-helpers.c b/xlators/protocol/legacy/server/src/server-helpers.c new file mode 100644 index 00000000000..d07e841f287 --- /dev/null +++ b/xlators/protocol/legacy/server/src/server-helpers.c @@ -0,0 +1,925 @@ +/* + Copyright (c) 2006-2009 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 "server-protocol.h" +#include "server-helpers.h" + + +/* server_loc_fill - derive a loc_t for a given inode number + * + * NOTE: make sure that @loc is empty, because any pointers it holds with reference will + * be leaked after returning from here. + */ +int +server_loc_fill (loc_t *loc, server_state_t *state, + ino_t ino, ino_t par, + const char *name, const char *path) +{ + inode_t *inode = NULL; + inode_t *parent = NULL; + int32_t ret = -1; + char *dentry_path = NULL; + + + GF_VALIDATE_OR_GOTO ("server", loc, out); + GF_VALIDATE_OR_GOTO ("server", state, out); + GF_VALIDATE_OR_GOTO ("server", path, out); + + /* anything beyond this point is success */ + ret = 0; + loc->ino = ino; + inode = loc->inode; + if (inode == NULL) { + if (ino) + inode = inode_search (state->itable, ino, NULL); + + if ((inode == NULL) && + (par && name)) + inode = inode_search (state->itable, par, name); + + loc->inode = inode; + if (inode) + loc->ino = inode->ino; + } + + parent = loc->parent; + if (parent == NULL) { + if (inode) + parent = inode_parent (inode, par, name); + else + parent = inode_search (state->itable, par, NULL); + loc->parent = parent; + } + + if (name && parent) { + ret = inode_path (parent, name, &dentry_path); + if (ret < 0) { + gf_log (state->bound_xl->name, GF_LOG_DEBUG, + "failed to build path for %"PRId64"/%s: %s", + parent->ino, name, strerror (-ret)); + } + } else if (inode) { + ret = inode_path (inode, NULL, &dentry_path); + if (ret < 0) { + gf_log (state->bound_xl->name, GF_LOG_DEBUG, + "failed to build path for %"PRId64": %s", + inode->ino, strerror (-ret)); + } + } + + if (dentry_path) { + if (strcmp (dentry_path, path)) { + gf_log (state->bound_xl->name, GF_LOG_DEBUG, + "paths differ for inode(%"PRId64"): " + "client path = %s. dentry path = %s", + ino, path, dentry_path); + } + + loc->path = dentry_path; + loc->name = strrchr (loc->path, '/'); + if (loc->name) + loc->name++; + } else { + loc->path = gf_strdup (path); + loc->name = strrchr (loc->path, '/'); + if (loc->name) + loc->name++; + } + +out: + return ret; +} + +/* + * stat_to_str - convert struct iatt to a ASCII string + * @stbuf: struct iatt pointer + * + * not for external reference + */ +char * +stat_to_str (struct iatt *stbuf) +{ + int ret = 0; + char *tmp_buf = NULL; + + uint64_t dev = stbuf->ia_gen; + uint64_t ino = stbuf->ia_ino; + uint32_t mode = st_mode_from_ia (stbuf->ia_prot, stbuf->ia_type); + uint32_t nlink = stbuf->ia_nlink; + uint32_t uid = stbuf->ia_uid; + uint32_t gid = stbuf->ia_gid; + uint64_t rdev = stbuf->ia_rdev; + uint64_t size = stbuf->ia_size; + uint32_t blksize = stbuf->ia_blksize; + uint64_t blocks = stbuf->ia_blocks; + uint32_t atime = stbuf->ia_atime; + uint32_t mtime = stbuf->ia_mtime; + uint32_t ctime = stbuf->ia_ctime; + + uint32_t atime_nsec = stbuf->ia_atime_nsec; + uint32_t mtime_nsec = stbuf->ia_mtime_nsec; + uint32_t ctime_nsec = stbuf->ia_ctime_nsec; + + + ret = gf_asprintf (&tmp_buf, + GF_STAT_PRINT_FMT_STR, + dev, + ino, + mode, + nlink, + uid, + gid, + rdev, + size, + blksize, + blocks, + atime, + atime_nsec, + mtime, + mtime_nsec, + ctime, + ctime_nsec); + if (-1 == ret) { + gf_log ("protocol/server", GF_LOG_DEBUG, + "asprintf failed while setting up stat buffer string"); + return NULL; + } + return tmp_buf; +} + + +void +server_loc_wipe (loc_t *loc) +{ + if (loc->parent) { + inode_unref (loc->parent); + loc->parent = NULL; + } + + if (loc->inode) { + inode_unref (loc->inode); + loc->inode = NULL; + } + + if (loc->path) + GF_FREE ((char *)loc->path); +} + + +void +server_resolve_wipe (server_resolve_t *resolve) +{ + struct resolve_comp *comp = NULL; + int i = 0; + + if (resolve->path) + GF_FREE (resolve->path); + + if (resolve->bname) + GF_FREE (resolve->bname); + + if (resolve->resolved) + GF_FREE (resolve->resolved); + + loc_wipe (&resolve->deep_loc); + + comp = resolve->components; + if (comp) { + for (i = 0; comp[i].basename; i++) { + if (comp[i].inode) + inode_unref (comp[i].inode); + } + GF_FREE (resolve->components); + } +} + + +void +free_state (server_state_t *state) +{ + if (state->trans) { + transport_unref (state->trans); + state->trans = NULL; + } + + if (state->fd) { + fd_unref (state->fd); + state->fd = NULL; + } + + if (state->iobref) { + iobref_unref (state->iobref); + state->iobref = NULL; + } + + if (state->iobuf) { + iobuf_unref (state->iobuf); + state->iobuf = NULL; + } + + if (state->dict) { + dict_unref (state->dict); + state->dict = NULL; + } + + if (state->volume) + GF_FREE ((char *)state->volume); + + if (state->name) + GF_FREE (state->name); + + server_loc_wipe (&state->loc); + server_loc_wipe (&state->loc2); + + server_resolve_wipe (&state->resolve); + server_resolve_wipe (&state->resolve2); + + GF_FREE (state); +} + + +call_frame_t * +server_copy_frame (call_frame_t *frame) +{ + call_frame_t *new_frame = NULL; + server_state_t *state = NULL, *new_state = NULL; + + state = frame->root->state; + + new_frame = copy_frame (frame); + + new_state = GF_CALLOC (1, sizeof (server_state_t), + gf_server_mt_server_state_t); + + new_frame->root->op = frame->root->op; + new_frame->root->type = frame->root->type; + new_frame->root->trans = state->trans; + new_frame->root->state = new_state; + + new_state->bound_xl = state->bound_xl; + new_state->trans = transport_ref (state->trans); + new_state->itable = state->itable; + + new_state->resolve.fd_no = -1; + new_state->resolve2.fd_no = -1; + + return new_frame; +} + + +int +gf_add_locker (struct _lock_table *table, const char *volume, + loc_t *loc, fd_t *fd, pid_t pid) +{ + int32_t ret = -1; + struct _locker *new = NULL; + uint8_t dir = 0; + + new = GF_CALLOC (1, sizeof (struct _locker), + gf_server_mt_locker); + if (new == NULL) { + gf_log ("server", GF_LOG_ERROR, + "failed to allocate memory for \'struct _locker\'"); + goto out; + } + INIT_LIST_HEAD (&new->lockers); + + new->volume = gf_strdup (volume); + + if (fd == NULL) { + loc_copy (&new->loc, loc); + dir = IA_ISDIR (new->loc.inode->ia_type); + } else { + new->fd = fd_ref (fd); + dir = IA_ISDIR (fd->inode->ia_type); + } + + new->pid = pid; + + LOCK (&table->lock); + { + if (dir) + list_add_tail (&new->lockers, &table->dir_lockers); + else + list_add_tail (&new->lockers, &table->file_lockers); + } + UNLOCK (&table->lock); +out: + return ret; +} + + +int +gf_del_locker (struct _lock_table *table, const char *volume, + loc_t *loc, fd_t *fd, pid_t pid) +{ + struct _locker *locker = NULL; + struct _locker *tmp = NULL; + int32_t ret = 0; + uint8_t dir = 0; + struct list_head *head = NULL; + struct list_head del; + + INIT_LIST_HEAD (&del); + + if (fd) { + dir = IA_ISDIR (fd->inode->ia_type); + } else { + dir = IA_ISDIR (loc->inode->ia_type); + } + + LOCK (&table->lock); + { + if (dir) { + head = &table->dir_lockers; + } else { + head = &table->file_lockers; + } + + list_for_each_entry_safe (locker, tmp, head, lockers) { + if (locker->fd && fd && + (locker->fd == fd) && (locker->pid == pid) + && !strcmp (locker->volume, volume)) { + list_move_tail (&locker->lockers, &del); + } else if (locker->loc.inode && + loc && + (locker->loc.inode == loc->inode) && + (locker->pid == pid) + && !strcmp (locker->volume, volume)) { + list_move_tail (&locker->lockers, &del); + } + } + } + UNLOCK (&table->lock); + + tmp = NULL; + locker = NULL; + + list_for_each_entry_safe (locker, tmp, &del, lockers) { + list_del_init (&locker->lockers); + if (locker->fd) + fd_unref (locker->fd); + else + loc_wipe (&locker->loc); + + GF_FREE (locker->volume); + GF_FREE (locker); + } + + return ret; +} + + +int +gf_direntry_to_bin (dir_entry_t *head, char *buffer) +{ + dir_entry_t *trav = NULL; + uint32_t len = 0; + uint32_t this_len = 0; + size_t buflen = -1; + char *ptr = NULL; + char *tmp_buf = NULL; + + trav = head->next; + while (trav) { + len += strlen (trav->name); + len += 1; + len += strlen (trav->link); + len += 1; /* for '\n' */ + len += 256; // max possible for statbuf; + trav = trav->next; + } + + ptr = buffer; + trav = head->next; + while (trav) { + tmp_buf = stat_to_str (&trav->buf); + /* tmp_buf will have \n before \0 */ + + this_len = sprintf (ptr, "%s/%s%s\n", + trav->name, tmp_buf, + trav->link); + + GF_FREE (tmp_buf); + trav = trav->next; + ptr += this_len; + } + + buflen = strlen (buffer); + + return buflen; +} + + +static struct _lock_table * +gf_lock_table_new (void) +{ + struct _lock_table *new = NULL; + + new = GF_CALLOC (1, sizeof (struct _lock_table), + gf_server_mt_lock_table); + if (new == NULL) { + gf_log ("server-protocol", GF_LOG_CRITICAL, + "failed to allocate memory for new lock table"); + goto out; + } + INIT_LIST_HEAD (&new->dir_lockers); + INIT_LIST_HEAD (&new->file_lockers); + LOCK_INIT (&new->lock); +out: + return new; +} + + +int +do_lock_table_cleanup (xlator_t *this, server_connection_t *conn, + call_frame_t *frame, struct _lock_table *ltable) +{ + struct list_head file_lockers, dir_lockers; + call_frame_t *tmp_frame = NULL; + struct flock flock = {0, }; + xlator_t *bound_xl = NULL; + struct _locker *locker = NULL, *tmp = NULL; + int ret = -1; + + bound_xl = conn->bound_xl; + INIT_LIST_HEAD (&file_lockers); + INIT_LIST_HEAD (&dir_lockers); + + LOCK (<able->lock); + { + list_splice_init (<able->file_lockers, + &file_lockers); + + list_splice_init (<able->dir_lockers, &dir_lockers); + } + UNLOCK (<able->lock); + + GF_FREE (ltable); + + flock.l_type = F_UNLCK; + flock.l_start = 0; + flock.l_len = 0; + list_for_each_entry_safe (locker, + tmp, &file_lockers, lockers) { + tmp_frame = copy_frame (frame); + if (tmp_frame == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "out of memory"); + goto out; + } + /* + pid = 0 is a special case that tells posix-locks + to release all locks from this transport + */ + tmp_frame->root->pid = 0; + tmp_frame->root->trans = conn; + + if (locker->fd) { + STACK_WIND (tmp_frame, server_nop_cbk, + bound_xl, + bound_xl->fops->finodelk, + locker->volume, + locker->fd, F_SETLK, &flock); + fd_unref (locker->fd); + } else { + STACK_WIND (tmp_frame, server_nop_cbk, + bound_xl, + bound_xl->fops->inodelk, + locker->volume, + &(locker->loc), F_SETLK, &flock); + loc_wipe (&locker->loc); + } + + GF_FREE (locker->volume); + + list_del_init (&locker->lockers); + GF_FREE (locker); + } + + tmp = NULL; + locker = NULL; + list_for_each_entry_safe (locker, tmp, &dir_lockers, lockers) { + tmp_frame = copy_frame (frame); + + tmp_frame->root->pid = 0; + tmp_frame->root->trans = conn; + + if (locker->fd) { + STACK_WIND (tmp_frame, server_nop_cbk, + bound_xl, + bound_xl->fops->fentrylk, + locker->volume, + locker->fd, NULL, + ENTRYLK_UNLOCK, ENTRYLK_WRLCK); + fd_unref (locker->fd); + } else { + STACK_WIND (tmp_frame, server_nop_cbk, + bound_xl, + bound_xl->fops->entrylk, + locker->volume, + &(locker->loc), NULL, + ENTRYLK_UNLOCK, ENTRYLK_WRLCK); + loc_wipe (&locker->loc); + } + + GF_FREE (locker->volume); + + list_del_init (&locker->lockers); + GF_FREE (locker); + } + ret = 0; + +out: + return ret; +} + + +static int +server_connection_cleanup_flush_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno) +{ + fd_t *fd = NULL; + + fd = frame->local; + + fd_unref (fd); + frame->local = NULL; + + STACK_DESTROY (frame->root); + return 0; +} + + +int +do_fd_cleanup (xlator_t *this, server_connection_t *conn, call_frame_t *frame, + fdentry_t *fdentries, int fd_count) +{ + fd_t *fd = NULL; + int i = 0, ret = -1; + call_frame_t *tmp_frame = NULL; + xlator_t *bound_xl = NULL; + + bound_xl = conn->bound_xl; + for (i = 0;i < fd_count; i++) { + fd = fdentries[i].fd; + + if (fd != NULL) { + tmp_frame = copy_frame (frame); + if (tmp_frame == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "out of memory"); + goto out; + } + tmp_frame->local = fd; + + tmp_frame->root->pid = 0; + tmp_frame->root->trans = conn; + tmp_frame->root->lk_owner = 0; + STACK_WIND (tmp_frame, + server_connection_cleanup_flush_cbk, + bound_xl, bound_xl->fops->flush, fd); + } + } + + GF_FREE (fdentries); + ret = 0; + +out: + return ret; +} + +int +do_connection_cleanup (xlator_t *this, server_connection_t *conn, + struct _lock_table *ltable, fdentry_t *fdentries, int fd_count) +{ + int ret = 0; + int saved_ret = 0; + call_frame_t *frame = NULL; + server_state_t *state = NULL; + + frame = create_frame (this, this->ctx->pool); + if (frame == NULL) { + gf_log (this->name, GF_LOG_ERROR, "out of memory"); + goto out; + } + + saved_ret = do_lock_table_cleanup (this, conn, frame, ltable); + + if (fdentries != NULL) { + ret = do_fd_cleanup (this, conn, frame, fdentries, fd_count); + } + + state = CALL_STATE (frame); + if (state) + GF_FREE (state); + + STACK_DESTROY (frame->root); + + if (saved_ret || ret) { + ret = -1; + } + +out: + return ret; +} + + +int +server_connection_cleanup (xlator_t *this, server_connection_t *conn) +{ + char do_cleanup = 0; + struct _lock_table *ltable = NULL; + fdentry_t *fdentries = NULL; + uint32_t fd_count = 0; + int ret = 0; + + if (conn == NULL) { + goto out; + } + + pthread_mutex_lock (&conn->lock); + { + conn->active_transports--; + if (conn->active_transports == 0) { + if (conn->ltable) { + ltable = conn->ltable; + conn->ltable = gf_lock_table_new (); + } + + if (conn->fdtable) { + fdentries = gf_fd_fdtable_get_all_fds (conn->fdtable, + &fd_count); + } + do_cleanup = 1; + } + } + pthread_mutex_unlock (&conn->lock); + + if (do_cleanup && conn->bound_xl) + ret = do_connection_cleanup (this, conn, ltable, fdentries, fd_count); + +out: + return ret; +} + + +int +server_connection_destroy (xlator_t *this, server_connection_t *conn) +{ + call_frame_t *frame = NULL, *tmp_frame = NULL; + xlator_t *bound_xl = NULL; + int32_t ret = -1; + server_state_t *state = NULL; + struct list_head file_lockers; + struct list_head dir_lockers; + struct _lock_table *ltable = NULL; + struct _locker *locker = NULL, *tmp = NULL; + struct flock flock = {0,}; + fd_t *fd = NULL; + int32_t i = 0; + fdentry_t *fdentries = NULL; + uint32_t fd_count = 0; + + if (conn == NULL) { + ret = 0; + goto out; + } + + bound_xl = (xlator_t *) (conn->bound_xl); + + if (bound_xl) { + /* trans will have ref_count = 1 after this call, but its + ok since this function is called in + GF_EVENT_TRANSPORT_CLEANUP */ + frame = create_frame (this, this->ctx->pool); + + pthread_mutex_lock (&(conn->lock)); + { + if (conn->ltable) { + ltable = conn->ltable; + conn->ltable = NULL; + } + } + pthread_mutex_unlock (&conn->lock); + + INIT_LIST_HEAD (&file_lockers); + INIT_LIST_HEAD (&dir_lockers); + + LOCK (<able->lock); + { + list_splice_init (<able->file_lockers, + &file_lockers); + + list_splice_init (<able->dir_lockers, &dir_lockers); + } + UNLOCK (<able->lock); + GF_FREE (ltable); + + flock.l_type = F_UNLCK; + flock.l_start = 0; + flock.l_len = 0; + list_for_each_entry_safe (locker, + tmp, &file_lockers, lockers) { + tmp_frame = copy_frame (frame); + /* + pid = 0 is a special case that tells posix-locks + to release all locks from this transport + */ + tmp_frame->root->pid = 0; + tmp_frame->root->trans = conn; + + if (locker->fd) { + STACK_WIND (tmp_frame, server_nop_cbk, + bound_xl, + bound_xl->fops->finodelk, + locker->volume, + locker->fd, F_SETLK, &flock); + fd_unref (locker->fd); + } else { + STACK_WIND (tmp_frame, server_nop_cbk, + bound_xl, + bound_xl->fops->inodelk, + locker->volume, + &(locker->loc), F_SETLK, &flock); + loc_wipe (&locker->loc); + } + + GF_FREE (locker->volume); + + list_del_init (&locker->lockers); + GF_FREE (locker); + } + + tmp = NULL; + locker = NULL; + list_for_each_entry_safe (locker, tmp, &dir_lockers, lockers) { + tmp_frame = copy_frame (frame); + + tmp_frame->root->pid = 0; + tmp_frame->root->trans = conn; + + if (locker->fd) { + STACK_WIND (tmp_frame, server_nop_cbk, + bound_xl, + bound_xl->fops->fentrylk, + locker->volume, + locker->fd, NULL, + ENTRYLK_UNLOCK, ENTRYLK_WRLCK); + fd_unref (locker->fd); + } else { + STACK_WIND (tmp_frame, server_nop_cbk, + bound_xl, + bound_xl->fops->entrylk, + locker->volume, + &(locker->loc), NULL, + ENTRYLK_UNLOCK, ENTRYLK_WRLCK); + loc_wipe (&locker->loc); + } + + GF_FREE (locker->volume); + + + list_del_init (&locker->lockers); + GF_FREE (locker); + } + + pthread_mutex_lock (&(conn->lock)); + { + if (conn->fdtable) { + fdentries = gf_fd_fdtable_get_all_fds (conn->fdtable, + &fd_count); + gf_fd_fdtable_destroy (conn->fdtable); + conn->fdtable = NULL; + } + } + pthread_mutex_unlock (&conn->lock); + + if (fdentries != NULL) { + for (i = 0; i < fd_count; i++) { + fd = fdentries[i].fd; + if (fd != NULL) { + tmp_frame = copy_frame (frame); + tmp_frame->local = fd; + + STACK_WIND (tmp_frame, + server_connection_cleanup_flush_cbk, + bound_xl, + bound_xl->fops->flush, + fd); + } + } + GF_FREE (fdentries); + } + } + + if (frame) { + state = CALL_STATE (frame); + if (state) + GF_FREE (state); + STACK_DESTROY (frame->root); + } + + gf_log (this->name, GF_LOG_INFO, "destroyed connection of %s", + conn->id); + + GF_FREE (conn->id); + GF_FREE (conn); + +out: + return ret; +} + + +server_connection_t * +server_connection_get (xlator_t *this, const char *id) +{ + server_connection_t *conn = NULL; + server_connection_t *trav = NULL; + server_conf_t *conf = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + list_for_each_entry (trav, &conf->conns, list) { + if (!strcmp (id, trav->id)) { + conn = trav; + break; + } + } + + if (!conn) { + conn = (void *) GF_CALLOC (1, sizeof (*conn), + gf_server_mt_server_connection_t); + + conn->id = gf_strdup (id); + conn->fdtable = gf_fd_fdtable_alloc (); + conn->ltable = gf_lock_table_new (); + + pthread_mutex_init (&conn->lock, NULL); + + list_add (&conn->list, &conf->conns); + } + + conn->ref++; + conn->active_transports++; + } + pthread_mutex_unlock (&conf->mutex); + + return conn; +} + + +void +server_connection_put (xlator_t *this, server_connection_t *conn) +{ + server_conf_t *conf = NULL; + server_connection_t *todel = NULL; + + if (conn == NULL) { + goto out; + } + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + conn->ref--; + + if (!conn->ref) { + list_del_init (&conn->list); + todel = conn; + } + } + pthread_mutex_unlock (&conf->mutex); + + if (todel) { + server_connection_destroy (this, todel); + } + +out: + return; +} diff --git a/xlators/protocol/legacy/server/src/server-helpers.h b/xlators/protocol/legacy/server/src/server-helpers.h new file mode 100644 index 00000000000..cbf57ae44d1 --- /dev/null +++ b/xlators/protocol/legacy/server/src/server-helpers.h @@ -0,0 +1,72 @@ +/* + Copyright (c) 2006-2009 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 __SERVER_HELPERS_H__ +#define __SERVER_HELPERS_H__ + +#define CALL_STATE(frame) ((server_state_t *)frame->root->state) + +#define BOUND_XL(frame) ((xlator_t *) CALL_STATE(frame)->bound_xl) + +#define TRANSPORT_FROM_FRAME(frame) ((transport_t *) CALL_STATE(frame)->trans) + +#define SERVER_CONNECTION(frame) \ + ((server_connection_t *) TRANSPORT_FROM_FRAME(frame)->xl_private) + +#define SERVER_CONF(frame) \ + ((server_conf_t *)TRANSPORT_FROM_FRAME(frame)->xl->private) + +#define TRANSPORT_FROM_XLATOR(this) ((((server_conf_t *)this->private))->trans) + +#define INODE_LRU_LIMIT(this) \ + (((server_conf_t *)(this->private))->inode_lru_limit) + +#define IS_ROOT_INODE(inode) (inode == inode->table->root) + +#define IS_NOT_ROOT(pathlen) ((pathlen > 2)? 1 : 0) + +char * +stat_to_str (struct iatt *stbuf); + +call_frame_t * +server_copy_frame (call_frame_t *frame); + +void free_state (server_state_t *state); + +void server_loc_wipe (loc_t *loc); + +int32_t +gf_add_locker (struct _lock_table *table, const char *volume, + loc_t *loc, + fd_t *fd, + pid_t pid); + +int32_t +gf_del_locker (struct _lock_table *table, const char *volume, + loc_t *loc, + fd_t *fd, + pid_t pid); + +int32_t +gf_direntry_to_bin (dir_entry_t *head, char *bufferp); + +void +server_print_request (call_frame_t *frame); + +#endif /* __SERVER_HELPERS_H__ */ diff --git a/xlators/protocol/legacy/server/src/server-mem-types.h b/xlators/protocol/legacy/server/src/server-mem-types.h new file mode 100644 index 00000000000..86877d79dac --- /dev/null +++ b/xlators/protocol/legacy/server/src/server-mem-types.h @@ -0,0 +1,39 @@ +/* + Copyright (c) 2008-2009 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 __AFR_MEM_TYPES_H__ +#define __AFR_MEM_TYPES_H__ + +#include "mem-types.h" + +enum gf_server_mem_types_ { + gf_server_mt_dir_entry_t = gf_common_mt_end + 1, + gf_server_mt_volfile_ctx, + gf_server_mt_server_state_t, + gf_server_mt_server_conf_t, + gf_server_mt_locker, + gf_server_mt_lock_table, + gf_server_mt_char, + gf_server_mt_server_connection_t, + gf_server_mt_resolve_comp, + gf_server_mt_end +}; +#endif + diff --git a/xlators/protocol/legacy/server/src/server-protocol.c b/xlators/protocol/legacy/server/src/server-protocol.c new file mode 100644 index 00000000000..de7d2ac0b5a --- /dev/null +++ b/xlators/protocol/legacy/server/src/server-protocol.c @@ -0,0 +1,6577 @@ +/* + Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is GF_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 <time.h> +#include <sys/uio.h> +#include <sys/resource.h> + +#include <libgen.h> + +#include "transport.h" +#include "fnmatch.h" +#include "xlator.h" +#include "protocol.h" +#include "server-protocol.h" +#include "server-helpers.h" +#include "call-stub.h" +#include "defaults.h" +#include "list.h" +#include "dict.h" +#include "compat.h" +#include "compat-errno.h" +#include "statedump.h" +#include "md5.h" + + +void +print_caller (char *str, int size, call_frame_t *frame) +{ + int filled = 0; + server_state_t *state = NULL; + transport_t *trans = NULL; + + state = CALL_STATE (frame); + trans = state->trans; + + filled += snprintf (str + filled, size - filled, + " Callid=%"PRId64", Client=%s", + frame->root->unique, + trans->peerinfo.identifier); + + return; +} + + +void +server_print_resolve (char *str, int size, server_resolve_t *resolve) +{ + int filled = 0; + + if (!resolve) { + snprintf (str, size, "<nul>"); + return; + } + + filled += snprintf (str + filled, size - filled, + " Resolve={"); + if (resolve->fd_no != -1) + filled += snprintf (str + filled, size - filled, + "fd=%"PRId64",", (uint64_t) resolve->fd_no); + if (resolve->ino) + filled += snprintf (str + filled, size - filled, + "ino=%"PRIu64",", (uint64_t) resolve->ino); + if (resolve->par) + filled += snprintf (str + filled, size - filled, + "par=%"PRIu64",", (uint64_t) resolve->par); + if (resolve->gen) + filled += snprintf (str + filled, size - filled, + "gen=%"PRIu64",", (uint64_t) resolve->gen); + if (resolve->bname) + filled += snprintf (str + filled, size - filled, + "bname=%s,", resolve->bname); + if (resolve->path) + filled += snprintf (str + filled, size - filled, + "path=%s", resolve->path); + + filled += snprintf (str + filled, size - filled, "}"); +} + + +void +server_print_loc (char *str, int size, loc_t *loc) +{ + int filled = 0; + + if (!loc) { + snprintf (str, size, "<nul>"); + return; + } + + filled += snprintf (str + filled, size - filled, + " Loc={"); + + if (loc->path) + filled += snprintf (str + filled, size - filled, + "path=%s,", loc->path); + if (loc->inode) + filled += snprintf (str + filled, size - filled, + "inode=%p,", loc->inode); + if (loc->parent) + filled += snprintf (str + filled, size - filled, + "parent=%p", loc->parent); + + filled += snprintf (str + filled, size - filled, "}"); +} + + +void +server_print_params (char *str, int size, server_state_t *state) +{ + int filled = 0; + + filled += snprintf (str + filled, size - filled, + " Params={"); + + if (state->fd) + filled += snprintf (str + filled, size - filled, + "fd=%p,", state->fd); + if (state->valid) + filled += snprintf (str + filled, size - filled, + "valid=%d,", state->valid); + if (state->flags) + filled += snprintf (str + filled, size - filled, + "flags=%d,", state->flags); + if (state->wbflags) + filled += snprintf (str + filled, size - filled, + "wbflags=%d,", state->wbflags); + if (state->size) + filled += snprintf (str + filled, size - filled, + "size=%Zu,", state->size); + if (state->offset) + filled += snprintf (str + filled, size - filled, + "offset=%"PRId64",", state->offset); + if (state->cmd) + filled += snprintf (str + filled, size - filled, + "cmd=%d,", state->cmd); + if (state->type) + filled += snprintf (str + filled, size - filled, + "type=%d,", state->type); + if (state->name) + filled += snprintf (str + filled, size - filled, + "name=%s,", state->name); + if (state->mask) + filled += snprintf (str + filled, size - filled, + "mask=%d,", state->mask); + if (state->volume) + filled += snprintf (str + filled, size - filled, + "volume=%s,", state->volume); + + filled += snprintf (str + filled, size - filled, + "bound_xl=%s}", state->bound_xl->name); +} + + +int +server_resolve_is_empty (server_resolve_t *resolve) +{ + if (resolve->fd_no != -1) + return 0; + + if (resolve->ino != 0) + return 0; + + if (resolve->gen != 0) + return 0; + + if (resolve->par != 0) + return 0; + + if (resolve->path != 0) + return 0; + + if (resolve->bname != 0) + return 0; + + return 1; +} + + +void +server_print_reply (call_frame_t *frame, int op_ret, int op_errno) +{ + server_conf_t *conf = NULL; + server_state_t *state = NULL; + xlator_t *this = NULL; + char caller[512]; + char fdstr[32]; + char *op = "UNKNOWN"; + + this = frame->this; + conf = this->private; + + if (!conf->trace) + return; + + state = CALL_STATE (frame); + + print_caller (caller, 256, frame); + + switch (frame->root->type) { + case GF_OP_TYPE_FOP_REQUEST: + case GF_OP_TYPE_FOP_REPLY: + op = gf_fop_list[frame->root->op]; + break; + case GF_OP_TYPE_MOP_REQUEST: + case GF_OP_TYPE_MOP_REPLY: + op = gf_mop_list[frame->root->op]; + break; + case GF_OP_TYPE_CBK_REQUEST: + case GF_OP_TYPE_CBK_REPLY: + op = gf_cbk_list[frame->root->op]; + break; + } + + fdstr[0] = '\0'; + if (state->fd) + snprintf (fdstr, 32, " fd=%p", state->fd); + + gf_log (this->name, GF_LOG_NORMAL, + "%s%s => (%d, %d)%s", + op, caller, op_ret, op_errno, fdstr); +} + + +void +server_print_request (call_frame_t *frame) +{ + server_conf_t *conf = NULL; + xlator_t *this = NULL; + server_state_t *state = NULL; + char resolve_vars[256]; + char resolve2_vars[256]; + char loc_vars[256]; + char loc2_vars[256]; + char other_vars[512]; + char caller[512]; + char *op = "UNKNOWN"; + + this = frame->this; + conf = this->private; + + state = CALL_STATE (frame); + + if (!conf->trace) + return; + + memset (resolve_vars, '\0', 256); + memset (resolve2_vars, '\0', 256); + memset (loc_vars, '\0', 256); + memset (loc2_vars, '\0', 256); + memset (other_vars, '\0', 256); + + print_caller (caller, 256, frame); + + if (!server_resolve_is_empty (&state->resolve)) { + server_print_resolve (resolve_vars, 256, &state->resolve); + server_print_loc (loc_vars, 256, &state->loc); + } + + if (!server_resolve_is_empty (&state->resolve2)) { + server_print_resolve (resolve2_vars, 256, &state->resolve2); + server_print_loc (loc2_vars, 256, &state->loc2); + } + + server_print_params (other_vars, 512, state); + + switch (frame->root->type) { + case GF_OP_TYPE_FOP_REQUEST: + case GF_OP_TYPE_FOP_REPLY: + op = gf_fop_list[frame->root->op]; + break; + case GF_OP_TYPE_MOP_REQUEST: + case GF_OP_TYPE_MOP_REPLY: + op = gf_mop_list[frame->root->op]; + break; + case GF_OP_TYPE_CBK_REQUEST: + case GF_OP_TYPE_CBK_REPLY: + op = gf_cbk_list[frame->root->op]; + break; + } + + gf_log (this->name, GF_LOG_NORMAL, + "%s%s%s%s%s%s%s", + gf_fop_list[frame->root->op], caller, + resolve_vars, loc_vars, resolve2_vars, loc2_vars, other_vars); +} + + +static void +protocol_server_reply (call_frame_t *frame, int type, int op, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iovec *vector, int count, + struct iobref *iobref) +{ + server_state_t *state = NULL; + xlator_t *bound_xl = NULL; + transport_t *trans = NULL; + int ret = 0; + + xlator_t *this = NULL; + + bound_xl = BOUND_XL (frame); + state = CALL_STATE (frame); + trans = state->trans; + this = frame->this; + + hdr->callid = hton64 (frame->root->unique); + hdr->type = hton32 (type); + hdr->op = hton32 (op); + + server_print_reply (frame, ntoh32 (hdr->rsp.op_ret), + gf_error_to_errno (ntoh32 (hdr->rsp.op_errno))); + + ret = transport_submit (trans, (char *)hdr, hdrlen, vector, + count, iobref); + if (ret < 0) { + gf_log ("protocol/server", GF_LOG_ERROR, + "frame %"PRId64": failed to submit. op= %d, type= %d", + frame->root->unique, op, type); + } + + STACK_DESTROY (frame->root); + + if (state) + free_state (state); + +} + + +/* + * server_lk_cbk - lk callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @lock: + * + * not for external reference + */ +int +server_lk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct flock *lock) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_lk_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + gf_flock_from_flock (&rsp->flock, lock); + } else if (op_errno != ENOSYS) { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": LK %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_LK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +int +server_inodelk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_inodelk_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + conn = SERVER_CONNECTION(frame); + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + if (state->flock.l_type == F_UNLCK) + gf_del_locker (conn->ltable, state->volume, + &state->loc, NULL, frame->root->pid); + else + gf_add_locker (conn->ltable, state->volume, + &state->loc, NULL, frame->root->pid); + } else if (op_errno != ENOSYS) { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": INODELK %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_INODELK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +int +server_finodelk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_finodelk_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + conn = SERVER_CONNECTION(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + state = CALL_STATE(frame); + + if (op_ret >= 0) { + if (state->flock.l_type == F_UNLCK) + gf_del_locker (conn->ltable, state->volume, + NULL, state->fd, + frame->root->pid); + else + gf_add_locker (conn->ltable, state->volume, + NULL, state->fd, + frame->root->pid); + } else if (op_errno != ENOSYS) { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": FINODELK %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_FINODELK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_entrylk_cbk - + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @lock: + * + * not for external reference + */ +int +server_entrylk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_entrylk_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + conn = SERVER_CONNECTION(frame); + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + if (state->cmd == ENTRYLK_UNLOCK) + gf_del_locker (conn->ltable, state->volume, + &state->loc, NULL, frame->root->pid); + else + gf_add_locker (conn->ltable, state->volume, + &state->loc, NULL, frame->root->pid); + } else if (op_errno != ENOSYS) { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": INODELK %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_ENTRYLK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +int +server_fentrylk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_fentrylk_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + conn = SERVER_CONNECTION(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + state = CALL_STATE(frame); + if (state->cmd == ENTRYLK_UNLOCK) + gf_del_locker (conn->ltable, state->volume, + NULL, state->fd, frame->root->pid); + else + gf_add_locker (conn->ltable, state->volume, + NULL, state->fd, frame->root->pid); + } else if (op_errno != ENOSYS) { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": FENTRYLK %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_FENTRYLK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_access_cbk - access callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int +server_access_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_access_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_ACCESS, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_rmdir_cbk - rmdir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int +server_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *preparent, + struct iatt *postparent) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_rmdir_rsp_t *rsp = NULL; + server_state_t *state = NULL; + int32_t gf_errno = 0; + size_t hdrlen = 0; + inode_t *parent = NULL; + + state = CALL_STATE(frame); + + if (op_ret == 0) { + inode_unlink (state->loc.inode, state->loc.parent, + state->loc.name); + parent = inode_parent (state->loc.inode, 0, NULL); + if (parent) + inode_unref (parent); + else + inode_forget (state->loc.inode, 0); + } else { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": RMDIR %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + gf_stat_from_iatt (&rsp->preparent, preparent); + gf_stat_from_iatt (&rsp->postparent, postparent); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_RMDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_mkdir_cbk - mkdir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int +server_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *stbuf, struct iatt *preparent, + struct iatt *postparent) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_mkdir_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + inode_t *link_inode = NULL; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + gf_stat_from_iatt (&rsp->stat, stbuf); + gf_stat_from_iatt (&rsp->preparent, preparent); + gf_stat_from_iatt (&rsp->postparent, postparent); + + link_inode = inode_link (inode, state->loc.parent, + state->loc.name, stbuf); + inode_lookup (link_inode); + inode_unref (link_inode); + } else { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": MKDIR %s ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + op_ret, strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_MKDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_mknod_cbk - mknod callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int +server_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + inode_t *inode, struct iatt *stbuf, struct iatt *preparent, + struct iatt *postparent) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_mknod_rsp_t *rsp = NULL; + server_state_t *state = NULL; + int32_t gf_errno = 0; + size_t hdrlen = 0; + inode_t *link_inode = NULL; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + gf_stat_from_iatt (&rsp->stat, stbuf); + gf_stat_from_iatt (&rsp->preparent, preparent); + gf_stat_from_iatt (&rsp->postparent, postparent); + + link_inode = inode_link (inode, state->loc.parent, + state->loc.name, stbuf); + inode_lookup (link_inode); + inode_unref (link_inode); + } else { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": MKNOD %s ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + op_ret, strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_MKNOD, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_fsyncdir_cbk - fsyncdir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int +server_fsyncdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fsyncdir_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + if (op_ret < 0) { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": FSYNCDIR %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_FSYNCDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + + +/* + * server_readdir_cbk - getdents callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int +server_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_readdir_rsp_t *rsp = NULL; + size_t hdrlen = 0; + size_t buf_size = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + if (op_ret > 0) + buf_size = gf_dirent_serialize (entries, NULL, 0); + + hdrlen = gf_hdr_len (rsp, buf_size); + hdr = gf_hdr_new (rsp, buf_size); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret > 0) { + rsp->size = hton32 (buf_size); + gf_dirent_serialize (entries, rsp->buf, buf_size); + } else { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": READDIR %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_READDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_releasedir_cbk - releasedir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int +server_releasedir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_cbk_releasedir_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_CBK_REPLY, GF_CBK_RELEASEDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_opendir_cbk - opendir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * @fd: file descriptor structure of opened directory + * + * not for external reference + */ +int +server_opendir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_opendir_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + uint64_t fd_no = 0; + + conn = SERVER_CONNECTION (frame); + + state = CALL_STATE (frame); + + if (op_ret >= 0) { + fd_bind (fd); + + fd_no = gf_fd_unused_get (conn->fdtable, fd); + fd_ref (fd); // on behalf of the client + } else { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": OPENDIR %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + rsp->fd = hton64 (fd_no); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_OPENDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_statfs_cbk - statfs callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * @buf: + * + * not for external reference + */ +int +server_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct statvfs *buf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_statfs_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE (frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + gf_statfs_from_statfs (&rsp->statfs, buf); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_STATFS, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_removexattr_cbk - removexattr callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int +server_removexattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_removexattr_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE (frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_REMOVEXATTR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_getxattr_cbk - getxattr callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * @value: + * + * not for external reference + */ +int +server_getxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_getxattr_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t len = 0; + int32_t gf_errno = 0; + int32_t ret = -1; + + state = CALL_STATE (frame); + + if (op_ret >= 0) { + len = dict_serialized_length (dict); + if (len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to get serialized length of " + "reply dict", + state->loc.path, state->resolve.ino); + op_ret = -1; + op_errno = EINVAL; + len = 0; + } + } + + hdrlen = gf_hdr_len (rsp, len + 1); + hdr = gf_hdr_new (rsp, len + 1); + rsp = gf_param (hdr); + + if (op_ret >= 0) { + ret = dict_serialize (dict, rsp->dict); + if (len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to serialize reply dict", + state->loc.path, state->resolve.ino); + op_ret = -1; + op_errno = -ret; + } + } + rsp->dict_len = hton32 (len); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_GETXATTR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +int +server_fgetxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fgetxattr_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t len = 0; + int32_t gf_errno = 0; + int32_t ret = -1; + + state = CALL_STATE (frame); + + if (op_ret >= 0) { + len = dict_serialized_length (dict); + if (len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to get serialized length of " + "reply dict", + state->loc.path, state->resolve.ino); + op_ret = -1; + op_errno = EINVAL; + len = 0; + } + } + + hdrlen = gf_hdr_len (rsp, len + 1); + hdr = gf_hdr_new (rsp, len + 1); + rsp = gf_param (hdr); + + if (op_ret >= 0) { + ret = dict_serialize (dict, rsp->dict); + if (len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to serialize reply dict", + state->loc.path, state->resolve.ino); + op_ret = -1; + op_errno = -ret; + } + } + rsp->dict_len = hton32 (len); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_FGETXATTR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_setxattr_cbk - setxattr callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int +server_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_setxattr_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE (frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_SETXATTR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +int +server_fsetxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fsetxattr_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_FSETXATTR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_rename_cbk - rename callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int +server_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *stbuf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_rename_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + stbuf->ia_ino = state->loc.inode->ino; + stbuf->ia_type = state->loc.inode->ia_type; + + gf_log (state->bound_xl->name, GF_LOG_TRACE, + "%"PRId64": RENAME_CBK (%"PRId64") %"PRId64"/%s " + "==> %"PRId64"/%s", + frame->root->unique, state->loc.inode->ino, + state->loc.parent->ino, state->loc.name, + state->loc2.parent->ino, state->loc2.name); + + inode_rename (state->itable, + state->loc.parent, state->loc.name, + state->loc2.parent, state->loc2.name, + state->loc.inode, stbuf); + gf_stat_from_iatt (&rsp->stat, stbuf); + + gf_stat_from_iatt (&rsp->preoldparent, preoldparent); + gf_stat_from_iatt (&rsp->postoldparent, postoldparent); + + gf_stat_from_iatt (&rsp->prenewparent, prenewparent); + gf_stat_from_iatt (&rsp->postnewparent, postnewparent); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_RENAME, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_unlink_cbk - unlink callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int +server_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *preparent, + struct iatt *postparent) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_unlink_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + inode_t *parent = NULL; + + state = CALL_STATE(frame); + + if (op_ret == 0) { + gf_log (state->bound_xl->name, GF_LOG_TRACE, + "%"PRId64": UNLINK_CBK %"PRId64"/%s (%"PRId64")", + frame->root->unique, state->loc.parent->ino, + state->loc.name, state->loc.inode->ino); + + inode_unlink (state->loc.inode, state->loc.parent, + state->loc.name); + + parent = inode_parent (state->loc.inode, 0, NULL); + if (parent) + inode_unref (parent); + else + inode_forget (state->loc.inode, 0); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": UNLINK %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + gf_stat_from_iatt (&rsp->preparent, preparent); + gf_stat_from_iatt (&rsp->postparent, postparent); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_UNLINK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_symlink_cbk - symlink callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int +server_symlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *stbuf, struct iatt *preparent, + struct iatt *postparent) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_symlink_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + inode_t *link_inode = NULL; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + + if (op_ret >= 0) { + gf_stat_from_iatt (&rsp->stat, stbuf); + gf_stat_from_iatt (&rsp->preparent, preparent); + gf_stat_from_iatt (&rsp->postparent, postparent); + + link_inode = inode_link (inode, state->loc.parent, + state->loc.name, stbuf); + inode_lookup (link_inode); + inode_unref (link_inode); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": SYMLINK %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_SYMLINK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_link_cbk - link callback for server protocol + * @frame: call frame + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int +server_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *stbuf, struct iatt *preparent, + struct iatt *postparent) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_link_rsp_t *rsp = NULL; + server_state_t *state = NULL; + int32_t gf_errno = 0; + size_t hdrlen = 0; + inode_t *link_inode = NULL; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + stbuf->ia_ino = state->loc.inode->ino; + + gf_stat_from_iatt (&rsp->stat, stbuf); + gf_stat_from_iatt (&rsp->preparent, preparent); + gf_stat_from_iatt (&rsp->postparent, postparent); + + gf_log (state->bound_xl->name, GF_LOG_TRACE, + "%"PRId64": LINK (%"PRId64") %"PRId64"/%s ==> %"PRId64"/%s", + frame->root->unique, inode->ino, + state->loc2.parent->ino, + state->loc2.name, state->loc.parent->ino, + state->loc.name); + + link_inode = inode_link (inode, state->loc2.parent, + state->loc2.name, stbuf); + inode_unref (link_inode); + } else { + gf_log (state->bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": LINK (%"PRId64") %"PRId64"/%s ==> %"PRId64"/%s " + " ==> %"PRId32" (%s)", + frame->root->unique, state->resolve2.ino, + state->resolve2.par, + state->resolve2.bname, state->resolve.par, + state->resolve.bname, + op_ret, strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_LINK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_truncate_cbk - truncate callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int +server_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_truncate_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE (frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + gf_stat_from_iatt (&rsp->prestat, prebuf); + gf_stat_from_iatt (&rsp->poststat, postbuf); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": TRUNCATE %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_TRUNCATE, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_fstat_cbk - fstat callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int +server_fstat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fstat_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + gf_stat_from_iatt (&rsp->stat, stbuf); + } else { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FSTAT %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_FSTAT, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_ftruncate_cbk - ftruncate callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int +server_ftruncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_ftruncate_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + gf_stat_from_iatt (&rsp->prestat, prebuf); + gf_stat_from_iatt (&rsp->poststat, postbuf); + } else { + state = CALL_STATE (frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FTRUNCATE %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_FTRUNCATE, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_flush_cbk - flush callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int +server_flush_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_flush_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + if (op_ret < 0) { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FLUSH %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_FLUSH, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_fsync_cbk - fsync callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int +server_fsync_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fsync_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + if (op_ret < 0) { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FSYNC %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + gf_stat_from_iatt (&(rsp->prestat), prebuf); + gf_stat_from_iatt (&(rsp->poststat), postbuf); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_FSYNC, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_release_cbk - rleease callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int +server_release_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_cbk_release_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_CBK_REPLY, GF_CBK_RELEASE, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_writev_cbk - writev callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ + +int +server_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_write_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + + if (op_ret >= 0) { + gf_stat_from_iatt (&rsp->prestat, prebuf); + gf_stat_from_iatt (&rsp->poststat, postbuf); + } else { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": WRITEV %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_WRITE, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_readv_cbk - readv callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @vector: + * @count: + * + * not for external reference + */ +int +server_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 iatt *stbuf, struct iobref *iobref) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_read_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + gf_stat_from_iatt (&rsp->stat, stbuf); + } else { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": READV %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_READ, + hdr, hdrlen, vector, count, iobref); + + return 0; +} + + +/* + * server_open_cbk - open callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @fd: + * + * not for external reference + */ +int +server_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_open_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + uint64_t fd_no = 0; + + conn = SERVER_CONNECTION (frame); + + state = CALL_STATE (frame); + + if (op_ret >= 0) { + fd_bind (fd); + + fd_no = gf_fd_unused_get (conn->fdtable, fd); + fd_ref (fd); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": OPEN %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + rsp->fd = hton64 (fd_no); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_OPEN, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_create_cbk - create callback for server + * @frame: call frame + * @cookie: + * @this: translator structure + * @op_ret: + * @op_errno: + * @fd: file descriptor + * @inode: inode structure + * @stbuf: struct iatt of created file + * + * not for external reference + */ +int +server_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + fd_t *fd, inode_t *inode, struct iatt *stbuf, + struct iatt *preparent, struct iatt *postparent) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_create_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + uint64_t fd_no = 0; + inode_t *link_inode = NULL; + + conn = SERVER_CONNECTION (frame); + + state = CALL_STATE (frame); + + if (op_ret >= 0) { + gf_log (state->bound_xl->name, GF_LOG_TRACE, + "%"PRId64": CREATE %"PRId64"/%s (%"PRId64")", + frame->root->unique, state->loc.parent->ino, + state->loc.name, stbuf->ia_ino); + + link_inode = inode_link (inode, state->loc.parent, + state->loc.name, stbuf); + + if (link_inode != inode) { + gf_log (this->name, GF_LOG_DEBUG, + "create(%s) inode (ptr=%p, ino=%"PRId64", " + "gen=%"PRId64") found conflict (ptr=%p, " + "ino=%"PRId64", gen=%"PRId64")", + state->loc.path, inode, inode->ino, + inode->generation, link_inode, + link_inode->ino, link_inode->generation); + + /* + VERY racy code (if used anywhere else) + -- don't do this without understanding + */ + + inode_unref (fd->inode); + fd->inode = inode_ref (link_inode); + } + + inode_lookup (link_inode); + inode_unref (link_inode); + + fd_bind (fd); + + fd_no = gf_fd_unused_get (conn->fdtable, fd); + fd_ref (fd); + + if ((fd_no < 0) || (fd == 0)) { + op_ret = fd_no; + op_errno = errno; + } + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": CREATE %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + rsp->fd = hton64 (fd_no); + + if (op_ret >= 0) { + gf_stat_from_iatt (&rsp->stat, stbuf); + gf_stat_from_iatt (&rsp->preparent, preparent); + gf_stat_from_iatt (&rsp->postparent, postparent); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_CREATE, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_readlink_cbk - readlink callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @buf: + * + * not for external reference + */ +int +server_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, const char *buf, + struct iatt *sbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_readlink_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + size_t linklen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + if (op_ret >= 0) { + linklen = strlen (buf) + 1; + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": READLINK %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + hdrlen = gf_hdr_len (rsp, linklen); + hdr = gf_hdr_new (rsp, linklen); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + + if (op_ret >= 0) { + gf_stat_from_iatt (&(rsp->buf), sbuf); + strcpy (rsp->path, buf); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_READLINK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_stat_cbk - stat callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int +server_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_stat_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE (frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + + if (op_ret == 0) { + gf_stat_from_iatt (&rsp->stat, stbuf); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": STAT %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_STAT, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_setattr_cbk - setattr callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ + +int +server_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + struct iatt *statpre, struct iatt *statpost) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_setattr_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE (frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + + if (op_ret == 0) { + gf_stat_from_iatt (&rsp->statpre, statpre); + gf_stat_from_iatt (&rsp->statpost, statpost); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": SETATTR %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_SETATTR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_setattr_cbk - setattr callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int +server_fsetattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + struct iatt *statpre, struct iatt *statpost) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fsetattr_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE (frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + + if (op_ret == 0) { + gf_stat_from_iatt (&rsp->statpre, statpre); + gf_stat_from_iatt (&rsp->statpost, statpost); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FSETATTR %"PRId64" (%"PRId64") ==> " + "%"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, + op_ret, strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_FSETATTR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_lookup_cbk - lookup callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @inode: + * @stbuf: + * + * not for external reference + */ +int +server_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + inode_t *inode, struct iatt *stbuf, dict_t *dict, + struct iatt *postparent) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_lookup_rsp_t *rsp = NULL; + server_state_t *state = NULL; + inode_t *root_inode = NULL; + int32_t dict_len = 0; + size_t hdrlen = 0; + int32_t gf_errno = 0; + int32_t ret = -1; + inode_t *link_inode = NULL; + loc_t fresh_loc = {0,}; + + state = CALL_STATE(frame); + + if (state->is_revalidate == 1 && op_ret == -1) { + state->is_revalidate = 2; + loc_copy (&fresh_loc, &state->loc); + inode_unref (fresh_loc.inode); + fresh_loc.inode = inode_new (state->itable); + + STACK_WIND (frame, server_lookup_cbk, + BOUND_XL (frame), BOUND_XL (frame)->fops->lookup, + &fresh_loc, state->dict); + + loc_wipe (&fresh_loc); + return 0; + } + + if (dict) { + dict_len = dict_serialized_length (dict); + if (dict_len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to get serialized " + "length of reply dict", + state->loc.path, state->loc.inode->ino); + op_ret = -1; + op_errno = EINVAL; + dict_len = 0; + } + } + + hdrlen = gf_hdr_len (rsp, dict_len); + hdr = gf_hdr_new (rsp, dict_len); + rsp = gf_param (hdr); + + if ((op_ret >= 0) && dict) { + ret = dict_serialize (dict, rsp->dict); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to serialize reply dict", + state->loc.path, state->loc.inode->ino); + op_ret = -1; + op_errno = -ret; + dict_len = 0; + } + } + rsp->dict_len = hton32 (dict_len); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (postparent) + gf_stat_from_iatt (&rsp->postparent, postparent); + + if (op_ret == 0) { + root_inode = BOUND_XL(frame)->itable->root; + if (inode == root_inode) { + /* we just looked up root ("/") */ + stbuf->ia_ino = 1; + if (inode->ia_type == 0) + inode->ia_type = stbuf->ia_type; + } + + gf_stat_from_iatt (&rsp->stat, stbuf); + + if (inode->ino != 1) { + link_inode = inode_link (inode, state->loc.parent, + state->loc.name, stbuf); + inode_lookup (link_inode); + inode_unref (link_inode); + } + } else { + if (state->is_revalidate && op_errno == ENOENT) { + if (state->loc.inode->ino != 1) { + inode_unlink (state->loc.inode, + state->loc.parent, + state->loc.name); + } + } + + gf_log (this->name, + (op_errno == ENOENT ? GF_LOG_TRACE : GF_LOG_DEBUG), + "%"PRId64": LOOKUP %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_LOOKUP, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +int +server_xattrop_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_xattrop_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t len = 0; + int32_t gf_errno = 0; + int32_t ret = -1; + + state = CALL_STATE (frame); + + if (op_ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": XATTROP %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + if ((op_ret >= 0) && dict) { + len = dict_serialized_length (dict); + if (len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to get serialized length" + " for reply dict", + state->loc.path, state->loc.inode->ino); + op_ret = -1; + op_errno = EINVAL; + len = 0; + } + } + + hdrlen = gf_hdr_len (rsp, len + 1); + hdr = gf_hdr_new (rsp, len + 1); + rsp = gf_param (hdr); + + if ((op_ret >= 0) && dict) { + ret = dict_serialize (dict, rsp->dict); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to serialize reply dict", + state->loc.path, state->loc.inode->ino); + op_ret = -1; + op_errno = -ret; + len = 0; + } + } + rsp->dict_len = hton32 (len); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_XATTROP, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +int +server_fxattrop_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_xattrop_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t len = 0; + int32_t gf_errno = 0; + int32_t ret = -1; + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + if (op_ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FXATTROP %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + if ((op_ret >= 0) && dict) { + len = dict_serialized_length (dict); + if (len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to get " + "serialized length for reply dict", + state->resolve.fd_no, state->fd->inode->ino); + op_ret = -1; + op_errno = EINVAL; + len = 0; + } + } + + hdrlen = gf_hdr_len (rsp, len + 1); + hdr = gf_hdr_new (rsp, len + 1); + rsp = gf_param (hdr); + + if ((op_ret >= 0) && dict) { + ret = dict_serialize (dict, rsp->dict); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to " + "serialize reply dict", + state->resolve.fd_no, state->fd->inode->ino); + op_ret = -1; + op_errno = -ret; + len = 0; + } + } + rsp->dict_len = hton32 (len); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_FXATTROP, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +int +server_lookup_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + if (!state->loc.inode) + state->loc.inode = inode_new (state->itable); + else + state->is_revalidate = 1; + + STACK_WIND (frame, server_lookup_cbk, + bound_xl, bound_xl->fops->lookup, + &state->loc, state->dict); + + return 0; +err: + server_lookup_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL, NULL, NULL); + + return 0; +} + + +int +server_lookup (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_lookup_req_t *req = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t pathlen = 0; + size_t baselen = 0; + size_t dictlen = 0; + dict_t *xattr_req = NULL; + char *req_dictbuf = NULL; + + req = gf_param (hdr); + + state = CALL_STATE (frame); + + pathlen = STRLEN_0 (req->path); + dictlen = ntoh32 (req->dictlen); + + /* NOTE: lookup() uses req->ino only to identify if a lookup() + * is requested for 'root' or not + */ + state->resolve.ino = ntoh64 (req->ino); + if (state->resolve.ino != 1) + state->resolve.ino = 0; + + state->resolve.type = RESOLVE_DONTCARE; + state->resolve.par = ntoh64 (req->par); + state->resolve.gen = ntoh64 (req->gen); + state->resolve.path = gf_strdup (req->path); + + if (IS_NOT_ROOT (pathlen)) { + state->resolve.bname = gf_strdup (req->bname + pathlen); + baselen = STRLEN_0 (state->resolve.bname); + } + + if (dictlen) { + /* Unserialize the dictionary */ + req_dictbuf = memdup (req->dict + pathlen + baselen, dictlen); + + xattr_req = dict_new (); + + ret = dict_unserialize (req_dictbuf, dictlen, &xattr_req); + if (ret < 0) { + gf_log (bound_xl->name, GF_LOG_ERROR, + "%"PRId64": %s (%"PRId64"): failed to " + "unserialize req-buffer to dictionary", + frame->root->unique, state->resolve.path, + state->resolve.ino); + GF_FREE (req_dictbuf); + goto err; + } + + xattr_req->extra_free = req_dictbuf; + state->dict = xattr_req; + } + + resolve_and_resume (frame, server_lookup_resume); + + return 0; +err: + if (xattr_req) + dict_unref (xattr_req); + + server_lookup_cbk (frame, NULL, frame->this, -1, EINVAL, NULL, NULL, + NULL, NULL); + return 0; +} + + +/* + * server_forget - forget function for server protocol + * + * not for external reference + */ +int +server_forget (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_log ("forget", GF_LOG_CRITICAL, "function not implemented"); + return 0; +} + + +int +server_stat_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_stat_cbk, + bound_xl, bound_xl->fops->stat, &state->loc); + return 0; +err: + server_stat_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_stat (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_stat_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + { + state->resolve.type = RESOLVE_MUST; + state->resolve.ino = ntoh64 (req->ino); + state->resolve.gen = ntoh64 (req->gen); + state->resolve.path = gf_strdup (req->path); + } + + resolve_and_resume (frame, server_stat_resume); + + return 0; +} + + +int +server_setattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_setattr_cbk, + bound_xl, bound_xl->fops->setattr, + &state->loc, &state->stbuf, state->valid); + return 0; +err: + server_setattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + + return 0; +} + + +int +server_setattr (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_setattr_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.ino = ntoh64 (req->ino); + state->resolve.gen = ntoh64 (req->gen); + state->resolve.path = gf_strdup (req->path); + + gf_stat_to_iatt (&req->stbuf, &state->stbuf); + state->valid = ntoh32 (req->valid); + + resolve_and_resume (frame, server_setattr_resume); + + return 0; +} + + +int +server_fsetattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fsetattr_cbk, + bound_xl, bound_xl->fops->fsetattr, + state->fd, &state->stbuf, state->valid); + return 0; +err: + server_fsetattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + + return 0; +} + + +int +server_fsetattr (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_fsetattr_req_t *req = NULL; + server_state_t *state = NULL; + + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = ntoh64 (req->fd); + + gf_stat_to_iatt (&req->stbuf, &state->stbuf); + state->valid = ntoh32 (req->valid); + + resolve_and_resume (frame, server_fsetattr_resume); + + return 0; +} + + +int +server_readlink_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_readlink_cbk, + bound_xl, bound_xl->fops->readlink, + &state->loc, state->size); + return 0; +err: + server_readlink_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + return 0; +} + + +int +server_readlink (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_readlink_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.ino = ntoh64 (req->ino); + state->resolve.gen = ntoh64 (req->gen); + state->resolve.path = gf_strdup (req->path); + + state->size = ntoh32 (req->size); + + resolve_and_resume (frame, server_readlink_resume); + + return 0; +} + + +int +server_create_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + state->loc.inode = inode_new (state->itable); + + state->fd = fd_create (state->loc.inode, frame->root->pid); + state->fd->flags = state->flags; + + STACK_WIND (frame, server_create_cbk, + bound_xl, bound_xl->fops->create, + &(state->loc), state->flags, state->mode, state->fd); + + return 0; +err: + server_create_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL, NULL, + NULL, NULL); + return 0; +} + + +int +server_create (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_create_req_t *req = NULL; + server_state_t *state = NULL; + int pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + pathlen = STRLEN_0 (req->path); + + state->resolve.type = RESOLVE_NOT; + state->resolve.par = ntoh64 (req->par); + state->resolve.gen = ntoh64 (req->gen); + state->resolve.path = gf_strdup (req->path); + state->resolve.bname = gf_strdup (req->bname + pathlen); + state->mode = ntoh32 (req->mode); + state->flags = gf_flags_to_flags (ntoh32 (req->flags)); + + resolve_and_resume (frame, server_create_resume); + + return 0; +} + + +int +server_open_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + state->fd = fd_create (state->loc.inode, frame->root->pid); + state->fd->flags = state->flags; + + STACK_WIND (frame, server_open_cbk, + bound_xl, bound_xl->fops->open, + &state->loc, state->flags, state->fd, 0); + + return 0; +err: + server_open_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_open (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_open_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.ino = ntoh64 (req->ino); + state->resolve.gen = ntoh64 (req->gen); + state->resolve.path = gf_strdup (req->path); + + state->flags = gf_flags_to_flags (ntoh32 (req->flags)); + + resolve_and_resume (frame, server_open_resume); + + return 0; +} + + +int +server_readv_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_readv_cbk, + bound_xl, bound_xl->fops->readv, + state->fd, state->size, state->offset); + + return 0; +err: + server_readv_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, 0, NULL, NULL); + return 0; +} + + +int +server_readv (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_read_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = ntoh64 (req->fd); + state->size = ntoh32 (req->size); + state->offset = ntoh64 (req->offset); + + resolve_and_resume (frame, server_readv_resume); + + return 0; +} + + +int +server_writev_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + struct iovec iov = {0, }; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + iov.iov_len = state->size; + + if (state->iobuf) { + iov.iov_base = state->iobuf->ptr; + } + + STACK_WIND (frame, server_writev_cbk, + bound_xl, bound_xl->fops->writev, + state->fd, &iov, 1, state->offset, state->iobref); + + return 0; +err: + server_writev_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + return 0; +} + + +int +server_writev (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_write_req_t *req = NULL; + server_state_t *state = NULL; + struct iobref *iobref = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = ntoh64 (req->fd); + state->offset = ntoh64 (req->offset); + state->size = ntoh32 (req->size); + + if (iobuf) { + iobref = iobref_new (); + iobref_add (iobref, iobuf); + + state->iobuf = iobuf; + state->iobref = iobref; + } + + resolve_and_resume (frame, server_writev_resume); + + return 0; +} + + +int +server_release (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_cbk_release_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION (frame); + state = CALL_STATE (frame); + req = gf_param (hdr); + + state->resolve.fd_no = ntoh64 (req->fd); + + gf_fd_put (conn->fdtable, state->resolve.fd_no); + + server_release_cbk (frame, NULL, frame->this, 0, 0); + + return 0; +} + + +int +server_fsync_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fsync_cbk, + bound_xl, bound_xl->fops->fsync, + state->fd, state->flags); + return 0; +err: + server_fsync_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + + return 0; +} + + +int +server_fsync (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_fsync_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = ntoh64 (req->fd); + state->flags = ntoh32 (req->data); + + resolve_and_resume (frame, server_fsync_resume); + + return 0; +} + + + +int +server_flush_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_flush_cbk, + bound_xl, bound_xl->fops->flush, state->fd); + return 0; +err: + server_flush_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + + return 0; +} + + +int +server_flush (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_fsync_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = ntoh64 (req->fd); + + resolve_and_resume (frame, server_flush_resume); + + return 0; +} + + + +int +server_ftruncate_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_ftruncate_cbk, + bound_xl, bound_xl->fops->ftruncate, + state->fd, state->offset); + return 0; +err: + server_ftruncate_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + + return 0; +} + + +int +server_ftruncate (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_ftruncate_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = ntoh64 (req->fd); + state->offset = ntoh64 (req->offset); + + resolve_and_resume (frame, server_ftruncate_resume); + + return 0; +} + + +int +server_fstat_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fstat_cbk, + bound_xl, bound_xl->fops->fstat, + state->fd); + return 0; +err: + server_fstat_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_fstat (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_fstat_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = ntoh64 (req->fd); + + resolve_and_resume (frame, server_fstat_resume); + + return 0; +} + + +int +server_truncate_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_truncate_cbk, + bound_xl, bound_xl->fops->truncate, + &state->loc, state->offset); + return 0; +err: + server_truncate_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + return 0; +} + + + +int +server_truncate (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_truncate_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (req->path); + state->resolve.ino = ntoh64 (req->ino); + state->resolve.gen = ntoh64 (req->gen); + state->offset = ntoh64 (req->offset); + + resolve_and_resume (frame, server_truncate_resume); + + return 0; +} + + +int +server_unlink_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_unlink_cbk, + bound_xl, bound_xl->fops->unlink, + &state->loc); + return 0; +err: + server_unlink_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + return 0; +} + + +int +server_unlink (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_unlink_req_t *req = NULL; + server_state_t *state = NULL; + int pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + pathlen = STRLEN_0 (req->path); + + state->resolve.type = RESOLVE_MUST; + state->resolve.par = ntoh64 (req->par); + state->resolve.gen = ntoh64 (req->gen); + state->resolve.path = gf_strdup (req->path); + state->resolve.bname = gf_strdup (req->bname + pathlen); + + resolve_and_resume (frame, server_unlink_resume); + + return 0; +} + + +int +server_setxattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_setxattr_cbk, + bound_xl, bound_xl->fops->setxattr, + &state->loc, state->dict, state->flags); + return 0; +err: + server_setxattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + + return 0; +} + + +int +server_setxattr (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_setxattr_req_t *req = NULL; + server_state_t *state = NULL; + dict_t *dict = NULL; + int32_t ret = -1; + size_t dict_len = 0; + char *req_dictbuf = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + dict_len = ntoh32 (req->dict_len); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (req->path + dict_len); + state->resolve.ino = ntoh64 (req->ino); + state->resolve.gen = ntoh64 (req->gen); + state->flags = ntoh32 (req->flags); + + if (dict_len) { + req_dictbuf = memdup (req->dict, dict_len); + + dict = dict_new (); + + ret = dict_unserialize (req_dictbuf, dict_len, &dict); + if (ret < 0) { + gf_log (bound_xl->name, GF_LOG_ERROR, + "%"PRId64": %s (%"PRId64"): failed to " + "unserialize request buffer to dictionary", + frame->root->unique, state->loc.path, + state->resolve.ino); + GF_FREE (req_dictbuf); + goto err; + } + + dict->extra_free = req_dictbuf; + state->dict = dict; + } + + resolve_and_resume (frame, server_setxattr_resume); + + return 0; +err: + if (dict) + dict_unref (dict); + + server_setxattr_cbk (frame, NULL, frame->this, -1, EINVAL); + + return 0; + +} + + +int +server_fsetxattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_setxattr_cbk, + bound_xl, bound_xl->fops->fsetxattr, + state->fd, state->dict, state->flags); + return 0; +err: + server_fsetxattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + + return 0; +} + + +int +server_fsetxattr (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_fsetxattr_req_t *req = NULL; + server_state_t *state = NULL; + dict_t *dict = NULL; + int32_t ret = -1; + size_t dict_len = 0; + char *req_dictbuf = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + dict_len = ntoh32 (req->dict_len); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = ntoh64 (req->fd); + state->flags = ntoh32 (req->flags); + + if (dict_len) { + req_dictbuf = memdup (req->dict, dict_len); + + dict = dict_new (); + + ret = dict_unserialize (req_dictbuf, dict_len, &dict); + if (ret < 0) { + gf_log (bound_xl->name, GF_LOG_ERROR, + "%"PRId64": %s (%"PRId64"): failed to " + "unserialize request buffer to dictionary", + frame->root->unique, state->loc.path, + state->resolve.ino); + GF_FREE (req_dictbuf); + goto err; + } + + dict->extra_free = req_dictbuf; + state->dict = dict; + } + + resolve_and_resume (frame, server_fsetxattr_resume); + + return 0; +err: + if (dict) + dict_unref (dict); + + server_setxattr_cbk (frame, NULL, frame->this, -1, EINVAL); + + return 0; +} + + +int +server_fxattrop_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fxattrop_cbk, + bound_xl, bound_xl->fops->fxattrop, + state->fd, state->flags, state->dict); + return 0; +err: + server_fxattrop_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_fxattrop (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_fxattrop_req_t *req = NULL; + dict_t *dict = NULL; + server_state_t *state = NULL; + size_t dict_len = 0; + char *req_dictbuf = NULL; + int32_t ret = -1; + + req = gf_param (hdr); + state = CALL_STATE(frame); + + dict_len = ntoh32 (req->dict_len); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = ntoh64 (req->fd); + + state->resolve.ino = ntoh64 (req->ino); + state->resolve.gen = ntoh64 (req->gen); + state->flags = ntoh32 (req->flags); + + if (dict_len) { + /* Unserialize the dictionary */ + req_dictbuf = memdup (req->dict, dict_len); + + dict = dict_new (); + + ret = dict_unserialize (req_dictbuf, dict_len, &dict); + if (ret < 0) { + gf_log (bound_xl->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to unserialize " + "request buffer to dictionary", + state->resolve.fd_no, state->fd->inode->ino); + GF_FREE (req_dictbuf); + goto fail; + } + dict->extra_free = req_dictbuf; + state->dict = dict; + dict = NULL; + } + + resolve_and_resume (frame, server_fxattrop_resume); + + return 0; + +fail: + if (dict) + dict_unref (dict); + + server_fxattrop_cbk (frame, NULL, frame->this, -1, EINVAL, NULL); + return 0; +} + + +int +server_xattrop_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_xattrop_cbk, + bound_xl, bound_xl->fops->xattrop, + &state->loc, state->flags, state->dict); + return 0; +err: + server_xattrop_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_xattrop (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_xattrop_req_t *req = NULL; + dict_t *dict = NULL; + server_state_t *state = NULL; + size_t dict_len = 0; + char *req_dictbuf = NULL; + int32_t ret = -1; + + req = gf_param (hdr); + state = CALL_STATE(frame); + + dict_len = ntoh32 (req->dict_len); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (req->path + dict_len); + state->resolve.ino = ntoh64 (req->ino); + state->resolve.gen = ntoh64 (req->gen); + state->flags = ntoh32 (req->flags); + + if (dict_len) { + /* Unserialize the dictionary */ + req_dictbuf = memdup (req->dict, dict_len); + + dict = dict_new (); + + ret = dict_unserialize (req_dictbuf, dict_len, &dict); + if (ret < 0) { + gf_log (bound_xl->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to unserialize " + "request buffer to dictionary", + state->resolve.fd_no, state->fd->inode->ino); + GF_FREE (req_dictbuf); + goto fail; + } + dict->extra_free = req_dictbuf; + state->dict = dict; + dict = NULL; + } + + resolve_and_resume (frame, server_xattrop_resume); + + return 0; + +fail: + if (dict) + dict_unref (dict); + + server_xattrop_cbk (frame, NULL, frame->this, -1, EINVAL, NULL); + return 0; +} + + +int +server_getxattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_getxattr_cbk, + bound_xl, bound_xl->fops->getxattr, + &state->loc, state->name); + return 0; +err: + server_getxattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_getxattr (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_getxattr_req_t *req = NULL; + server_state_t *state = NULL; + size_t namelen = 0; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + pathlen = STRLEN_0 (req->path); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (req->path); + state->resolve.ino = ntoh64 (req->ino); + state->resolve.gen = ntoh64 (req->gen); + + namelen = ntoh32 (req->namelen); + if (namelen) + state->name = gf_strdup (req->name + pathlen); + + resolve_and_resume (frame, server_getxattr_resume); + + return 0; +} + + +int +server_fgetxattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fgetxattr_cbk, + bound_xl, bound_xl->fops->fgetxattr, + state->fd, state->name); + return 0; +err: + server_fgetxattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_fgetxattr (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_fgetxattr_req_t *req = NULL; + server_state_t *state = NULL; + size_t namelen = 0; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = ntoh64 (req->fd); + + namelen = ntoh32 (req->namelen); + if (namelen) + state->name = gf_strdup (req->name); + + resolve_and_resume (frame, server_fgetxattr_resume); + + return 0; +} + + +int +server_removexattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_removexattr_cbk, + bound_xl, bound_xl->fops->removexattr, + &state->loc, state->name); + return 0; +err: + server_removexattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + return 0; +} + + +int +server_removexattr (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_removexattr_req_t *req = NULL; + server_state_t *state = NULL; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE (frame); + pathlen = STRLEN_0 (req->path); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (req->path); + state->resolve.ino = ntoh64 (req->ino); + state->resolve.gen = ntoh64 (req->gen); + state->name = gf_strdup (req->name + pathlen); + + resolve_and_resume (frame, server_removexattr_resume); + + return 0; +} + + +int +server_statfs_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret !=0) + goto err; + + STACK_WIND (frame, server_statfs_cbk, + bound_xl, bound_xl->fops->statfs, + &state->loc); + return 0; + +err: + server_statfs_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_statfs (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_statfs_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.ino = ntoh64 (req->ino); + if (!state->resolve.ino) + state->resolve.ino = 1; + state->resolve.gen = ntoh64 (req->gen); + state->resolve.path = gf_strdup (req->path); + + resolve_and_resume (frame, server_statfs_resume); + + return 0; +} + + +int +server_opendir_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + state->fd = fd_create (state->loc.inode, frame->root->pid); + + STACK_WIND (frame, server_opendir_cbk, + bound_xl, bound_xl->fops->opendir, + &state->loc, state->fd); + return 0; +err: + server_opendir_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_opendir (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_opendir_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (req->path); + state->resolve.ino = ntoh64 (req->ino); + state->resolve.gen = ntoh64 (req->gen); + + resolve_and_resume (frame, server_opendir_resume); + + return 0; +} + + +int +server_releasedir (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_cbk_releasedir_req_t *req = NULL; + server_connection_t *conn = NULL; + uint64_t fd_no = 0; + + conn = SERVER_CONNECTION (frame); + + req = gf_param (hdr); + + fd_no = ntoh64 (req->fd); + + gf_fd_put (conn->fdtable, fd_no); + + server_releasedir_cbk (frame, NULL, frame->this, 0, 0); + + return 0; +} + +/* + * server_readdirp_cbk - getdents callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int +server_readdirp_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_readdirp_rsp_t *rsp = NULL; + size_t hdrlen = 0; + size_t buf_size = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + if (op_ret > 0) + buf_size = gf_dirent_serialize (entries, NULL, 0); + + hdrlen = gf_hdr_len (rsp, buf_size); + hdr = gf_hdr_new (rsp, buf_size); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret > 0) { + rsp->size = hton32 (buf_size); + gf_dirent_serialize (entries, rsp->buf, buf_size); + } else { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": READDIRP %"PRId64" (%"PRId64") ==>" + "%"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_READDIRP, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +int +server_readdirp_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_readdirp_cbk, bound_xl, + bound_xl->fops->readdirp, state->fd, state->size, + state->offset); + + return 0; +err: + server_readdirp_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + +/* + * server_readdirp - readdirp function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int +server_readdirp (call_frame_t *frame, xlator_t *bound_xl, gf_hdr_common_t *hdr, + size_t hdrlen, struct iobuf *iobuf) +{ + gf_fop_readdirp_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = ntoh64 (req->fd); + state->size = ntoh32 (req->size); + state->offset = ntoh64 (req->offset); + + resolve_and_resume (frame, server_readdirp_resume); + + return 0; +} + + +int + server_readdir_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_readdir_cbk, + bound_xl, + bound_xl->fops->readdir, + state->fd, state->size, state->offset); + + return 0; +err: + server_readdir_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} +/* + * server_readdir - readdir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int +server_readdir (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_readdir_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = ntoh64 (req->fd); + state->size = ntoh32 (req->size); + state->offset = ntoh64 (req->offset); + + resolve_and_resume (frame, server_readdir_resume); + + return 0; +} + +int +server_fsyncdir_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fsyncdir_cbk, + bound_xl, + bound_xl->fops->fsyncdir, + state->fd, state->flags); + return 0; + +err: + server_fsyncdir_cbk (frame, NULL, frame->this, + state->resolve.op_ret, + state->resolve.op_errno); + return 0; +} + +/* + * server_fsyncdir - fsyncdir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int +server_fsyncdir (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_fsyncdir_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION (frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = ntoh64 (req->fd); + state->flags = ntoh32 (req->data); + + resolve_and_resume (frame, server_fsyncdir_resume); + + return 0; +} + + +int +server_mknod_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + state->loc.inode = inode_new (state->itable); + + STACK_WIND (frame, server_mknod_cbk, + bound_xl, bound_xl->fops->mknod, + &(state->loc), state->mode, state->dev); + + return 0; +err: + server_mknod_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL, NULL, NULL); + return 0; +} + + + +int +server_mknod (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_mknod_req_t *req = NULL; + server_state_t *state = NULL; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE (frame); + pathlen = STRLEN_0 (req->path); + + state->resolve.type = RESOLVE_NOT; + state->resolve.par = ntoh64 (req->par); + state->resolve.gen = ntoh64 (req->gen); + state->resolve.path = gf_strdup (req->path); + state->resolve.bname = gf_strdup (req->bname + pathlen); + + state->mode = ntoh32 (req->mode); + state->dev = ntoh64 (req->dev); + + resolve_and_resume (frame, server_mknod_resume); + + return 0; +} + + +int +server_mkdir_resume (call_frame_t *frame, xlator_t *bound_xl) + +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + state->loc.inode = inode_new (state->itable); + + STACK_WIND (frame, server_mkdir_cbk, + bound_xl, bound_xl->fops->mkdir, + &(state->loc), state->mode); + + return 0; +err: + server_mkdir_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL, NULL, NULL); + return 0; +} + + +int +server_mkdir (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_mkdir_req_t *req = NULL; + server_state_t *state = NULL; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE (frame); + pathlen = STRLEN_0 (req->path); + + state->resolve.type = RESOLVE_NOT; + state->resolve.par = ntoh64 (req->par); + state->resolve.gen = ntoh64 (req->gen); + state->resolve.path = gf_strdup (req->path); + state->resolve.bname = gf_strdup (req->bname + pathlen); + + state->mode = ntoh32 (req->mode); + + resolve_and_resume (frame, server_mkdir_resume); + + return 0; +} + + +int +server_rmdir_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_rmdir_cbk, + bound_xl, bound_xl->fops->rmdir, &state->loc); + return 0; +err: + server_rmdir_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + return 0; +} + +int +server_rmdir (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_rmdir_req_t *req = NULL; + server_state_t *state = NULL; + int pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE (frame); + pathlen = STRLEN_0 (req->path); + + state->resolve.type = RESOLVE_MUST; + state->resolve.par = ntoh64 (req->par); + state->resolve.gen = ntoh64 (req->gen); + state->resolve.path = gf_strdup (req->path); + state->resolve.bname = gf_strdup (req->bname + pathlen); + + resolve_and_resume (frame, server_rmdir_resume); + + return 0; +} + + +int +server_inodelk_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_inodelk_cbk, + bound_xl, bound_xl->fops->inodelk, + state->volume, &state->loc, state->cmd, &state->flock); + return 0; +err: + server_inodelk_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + return 0; +} + + +int +server_inodelk (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_inodelk_req_t *req = NULL; + server_state_t *state = NULL; + size_t pathlen = 0; + size_t vollen = 0; + int cmd = 0; + + req = gf_param (hdr); + state = CALL_STATE (frame); + pathlen = STRLEN_0 (req->path); + vollen = STRLEN_0 (req->volume + pathlen); + + state->resolve.type = RESOLVE_EXACT; + state->resolve.ino = ntoh64 (req->ino); + state->resolve.gen = ntoh64 (req->gen); + state->resolve.path = gf_strdup (req->path); + + cmd = ntoh32 (req->cmd); + switch (cmd) { + case GF_LK_GETLK: + state->cmd = F_GETLK; + break; + case GF_LK_SETLK: + state->cmd = F_SETLK; + break; + case GF_LK_SETLKW: + state->cmd = F_SETLKW; + break; + } + + state->type = ntoh32 (req->type); + state->volume = gf_strdup (req->volume + pathlen); + + gf_flock_to_flock (&req->flock, &state->flock); + + switch (state->type) { + case GF_LK_F_RDLCK: + state->flock.l_type = F_RDLCK; + break; + case GF_LK_F_WRLCK: + state->flock.l_type = F_WRLCK; + break; + case GF_LK_F_UNLCK: + state->flock.l_type = F_UNLCK; + break; + } + + resolve_and_resume (frame, server_inodelk_resume); + + return 0; +} + +int +server_finodelk_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_finodelk_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->finodelk, + state->volume, state->fd, state->cmd, &state->flock); + + return 0; +err: + server_finodelk_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + + return 0; +} + +int +server_finodelk (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_finodelk_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + + state->resolve.type = RESOLVE_EXACT; + state->volume = gf_strdup (req->volume); + state->resolve.fd_no = ntoh64 (req->fd); + state->cmd = ntoh32 (req->cmd); + + switch (state->cmd) { + case GF_LK_GETLK: + state->cmd = F_GETLK; + break; + case GF_LK_SETLK: + state->cmd = F_SETLK; + break; + case GF_LK_SETLKW: + state->cmd = F_SETLKW; + break; + } + + state->type = ntoh32 (req->type); + + gf_flock_to_flock (&req->flock, &state->flock); + + switch (state->type) { + case GF_LK_F_RDLCK: + state->flock.l_type = F_RDLCK; + break; + case GF_LK_F_WRLCK: + state->flock.l_type = F_WRLCK; + break; + case GF_LK_F_UNLCK: + state->flock.l_type = F_UNLCK; + break; + } + + resolve_and_resume (frame, server_finodelk_resume); + + return 0; +} + + +int +server_entrylk_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_entrylk_cbk, + bound_xl, bound_xl->fops->entrylk, + state->volume, &state->loc, state->name, + state->cmd, state->type); + return 0; +err: + server_entrylk_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + return 0; +} + + +int +server_entrylk (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_entrylk_req_t *req = NULL; + server_state_t *state = NULL; + size_t pathlen = 0; + size_t namelen = 0; + size_t vollen = 0; + + req = gf_param (hdr); + state = CALL_STATE (frame); + pathlen = STRLEN_0 (req->path); + namelen = ntoh64 (req->namelen); + vollen = STRLEN_0(req->volume + pathlen + namelen); + + state->resolve.type = RESOLVE_EXACT; + state->resolve.path = gf_strdup (req->path); + state->resolve.ino = ntoh64 (req->ino); + state->resolve.gen = ntoh64 (req->gen); + + if (namelen) + state->name = gf_strdup (req->name + pathlen); + state->volume = gf_strdup (req->volume + pathlen + namelen); + + state->cmd = ntoh32 (req->cmd); + state->type = ntoh32 (req->type); + + resolve_and_resume (frame, server_entrylk_resume); + + return 0; +} + +int +server_fentrylk_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fentrylk_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->fentrylk, + state->volume, state->fd, state->name, + state->cmd, state->type); + + return 0; +err: + server_fentrylk_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + return 0; +} + +int +server_fentrylk (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_fentrylk_req_t *req = NULL; + server_state_t *state = NULL; + size_t namelen = 0; + size_t vollen = 0; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION (frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + vollen = STRLEN_0(req->volume + namelen); + + state->resolve.type = RESOLVE_EXACT; + state->resolve.fd_no = ntoh64 (req->fd); + state->cmd = ntoh32 (req->cmd); + state->type = ntoh32 (req->type); + namelen = ntoh64 (req->namelen); + if (namelen) + state->name = req->name; + state->volume = gf_strdup (req->volume + namelen); + + + resolve_and_resume (frame, server_finodelk_resume); + + return 0; +} + + +int +server_access_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_access_cbk, + bound_xl, bound_xl->fops->access, + &state->loc, state->mask); + return 0; +err: + server_access_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + return 0; +} + + +int +server_access (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_access_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.ino = hton64 (req->ino); + state->resolve.gen = hton64 (req->gen); + state->resolve.path = gf_strdup (req->path); + + state->mask = ntoh32 (req->mask); + + resolve_and_resume (frame, server_access_resume); + + return 0; +} + + +int +server_symlink_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + state->loc.inode = inode_new (state->itable); + + STACK_WIND (frame, server_symlink_cbk, + bound_xl, bound_xl->fops->symlink, + state->name, &state->loc); + + return 0; +err: + server_symlink_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL, NULL, NULL); + return 0; +} + + + +int +server_symlink (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + server_state_t *state = NULL; + gf_fop_symlink_req_t *req = NULL; + size_t pathlen = 0; + size_t baselen = 0; + + req = gf_param (hdr); + state = CALL_STATE (frame); + pathlen = STRLEN_0 (req->path); + baselen = STRLEN_0 (req->bname + pathlen); + + state->resolve.type = RESOLVE_NOT; + state->resolve.par = ntoh64 (req->par); + state->resolve.gen = ntoh64 (req->gen); + state->resolve.path = gf_strdup (req->path); + state->resolve.bname = gf_strdup (req->bname + pathlen); + state->name = gf_strdup (req->linkname + pathlen + baselen); + + resolve_and_resume (frame, server_symlink_resume); + + return 0; +} + + +int +server_link_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + int op_ret = 0; + int op_errno = 0; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) { + op_ret = state->resolve.op_ret; + op_errno = state->resolve.op_errno; + goto err; + } + + if (state->resolve2.op_ret != 0) { + op_ret = state->resolve2.op_ret; + op_errno = state->resolve2.op_errno; + goto err; + } + + state->loc2.inode = inode_ref (state->loc.inode); + + STACK_WIND (frame, server_link_cbk, + bound_xl, bound_xl->fops->link, + &state->loc, &state->loc2); + return 0; +err: + server_link_cbk (frame, NULL, frame->this, op_ret, op_errno, + NULL, NULL, NULL, NULL); + return 0; +} + + +int +server_link (call_frame_t *frame, xlator_t *this, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_link_req_t *req = NULL; + server_state_t *state = NULL; + size_t oldpathlen = 0; + size_t newpathlen = 0; + size_t newbaselen = 0; + + req = gf_param (hdr); + state = CALL_STATE (frame); + oldpathlen = STRLEN_0 (req->oldpath); + newpathlen = STRLEN_0 (req->newpath + oldpathlen); + newbaselen = STRLEN_0 (req->newbname + oldpathlen + newpathlen); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (req->oldpath); + state->resolve.ino = ntoh64 (req->oldino); + state->resolve.gen = ntoh64 (req->oldgen); + + state->resolve2.type = RESOLVE_NOT; + state->resolve2.path = gf_strdup (req->newpath + oldpathlen); + state->resolve2.bname = gf_strdup (req->newbname + oldpathlen + newpathlen); + state->resolve2.par = ntoh64 (req->newpar); + state->resolve2.gen = ntoh64 (req->newgen); + + resolve_and_resume (frame, server_link_resume); + + return 0; +} + + +int +server_rename_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + int op_ret = 0; + int op_errno = 0; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) { + op_ret = state->resolve.op_ret; + op_errno = state->resolve.op_errno; + goto err; + } + + if (state->resolve2.op_ret != 0) { + op_ret = state->resolve2.op_ret; + op_errno = state->resolve2.op_errno; + goto err; + } + + STACK_WIND (frame, server_rename_cbk, + bound_xl, bound_xl->fops->rename, + &state->loc, &state->loc2); + return 0; +err: + server_rename_cbk (frame, NULL, frame->this, op_ret, op_errno, + NULL, NULL, NULL, NULL, NULL); + return 0; +} + + +int +server_rename (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_rename_req_t *req = NULL; + server_state_t *state = NULL; + size_t oldpathlen = 0; + size_t oldbaselen = 0; + size_t newpathlen = 0; + size_t newbaselen = 0; + + req = gf_param (hdr); + + state = CALL_STATE (frame); + oldpathlen = STRLEN_0 (req->oldpath); + oldbaselen = STRLEN_0 (req->oldbname + oldpathlen); + newpathlen = STRLEN_0 (req->newpath + oldpathlen + oldbaselen); + newbaselen = STRLEN_0 (req->newbname + oldpathlen + + oldbaselen + newpathlen); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (req->oldpath); + state->resolve.bname = gf_strdup (req->oldbname + oldpathlen); + state->resolve.par = ntoh64 (req->oldpar); + state->resolve.gen = ntoh64 (req->oldgen); + + state->resolve2.type = RESOLVE_MAY; + state->resolve2.path = gf_strdup (req->newpath + oldpathlen + oldbaselen); + state->resolve2.bname = gf_strdup (req->newbname + oldpathlen + oldbaselen + + newpathlen); + state->resolve2.par = ntoh64 (req->newpar); + state->resolve2.gen = ntoh64 (req->newgen); + + resolve_and_resume (frame, server_rename_resume); + + return 0; +} + +int +server_lk_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_lk_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->lk, + state->fd, state->cmd, &state->flock); + + return 0; + +err: + server_lk_cbk (frame, NULL, frame->this, + state->resolve.op_ret, + state->resolve.op_errno, + NULL); + return 0; +} + +/* + * server_lk - lk function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ + +int +server_lk (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_lk_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION (frame); + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.fd_no = ntoh64 (req->fd); + state->cmd = ntoh32 (req->cmd); + state->type = ntoh32 (req->type); + + switch (state->cmd) { + case GF_LK_GETLK: + state->cmd = F_GETLK; + break; + case GF_LK_SETLK: + state->cmd = F_SETLK; + break; + case GF_LK_SETLKW: + state->cmd = F_SETLKW; + break; + } + + gf_flock_to_flock (&req->flock, &state->flock); + + switch (state->type) { + case GF_LK_F_RDLCK: + state->flock.l_type = F_RDLCK; + break; + case GF_LK_F_WRLCK: + state->flock.l_type = F_WRLCK; + break; + case GF_LK_F_UNLCK: + state->flock.l_type = F_UNLCK; + break; + default: + gf_log (bound_xl->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): Unknown lock type: %"PRId32"!", + state->resolve.fd_no, state->fd->inode->ino, state->type); + break; + } + + + resolve_and_resume (frame, server_lk_resume); + + return 0; +} + +/* xxx_MOPS */ +int +_volfile_update_checksum (xlator_t *this, char *key, uint32_t checksum) +{ + server_conf_t *conf = NULL; + struct _volfile_ctx *temp_volfile = NULL; + + conf = this->private; + temp_volfile = conf->volfile; + + while (temp_volfile) { + if ((NULL == key) && (NULL == temp_volfile->key)) + break; + if ((NULL == key) || (NULL == temp_volfile->key)) { + temp_volfile = temp_volfile->next; + continue; + } + if (strcmp (temp_volfile->key, key) == 0) + break; + temp_volfile = temp_volfile->next; + } + + if (!temp_volfile) { + temp_volfile = GF_CALLOC (1, sizeof (struct _volfile_ctx), + gf_server_mt_volfile_ctx); + + temp_volfile->next = conf->volfile; + temp_volfile->key = (key)? gf_strdup (key): NULL; + temp_volfile->checksum = checksum; + + conf->volfile = temp_volfile; + goto out; + } + + if (temp_volfile->checksum != checksum) { + gf_log (this->name, GF_LOG_CRITICAL, + "the volume file got modified between earlier access " + "and now, this may lead to inconsistency between " + "clients, advised to remount client"); + temp_volfile->checksum = checksum; + } + + out: + return 0; +} + + +size_t +build_volfile_path (xlator_t *this, const char *key, char *path, + size_t path_len) +{ + int ret = -1; + int free_filename = 0; + int free_conf_dir = 0; + char *filename = NULL; + char *conf_dir = CONFDIR; + struct stat buf = {0,}; + data_t * conf_dir_data = NULL; + char data_key[256] = {0,}; + + /* Inform users that this option is changed now */ + ret = dict_get_str (this->options, "client-volume-filename", + &filename); + if (ret == 0) { + gf_log (this->name, GF_LOG_WARNING, + "option 'client-volume-filename' is changed to " + "'volume-filename.<key>' which now takes 'key' as an " + "option to choose/fetch different files from server. " + "Refer documentation or contact developers for more " + "info. Currently defaulting to given file '%s'", + filename); + } + + if (key && !filename) { + sprintf (data_key, "volume-filename.%s", key); + ret = dict_get_str (this->options, data_key, &filename); + + if (ret < 0) { + + conf_dir_data = dict_get (this->options, "conf-dir"); + if (conf_dir_data) { + /* Check whether the specified directory exists, + or directory specified is non standard */ + ret = stat (conf_dir_data->data, &buf); + if ((ret != 0) || !S_ISDIR (buf.st_mode)) { + gf_log (this->name, GF_LOG_ERROR, + "Directory '%s' doesn't" + "exist, exiting.", + conf_dir_data->data); + ret = -1; + goto out; + } + /* Make sure that conf-dir doesn't + * contain ".." in path + */ + if ((gf_strstr (conf_dir_data->data, + "/", "..")) == -1) { + ret = -1; + gf_log (this->name, GF_LOG_ERROR, + "%s: invalid conf_dir", + conf_dir_data->data); + goto out; + } + + /* Make sure that key doesn't + * contain "../" in path + */ + + if ((gf_strstr (key, "/", "..")) == -1) { + ret = -1; + gf_log (this->name, GF_LOG_ERROR, + "%s: invalid key", key); + goto out; + } + + conf_dir = gf_strdup (conf_dir_data->data); + free_conf_dir = 1; + } + + ret = gf_asprintf (&filename, "%s/%s.vol", + conf_dir, key); + if (-1 == ret) + goto out; + + free_filename = 1; + } + } + + if (!filename) { + ret = dict_get_str (this->options, + "volume-filename.default", &filename); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "no default volume filename given, " + "defaulting to %s", DEFAULT_VOLUME_FILE_PATH); + filename = DEFAULT_VOLUME_FILE_PATH; + } + } + + ret = -1; + + if ((filename) && (path_len > strlen (filename))) { + strcpy (path, filename); + ret = strlen (filename); + } + +out: + if (free_conf_dir) + GF_FREE (conf_dir); + + if (free_filename) + GF_FREE (filename); + + return ret; +} + +int +_validate_volfile_checksum (xlator_t *this, char *key, + uint32_t checksum) +{ + char filename[ZR_PATH_MAX] = {0,}; + server_conf_t *conf = NULL; + struct _volfile_ctx *temp_volfile = NULL; + int ret = 0; + uint32_t local_checksum = 0; + + conf = this->private; + temp_volfile = conf->volfile; + + if (!checksum) + goto out; + + if (!temp_volfile) { + ret = build_volfile_path (this, key, filename, + sizeof (filename)); + if (ret <= 0) + goto out; + ret = open (filename, O_RDONLY); + if (-1 == ret) { + ret = 0; + gf_log (this->name, GF_LOG_DEBUG, + "failed to open volume file (%s) : %s", + filename, strerror (errno)); + goto out; + } + get_checksum_for_file (ret, &local_checksum); + _volfile_update_checksum (this, key, local_checksum); + close (ret); + } + + temp_volfile = conf->volfile; + while (temp_volfile) { + if ((NULL == key) && (NULL == temp_volfile->key)) + break; + if ((NULL == key) || (NULL == temp_volfile->key)) { + temp_volfile = temp_volfile->next; + continue; + } + if (strcmp (temp_volfile->key, key) == 0) + break; + temp_volfile = temp_volfile->next; + } + + if (!temp_volfile) + goto out; + + if ((temp_volfile->checksum) && + (checksum != temp_volfile->checksum)) + ret = -1; + +out: + return ret; +} + +/* Management Calls */ +/* + * mop_getspec - getspec function for server protocol + * @frame: call frame + * @bound_xl: + * @params: + * + */ +int +mop_getspec (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_hdr_common_t *_hdr = NULL; + gf_mop_getspec_rsp_t *rsp = NULL; + int32_t ret = -1; + int32_t op_errno = ENOENT; + int32_t gf_errno = 0; + int32_t spec_fd = -1; + size_t file_len = 0; + size_t _hdrlen = 0; + char filename[ZR_PATH_MAX] = {0,}; + struct stat stbuf = {0,}; + gf_mop_getspec_req_t *req = NULL; + uint32_t checksum = 0; + uint32_t flags = 0; + uint32_t keylen = 0; + char *key = NULL; + server_conf_t *conf = NULL; + + req = gf_param (hdr); + flags = ntoh32 (req->flags); + keylen = ntoh32 (req->keylen); + if (keylen) { + key = req->key; + } + + conf = frame->this->private; + + ret = build_volfile_path (frame->this, key, filename, + sizeof (filename)); + if (ret > 0) { + /* to allocate the proper buffer to hold the file data */ + ret = stat (filename, &stbuf); + if (ret < 0){ + gf_log (frame->this->name, GF_LOG_ERROR, + "Unable to stat %s (%s)", + filename, strerror (errno)); + goto fail; + } + + spec_fd = open (filename, O_RDONLY); + if (spec_fd < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Unable to open %s (%s)", + filename, strerror (errno)); + goto fail; + } + ret = 0; + file_len = stbuf.st_size; + if (conf->verify_volfile_checksum) { + get_checksum_for_file (spec_fd, &checksum); + _volfile_update_checksum (frame->this, key, checksum); + } + } else { + errno = ENOENT; + } + +fail: + op_errno = errno; + + _hdrlen = gf_hdr_len (rsp, file_len + 1); + _hdr = gf_hdr_new (rsp, file_len + 1); + rsp = gf_param (_hdr); + + _hdr->rsp.op_ret = hton32 (ret); + gf_errno = gf_errno_to_error (op_errno); + _hdr->rsp.op_errno = hton32 (gf_errno); + + if (file_len) { + ret = read (spec_fd, rsp->spec, file_len); + close (spec_fd); + } + protocol_server_reply (frame, GF_OP_TYPE_MOP_REPLY, GF_MOP_GETSPEC, + _hdr, _hdrlen, NULL, 0, NULL); + + return 0; +} + + +int +server_checksum_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + uint8_t *fchecksum, uint8_t *dchecksum) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_checksum_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + hdrlen = gf_hdr_len (rsp, NAME_MAX + 1 + NAME_MAX + 1); + hdr = gf_hdr_new (rsp, NAME_MAX + 1 + NAME_MAX + 1); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + memcpy (rsp->fchecksum, fchecksum, NAME_MAX); + rsp->fchecksum[NAME_MAX] = '\0'; + memcpy (rsp->dchecksum + NAME_MAX, + dchecksum, NAME_MAX); + rsp->dchecksum[NAME_MAX + NAME_MAX] = '\0'; + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_CHECKSUM, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +int +server_checksum_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + int op_ret = 0; + int op_errno = 0; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) { + op_ret = state->resolve.op_ret; + op_errno = state->resolve.op_errno; + goto err; + } + + STACK_WIND (frame, server_checksum_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->checksum, + &state->loc, state->flags); + + return 0; +err: + server_checksum_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + + return 0; +} + +int +server_checksum (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_checksum_req_t *req = NULL; + server_state_t *state = NULL; + + req = gf_param (hdr); + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MAY; + state->resolve.path = gf_strdup (req->path); + state->resolve.gen = ntoh64 (req->gen); + state->resolve.ino = ntoh64 (req->ino); + state->flags = ntoh32 (req->flag); + + resolve_and_resume (frame, server_checksum_resume); + + return 0; +} + + +int +server_rchecksum_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + uint32_t weak_checksum, uint8_t *strong_checksum) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_rchecksum_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + hdrlen = gf_hdr_len (rsp, MD5_DIGEST_LEN + 1); + hdr = gf_hdr_new (rsp, MD5_DIGEST_LEN + 1); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + rsp->weak_checksum = weak_checksum; + + memcpy (rsp->strong_checksum, + strong_checksum, MD5_DIGEST_LEN); + + rsp->strong_checksum[MD5_DIGEST_LEN] = '\0'; + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_RCHECKSUM, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +int +server_rchecksum_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + int op_ret = 0; + int op_errno = 0; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) { + op_ret = state->resolve.op_ret; + op_errno = state->resolve.op_errno; + goto err; + } + + STACK_WIND (frame, server_rchecksum_cbk, + bound_xl, + bound_xl->fops->rchecksum, + state->fd, state->offset, state->size); + + return 0; +err: + server_rchecksum_cbk (frame, NULL, frame->this, -1, EINVAL, 0, NULL); + + return 0; + +} + +int +server_rchecksum (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_rchecksum_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + + state = CALL_STATE(frame); + + state->resolve.type = RESOLVE_MAY; + state->resolve.fd_no = ntoh64 (req->fd); + state->offset = ntoh64 (req->offset); + state->size = ntoh32 (req->len); + + resolve_and_resume (frame, server_rchecksum_resume); + + return 0; +} + + +/* + * mop_unlock - unlock management function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + */ +int +mop_getvolume (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + return 0; +} + +struct __get_xl_struct { + const char *name; + xlator_t *reply; +}; + +void __check_and_set (xlator_t *each, void *data) +{ + if (!strcmp (each->name, + ((struct __get_xl_struct *) data)->name)) + ((struct __get_xl_struct *) data)->reply = each; +} + +static xlator_t * +get_xlator_by_name (xlator_t *some_xl, const char *name) +{ + struct __get_xl_struct get = { + .name = name, + .reply = NULL + }; + + xlator_foreach (some_xl, __check_and_set, &get); + + return get.reply; +} + + +/* + * mop_setvolume - setvolume management function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + */ +int +mop_setvolume (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *req_hdr, size_t req_hdrlen, + struct iobuf *iobuf) +{ + server_connection_t *conn = NULL; + server_conf_t *conf = NULL; + gf_hdr_common_t *rsp_hdr = NULL; + gf_mop_setvolume_req_t *req = NULL; + gf_mop_setvolume_rsp_t *rsp = NULL; + peer_info_t *peerinfo = NULL; + int32_t ret = -1; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + int32_t gf_errno = 0; + dict_t *reply = NULL; + dict_t *config_params = NULL; + dict_t *params = NULL; + char *name = NULL; + char *version = NULL; + char *process_uuid = NULL; + xlator_t *xl = NULL; + transport_t *trans = NULL; + size_t rsp_hdrlen = -1; + size_t dict_len = -1; + size_t req_dictlen = -1; + char *msg = NULL; + char *volfile_key = NULL; + uint32_t checksum = 0; + int32_t lru_limit = 1024; + + params = dict_new (); + reply = dict_new (); + + req = gf_param (req_hdr); + req_dictlen = ntoh32 (req->dict_len); + ret = dict_unserialize (req->buf, req_dictlen, ¶ms); + + config_params = dict_copy_with_ref (frame->this->options, NULL); + trans = TRANSPORT_FROM_FRAME(frame); + conf = SERVER_CONF(frame); + + if (ret < 0) { + ret = dict_set_str (reply, "ERROR", + "Internal error: failed to unserialize " + "request dictionary"); + if (ret < 0) + gf_log (bound_xl->name, GF_LOG_DEBUG, + "failed to set error msg \"%s\"", + "Internal error: failed to unserialize " + "request dictionary"); + + op_ret = -1; + op_errno = EINVAL; + goto fail; + } + + ret = dict_get_str (params, "process-uuid", &process_uuid); + if (ret < 0) { + ret = dict_set_str (reply, "ERROR", + "UUID not specified"); + if (ret < 0) + gf_log (bound_xl->name, GF_LOG_DEBUG, + "failed to set error msg"); + + op_ret = -1; + op_errno = EINVAL; + goto fail; + } + + + conn = server_connection_get (frame->this, process_uuid); + if (trans->xl_private != conn) + trans->xl_private = conn; + + ret = dict_get_str (params, "protocol-version", &version); + if (ret < 0) { + ret = dict_set_str (reply, "ERROR", + "No version number specified"); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_DEBUG, + "failed to set error msg"); + + op_ret = -1; + op_errno = EINVAL; + goto fail; + } + + ret = strcmp (version, GF_PROTOCOL_VERSION); + if (ret != 0) { + ret = gf_asprintf (&msg, "protocol version mismatch: client(%s) " + "- server(%s)", version, GF_PROTOCOL_VERSION); + if (-1 == ret) { + gf_log (trans->xl->name, GF_LOG_ERROR, + "gf_asprintf failed while setting up error msg"); + goto fail; + } + ret = dict_set_dynstr (reply, "ERROR", msg); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_DEBUG, + "failed to set error msg"); + + op_ret = -1; + op_errno = EINVAL; + goto fail; + } + + ret = dict_get_str (params, + "remote-subvolume", &name); + if (ret < 0) { + ret = dict_set_str (reply, "ERROR", + "No remote-subvolume option specified"); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_DEBUG, + "failed to set error msg"); + + op_ret = -1; + op_errno = EINVAL; + goto fail; + } + + xl = get_xlator_by_name (frame->this, name); + if (xl == NULL) { + ret = gf_asprintf (&msg, "remote-subvolume \"%s\" is not found", + name); + if (-1 == ret) { + gf_log (trans->xl->name, GF_LOG_ERROR, + "gf_asprintf failed while setting error msg"); + goto fail; + } + ret = dict_set_dynstr (reply, "ERROR", msg); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_DEBUG, + "failed to set error msg"); + + op_ret = -1; + op_errno = ENOENT; + goto fail; + } + + if (conf->verify_volfile_checksum) { + ret = dict_get_uint32 (params, "volfile-checksum", &checksum); + if (ret == 0) { + ret = dict_get_str (params, "volfile-key", + &volfile_key); + + ret = _validate_volfile_checksum (trans->xl, + volfile_key, + checksum); + if (-1 == ret) { + ret = dict_set_str (reply, "ERROR", + "volume-file checksum " + "varies from earlier " + "access"); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_DEBUG, + "failed to set error msg"); + + op_ret = -1; + op_errno = ESTALE; + goto fail; + } + } + } + + + peerinfo = &trans->peerinfo; + ret = dict_set_static_ptr (params, "peer-info", peerinfo); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_DEBUG, + "failed to set peer-info"); + ret = dict_set_str (params, "peer-info-name", peerinfo->identifier); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_DEBUG, + "failed to set peer-info-name"); + + if (conf->auth_modules == NULL) { + gf_log (trans->xl->name, GF_LOG_ERROR, + "Authentication module not initialized"); + } + + ret = gf_authenticate (params, config_params, + conf->auth_modules); + if (ret == AUTH_ACCEPT) { + gf_log (trans->xl->name, GF_LOG_INFO, + "accepted client from %s", + peerinfo->identifier); + op_ret = 0; + conn->bound_xl = xl; + ret = dict_set_str (reply, "ERROR", "Success"); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_DEBUG, + "failed to set error msg"); + } else { + gf_log (trans->xl->name, GF_LOG_ERROR, + "Cannot authenticate client from %s", + peerinfo->identifier); + op_ret = -1; + op_errno = EACCES; + ret = dict_set_str (reply, "ERROR", "Authentication failed"); + if (ret < 0) + gf_log (bound_xl->name, GF_LOG_DEBUG, + "failed to set error msg"); + + goto fail; + } + + if (conn->bound_xl == NULL) { + ret = dict_set_str (reply, "ERROR", + "Check volfile and handshake " + "options in protocol/client"); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_DEBUG, + "failed to set error msg"); + + op_ret = -1; + op_errno = EACCES; + goto fail; + } + + if ((conn->bound_xl != NULL) && + (ret >= 0) && + (conn->bound_xl->itable == NULL)) { + /* create inode table for this bound_xl, if one doesn't + already exist */ + lru_limit = INODE_LRU_LIMIT (frame->this); + + gf_log (trans->xl->name, GF_LOG_TRACE, + "creating inode table with lru_limit=%"PRId32", " + "xlator=%s", lru_limit, conn->bound_xl->name); + + conn->bound_xl->itable = + inode_table_new (lru_limit, + conn->bound_xl); + } + + ret = dict_set_str (reply, "process-uuid", + xl->ctx->process_uuid); + + ret = dict_set_uint64 (reply, "transport-ptr", + ((uint64_t) (long) trans)); + +fail: + dict_len = dict_serialized_length (reply); + if (dict_len < 0) { + gf_log (xl->name, GF_LOG_DEBUG, + "failed to get serialized length of reply dict"); + op_ret = -1; + op_errno = EINVAL; + dict_len = 0; + } + + rsp_hdr = gf_hdr_new (rsp, dict_len); + rsp_hdrlen = gf_hdr_len (rsp, dict_len); + rsp = gf_param (rsp_hdr); + + if (dict_len) { + ret = dict_serialize (reply, rsp->buf); + if (ret < 0) { + gf_log (xl->name, GF_LOG_DEBUG, + "failed to serialize reply dict"); + op_ret = -1; + op_errno = -ret; + } + } + rsp->dict_len = hton32 (dict_len); + + rsp_hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + rsp_hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_MOP_REPLY, GF_MOP_SETVOLUME, + rsp_hdr, rsp_hdrlen, NULL, 0, NULL); + + dict_unref (params); + dict_unref (reply); + dict_unref (config_params); + + return 0; +} + + +int +mop_ping (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_hdr_common_t *rsp_hdr = NULL; + gf_mop_ping_rsp_t *rsp = NULL; + size_t rsp_hdrlen = 0; + + rsp_hdrlen = gf_hdr_len (rsp, 0); + rsp_hdr = gf_hdr_new (rsp, 0); + + hdr->rsp.op_ret = 0; + + protocol_server_reply (frame, GF_OP_TYPE_MOP_REPLY, GF_MOP_PING, + rsp_hdr, rsp_hdrlen, NULL, 0, NULL); + + return 0; +} + + +int +mop_log (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_mop_log_req_t * req = NULL; + char * msg = NULL; + uint32_t msglen = 0; + + transport_t * trans = NULL; + + trans = TRANSPORT_FROM_FRAME (frame); + + req = gf_param (hdr); + msglen = ntoh32 (req->msglen); + + if (msglen) + msg = req->msg; + + gf_log_from_client (msg, trans->peerinfo.identifier); + + return 0; +} + + +/* ENOSYS operations (for backword compatibility) */ +int +server_setdents (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_hdr_common_t *rsp_hdr = NULL; + gf_mop_ping_rsp_t *rsp = NULL; /* Using for NULL */ + size_t rsp_hdrlen = 0; + int32_t gf_errno = 0; + + rsp_hdrlen = gf_hdr_len (rsp, 0); + rsp_hdr = gf_hdr_new (rsp, 0); + + gf_errno = gf_errno_to_error (ENOSYS); + hdr->rsp.op_errno = hton32 (gf_errno); + hdr->rsp.op_ret = -1; + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_SETDENTS, + rsp_hdr, rsp_hdrlen, NULL, 0, NULL); + + return 0; +} + +/* */ +int +server_getdents (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_hdr_common_t *rsp_hdr = NULL; + gf_mop_ping_rsp_t *rsp = NULL; /* Using for NULL */ + size_t rsp_hdrlen = 0; + int32_t gf_errno = 0; + + rsp_hdrlen = gf_hdr_len (rsp, 0); + rsp_hdr = gf_hdr_new (rsp, 0); + + gf_errno = gf_errno_to_error (ENOSYS); + hdr->rsp.op_errno = hton32 (gf_errno); + hdr->rsp.op_ret = -1; + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_GETDENTS, + rsp_hdr, rsp_hdrlen, NULL, 0, NULL); + + return 0; +} + +/* */ +int +server_lock_notify (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_hdr_common_t *rsp_hdr = NULL; + gf_mop_ping_rsp_t *rsp = NULL; /* Using for NULL */ + size_t rsp_hdrlen = 0; + int32_t gf_errno = 0; + + rsp_hdrlen = gf_hdr_len (rsp, 0); + rsp_hdr = gf_hdr_new (rsp, 0); + + gf_errno = gf_errno_to_error (ENOSYS); + hdr->rsp.op_errno = hton32 (gf_errno); + hdr->rsp.op_ret = -1; + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_LOCK_NOTIFY, + rsp_hdr, rsp_hdrlen, NULL, 0, NULL); + + return 0; +} + +/* */ +int +server_lock_fnotify (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_hdr_common_t *rsp_hdr = NULL; + gf_mop_ping_rsp_t *rsp = NULL; /* Using for NULL */ + size_t rsp_hdrlen = 0; + int32_t gf_errno = 0; + + rsp_hdrlen = gf_hdr_len (rsp, 0); + rsp_hdr = gf_hdr_new (rsp, 0); + + gf_errno = gf_errno_to_error (ENOSYS); + hdr->rsp.op_errno = hton32 (gf_errno); + hdr->rsp.op_ret = -1; + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_PROTO_FOP_LOCK_FNOTIFY, + rsp_hdr, rsp_hdrlen, NULL, 0, NULL); + + return 0; +} + + +int +mop_stats (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_hdr_common_t *rsp_hdr = NULL; + gf_mop_ping_rsp_t *rsp = NULL; /* Using for NULL */ + size_t rsp_hdrlen = 0; + int32_t gf_errno = 0; + + rsp_hdrlen = gf_hdr_len (rsp, 0); + rsp_hdr = gf_hdr_new (rsp, 0); + + gf_errno = gf_errno_to_error (ENOSYS); + hdr->rsp.op_errno = hton32 (gf_errno); + hdr->rsp.op_ret = -1; + + protocol_server_reply (frame, GF_OP_TYPE_MOP_REPLY, GF_MOP_STATS, + rsp_hdr, rsp_hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * unknown_op_cbk - This function is called when a opcode for unknown + * type is called. Helps to keep the backward/forward + * compatiblity + * @frame: call frame + * @type: + * @opcode: + * + */ + +int +unknown_op_cbk (call_frame_t *frame, int32_t type, int32_t opcode) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_flush_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (-1); + gf_errno = gf_errno_to_error (ENOSYS); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, type, opcode, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * get_frame_for_transport - get call frame for specified transport object + * + * @trans: transport object + * + */ +static call_frame_t * +get_frame_for_transport (transport_t *trans) +{ + call_frame_t *frame = NULL; + call_pool_t *pool = NULL; + server_connection_t *conn = NULL; + server_state_t *state = NULL;; + + GF_VALIDATE_OR_GOTO("server", trans, out); + + if (trans->xl && trans->xl->ctx) + pool = trans->xl->ctx->pool; + GF_VALIDATE_OR_GOTO("server", pool, out); + + frame = create_frame (trans->xl, pool); + GF_VALIDATE_OR_GOTO("server", frame, out); + + state = GF_CALLOC (1, sizeof (*state), + gf_server_mt_server_state_t); + GF_VALIDATE_OR_GOTO("server", state, out); + + conn = trans->xl_private; + if (conn) { + if (conn->bound_xl) + state->itable = conn->bound_xl->itable; + state->bound_xl = conn->bound_xl; + } + + state->trans = transport_ref (trans); + state->resolve.fd_no = -1; + state->resolve2.fd_no = -1; + + frame->root->trans = conn; + frame->root->state = state; /* which socket */ + frame->root->unique = 0; /* which call */ + +out: + return frame; +} + + +int +server_decode_groups (call_frame_t *frame, gf_hdr_common_t *hdr) +{ + int i = 0; + + if ((!frame) || (!hdr)) + return 0; + + frame->root->ngrps = ntoh32 (hdr->req.ngrps); + if (frame->root->ngrps == 0) + return 0; + + if (frame->root->ngrps > GF_REQUEST_MAXGROUPS) + return -1; + + for (; i < frame->root->ngrps; ++i) + frame->root->groups[i] = ntoh32 (hdr->req.groups[i]); + + return 0; +} + + +/* + * get_frame_for_call - create a frame into the capable of + * generating and replying the reply packet by itself. + * By making a call with this frame, the last UNWIND + * function will have all needed state from its + * frame_t->root to send reply. + * @trans: + * @blk: + * @params: + * + * not for external reference + */ +static call_frame_t * +get_frame_for_call (transport_t *trans, gf_hdr_common_t *hdr) +{ + call_frame_t *frame = NULL; + + frame = get_frame_for_transport (trans); + + frame->root->op = ntoh32 (hdr->op); + frame->root->type = ntoh32 (hdr->type); + + frame->root->uid = ntoh32 (hdr->req.uid); + frame->root->unique = ntoh64 (hdr->callid); /* which call */ + frame->root->gid = ntoh32 (hdr->req.gid); + frame->root->pid = ntoh32 (hdr->req.pid); + frame->root->lk_owner = ntoh64 (hdr->req.lk_owner); + server_decode_groups (frame, hdr); + + return frame; +} + +/* + * prototype of operations function for each of mop and + * fop at server protocol level + * + * @frame: call frame pointer + * @bound_xl: the xlator that this frame is bound to + * @params: parameters dictionary + * + * to be used by protocol interpret, _not_ for exterenal reference + */ +typedef int32_t (*gf_op_t) (call_frame_t *frame, xlator_t *bould_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf); + + +static gf_op_t gf_fops[] = { + [GF_PROTO_FOP_STAT] = server_stat, + [GF_PROTO_FOP_READLINK] = server_readlink, + [GF_PROTO_FOP_MKNOD] = server_mknod, + [GF_PROTO_FOP_MKDIR] = server_mkdir, + [GF_PROTO_FOP_UNLINK] = server_unlink, + [GF_PROTO_FOP_RMDIR] = server_rmdir, + [GF_PROTO_FOP_SYMLINK] = server_symlink, + [GF_PROTO_FOP_RENAME] = server_rename, + [GF_PROTO_FOP_LINK] = server_link, + [GF_PROTO_FOP_TRUNCATE] = server_truncate, + [GF_PROTO_FOP_OPEN] = server_open, + [GF_PROTO_FOP_READ] = server_readv, + [GF_PROTO_FOP_WRITE] = server_writev, + [GF_PROTO_FOP_STATFS] = server_statfs, + [GF_PROTO_FOP_FLUSH] = server_flush, + [GF_PROTO_FOP_FSYNC] = server_fsync, + [GF_PROTO_FOP_SETXATTR] = server_setxattr, + [GF_PROTO_FOP_GETXATTR] = server_getxattr, + [GF_PROTO_FOP_FGETXATTR] = server_fgetxattr, + [GF_PROTO_FOP_FSETXATTR] = server_fsetxattr, + [GF_PROTO_FOP_REMOVEXATTR] = server_removexattr, + [GF_PROTO_FOP_OPENDIR] = server_opendir, + [GF_PROTO_FOP_FSYNCDIR] = server_fsyncdir, + [GF_PROTO_FOP_ACCESS] = server_access, + [GF_PROTO_FOP_CREATE] = server_create, + [GF_PROTO_FOP_FTRUNCATE] = server_ftruncate, + [GF_PROTO_FOP_FSTAT] = server_fstat, + [GF_PROTO_FOP_LK] = server_lk, + [GF_PROTO_FOP_LOOKUP] = server_lookup, + [GF_PROTO_FOP_READDIR] = server_readdir, + [GF_PROTO_FOP_READDIRP] = server_readdirp, + [GF_PROTO_FOP_INODELK] = server_inodelk, + [GF_PROTO_FOP_FINODELK] = server_finodelk, + [GF_PROTO_FOP_ENTRYLK] = server_entrylk, + [GF_PROTO_FOP_FENTRYLK] = server_fentrylk, + [GF_PROTO_FOP_CHECKSUM] = server_checksum, + [GF_PROTO_FOP_RCHECKSUM] = server_rchecksum, + [GF_PROTO_FOP_XATTROP] = server_xattrop, + [GF_PROTO_FOP_FXATTROP] = server_fxattrop, + [GF_PROTO_FOP_SETATTR] = server_setattr, + [GF_PROTO_FOP_FSETATTR] = server_fsetattr, + [GF_PROTO_FOP_SETDENTS] = server_setdents, + [GF_PROTO_FOP_GETDENTS] = server_getdents, + [GF_PROTO_FOP_LOCK_NOTIFY] = server_lock_notify, + [GF_PROTO_FOP_LOCK_FNOTIFY] = server_lock_fnotify, +}; + + + +static gf_op_t gf_mops[] = { + [GF_MOP_SETVOLUME] = mop_setvolume, + [GF_MOP_GETVOLUME] = mop_getvolume, + [GF_MOP_GETSPEC] = mop_getspec, + [GF_MOP_PING] = mop_ping, + [GF_MOP_LOG] = mop_log, + [GF_MOP_STATS] = mop_stats, +}; + +static gf_op_t gf_cbks[] = { + [GF_CBK_FORGET] = server_forget, + [GF_CBK_RELEASE] = server_release, + [GF_CBK_RELEASEDIR] = server_releasedir +}; + +int +protocol_server_interpret (xlator_t *this, transport_t *trans, + char *hdr_p, size_t hdrlen, struct iobuf *iobuf) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + xlator_t *bound_xl = NULL; + call_frame_t *frame = NULL; + peer_info_t *peerinfo = NULL; + int32_t type = -1; + int32_t op = -1; + int32_t ret = -1; + + hdr = (gf_hdr_common_t *)hdr_p; + type = ntoh32 (hdr->type); + op = ntoh32 (hdr->op); + + conn = trans->xl_private; + if (conn) + bound_xl = conn->bound_xl; + + peerinfo = &trans->peerinfo; + switch (type) { + case GF_OP_TYPE_FOP_REQUEST: + if ((op < 0) || (op >= GF_PROTO_FOP_MAXVALUE)) { + gf_log (this->name, GF_LOG_ERROR, + "invalid fop %"PRId32" from client %s", + op, peerinfo->identifier); + break; + } + if (bound_xl == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "Received fop %"PRId32" before " + "authentication.", op); + break; + } + frame = get_frame_for_call (trans, hdr); + frame->op = op; + ret = gf_fops[op] (frame, bound_xl, hdr, hdrlen, iobuf); + break; + + case GF_OP_TYPE_MOP_REQUEST: + if ((op < 0) || (op >= GF_MOP_MAXVALUE)) { + gf_log (this->name, GF_LOG_ERROR, + "invalid mop %"PRId32" from client %s", + op, peerinfo->identifier); + break; + } + frame = get_frame_for_call (trans, hdr); + frame->op = op; + ret = gf_mops[op] (frame, bound_xl, hdr, hdrlen, iobuf); + break; + + case GF_OP_TYPE_CBK_REQUEST: + if ((op < 0) || (op >= GF_CBK_MAXVALUE)) { + gf_log (this->name, GF_LOG_ERROR, + "invalid cbk %"PRId32" from client %s", + op, peerinfo->identifier); + break; + } + if (bound_xl == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "Received cbk %d before authentication.", op); + break; + } + + frame = get_frame_for_call (trans, hdr); + ret = gf_cbks[op] (frame, bound_xl, hdr, hdrlen, iobuf); + break; + + default: + break; + } + + return ret; +} + + +/* + * server_nop_cbk - nop callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int +server_nop_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + if (state) + free_state (state); + STACK_DESTROY (frame->root); + return 0; +} + +/* + * server_fd - fdtable dump function for server protocol + * @this: + * + */ +int +server_fd (xlator_t *this) +{ + server_conf_t *conf = NULL; + server_connection_t *trav = NULL; + char key[GF_DUMP_MAX_BUF_LEN]; + int i = 1; + int ret = -1; + + if (!this) + return -1; + + conf = this->private; + if (!conf) { + gf_log (this->name, GF_LOG_WARNING, + "conf null in xlator"); + return -1; + } + + gf_proc_dump_add_section("xlator.protocol.server.conn"); + + ret = pthread_mutex_trylock (&conf->mutex); + if (ret) { + gf_log("", GF_LOG_WARNING, "Unable to dump fdtable" + " errno: %d", errno); + return -1; + } + + list_for_each_entry (trav, &conf->conns, list) { + if (trav->id) { + gf_proc_dump_build_key(key, + "xlator.protocol.server.conn", + "%d.id", i); + gf_proc_dump_write(key, "%s", trav->id); + } + + gf_proc_dump_build_key(key,"xlator.protocol.server.conn", + "%d.ref",i) + gf_proc_dump_write(key, "%d", trav->ref); + if (trav->bound_xl) { + gf_proc_dump_build_key(key, + "xlator.protocol.server.conn", + "%d.bound_xl", i); + gf_proc_dump_write(key, "%s", trav->bound_xl->name); + } + + gf_proc_dump_build_key(key, + "xlator.protocol.server.conn", + "%d.id", i); + fdtable_dump(trav->fdtable,key); + i++; + } + pthread_mutex_unlock (&conf->mutex); + + + return 0; + } + +int +server_priv (xlator_t *this) +{ + return 0; +} + +int +server_inode (xlator_t *this) +{ + server_conf_t *conf = NULL; + server_connection_t *trav = NULL; + char key[GF_DUMP_MAX_BUF_LEN]; + int i = 1; + int ret = -1; + + if (!this) + return -1; + + conf = this->private; + if (!conf) { + gf_log (this->name, GF_LOG_WARNING, + "conf null in xlator"); + return -1; + } + + ret = pthread_mutex_trylock (&conf->mutex); + if (ret) { + gf_log("", GF_LOG_WARNING, "Unable to dump itable" + " errno: %d", errno); + return -1; + } + + list_for_each_entry (trav, &conf->conns, list) { + if (trav->bound_xl && trav->bound_xl->itable) { + gf_proc_dump_build_key(key, + "xlator.protocol.server.conn", + "%d.bound_xl.%s", + i, trav->bound_xl->name); + inode_table_dump(trav->bound_xl->itable,key); + i++; + } + } + pthread_mutex_unlock (&conf->mutex); + + + return 0; +} + + +static void +get_auth_types (dict_t *this, char *key, data_t *value, void *data) +{ + dict_t *auth_dict = NULL; + char *saveptr = NULL; + char *tmp = NULL; + char *key_cpy = NULL; + int32_t ret = -1; + + auth_dict = data; + key_cpy = gf_strdup (key); + GF_VALIDATE_OR_GOTO("server", key_cpy, out); + + tmp = strtok_r (key_cpy, ".", &saveptr); + ret = strcmp (tmp, "auth"); + if (ret == 0) { + tmp = strtok_r (NULL, ".", &saveptr); + if (strcmp (tmp, "ip") == 0) { + /* TODO: backward compatibility, remove when + newer versions are available */ + tmp = "addr"; + gf_log ("server", GF_LOG_WARNING, + "assuming 'auth.ip' to be 'auth.addr'"); + } + ret = dict_set_dynptr (auth_dict, tmp, NULL, 0); + if (ret < 0) { + gf_log ("server", GF_LOG_DEBUG, + "failed to dict_set_dynptr"); + } + } + + GF_FREE (key_cpy); +out: + return; +} + + +int +validate_auth_options (xlator_t *this, dict_t *dict) +{ + int ret = -1; + int error = 0; + xlator_list_t *trav = NULL; + data_pair_t *pair = NULL; + char *saveptr = NULL; + char *tmp = NULL; + char *key_cpy = NULL; + + trav = this->children; + while (trav) { + error = -1; + for (pair = dict->members_list; pair; pair = pair->next) { + key_cpy = gf_strdup (pair->key); + tmp = strtok_r (key_cpy, ".", &saveptr); + ret = strcmp (tmp, "auth"); + if (ret == 0) { + /* for module type */ + tmp = strtok_r (NULL, ".", &saveptr); + /* for volume name */ + tmp = strtok_r (NULL, ".", &saveptr); + } + + if (strcmp (tmp, trav->xlator->name) == 0) { + error = 0; + GF_FREE (key_cpy); + break; + } + GF_FREE (key_cpy); + } + if (-1 == error) { + gf_log (this->name, GF_LOG_ERROR, + "volume '%s' defined as subvolume, but no " + "authentication defined for the same", + trav->xlator->name); + break; + } + trav = trav->next; + } + + return error; +} + +int32_t +mem_acct_init (xlator_t *this) +{ + int ret = -1; + + if (!this) + return ret; + + ret = xlator_mem_acct_init (this, gf_server_mt_end + 1); + + if (ret != 0) { + gf_log (this->name, GF_LOG_ERROR, "Memory accounting init" + " failed"); + return ret; + } + + return ret; +} + + +/* + * init - called during server protocol initialization + * + * @this: + * + */ +int +init (xlator_t *this) +{ + int32_t ret = -1; + transport_t *trans = NULL; + server_conf_t *conf = NULL; + data_t *data = NULL; + data_t *trace = NULL; + + if (this->children == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "protocol/server should have subvolume"); + goto out; + } + + trans = transport_load (this->options, this); + if (trans == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "failed to load transport"); + goto out; + } + + ret = transport_listen (trans); + if (ret == -1) { + gf_log (this->name, GF_LOG_ERROR, + "failed to bind/listen on socket"); + goto out; + } + + conf = GF_CALLOC (1, sizeof (server_conf_t), + gf_server_mt_server_conf_t); + GF_VALIDATE_OR_GOTO(this->name, conf, out); + + INIT_LIST_HEAD (&conf->conns); + pthread_mutex_init (&conf->mutex, NULL); + + conf->trans = trans; + + conf->auth_modules = dict_new (); + GF_VALIDATE_OR_GOTO(this->name, conf->auth_modules, out); + + dict_foreach (this->options, get_auth_types, + conf->auth_modules); + ret = validate_auth_options (this, this->options); + if (ret == -1) { + /* logging already done in validate_auth_options function. */ + goto out; + } + + ret = gf_auth_init (this, conf->auth_modules); + if (ret) { + dict_unref (conf->auth_modules); + goto out; + } + + this->private = conf; + + ret = dict_get_int32 (this->options, "inode-lru-limit", + &conf->inode_lru_limit); + if (ret < 0) { + conf->inode_lru_limit = 1024; + } + + ret = dict_get_int32 (this->options, "limits.transaction-size", + &conf->max_block_size); + if (ret < 0) { + gf_log (this->name, GF_LOG_TRACE, + "defaulting limits.transaction-size to %d", + DEFAULT_BLOCK_SIZE); + conf->max_block_size = DEFAULT_BLOCK_SIZE; + } + + conf->verify_volfile_checksum = 1; + data = dict_get (this->options, "verify-volfile-checksum"); + if (data) { + ret = gf_string2boolean(data->data, + &conf->verify_volfile_checksum); + if (ret != 0) { + gf_log (this->name, GF_LOG_DEBUG, + "wrong value for verify-volfile-checksum"); + conf->verify_volfile_checksum = 1; + } + } + + trace = dict_get (this->options, "trace"); + if (trace) { + if (gf_string2boolean (trace->data, + &conf->trace) == -1) { + gf_log (this->name, GF_LOG_ERROR, + "'trace' takes on only boolean values."); + return -1; + } + } + +#ifndef GF_DARWIN_HOST_OS + { + struct rlimit lim; + + lim.rlim_cur = 1048576; + lim.rlim_max = 1048576; + + if (setrlimit (RLIMIT_NOFILE, &lim) == -1) { + gf_log (this->name, GF_LOG_WARNING, + "WARNING: Failed to set 'ulimit -n 1M': %s", + strerror(errno)); + lim.rlim_cur = 65536; + lim.rlim_max = 65536; + + if (setrlimit (RLIMIT_NOFILE, &lim) == -1) { + gf_log (this->name, GF_LOG_WARNING, + "Failed to set max open fd to 64k: %s", + strerror(errno)); + } else { + gf_log (this->name, GF_LOG_TRACE, + "max open fd set to 64k"); + } + } + } +#endif + this->graph->top = this; + + ret = 0; +out: + return ret; +} + + + +int +protocol_server_pollin (xlator_t *this, transport_t *trans) +{ + char *hdr = NULL; + size_t hdrlen = 0; + int ret = -1; + struct iobuf *iobuf = NULL; + + + ret = transport_receive (trans, &hdr, &hdrlen, &iobuf); + + if (ret == 0) + ret = protocol_server_interpret (this, trans, hdr, + hdrlen, iobuf); + + /* TODO: use mem-pool */ + GF_FREE (hdr); + + return ret; +} + + +/* + * fini - finish function for server protocol, called before + * unloading server protocol. + * + * @this: + * + */ +void +fini (xlator_t *this) +{ + server_conf_t *conf = this->private; + + GF_VALIDATE_OR_GOTO(this->name, conf, out); + + if (conf->auth_modules) { + dict_unref (conf->auth_modules); + } + + GF_FREE (conf); + this->private = NULL; +out: + return; +} + +/* + * server_protocol_notify - notify function for server protocol + * @this: + * @trans: + * @event: + * + */ +int +notify (xlator_t *this, int32_t event, void *data, ...) +{ + int ret = 0; + transport_t *trans = data; + peer_info_t *peerinfo = NULL; + peer_info_t *myinfo = NULL; + + if (trans != NULL) { + peerinfo = &(trans->peerinfo); + myinfo = &(trans->myinfo); + } + + switch (event) { + case GF_EVENT_POLLIN: + ret = protocol_server_pollin (this, trans); + break; + case GF_EVENT_POLLERR: + { + gf_log (trans->xl->name, GF_LOG_INFO, "%s disconnected", + peerinfo->identifier); + + ret = -1; + transport_disconnect (trans); + if (trans->xl_private == NULL) { + gf_log (this->name, GF_LOG_DEBUG, + "POLLERR received on (%s) even before " + "handshake with (%s) is successful", + myinfo->identifier, peerinfo->identifier); + } else { + /* + * FIXME: shouldn't we check for return value? + * what should be done if cleanup fails? + */ + server_connection_cleanup (this, trans->xl_private); + } + } + break; + + case GF_EVENT_TRANSPORT_CLEANUP: + { + if (trans->xl_private) { + server_connection_put (this, trans->xl_private); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "transport (%s) cleaned up even before " + "handshake with (%s) is successful", + myinfo->identifier, peerinfo->identifier); + } + } + break; + + default: + default_notify (this, event, data); + break; + } + + return ret; +} + + +struct xlator_fops fops = { +}; + +struct xlator_cbks cbks = { +}; + +struct xlator_dumpops dumpops = { + .inode = server_inode, + .priv = server_priv, + .fd = server_fd, +}; + + +struct volume_options options[] = { + { .key = {"transport-type"}, + .value = {"tcp", "socket", "ib-verbs", "unix", "ib-sdp", + "tcp/server", "ib-verbs/server"}, + .type = GF_OPTION_TYPE_STR + }, + { .key = {"volume-filename.*"}, + .type = GF_OPTION_TYPE_PATH, + }, + { .key = {"inode-lru-limit"}, + .type = GF_OPTION_TYPE_INT, + .min = 0, + .max = (1 * GF_UNIT_MB) + }, + { .key = {"client-volume-filename"}, + .type = GF_OPTION_TYPE_PATH + }, + { .key = {"verify-volfile-checksum"}, + .type = GF_OPTION_TYPE_BOOL + }, + { .key = {"trace"}, + .type = GF_OPTION_TYPE_BOOL + }, + { .key = {"conf-dir"}, + .type = GF_OPTION_TYPE_PATH, + }, + + { .key = {NULL} }, +}; diff --git a/xlators/protocol/legacy/server/src/server-protocol.h b/xlators/protocol/legacy/server/src/server-protocol.h new file mode 100644 index 00000000000..0c21000596f --- /dev/null +++ b/xlators/protocol/legacy/server/src/server-protocol.h @@ -0,0 +1,198 @@ +/* + Copyright (c) 2006-2009 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 _SERVER_PROTOCOL_H_ +#define _SERVER_PROTOCOL_H_ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> + +#include "glusterfs.h" +#include "xlator.h" +#include "logging.h" +#include "call-stub.h" +#include "fd.h" +#include "byte-order.h" +#include "server-mem-types.h" +#include "authenticate.h" +#include "transport.h" + +#define DEFAULT_BLOCK_SIZE 4194304 /* 4MB */ +#define DEFAULT_VOLUME_FILE_PATH CONFDIR "/glusterfs.vol" + +typedef struct _server_state server_state_t; + +struct _locker { + struct list_head lockers; + char *volume; + loc_t loc; + fd_t *fd; + pid_t pid; +}; + +struct _lock_table { + struct list_head file_lockers; + struct list_head dir_lockers; + gf_lock_t lock; + size_t count; +}; + + +/* private structure per connection (transport object) + * used as transport_t->xl_private + */ +struct _server_connection { + struct list_head list; + char *id; + int ref; + int active_transports; + pthread_mutex_t lock; + char disconnected; + fdtable_t *fdtable; + struct _lock_table *ltable; + xlator_t *bound_xl; +}; + +typedef struct _server_connection server_connection_t; + + +server_connection_t * +server_connection_get (xlator_t *this, const char *id); + +void +server_connection_put (xlator_t *this, server_connection_t *conn); + +int +server_connection_destroy (xlator_t *this, server_connection_t *conn); + +int +server_connection_cleanup (xlator_t *this, server_connection_t *conn); + +int +server_nop_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno); + + +struct _volfile_ctx { + struct _volfile_ctx *next; + char *key; + uint32_t checksum; +}; + +typedef struct { + struct _volfile_ctx *volfile; + + dict_t *auth_modules; + transport_t *trans; + int32_t max_block_size; + int32_t inode_lru_limit; + pthread_mutex_t mutex; + struct list_head conns; + gf_boolean_t verify_volfile_checksum; + gf_boolean_t trace; +} server_conf_t; + + +typedef enum { + RESOLVE_MUST = 1, + RESOLVE_NOT, + RESOLVE_MAY, + RESOLVE_DONTCARE, + RESOLVE_EXACT +} server_resolve_type_t; + + +struct resolve_comp { + char *basename; + ino_t ino; + uint64_t gen; + inode_t *inode; +}; + +typedef struct { + server_resolve_type_t type; + uint64_t fd_no; + ino_t ino; + uint64_t gen; + ino_t par; + char *path; + char *bname; + char *resolved; + int op_ret; + int op_errno; + loc_t deep_loc; + struct resolve_comp *components; + int comp_count; +} server_resolve_t; + + +typedef int (*server_resume_fn_t) (call_frame_t *frame, xlator_t *bound_xl); + +int +resolve_and_resume (call_frame_t *frame, server_resume_fn_t fn); + +struct _server_state { + transport_t *trans; + xlator_t *bound_xl; + inode_table_t *itable; + + server_resume_fn_t resume_fn; + + loc_t loc; + loc_t loc2; + server_resolve_t resolve; + server_resolve_t resolve2; + + /* used within resolve_and_resume */ + loc_t *loc_now; + server_resolve_t *resolve_now; + + struct iatt stbuf; + int valid; + + fd_t *fd; + int flags; + int wbflags; + struct iobuf *iobuf; + struct iobref *iobref; + + size_t size; + off_t offset; + mode_t mode; + dev_t dev; + size_t nr_count; + int cmd; + int type; + char *name; + int name_len; + + int mask; + char is_revalidate; + dict_t *dict; + struct flock flock; + const char *volume; + dir_entry_t *entry; +}; + + +#endif diff --git a/xlators/protocol/legacy/server/src/server-resolve.c b/xlators/protocol/legacy/server/src/server-resolve.c new file mode 100644 index 00000000000..f0da94384eb --- /dev/null +++ b/xlators/protocol/legacy/server/src/server-resolve.c @@ -0,0 +1,656 @@ +/* + Copyright (c) 2009 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 "server-protocol.h" +#include "server-helpers.h" + +#include "compat-errno.h" + +int +server_resolve_all (call_frame_t *frame); +int +resolve_entry_simple (call_frame_t *frame); +int +resolve_inode_simple (call_frame_t *frame); +int +resolve_path_simple (call_frame_t *frame); + +int +component_count (const char *path) +{ + int count = 0; + const char *trav = NULL; + + trav = path; + + for (trav = path; *trav; trav++) { + if (*trav == '/') + count++; + } + + return count + 2; +} + + +int +prepare_components (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + char *resolved = NULL; + int count = 0; + struct resolve_comp *components = NULL; + int i = 0; + char *trav = NULL; + + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + + resolved = gf_strdup (resolve->path); + resolve->resolved = resolved; + + count = component_count (resolve->path); + components = GF_CALLOC (sizeof (*components), count, + gf_server_mt_resolve_comp); + resolve->components = components; + + components[0].basename = ""; + components[0].ino = 1; + components[0].gen = 0; + components[0].inode = state->itable->root; + + i = 1; + for (trav = resolved; *trav; trav++) { + if (*trav == '/') { + components[i].basename = trav + 1; + *trav = 0; + i++; + } + } + + return 0; +} + + +int +resolve_loc_touchup (call_frame_t *frame) +{ + server_state_t *state = NULL; + server_resolve_t *resolve = NULL; + loc_t *loc = NULL; + char *path = NULL; + int ret = 0; + + state = CALL_STATE (frame); + + resolve = state->resolve_now; + loc = state->loc_now; + + if (!loc->path) { + if (loc->parent && resolve->bname) { + ret = inode_path (loc->parent, resolve->bname, &path); + } else if (loc->inode) { + ret = inode_path (loc->inode, NULL, &path); + } + + if (!path) + path = gf_strdup (resolve->path); + + loc->path = path; + } + + loc->name = strrchr (loc->path, '/'); + if (loc->name) + loc->name++; + + if (!loc->parent && loc->inode) { + loc->parent = inode_parent (loc->inode, 0, NULL); + } + + return 0; +} + + +int +resolve_deep_continue (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + int ret = 0; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + + resolve->op_ret = 0; + resolve->op_errno = 0; + + if (resolve->par) + ret = resolve_entry_simple (frame); + else if (resolve->ino) + ret = resolve_inode_simple (frame); + else if (resolve->path) + ret = resolve_path_simple (frame); + + resolve_loc_touchup (frame); + + server_resolve_all (frame); + + return 0; +} + + +int +resolve_deep_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, inode_t *inode, struct iatt *buf, + dict_t *xattr, struct iatt *postparent) +{ + server_state_t *state = NULL; + server_resolve_t *resolve = NULL; + struct resolve_comp *components = NULL; + int i = 0; + inode_t *link_inode = NULL; + + state = CALL_STATE (frame); + resolve = state->resolve_now; + components = resolve->components; + + i = (long) cookie; + + if (op_ret == -1) { + goto get_out_of_here; + } + + if (i != 0) { + /* no linking for root inode */ + link_inode = inode_link (inode, resolve->deep_loc.parent, + resolve->deep_loc.name, buf); + inode_lookup (link_inode); + components[i].inode = link_inode; + link_inode = NULL; + } + + loc_wipe (&resolve->deep_loc); + + i++; /* next component */ + + if (!components[i].basename) { + /* all components of the path are resolved */ + goto get_out_of_here; + } + + /* join the current component with the path resolved until now */ + *(components[i].basename - 1) = '/'; + + resolve->deep_loc.path = gf_strdup (resolve->resolved); + resolve->deep_loc.parent = inode_ref (components[i-1].inode); + resolve->deep_loc.inode = inode_new (state->itable); + resolve->deep_loc.name = components[i].basename; + + STACK_WIND_COOKIE (frame, resolve_deep_cbk, (void *) (long) i, + BOUND_XL (frame), BOUND_XL (frame)->fops->lookup, + &resolve->deep_loc, NULL); + return 0; + +get_out_of_here: + resolve_deep_continue (frame); + return 0; +} + + +int +resolve_path_deep (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + int i = 0; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + + gf_log (BOUND_XL (frame)->name, GF_LOG_DEBUG, + "RESOLVE %s() seeking deep resolution of %s", + gf_fop_list[frame->root->op], resolve->path); + + prepare_components (frame); + + /* start from the root */ + resolve->deep_loc.inode = state->itable->root; + resolve->deep_loc.path = gf_strdup ("/"); + resolve->deep_loc.name = ""; + + STACK_WIND_COOKIE (frame, resolve_deep_cbk, (void *) (long) i, + BOUND_XL (frame), BOUND_XL (frame)->fops->lookup, + &resolve->deep_loc, NULL); + return 0; +} + + +int +resolve_path_simple (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + struct resolve_comp *components = NULL; + int ret = -1; + int par_idx = 0; + int ino_idx = 0; + int i = 0; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + components = resolve->components; + + if (!components) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + goto out; + } + + for (i = 0; components[i].basename; i++) { + par_idx = ino_idx; + ino_idx = i; + } + + if (!components[par_idx].inode) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + goto out; + } + + if (!components[ino_idx].inode && + (resolve->type == RESOLVE_MUST || resolve->type == RESOLVE_EXACT)) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + goto out; + } + + if (components[ino_idx].inode && resolve->type == RESOLVE_NOT) { + resolve->op_ret = -1; + resolve->op_errno = EEXIST; + goto out; + } + + if (components[ino_idx].inode) + state->loc_now->inode = inode_ref (components[ino_idx].inode); + state->loc_now->parent = inode_ref (components[par_idx].inode); + + ret = 0; + +out: + return ret; +} + +/* + Check if the requirements are fulfilled by entries in the inode cache itself + Return value: + <= 0 - simple resolution was decisive and complete (either success or failure) + > 0 - indecisive, need to perform deep resolution +*/ + +int +resolve_entry_simple (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + inode_t *parent = NULL; + inode_t *inode = NULL; + int ret = 0; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + + parent = inode_get (state->itable, resolve->par, 0); + if (!parent) { + /* simple resolution is indecisive. need to perform + deep resolution */ + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + ret = 1; + + inode = inode_grep (state->itable, parent, resolve->bname); + if (inode != NULL) { + gf_log (this->name, GF_LOG_DEBUG, "%"PRId64": inode " + "(pointer:%p ino: %"PRIu64") present but parent" + " is NULL for path (%s)", frame->root->unique, + inode, inode->ino, resolve->path); + inode_unref (inode); + } + goto out; + } + + if (parent->ino != 1 && parent->generation != resolve->gen) { + /* simple resolution is decisive - request was for a + stale handle */ + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + ret = -1; + goto out; + } + + /* expected @parent was found from the inode cache */ + state->loc_now->parent = inode_ref (parent); + + inode = inode_grep (state->itable, parent, resolve->bname); + if (!inode) { + switch (resolve->type) { + case RESOLVE_DONTCARE: + case RESOLVE_NOT: + ret = 0; + break; + case RESOLVE_MAY: + ret = 1; + break; + default: + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + ret = 1; + break; + } + + goto out; + } + + if (resolve->type == RESOLVE_NOT) { + gf_log (this->name, GF_LOG_DEBUG, "inode (pointer: %p ino:%" + PRIu64") found for path (%s) while type is RESOLVE_NOT", + inode, inode->ino, resolve->path); + resolve->op_ret = -1; + resolve->op_errno = EEXIST; + ret = -1; + goto out; + } + + ret = 0; + + state->loc_now->inode = inode_ref (inode); + +out: + if (parent) + inode_unref (parent); + + if (inode) + inode_unref (inode); + + return ret; +} + + +int +server_resolve_entry (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + int ret = 0; + loc_t *loc = NULL; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + loc = state->loc_now; + + ret = resolve_entry_simple (frame); + + if (ret > 0) { + loc_wipe (loc); + resolve_path_deep (frame); + return 0; + } + + if (ret == 0) + resolve_loc_touchup (frame); + + server_resolve_all (frame); + + return 0; +} + + +int +resolve_inode_simple (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + inode_t *inode = NULL; + int ret = 0; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + + if (resolve->type == RESOLVE_EXACT) { + inode = inode_get (state->itable, resolve->ino, resolve->gen); + } else { + inode = inode_get (state->itable, resolve->ino, 0); + } + + if (!inode) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + ret = 1; + goto out; + } + + if (inode->ino != 1 && inode->generation != resolve->gen) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + ret = -1; + goto out; + } + + ret = 0; + + state->loc_now->inode = inode_ref (inode); + +out: + if (inode) + inode_unref (inode); + + return ret; +} + + +int +server_resolve_inode (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + int ret = 0; + loc_t *loc = NULL; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + loc = state->loc_now; + + ret = resolve_inode_simple (frame); + + if (ret > 0) { + loc_wipe (loc); + resolve_path_deep (frame); + return 0; + } + + if (ret == 0) + resolve_loc_touchup (frame); + + server_resolve_all (frame); + + return 0; +} + + +int +server_resolve_fd (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + server_connection_t *conn = NULL; + uint64_t fd_no = -1; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + conn = SERVER_CONNECTION (frame); + + fd_no = resolve->fd_no; + + state->fd = gf_fd_fdptr_get (conn->fdtable, fd_no); + + if (!state->fd) { + resolve->op_ret = -1; + resolve->op_errno = EBADFD; + } + + server_resolve_all (frame); + + return 0; +} + + +int +server_resolve (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + + if (resolve->fd_no != -1) { + + server_resolve_fd (frame); + + } else if (resolve->par) { + + server_resolve_entry (frame); + + } else if (resolve->ino) { + + server_resolve_inode (frame); + + } else if (resolve->path) { + + resolve_path_deep (frame); + + } else { + + resolve->op_ret = -1; + resolve->op_errno = EINVAL; + + server_resolve_all (frame); + } + + return 0; +} + + +int +server_resolve_done (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *bound_xl = NULL; + + state = CALL_STATE (frame); + bound_xl = BOUND_XL (frame); + + server_print_request (frame); + + state->resume_fn (frame, bound_xl); + + return 0; +} + + +/* + * This function is called multiple times, once per resolving one location/fd. + * state->resolve_now is used to decide which location/fd is to be resolved now + */ +int +server_resolve_all (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + + this = frame->this; + state = CALL_STATE (frame); + + if (state->resolve_now == NULL) { + + state->resolve_now = &state->resolve; + state->loc_now = &state->loc; + + server_resolve (frame); + + } else if (state->resolve_now == &state->resolve) { + + state->resolve_now = &state->resolve2; + state->loc_now = &state->loc2; + + server_resolve (frame); + + } else if (state->resolve_now == &state->resolve2) { + + server_resolve_done (frame); + + } else { + gf_log (this->name, GF_LOG_ERROR, + "Invalid pointer for state->resolve_now"); + } + + return 0; +} + + +int +resolve_and_resume (call_frame_t *frame, server_resume_fn_t fn) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + + state = CALL_STATE (frame); + state->resume_fn = fn; + + this = frame->this; + + server_resolve_all (frame); + + return 0; +} |