/*
  Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
  This file is part of GlusterFS.

  This file is licensed to you under your choice of the GNU Lesser
  General Public License, version 3 or any later version (LGPLv3 or
  later), or the GNU General Public License, version 2 (GPLv2), in all
  cases as published by the Free Software Foundation.
*/

#include "client.h"
#include <glusterfs/fd.h>
#include "client-messages.h"
#include "client-common.h"
#include <glusterfs/compat-errno.h>
#include <glusterfs/common-utils.h>

int
client_fd_lk_list_empty(fd_lk_ctx_t *lk_ctx, gf_boolean_t try_lock)
{
    int ret = 1;

    if (!lk_ctx) {
        ret = -1;
        goto out;
    }

    if (try_lock) {
        ret = TRY_LOCK(&lk_ctx->lock);
        if (ret != 0) {
            ret = -1;
            goto out;
        }
    } else {
        LOCK(&lk_ctx->lock);
    }

    ret = list_empty(&lk_ctx->lk_list);
    UNLOCK(&lk_ctx->lock);
out:
    return ret;
}

clnt_fd_ctx_t *
this_fd_del_ctx(fd_t *file, xlator_t *this)
{
    int dict_ret = -1;
    uint64_t ctxaddr = 0;

    GF_VALIDATE_OR_GOTO("client", this, out);
    GF_VALIDATE_OR_GOTO(this->name, file, out);

    dict_ret = fd_ctx_del(file, this, &ctxaddr);

    if (dict_ret < 0) {
        ctxaddr = 0;
    }

out:
    return (clnt_fd_ctx_t *)(unsigned long)ctxaddr;
}

clnt_fd_ctx_t *
this_fd_get_ctx(fd_t *file, xlator_t *this)
{
    int dict_ret = -1;
    uint64_t ctxaddr = 0;

    GF_VALIDATE_OR_GOTO("client", this, out);
    GF_VALIDATE_OR_GOTO(this->name, file, out);

    dict_ret = fd_ctx_get(file, this, &ctxaddr);

    if (dict_ret < 0) {
        ctxaddr = 0;
    }

out:
    return (clnt_fd_ctx_t *)(unsigned long)ctxaddr;
}

void
this_fd_set_ctx(fd_t *file, xlator_t *this, loc_t *loc, clnt_fd_ctx_t *ctx)
{
    uint64_t oldaddr = 0;
    int32_t ret = -1;

    GF_VALIDATE_OR_GOTO("client", this, out);
    GF_VALIDATE_OR_GOTO(this->name, file, out);

    ret = fd_ctx_get(file, this, &oldaddr);
    if (ret >= 0) {
        if (loc)
            gf_msg(this->name, GF_LOG_INFO, 0, PC_MSG_FD_DUPLICATE_TRY,
                   "%s (%s): trying duplicate remote fd set. ", loc->path,
                   uuid_utoa(loc->inode->gfid));
        else
            gf_msg(this->name, GF_LOG_INFO, 0, PC_MSG_FD_DUPLICATE_TRY,
                   "%p: trying duplicate remote fd set. ", file);
    }

    ret = fd_ctx_set(file, this, (uint64_t)(unsigned long)ctx);
    if (ret < 0) {
        if (loc)
            gf_msg(this->name, GF_LOG_WARNING, 0, PC_MSG_FD_SET_FAIL,
                   "%s (%s): failed to set remote fd", loc->path,
                   uuid_utoa(loc->inode->gfid));
        else
            gf_msg(this->name, GF_LOG_WARNING, 0, PC_MSG_FD_SET_FAIL,
                   "%p: failed to set remote fd", file);
    }
out:
    return;
}

int
client_local_wipe(clnt_local_t *local)
{
    if (local) {
        loc_wipe(&local->loc);
        loc_wipe(&local->loc2);

        if (local->fd) {
            fd_unref(local->fd);
        }

        if (local->iobref) {
            iobref_unref(local->iobref);
        }

        GF_FREE(local->name);
        local->compound_args = NULL;
        mem_put(local);
    }

    return 0;
}
int
unserialize_rsp_dirent(xlator_t *this, struct gfs3_readdir_rsp *rsp,
                       gf_dirent_t *entries)
{
    struct gfs3_dirlist *trav = NULL;
    gf_dirent_t *entry = NULL;
    int entry_len = 0;
    int ret = -1;
    clnt_conf_t *conf = NULL;

    conf = this->private;

    trav = rsp->reply;
    while (trav) {
        entry_len = gf_dirent_size(trav->name);
        entry = GF_CALLOC(1, entry_len, gf_common_mt_gf_dirent_t);
        if (!entry)
            goto out;

        entry->d_ino = trav->d_ino;
        gf_itransform(this, trav->d_off, &entry->d_off, conf->client_id);
        entry->d_len = trav->d_len;
        entry->d_type = trav->d_type;

        strcpy(entry->d_name, trav->name);

        list_add_tail(&entry->list, &entries->list);

        trav = trav->nextentry;
    }

    ret = 0;
out:
    return ret;
}

int
unserialize_rsp_direntp(xlator_t *this, fd_t *fd, struct gfs3_readdirp_rsp *rsp,
                        gf_dirent_t *entries)
{
    struct gfs3_dirplist *trav = NULL;
    char *buf = NULL;
    gf_dirent_t *entry = NULL;
    inode_table_t *itable = NULL;
    int entry_len = 0;
    int ret = -1;
    clnt_conf_t *conf = NULL;

    trav = rsp->reply;

    if (fd)
        itable = fd->inode->table;

    conf = this->private;
    if (!conf)
        goto out;

    while (trav) {
        entry_len = gf_dirent_size(trav->name);
        entry = GF_CALLOC(1, entry_len, gf_common_mt_gf_dirent_t);
        if (!entry)
            goto out;

        entry->d_ino = trav->d_ino;
        gf_itransform(this, trav->d_off, &entry->d_off, conf->client_id);
        entry->d_len = trav->d_len;
        entry->d_type = trav->d_type;

        gf_stat_to_iatt(&trav->stat, &entry->d_stat);

        strcpy(entry->d_name, trav->name);

        if (trav->dict.dict_val) {
            /* Dictionary is sent along with response */
            buf = memdup(trav->dict.dict_val, trav->dict.dict_len);
            if (!buf)
                goto out;

            entry->dict = dict_new();

            ret = dict_unserialize(buf, trav->dict.dict_len, &entry->dict);
            if (ret < 0) {
                gf_msg(THIS->name, GF_LOG_WARNING, EINVAL,
                       PC_MSG_DICT_UNSERIALIZE_FAIL,
                       "failed to unserialize xattr dict");
                goto out;
            }
            GF_FREE(buf);
            buf = NULL;
        }

        entry->inode = inode_find(itable, entry->d_stat.ia_gfid);
        if (!entry->inode)
            entry->inode = inode_new(itable);

        list_add_tail(&entry->list, &entries->list);

        trav = trav->nextentry;
    }

    ret = 0;
out:
    if (buf)
        GF_FREE(buf);
    return ret;
}

int
clnt_readdirp_rsp_cleanup(gfs3_readdirp_rsp *rsp)
{
    gfs3_dirplist *prev = NULL;
    gfs3_dirplist *trav = NULL;

    trav = rsp->reply;
    prev = trav;
    while (trav) {
        trav = trav->nextentry;
        /* on client, the rpc lib allocates this */
        free(prev->dict.dict_val);
        free(prev->name);
        free(prev);
        prev = trav;
    }

    return 0;
}

int
unserialize_rsp_dirent_v2(xlator_t *this, struct gfx_readdir_rsp *rsp,
                          gf_dirent_t *entries)
{
    struct gfx_dirlist *trav = NULL;
    gf_dirent_t *entry = NULL;
    int entry_len = 0;
    int ret = -1;
    clnt_conf_t *conf = NULL;

    conf = this->private;

    trav = rsp->reply;
    while (trav) {
        entry_len = gf_dirent_size(trav->name);
        entry = GF_CALLOC(1, entry_len, gf_common_mt_gf_dirent_t);
        if (!entry)
            goto out;

        entry->d_ino = trav->d_ino;
        gf_itransform(this, trav->d_off, &entry->d_off, conf->client_id);
        entry->d_len = trav->d_len;
        entry->d_type = trav->d_type;

        strcpy(entry->d_name, trav->name);

        list_add_tail(&entry->list, &entries->list);

        trav = trav->nextentry;
    }

    ret = 0;
out:
    return ret;
}

int
unserialize_rsp_direntp_v2(xlator_t *this, fd_t *fd,
                           struct gfx_readdirp_rsp *rsp, gf_dirent_t *entries)
{
    struct gfx_dirplist *trav = NULL;
    gf_dirent_t *entry = NULL;
    inode_table_t *itable = NULL;
    int entry_len = 0;
    int ret = -1;
    clnt_conf_t *conf = NULL;

    trav = rsp->reply;

    if (fd)
        itable = fd->inode->table;

    conf = this->private;
    if (!conf)
        goto out;

    while (trav) {
        entry_len = gf_dirent_size(trav->name);
        entry = GF_CALLOC(1, entry_len, gf_common_mt_gf_dirent_t);
        if (!entry)
            goto out;

        entry->d_ino = trav->d_ino;
        gf_itransform(this, trav->d_off, &entry->d_off, conf->client_id);
        entry->d_len = trav->d_len;
        entry->d_type = trav->d_type;

        gfx_stat_to_iattx(&trav->stat, &entry->d_stat);

        strcpy(entry->d_name, trav->name);

        xdr_to_dict(&trav->dict, &entry->dict);

        entry->inode = inode_find(itable, entry->d_stat.ia_gfid);
        if (!entry->inode)
            entry->inode = inode_new(itable);

        list_add_tail(&entry->list, &entries->list);

        trav = trav->nextentry;
    }

    ret = 0;
out:
    return ret;
}

int
clnt_readdirp_rsp_cleanup_v2(gfx_readdirp_rsp *rsp)
{
    gfx_dirplist *prev = NULL;
    gfx_dirplist *trav = NULL;

    trav = rsp->reply;
    prev = trav;
    while (trav) {
        trav = trav->nextentry;
        free(prev->name);
        free(prev);
        prev = trav;
    }

    return 0;
}

int
clnt_readdir_rsp_cleanup(gfs3_readdir_rsp *rsp)
{
    gfs3_dirlist *prev = NULL;
    gfs3_dirlist *trav = NULL;

    trav = rsp->reply;
    prev = trav;
    while (trav) {
        trav = trav->nextentry;
        /* on client, the rpc lib allocates this */
        free(prev->name);
        free(prev);
        prev = trav;
    }

    return 0;
}

int
clnt_readdir_rsp_cleanup_v2(gfx_readdir_rsp *rsp)
{
    gfx_dirlist *prev = NULL;
    gfx_dirlist *trav = NULL;

    trav = rsp->reply;
    prev = trav;
    while (trav) {
        trav = trav->nextentry;
        /* on client, the rpc lib allocates this */
        free(prev->name);
        free(prev);
        prev = trav;
    }

    return 0;
}

int
client_get_remote_fd(xlator_t *this, fd_t *fd, int flags, int64_t *remote_fd)
{
    clnt_fd_ctx_t *fdctx = NULL;
    clnt_conf_t *conf = NULL;

    GF_VALIDATE_OR_GOTO(this->name, fd, out);
    GF_VALIDATE_OR_GOTO(this->name, remote_fd, out);

    conf = this->private;
    pthread_spin_lock(&conf->fd_lock);
    {
        fdctx = this_fd_get_ctx(fd, this);
        if (!fdctx) {
            if (fd->anonymous) {
                *remote_fd = GF_ANON_FD_NO;
            } else {
                *remote_fd = -1;
                gf_msg_debug(this->name, EBADF, "not a valid fd for gfid: %s",
                             uuid_utoa(fd->inode->gfid));
            }
        } else {
            if (__is_fd_reopen_in_progress(fdctx))
                *remote_fd = -1;
            else
                *remote_fd = fdctx->remote_fd;
        }
    }
    pthread_spin_unlock(&conf->fd_lock);

    if ((flags & FALLBACK_TO_ANON_FD) && (*remote_fd == -1))
        *remote_fd = GF_ANON_FD_NO;

    return 0;
out:
    return -1;
}

gf_boolean_t
client_is_reopen_needed(fd_t *fd, xlator_t *this, int64_t remote_fd)
{
    clnt_conf_t *conf = NULL;
    clnt_fd_ctx_t *fdctx = NULL;
    gf_boolean_t res = _gf_false;

    conf = this->private;
    pthread_spin_lock(&conf->fd_lock);
    {
        fdctx = this_fd_get_ctx(fd, this);
        if (fdctx && (fdctx->remote_fd == -1) && (remote_fd == GF_ANON_FD_NO))
            res = _gf_true;
    }
    pthread_spin_unlock(&conf->fd_lock);

    return res;
}

int
client_fd_fop_prepare_local(call_frame_t *frame, fd_t *fd, int64_t remote_fd)
{
    xlator_t *this = NULL;
    clnt_local_t *local = NULL;
    int ret = 0;

    if (!frame || !fd) {
        ret = -EINVAL;
        goto out;
    }

    this = frame->this;

    frame->local = mem_get0(this->local_pool);
    if (frame->local == NULL) {
        ret = -ENOMEM;
        goto out;
    }

    local = frame->local;
    local->fd = fd_ref(fd);
    local->attempt_reopen = client_is_reopen_needed(fd, this, remote_fd);

    return 0;
out:
    return ret;
}

int
client_process_response(call_frame_t *frame, xlator_t *this,
                        struct rpc_req *req, gfs3_compound_rsp *rsp,
                        compound_args_cbk_t *args_cbk, int index)
{
    int ret = 0;
    dict_t *xdata = NULL;
    dict_t *xattr = NULL;
    struct iovec vector[MAX_IOVEC] = {
        {0},
    };
    gf_dirent_t entries;
    default_args_cbk_t *this_args_cbk = &args_cbk->rsp_list[index];
    clnt_local_t *local = frame->local;
    compound_rsp *this_rsp = NULL;
    compound_args_t *args = local->compound_args;

    this_rsp = &rsp->compound_rsp_array.compound_rsp_array_val[index];
    args_cbk->enum_list[index] = this_rsp->fop_enum;

    INIT_LIST_HEAD(&entries.list);

    switch (args_cbk->enum_list[index]) {
        case GF_FOP_STAT: {
            gfs3_stat_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_stat_rsp;

            client_post_stat(this, tmp_rsp, &this_args_cbk->stat, &xdata);

            CLIENT_POST_FOP_TYPE(stat, this_rsp, this_args_cbk,
                                 &this_args_cbk->stat, xdata);
            break;
        }
        case GF_FOP_READLINK: {
            gfs3_readlink_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_readlink_rsp;

            client_post_readlink(this, tmp_rsp, &this_args_cbk->stat, &xdata);
            CLIENT_POST_FOP_TYPE(readlink, this_rsp, this_args_cbk,
                                 tmp_rsp->path, &this_args_cbk->stat, xdata);
            break;
        }
        case GF_FOP_MKNOD: {
            gfs3_mknod_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_mknod_rsp;

            client_post_mknod(this, tmp_rsp, &this_args_cbk->stat,
                              &this_args_cbk->preparent,
                              &this_args_cbk->postparent, &xdata);
            CLIENT_POST_FOP_TYPE(mknod, this_rsp, this_args_cbk,
                                 local->loc.inode, &this_args_cbk->stat,
                                 &this_args_cbk->preparent,
                                 &this_args_cbk->postparent, xdata);
            break;
        }
        case GF_FOP_MKDIR: {
            gfs3_mkdir_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_mkdir_rsp;

            client_post_mkdir(this, tmp_rsp, &this_args_cbk->stat,
                              &this_args_cbk->preparent,
                              &this_args_cbk->postparent, &xdata);
            CLIENT_POST_FOP_TYPE(mkdir, this_rsp, this_args_cbk,
                                 local->loc.inode, &this_args_cbk->stat,
                                 &this_args_cbk->preparent,
                                 &this_args_cbk->postparent, xdata);
            break;
        }
        case GF_FOP_UNLINK: {
            gfs3_unlink_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_unlink_rsp;

            client_post_unlink(this, tmp_rsp, &this_args_cbk->preparent,
                               &this_args_cbk->postparent, &xdata);
            CLIENT_POST_FOP_TYPE(unlink, this_rsp, this_args_cbk,
                                 &this_args_cbk->preparent,
                                 &this_args_cbk->postparent, xdata);
            break;
        }
        case GF_FOP_RMDIR: {
            gfs3_rmdir_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_rmdir_rsp;

            client_post_rmdir(this, tmp_rsp, &this_args_cbk->preparent,
                              &this_args_cbk->postparent, &xdata);
            CLIENT_POST_FOP_TYPE(rmdir, this_rsp, this_args_cbk,
                                 &this_args_cbk->preparent,
                                 &this_args_cbk->postparent, xdata);
            break;
        }
        case GF_FOP_SYMLINK: {
            gfs3_symlink_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_symlink_rsp;

            client_post_symlink(this, tmp_rsp, &this_args_cbk->stat,
                                &this_args_cbk->preparent,
                                &this_args_cbk->postparent, &xdata);
            CLIENT_POST_FOP_TYPE(
                symlink, this_rsp, this_args_cbk, NULL, &this_args_cbk->stat,
                &this_args_cbk->preparent, &this_args_cbk->postparent, xdata);
            break;
        }
        case GF_FOP_RENAME: {
            gfs3_rename_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_rename_rsp;

            client_post_rename(
                this, tmp_rsp, &this_args_cbk->stat, &this_args_cbk->preparent,
                &this_args_cbk->postparent, &this_args_cbk->preparent2,
                &this_args_cbk->postparent2, &xdata);
            CLIENT_POST_FOP_TYPE(
                rename, this_rsp, this_args_cbk, &this_args_cbk->stat,
                &this_args_cbk->preparent, &this_args_cbk->postparent,
                &this_args_cbk->preparent2, &this_args_cbk->postparent2, xdata);
            break;
        }
        case GF_FOP_LINK: {
            gfs3_link_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_link_rsp;

            client_post_link(this, tmp_rsp, &this_args_cbk->stat,
                             &this_args_cbk->preparent,
                             &this_args_cbk->postparent, &xdata);
            CLIENT_POST_FOP_TYPE(
                link, this_rsp, this_args_cbk, NULL, &this_args_cbk->stat,
                &this_args_cbk->preparent, &this_args_cbk->postparent, xdata);
            break;
        }
        case GF_FOP_TRUNCATE: {
            gfs3_truncate_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_truncate_rsp;

            client_post_truncate(this, tmp_rsp, &this_args_cbk->prestat,
                                 &this_args_cbk->poststat, &xdata);
            CLIENT_POST_FOP_TYPE(truncate, this_rsp, this_args_cbk,
                                 &this_args_cbk->prestat,
                                 &this_args_cbk->poststat, xdata);
            break;
        }
        case GF_FOP_OPEN: {
            gfs3_open_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_open_rsp;

            client_post_open(this, tmp_rsp, &xdata);
            CLIENT_POST_FOP_TYPE(open, this_rsp, this_args_cbk, local->fd,
                                 xdata);
            if (-1 != this_args_cbk->op_ret)
                ret = client_add_fd_to_saved_fds(this, local->fd, &local->loc,
                                                 args->req_list[index].flags,
                                                 tmp_rsp->fd, 0);
            break;
        }
        case GF_FOP_READ: {
            gfs3_read_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_read_rsp;

            client_post_readv(this, tmp_rsp, &this_args_cbk->iobref,
                              req->rsp_iobref, &this_args_cbk->stat, vector,
                              &req->rsp[1], &this_args_cbk->count, &xdata);

            /* Each read should be given read response that only
             * corresponds to its request.
             * Modify the iovecs accordingly.
             * After each read, store the length of data already read
             * so that the next ones can continue from there.
             */
            if (local->read_length) {
                vector[0].iov_base += local->read_length;
                local->read_length += tmp_rsp->op_ret;
            } else {
                local->read_length = tmp_rsp->op_ret;
            }

            args_readv_cbk_store(this_args_cbk, tmp_rsp->op_ret,
                                 gf_error_to_errno(tmp_rsp->op_errno), vector,
                                 this_args_cbk->count, &this_args_cbk->stat,
                                 this_args_cbk->iobref, xdata);

            if (tmp_rsp->op_ret >= 0)
                if (local->attempt_reopen)
                    client_attempt_reopen(local->fd, this);

            break;
        }
        case GF_FOP_WRITE: {
            gfs3_write_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_write_rsp;

            client_post_writev(this, tmp_rsp, &this_args_cbk->prestat,
                               &this_args_cbk->poststat, &xdata);
            args_writev_cbk_store(this_args_cbk, tmp_rsp->op_ret,
                                  gf_error_to_errno(tmp_rsp->op_errno),
                                  &this_args_cbk->prestat,
                                  &this_args_cbk->poststat, xdata);

            if (tmp_rsp->op_ret == 0)
                if (local->attempt_reopen)
                    client_attempt_reopen(local->fd, this);
            break;
        }
        case GF_FOP_STATFS: {
            gfs3_statfs_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_statfs_rsp;

            client_post_statfs(this, tmp_rsp, &this_args_cbk->statvfs, &xdata);

            CLIENT_POST_FOP_TYPE(statfs, this_rsp, this_args_cbk,
                                 &this_args_cbk->statvfs, xdata);
            break;
        }
        case GF_FOP_FLUSH: {
            gf_common_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_flush_rsp;

            client_post_flush(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP(flush, this_rsp, this_args_cbk, xdata);
            if (this_args_cbk->op_ret >= 0 && !fd_is_anonymous(local->fd)) {
                /* Delete all saved locks of the owner issuing flush */
                ret = delete_granted_locks_owner(local->fd, &local->owner);
                gf_msg_trace(this->name, 0,
                             "deleting locks of owner (%s) returned %d",
                             lkowner_utoa(&local->owner), ret);
            }
            break;
        }
        case GF_FOP_FSYNC: {
            gfs3_fsync_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_fsync_rsp;

            client_post_fsync(this, tmp_rsp, &this_args_cbk->prestat,
                              &this_args_cbk->poststat, &xdata);

            CLIENT_POST_FOP_TYPE(fsync, this_rsp, this_args_cbk,
                                 &this_args_cbk->prestat,
                                 &this_args_cbk->poststat, xdata);
            break;
        }
        case GF_FOP_SETXATTR: {
            gf_common_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_setxattr_rsp;

            client_post_setxattr(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP(setxattr, this_rsp, this_args_cbk, xdata);
            break;
        }
        case GF_FOP_GETXATTR: {
            gfs3_getxattr_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_getxattr_rsp;

            client_post_getxattr(this, tmp_rsp, &xattr, &xdata);

            CLIENT_POST_FOP_TYPE(getxattr, this_rsp, this_args_cbk, xattr,
                                 xdata);
            break;
        }
        case GF_FOP_REMOVEXATTR: {
            gf_common_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_removexattr_rsp;

            client_post_removexattr(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP(removexattr, this_rsp, this_args_cbk, xdata);
            break;
        }
        case GF_FOP_OPENDIR: {
            gfs3_opendir_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_opendir_rsp;

            client_post_opendir(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP_TYPE(opendir, this_rsp, this_args_cbk, local->fd,
                                 xdata);
            if (-1 != this_args_cbk->op_ret)
                ret = client_add_fd_to_saved_fds(this, local->fd, &local->loc,
                                                 args->req_list[index].flags,
                                                 tmp_rsp->fd, 0);
            break;
        }
        case GF_FOP_FSYNCDIR: {
            gf_common_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_fsyncdir_rsp;

            client_post_fsyncdir(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP(fsyncdir, this_rsp, this_args_cbk, xdata);
            break;
        }
        case GF_FOP_ACCESS: {
            gf_common_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_access_rsp;

            client_post_access(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP(access, this_rsp, this_args_cbk, xdata);
            break;
        }
        case GF_FOP_CREATE: {
            gfs3_create_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_create_rsp;

            client_post_create(this, tmp_rsp, &this_args_cbk->stat,
                               &this_args_cbk->preparent,
                               &this_args_cbk->postparent, local, &xdata);

            CLIENT_POST_FOP_TYPE(create, this_rsp, this_args_cbk, local->fd,
                                 local->loc.inode, &this_args_cbk->stat,
                                 &this_args_cbk->preparent,
                                 &this_args_cbk->postparent, xdata);
            if (-1 != this_args_cbk->op_ret)
                ret = client_add_fd_to_saved_fds(this, local->fd, &local->loc,
                                                 args->req_list[index].flags,
                                                 tmp_rsp->fd, 0);
            break;
        }
        case GF_FOP_FTRUNCATE: {
            gfs3_ftruncate_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_ftruncate_rsp;

            client_post_ftruncate(this, tmp_rsp, &this_args_cbk->prestat,
                                  &this_args_cbk->poststat, &xdata);
            CLIENT_POST_FOP_TYPE(ftruncate, this_rsp, this_args_cbk,
                                 &this_args_cbk->prestat,
                                 &this_args_cbk->poststat, xdata);
            break;
        }
        case GF_FOP_FSTAT: {
            gfs3_fstat_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_fstat_rsp;

            client_post_fstat(this, tmp_rsp, &this_args_cbk->stat, &xdata);

            CLIENT_POST_FOP_TYPE(fstat, this_rsp, this_args_cbk,
                                 &this_args_cbk->stat, xdata);
            break;
        }
        case GF_FOP_LK: {
            gfs3_lk_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_lk_rsp;

            client_post_lk(this, tmp_rsp, &this_args_cbk->lock, &xdata);

            CLIENT_POST_FOP_TYPE(lk, this_rsp, this_args_cbk,
                                 &this_args_cbk->lock, xdata);
            break;
        }
        case GF_FOP_LOOKUP: {
            gfs3_lookup_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_lookup_rsp;

            client_post_lookup(this, tmp_rsp, &this_args_cbk->stat,
                               &this_args_cbk->postparent, &xdata);
            CLIENT_POST_FOP_TYPE(lookup, this_rsp, this_args_cbk,
                                 local->loc.inode, &this_args_cbk->stat, xdata,
                                 &this_args_cbk->postparent);
            break;
        }
        case GF_FOP_READDIR: {
            gfs3_readdir_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_readdir_rsp;

            client_post_readdir(this, tmp_rsp, &entries, &xdata);

            CLIENT_POST_FOP_TYPE(readdir, this_rsp, this_args_cbk, &entries,
                                 xdata);
            break;
        }
        case GF_FOP_INODELK: {
            gf_common_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_inodelk_rsp;

            client_post_inodelk(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP(inodelk, this_rsp, this_args_cbk, xdata);
            break;
        }
        case GF_FOP_FINODELK: {
            gf_common_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_finodelk_rsp;

            client_post_finodelk(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP(finodelk, this_rsp, this_args_cbk, xdata);
            if (tmp_rsp->op_ret == 0)
                if (local->attempt_reopen)
                    client_attempt_reopen(local->fd, this);
            break;
        }
        case GF_FOP_ENTRYLK: {
            gf_common_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_entrylk_rsp;

            client_post_entrylk(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP(entrylk, this_rsp, this_args_cbk, xdata);
            break;
        }
        case GF_FOP_FENTRYLK: {
            gf_common_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_fentrylk_rsp;

            client_post_fentrylk(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP(fentrylk, this_rsp, this_args_cbk, xdata);
            break;
        }
        case GF_FOP_XATTROP: {
            gfs3_xattrop_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_xattrop_rsp;

            client_post_xattrop(this, tmp_rsp, &xattr, &xdata);

            CLIENT_POST_FOP_TYPE(xattrop, this_rsp, this_args_cbk, xattr,
                                 xdata);
            break;
        }
        case GF_FOP_FXATTROP: {
            gfs3_fxattrop_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_fxattrop_rsp;

            client_post_fxattrop(this, tmp_rsp, &xattr, &xdata);

            CLIENT_POST_FOP_TYPE(fxattrop, this_rsp, this_args_cbk, xattr,
                                 xdata);
            if (rsp->op_ret == 0)
                if (local->attempt_reopen)
                    client_attempt_reopen(local->fd, this);
            break;
        }
        case GF_FOP_FGETXATTR: {
            gfs3_fgetxattr_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_fgetxattr_rsp;

            client_post_fgetxattr(this, tmp_rsp, &xattr, &xdata);

            CLIENT_POST_FOP_TYPE(fgetxattr, this_rsp, this_args_cbk, xattr,
                                 xdata);
            break;
        }
        case GF_FOP_FSETXATTR: {
            gf_common_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_fsetxattr_rsp;

            client_post_fsetxattr(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP(fsetxattr, this_rsp, this_args_cbk, xdata);
            break;
        }
        case GF_FOP_RCHECKSUM: {
            gfs3_rchecksum_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_rchecksum_rsp;

            client_post_rchecksum(this, tmp_rsp, &xdata);

            break;
            CLIENT_POST_FOP_TYPE(
                rchecksum, this_rsp, this_args_cbk, tmp_rsp->weak_checksum,
                (uint8_t *)tmp_rsp->strong_checksum.strong_checksum_val, xdata);
            break;
        }
        case GF_FOP_SETATTR: {
            gfs3_setattr_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_setattr_rsp;

            client_post_setattr(this, tmp_rsp, &this_args_cbk->prestat,
                                &this_args_cbk->poststat, &xdata);

            CLIENT_POST_FOP_TYPE(setattr, this_rsp, this_args_cbk,
                                 &this_args_cbk->prestat,
                                 &this_args_cbk->poststat, xdata);
            break;
        }
        case GF_FOP_FSETATTR: {
            gfs3_fsetattr_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_fsetattr_rsp;

            client_post_fsetattr(this, tmp_rsp, &this_args_cbk->prestat,
                                 &this_args_cbk->poststat, &xdata);

            CLIENT_POST_FOP_TYPE(fsetattr, this_rsp, this_args_cbk,
                                 &this_args_cbk->prestat,
                                 &this_args_cbk->poststat, xdata);
            break;
        }
        case GF_FOP_READDIRP: {
            gfs3_readdirp_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_readdirp_rsp;

            client_post_readdirp(this, tmp_rsp, local->fd, &entries, &xdata);

            CLIENT_POST_FOP_TYPE(readdirp, this_rsp, this_args_cbk, &entries,
                                 xdata);
            break;
        }
        case GF_FOP_FREMOVEXATTR: {
            gf_common_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_fremovexattr_rsp;

            client_post_fremovexattr(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP(fremovexattr, this_rsp, this_args_cbk, xdata);
            break;
        }
        case GF_FOP_FALLOCATE: {
            gfs3_fallocate_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_fallocate_rsp;

            client_post_fallocate(this, tmp_rsp, &this_args_cbk->prestat,
                                  &this_args_cbk->poststat, &xdata);

            CLIENT_POST_FOP_TYPE(fallocate, this_rsp, this_args_cbk,
                                 &this_args_cbk->prestat,
                                 &this_args_cbk->poststat, xdata);
            break;
        }
        case GF_FOP_DISCARD: {
            gfs3_discard_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_discard_rsp;

            client_post_discard(this, tmp_rsp, &this_args_cbk->prestat,
                                &this_args_cbk->poststat, &xdata);

            CLIENT_POST_FOP_TYPE(discard, this_rsp, this_args_cbk,
                                 &this_args_cbk->prestat,
                                 &this_args_cbk->poststat, xdata);
            break;
        }
        case GF_FOP_ZEROFILL: {
            gfs3_zerofill_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_zerofill_rsp;

            client_post_zerofill(this, tmp_rsp, &this_args_cbk->prestat,
                                 &this_args_cbk->poststat, &xdata);

            CLIENT_POST_FOP_TYPE(zerofill, this_rsp, this_args_cbk,
                                 &this_args_cbk->prestat,
                                 &this_args_cbk->poststat, xdata);
            break;
        }
        case GF_FOP_IPC: {
            gfs3_ipc_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_ipc_rsp;

            client_post_ipc(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP_TYPE(ipc, this_rsp, this_args_cbk, xdata);
            break;
        }
        case GF_FOP_SEEK: {
            gfs3_seek_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_seek_rsp;

            client_post_seek(this, tmp_rsp, &xdata);

            CLIENT_POST_FOP_TYPE(seek, this_rsp, this_args_cbk, tmp_rsp->offset,
                                 xdata);
            break;
        }
        case GF_FOP_LEASE: {
            gfs3_lease_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_u.compound_lease_rsp;

            client_post_lease(this, tmp_rsp, &this_args_cbk->lease, &xdata);

            CLIENT_POST_FOP_TYPE(lease, this_rsp, this_args_cbk,
                                 &this_args_cbk->lease, xdata);
            break;
        }
        default:
            return -ENOTSUP;
    }

    if (xdata)
        dict_unref(xdata);
    if (xattr)
        dict_unref(xattr);
    gf_dirent_free(&entries);
    return 0;
}

int
client_handle_fop_requirements(
    xlator_t *this, call_frame_t *frame, gfs3_compound_req *req,
    clnt_local_t *local, struct iobref **req_iobref, struct iobref **rsp_iobref,
    struct iovec *req_vector, struct iovec *rsp_vector, int *req_count,
    int *rsp_count, default_args_t *args, int fop_enum, int index)
{
    int ret = 0;
    int op_errno = ENOMEM;
    struct iobuf *rsp_iobuf = NULL;
    int64_t remote_fd = -1;
    compound_req *this_req = &req->compound_req_array
                                  .compound_req_array_val[index];

    this_req->fop_enum = fop_enum;

    switch (fop_enum) {
        case GF_FOP_STAT:
            CLIENT_PRE_FOP(stat, this,
                           &this_req->compound_req_u.compound_stat_req,
                           op_errno, out, &args->loc, args->xdata);
            break;
        case GF_FOP_READLINK:
            CLIENT_PRE_FOP(readlink, this,
                           &this_req->compound_req_u.compound_readlink_req,
                           op_errno, out, &args->loc, args->size, args->xdata);
            break;
        case GF_FOP_MKNOD:
            CLIENT_PRE_FOP(mknod, this,
                           &this_req->compound_req_u.compound_mknod_req,
                           op_errno, out, &args->loc, args->mode, args->rdev,
                           args->umask, args->xdata);
            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_MKDIR:
            CLIENT_PRE_FOP(mkdir, this,
                           &this_req->compound_req_u.compound_mkdir_req,
                           op_errno, out, &args->loc, args->mode, args->umask,
                           args->xdata);
            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_UNLINK:
            CLIENT_PRE_FOP(unlink, this,
                           &this_req->compound_req_u.compound_unlink_req,
                           op_errno, out, &args->loc, args->xflag, args->xdata);
            break;
        case GF_FOP_RMDIR:
            CLIENT_PRE_FOP(rmdir, this,
                           &this_req->compound_req_u.compound_rmdir_req,
                           op_errno, out, &args->loc, args->flags, args->xdata);
            break;
        case GF_FOP_SYMLINK:
            CLIENT_PRE_FOP(symlink, this,
                           &this_req->compound_req_u.compound_symlink_req,
                           op_errno, out, &args->loc, args->linkname,
                           args->umask, args->xdata);
            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_RENAME:
            CLIENT_PRE_FOP(rename, this,
                           &this_req->compound_req_u.compound_rename_req,
                           op_errno, out, &args->loc, &args->loc2, args->xdata);
            break;
        case GF_FOP_LINK:
            CLIENT_PRE_FOP(link, this,
                           &this_req->compound_req_u.compound_link_req,
                           op_errno, out, &args->loc, &args->loc2, args->xdata);
            break;
        case GF_FOP_TRUNCATE:
            CLIENT_PRE_FOP(
                truncate, this, &this_req->compound_req_u.compound_truncate_req,
                op_errno, out, &args->loc, args->offset, args->xdata);
            break;
        case GF_FOP_OPEN:
            CLIENT_PRE_FOP(
                open, this, &this_req->compound_req_u.compound_open_req,
                op_errno, out, &args->loc, args->fd, args->flags, args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            break;
        case GF_FOP_READ:
            op_errno = client_pre_readv(
                this, &this_req->compound_req_u.compound_read_req, args->fd,
                args->size, args->offset, args->flags, args->xdata);

            if (op_errno) {
                op_errno = -op_errno;
                goto out;
            }
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            local->attempt_reopen = client_is_reopen_needed(args->fd, this,
                                                            remote_fd);
            rsp_iobuf = iobuf_get2(this->ctx->iobuf_pool, args->size);
            if (rsp_iobuf == NULL) {
                op_errno = ENOMEM;
                goto out;
            }

            if (!*rsp_iobref) {
                *rsp_iobref = iobref_new();
                if (*rsp_iobref == NULL) {
                    op_errno = ENOMEM;
                    goto out;
                }
            }

            if (*rsp_count + 1 >= MAX_IOVEC) {
                op_errno = ENOMEM;
                goto out;
            }
            rsp_vector[*rsp_count].iov_base = iobuf_ptr(rsp_iobuf);
            rsp_vector[*rsp_count].iov_len = iobuf_pagesize(rsp_iobuf);
            iobref_add(*rsp_iobref, rsp_iobuf);
            iobuf_unref(rsp_iobuf);
            rsp_iobuf = NULL;
            if (args->size > rsp_vector[*rsp_count].iov_len) {
                gf_msg(this->name, GF_LOG_WARNING, ENOMEM, PC_MSG_NO_MEMORY,
                       "read-size (%lu) is bigger than iobuf size "
                       "(%lu)",
                       (unsigned long)args->size,
                       (unsigned long)rsp_vector[*rsp_count].iov_len);
                op_errno = EINVAL;
                goto out;
            }
            *rsp_count += 1;

            break;
        case GF_FOP_WRITE:
            op_errno = client_pre_writev(
                this, &this_req->compound_req_u.compound_write_req, args->fd,
                iov_length(args->vector, args->count), args->offset,
                args->flags, &args->xdata);

            if (op_errno) {
                op_errno = -op_errno;
                goto out;
            }
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            local->attempt_reopen = client_is_reopen_needed(args->fd, this,
                                                            remote_fd);

            if (*req_count + args->count >= MAX_IOVEC) {
                op_errno = ENOMEM;
                goto out;
            }
            memcpy(&req_vector[*req_count], args->vector,
                   (args->count * sizeof(req_vector[0])));
            *req_count += args->count;

            if (!*req_iobref)
                *req_iobref = args->iobref;
            else if (iobref_merge(*req_iobref, args->iobref))
                goto out;
            break;
        case GF_FOP_STATFS:
            CLIENT_PRE_FOP(statfs, this,
                           &this_req->compound_req_u.compound_statfs_req,
                           op_errno, out, &args->loc, args->xdata);
            break;
        case GF_FOP_FLUSH:
            CLIENT_PRE_FOP(flush, this,
                           &this_req->compound_req_u.compound_flush_req,
                           op_errno, out, args->fd, args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            local->owner = frame->root->lk_owner;
            break;
        case GF_FOP_FSYNC:
            CLIENT_PRE_FOP(
                fsync, this, &this_req->compound_req_u.compound_fsync_req,
                op_errno, out, args->fd, args->datasync, args->xdata);
            break;
        case GF_FOP_SETXATTR:
            CLIENT_PRE_FOP(setxattr, this,
                           &this_req->compound_req_u.compound_setxattr_req,
                           op_errno, out, &args->loc, args->xattr, args->flags,
                           args->xdata);
            break;
        case GF_FOP_GETXATTR:
            CLIENT_PRE_FOP(getxattr, this,
                           &this_req->compound_req_u.compound_getxattr_req,
                           op_errno, out, &args->loc, args->name, args->xdata);
            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_REMOVEXATTR:
            CLIENT_PRE_FOP(removexattr, this,
                           &this_req->compound_req_u.compound_removexattr_req,
                           op_errno, out, &args->loc, args->name, args->xdata);
            break;
        case GF_FOP_OPENDIR:
            CLIENT_PRE_FOP(opendir, this,
                           &this_req->compound_req_u.compound_opendir_req,
                           op_errno, out, &args->loc, args->fd, args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_FSYNCDIR:
            CLIENT_PRE_FOP(
                fsyncdir, this, &this_req->compound_req_u.compound_fsyncdir_req,
                op_errno, out, args->fd, args->datasync, args->xdata);
            break;
        case GF_FOP_ACCESS:
            CLIENT_PRE_FOP(access, this,
                           &this_req->compound_req_u.compound_access_req,
                           op_errno, out, &args->loc, args->mask, args->xdata);
            break;
        case GF_FOP_CREATE:
            CLIENT_PRE_FOP(create, this,
                           &this_req->compound_req_u.compound_create_req,
                           op_errno, out, &args->loc, args->fd, args->mode,
                           args->flags, args->umask, args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);

            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_FTRUNCATE:
            CLIENT_PRE_FOP(ftruncate, this,
                           &this_req->compound_req_u.compound_ftruncate_req,
                           op_errno, out, args->fd, args->offset, args->xdata);
            break;
        case GF_FOP_FSTAT:
            CLIENT_PRE_FOP(fstat, this,
                           &this_req->compound_req_u.compound_fstat_req,
                           op_errno, out, args->fd, args->xdata);
            break;
        case GF_FOP_LK:
            CLIENT_PRE_FOP(lk, this, &this_req->compound_req_u.compound_lk_req,
                           op_errno, out, args->cmd, &args->lock, args->fd,
                           args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            local->owner = frame->root->lk_owner;
            break;
        case GF_FOP_LOOKUP:
            CLIENT_PRE_FOP(lookup, this,
                           &this_req->compound_req_u.compound_lookup_req,
                           op_errno, out, &args->loc, args->xdata);
            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_READDIR:
            CLIENT_PRE_FOP(
                readdir, this, &this_req->compound_req_u.compound_readdir_req,
                op_errno, out, args->fd, args->size, args->offset, args->xdata);
            break;
        case GF_FOP_INODELK:
            CLIENT_PRE_FOP(inodelk, this,
                           &this_req->compound_req_u.compound_inodelk_req,
                           op_errno, out, &args->loc, args->cmd, &args->lock,
                           args->volume, args->xdata);
            break;
        case GF_FOP_FINODELK:
            CLIENT_PRE_FOP(finodelk, this,
                           &this_req->compound_req_u.compound_finodelk_req,
                           op_errno, out, args->fd, args->cmd, &args->lock,
                           args->volume, args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            local->attempt_reopen = client_is_reopen_needed(args->fd, this,
                                                            remote_fd);
            break;
        case GF_FOP_ENTRYLK:
            CLIENT_PRE_FOP(
                entrylk, this, &this_req->compound_req_u.compound_entrylk_req,
                op_errno, out, &args->loc, args->entrylkcmd, args->entrylktype,
                args->volume, args->name, args->xdata);
            break;
        case GF_FOP_FENTRYLK:
            CLIENT_PRE_FOP(
                fentrylk, this, &this_req->compound_req_u.compound_fentrylk_req,
                op_errno, out, args->fd, args->entrylkcmd, args->entrylktype,
                args->volume, args->name, args->xdata);
            break;
        case GF_FOP_XATTROP:
            CLIENT_PRE_FOP(xattrop, this,
                           &this_req->compound_req_u.compound_xattrop_req,
                           op_errno, out, &args->loc, args->xattr, args->optype,
                           args->xdata);
            break;
        case GF_FOP_FXATTROP:
            CLIENT_PRE_FOP(fxattrop, this,
                           &this_req->compound_req_u.compound_fxattrop_req,
                           op_errno, out, args->fd, args->xattr, args->optype,
                           args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            local->attempt_reopen = client_is_reopen_needed(args->fd, this,
                                                            remote_fd);
            break;
        case GF_FOP_FGETXATTR:
            CLIENT_PRE_FOP(fgetxattr, this,
                           &this_req->compound_req_u.compound_fgetxattr_req,
                           op_errno, out, args->fd, args->name, args->xdata);
            break;
        case GF_FOP_FSETXATTR:
            CLIENT_PRE_FOP(fsetxattr, this,
                           &this_req->compound_req_u.compound_fsetxattr_req,
                           op_errno, out, args->fd, args->flags, args->xattr,
                           args->xdata);
            break;
        case GF_FOP_RCHECKSUM:
            CLIENT_PRE_FOP(rchecksum, this,
                           &this_req->compound_req_u.compound_rchecksum_req,
                           op_errno, out, args->fd, args->size, args->offset,
                           args->xdata);
            break;
        case GF_FOP_SETATTR:
            CLIENT_PRE_FOP(setattr, this,
                           &this_req->compound_req_u.compound_setattr_req,
                           op_errno, out, &args->loc, args->valid, &args->stat,
                           args->xdata);
            break;
        case GF_FOP_FSETATTR:
            CLIENT_PRE_FOP(
                fsetattr, this, &this_req->compound_req_u.compound_fsetattr_req,
                op_errno, out, args->fd, args->valid, &args->stat, args->xdata);
            break;
        case GF_FOP_READDIRP:
            CLIENT_PRE_FOP(
                readdirp, this, &this_req->compound_req_u.compound_readdirp_req,
                op_errno, out, args->fd, args->size, args->offset, args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            break;
        case GF_FOP_FREMOVEXATTR:
            CLIENT_PRE_FOP(fremovexattr, this,
                           &this_req->compound_req_u.compound_fremovexattr_req,
                           op_errno, out, args->fd, args->name, args->xdata);
            break;
        case GF_FOP_FALLOCATE:
            CLIENT_PRE_FOP(fallocate, this,
                           &this_req->compound_req_u.compound_fallocate_req,
                           op_errno, out, args->fd, args->flags, args->offset,
                           args->size, args->xdata);
            break;
        case GF_FOP_DISCARD:
            CLIENT_PRE_FOP(
                discard, this, &this_req->compound_req_u.compound_discard_req,
                op_errno, out, args->fd, args->offset, args->size, args->xdata);
            break;
        case GF_FOP_ZEROFILL:
            CLIENT_PRE_FOP(
                zerofill, this, &this_req->compound_req_u.compound_zerofill_req,
                op_errno, out, args->fd, args->offset, args->size, args->xdata);
            break;
        case GF_FOP_IPC:
            CLIENT_PRE_FOP(ipc, this,
                           &this_req->compound_req_u.compound_ipc_req, op_errno,
                           out, args->cmd, args->xdata);
            break;
        case GF_FOP_SEEK:
            CLIENT_PRE_FOP(
                seek, this, &this_req->compound_req_u.compound_seek_req,
                op_errno, out, args->fd, args->offset, args->what, args->xdata);
            break;
        case GF_FOP_LEASE:
            CLIENT_PRE_FOP(
                lease, this, &this_req->compound_req_u.compound_lease_req,
                op_errno, out, &args->loc, &args->lease, args->xdata);
            break;
        default:
            return ENOTSUP;
    }
    return 0;
out:
    return op_errno;
}

void
compound_request_cleanup(gfs3_compound_req *req)
{
    int i = 0;
    int length = req->compound_req_array.compound_req_array_len;
    compound_req *curr_req = NULL;

    if (!req->compound_req_array.compound_req_array_val)
        return;

    for (i = 0; i < length; i++) {
        curr_req = &req->compound_req_array.compound_req_array_val[i];

        switch (curr_req->fop_enum) {
            case GF_FOP_STAT:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, stat);
                break;
            case GF_FOP_READLINK:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, readlink);
                break;
            case GF_FOP_MKNOD:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, mknod);
                break;
            case GF_FOP_MKDIR:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, mkdir);
                break;
            case GF_FOP_UNLINK:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, unlink);
                break;
            case GF_FOP_RMDIR:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, rmdir);
                break;
            case GF_FOP_SYMLINK:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, symlink);
                break;
            case GF_FOP_RENAME:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, rename);
                break;
            case GF_FOP_LINK:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, link);
                break;
            case GF_FOP_TRUNCATE:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, truncate);
                break;
            case GF_FOP_OPEN:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, open);
                break;
            case GF_FOP_READ:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, read);
                break;
            case GF_FOP_WRITE:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, write);
                break;
            case GF_FOP_STATFS:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, statfs);
                break;
            case GF_FOP_FLUSH:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, flush);
                break;
            case GF_FOP_FSYNC:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, fsync);
                break;
            case GF_FOP_SETXATTR: {
                gfs3_setxattr_req *args = &CPD_REQ_FIELD(curr_req, setxattr);
                GF_FREE(args->dict.dict_val);
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, setxattr);
                break;
            }
            case GF_FOP_GETXATTR:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, getxattr);
                break;
            case GF_FOP_REMOVEXATTR:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, removexattr);
                break;
            case GF_FOP_OPENDIR:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, opendir);
                break;
            case GF_FOP_FSYNCDIR:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, fsyncdir);
                break;
            case GF_FOP_ACCESS:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, access);
                break;
            case GF_FOP_CREATE:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, create);
                break;
            case GF_FOP_FTRUNCATE:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, ftruncate);
                break;
            case GF_FOP_FSTAT:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, fstat);
                break;
            case GF_FOP_LK:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, lk);
                break;
            case GF_FOP_LOOKUP:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, lookup);
                break;
            case GF_FOP_READDIR:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, readdir);
                break;
            case GF_FOP_INODELK:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, inodelk);
                break;
            case GF_FOP_FINODELK:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, finodelk);
                break;
            case GF_FOP_ENTRYLK:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, entrylk);
                break;
            case GF_FOP_FENTRYLK:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, fentrylk);
                break;
            case GF_FOP_XATTROP: {
                gfs3_xattrop_req *args = &CPD_REQ_FIELD(curr_req, xattrop);
                GF_FREE(args->dict.dict_val);
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, xattrop);
                break;
            }
            case GF_FOP_FXATTROP: {
                gfs3_fxattrop_req *args = &CPD_REQ_FIELD(curr_req, fxattrop);
                GF_FREE(args->dict.dict_val);
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, fxattrop);
                break;
            }
            case GF_FOP_FGETXATTR:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, fgetxattr);
                break;
            case GF_FOP_FSETXATTR: {
                gfs3_fsetxattr_req *args = &CPD_REQ_FIELD(curr_req, fsetxattr);
                GF_FREE(args->dict.dict_val);
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, fsetxattr);
                break;
            }
            case GF_FOP_RCHECKSUM:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, rchecksum);
                break;
            case GF_FOP_SETATTR:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, setattr);
                break;
            case GF_FOP_FSETATTR:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, fsetattr);
                break;
            case GF_FOP_READDIRP: {
                gfs3_readdirp_req *args = &CPD_REQ_FIELD(curr_req, readdirp);
                GF_FREE(args->dict.dict_val);
                break;
            }
            case GF_FOP_FREMOVEXATTR:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, fremovexattr);
                break;
            case GF_FOP_FALLOCATE:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, fallocate);
                break;
            case GF_FOP_DISCARD:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, discard);
                break;
            case GF_FOP_ZEROFILL:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, zerofill);
                break;
            case GF_FOP_IPC:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, ipc);
                break;
            case GF_FOP_SEEK:
                CLIENT_COMPOUND_FOP_CLEANUP(curr_req, seek);
                break;
            default:
                break;
        }
    }

    GF_FREE(req->compound_req_array.compound_req_array_val);
    return;
}

void
clnt_getactivelk_rsp_cleanup(gfs3_getactivelk_rsp *rsp)
{
    gfs3_locklist *trav = NULL;
    gfs3_locklist *next = NULL;

    trav = rsp->reply;

    while (trav) {
        next = trav->nextentry;
        free(trav->client_uid);
        free(trav);
        trav = next;
    }
}

void
clnt_getactivelk_rsp_cleanup_v2(gfx_getactivelk_rsp *rsp)
{
    gfs3_locklist *trav = NULL;
    gfs3_locklist *next = NULL;

    trav = rsp->reply;

    while (trav) {
        next = trav->nextentry;
        free(trav->client_uid);
        free(trav);
        trav = next;
    }
}
int
clnt_unserialize_rsp_locklist(xlator_t *this, struct gfs3_getactivelk_rsp *rsp,
                              lock_migration_info_t *lmi)
{
    struct gfs3_locklist *trav = NULL;
    lock_migration_info_t *temp = NULL;
    int ret = -1;
    clnt_conf_t *conf = NULL;

    trav = rsp->reply;

    conf = this->private;
    if (!conf)
        goto out;

    while (trav) {
        temp = GF_CALLOC(1, sizeof(*lmi), gf_common_mt_lock_mig);
        if (temp == NULL) {
            gf_msg(this->name, GF_LOG_ERROR, 0, 0, "No memory");
            goto out;
        }

        INIT_LIST_HEAD(&temp->list);

        gf_proto_flock_to_flock(&trav->flock, &temp->flock);

        temp->lk_flags = trav->lk_flags;

        temp->client_uid = gf_strdup(trav->client_uid);

        list_add_tail(&temp->list, &lmi->list);

        trav = trav->nextentry;
    }

    ret = 0;
out:
    return ret;
}
int
clnt_unserialize_rsp_locklist_v2(xlator_t *this,
                                 struct gfx_getactivelk_rsp *rsp,
                                 lock_migration_info_t *lmi)
{
    struct gfs3_locklist *trav = NULL;
    lock_migration_info_t *temp = NULL;
    int ret = -1;
    clnt_conf_t *conf = NULL;

    trav = rsp->reply;

    conf = this->private;
    if (!conf)
        goto out;

    while (trav) {
        temp = GF_CALLOC(1, sizeof(*lmi), gf_common_mt_lock_mig);
        if (temp == NULL) {
            gf_msg(this->name, GF_LOG_ERROR, 0, 0, "No memory");
            goto out;
        }

        INIT_LIST_HEAD(&temp->list);

        gf_proto_flock_to_flock(&trav->flock, &temp->flock);

        temp->lk_flags = trav->lk_flags;

        temp->client_uid = gf_strdup(trav->client_uid);

        list_add_tail(&temp->list, &lmi->list);

        trav = trav->nextentry;
    }

    ret = 0;
out:
    return ret;
}

void
clnt_setactivelk_req_cleanup(gfs3_setactivelk_req *req)
{
    gfs3_locklist *trav = NULL;
    gfs3_locklist *next = NULL;

    trav = req->request;

    while (trav) {
        next = trav->nextentry;
        GF_FREE(trav->client_uid);
        GF_FREE(trav);
        trav = next;
    }
}

void
clnt_setactivelk_req_cleanup_v2(gfx_setactivelk_req *req)
{
    gfs3_locklist *trav = NULL;
    gfs3_locklist *next = NULL;

    trav = req->request;

    while (trav) {
        next = trav->nextentry;
        GF_FREE(trav->client_uid);
        GF_FREE(trav);
        trav = next;
    }
}

int
serialize_req_locklist(lock_migration_info_t *locklist,
                       gfs3_setactivelk_req *req)
{
    lock_migration_info_t *tmp = NULL;
    gfs3_locklist *trav = NULL;
    gfs3_locklist *prev = NULL;
    int ret = -1;

    GF_VALIDATE_OR_GOTO("server", locklist, out);
    GF_VALIDATE_OR_GOTO("server", req, out);

    list_for_each_entry(tmp, &locklist->list, list)
    {
        trav = GF_CALLOC(1, sizeof(*trav), gf_client_mt_clnt_lock_request_t);
        if (!trav)
            goto out;

        switch (tmp->flock.l_type) {
            case F_RDLCK:
                tmp->flock.l_type = GF_LK_F_RDLCK;
                break;
            case F_WRLCK:
                tmp->flock.l_type = GF_LK_F_WRLCK;
                break;
            case F_UNLCK:
                tmp->flock.l_type = GF_LK_F_UNLCK;
                break;

            default:
                gf_msg(THIS->name, GF_LOG_ERROR, 0, 0,
                       "Unknown lock type: %" PRId32 "!", tmp->flock.l_type);
                break;
        }

        gf_proto_flock_from_flock(&trav->flock, &tmp->flock);

        trav->lk_flags = tmp->lk_flags;

        trav->client_uid = gf_strdup(tmp->client_uid);
        if (!trav->client_uid) {
            gf_msg(THIS->name, GF_LOG_ERROR, 0, 0,
                   "client_uid could not be allocated");
            ret = -1;
            goto out;
        }

        if (prev)
            prev->nextentry = trav;
        else
            req->request = trav;

        prev = trav;
        trav = NULL;
    }

    ret = 0;
out:
    GF_FREE(trav);

    return ret;
}

int
serialize_req_locklist_v2(lock_migration_info_t *locklist,
                          gfx_setactivelk_req *req)
{
    lock_migration_info_t *tmp = NULL;
    gfs3_locklist *trav = NULL;
    gfs3_locklist *prev = NULL;
    int ret = -1;

    GF_VALIDATE_OR_GOTO("server", locklist, out);
    GF_VALIDATE_OR_GOTO("server", req, out);

    list_for_each_entry(tmp, &locklist->list, list)
    {
        trav = GF_CALLOC(1, sizeof(*trav), gf_client_mt_clnt_lock_request_t);
        if (!trav)
            goto out;

        switch (tmp->flock.l_type) {
            case F_RDLCK:
                tmp->flock.l_type = GF_LK_F_RDLCK;
                break;
            case F_WRLCK:
                tmp->flock.l_type = GF_LK_F_WRLCK;
                break;
            case F_UNLCK:
                tmp->flock.l_type = GF_LK_F_UNLCK;
                break;

            default:
                gf_msg(THIS->name, GF_LOG_ERROR, 0, 0,
                       "Unknown lock type: %" PRId32 "!", tmp->flock.l_type);
                break;
        }

        gf_proto_flock_from_flock(&trav->flock, &tmp->flock);

        trav->lk_flags = tmp->lk_flags;

        trav->client_uid = gf_strdup(tmp->client_uid);
        if (!trav->client_uid) {
            gf_msg(THIS->name, GF_LOG_ERROR, 0, 0,
                   "client_uid could not be allocated");
            ret = -1;
            goto out;
        }

        if (prev)
            prev->nextentry = trav;
        else
            req->request = trav;

        prev = trav;
        trav = NULL;
    }

    ret = 0;
out:
    GF_FREE(trav);

    return ret;
}

void
client_compound_rsp_cleanup(gfs3_compound_rsp *rsp, int len)
{
    int i = 0;
    compound_rsp *this_rsp = NULL;

    for (i = 0; i < len; i++) {
        this_rsp = &rsp->compound_rsp_array.compound_rsp_array_val[i];
        switch (this_rsp->fop_enum) {
            case GF_FOP_STAT:
                CLIENT_FOP_RSP_CLEANUP(rsp, stat, i);
                break;
            case GF_FOP_MKNOD:
                CLIENT_FOP_RSP_CLEANUP(rsp, mknod, i);
                break;
            case GF_FOP_MKDIR:
                CLIENT_FOP_RSP_CLEANUP(rsp, mkdir, i);
                break;
            case GF_FOP_UNLINK:
                CLIENT_FOP_RSP_CLEANUP(rsp, unlink, i);
                break;
            case GF_FOP_RMDIR:
                CLIENT_FOP_RSP_CLEANUP(rsp, rmdir, i);
                break;
            case GF_FOP_SYMLINK:
                CLIENT_FOP_RSP_CLEANUP(rsp, symlink, i);
                break;
            case GF_FOP_RENAME:
                CLIENT_FOP_RSP_CLEANUP(rsp, rename, i);
                break;
            case GF_FOP_LINK:
                CLIENT_FOP_RSP_CLEANUP(rsp, link, i);
                break;
            case GF_FOP_TRUNCATE:
                CLIENT_FOP_RSP_CLEANUP(rsp, truncate, i);
                break;
            case GF_FOP_OPEN:
                CLIENT_FOP_RSP_CLEANUP(rsp, open, i);
                break;
            case GF_FOP_READ:
                CLIENT_FOP_RSP_CLEANUP(rsp, read, i);
                break;
            case GF_FOP_WRITE:
                CLIENT_FOP_RSP_CLEANUP(rsp, write, i);
                break;
            case GF_FOP_STATFS:
                CLIENT_FOP_RSP_CLEANUP(rsp, statfs, i);
                break;
            case GF_FOP_FSYNC:
                CLIENT_FOP_RSP_CLEANUP(rsp, fsync, i);
                break;
            case GF_FOP_OPENDIR:
                CLIENT_FOP_RSP_CLEANUP(rsp, opendir, i);
                break;
            case GF_FOP_CREATE:
                CLIENT_FOP_RSP_CLEANUP(rsp, create, i);
                break;
            case GF_FOP_FTRUNCATE:
                CLIENT_FOP_RSP_CLEANUP(rsp, ftruncate, i);
                break;
            case GF_FOP_FSTAT:
                CLIENT_FOP_RSP_CLEANUP(rsp, fstat, i);
                break;
            case GF_FOP_LOOKUP:
                CLIENT_FOP_RSP_CLEANUP(rsp, lookup, i);
                break;
            case GF_FOP_SETATTR:
                CLIENT_FOP_RSP_CLEANUP(rsp, setattr, i);
                break;
            case GF_FOP_FSETATTR:
                CLIENT_FOP_RSP_CLEANUP(rsp, fsetattr, i);
                break;
            case GF_FOP_FALLOCATE:
                CLIENT_FOP_RSP_CLEANUP(rsp, fallocate, i);
                break;
            case GF_FOP_DISCARD:
                CLIENT_FOP_RSP_CLEANUP(rsp, discard, i);
                break;
            case GF_FOP_ZEROFILL:
                CLIENT_FOP_RSP_CLEANUP(rsp, zerofill, i);
                break;
            case GF_FOP_IPC:
                CLIENT_FOP_RSP_CLEANUP(rsp, ipc, i);
                break;
            case GF_FOP_SEEK:
                CLIENT_FOP_RSP_CLEANUP(rsp, seek, i);
                break;
            case GF_FOP_LEASE:
                CLIENT_FOP_RSP_CLEANUP(rsp, lease, i);
                break;
            /* fops that use gf_common_rsp */
            case GF_FOP_FLUSH:
                CLIENT_COMMON_RSP_CLEANUP(rsp, flush, i);
                break;
            case GF_FOP_SETXATTR:
                CLIENT_COMMON_RSP_CLEANUP(rsp, setxattr, i);
                break;
            case GF_FOP_REMOVEXATTR:
                CLIENT_COMMON_RSP_CLEANUP(rsp, removexattr, i);
                break;
            case GF_FOP_FSETXATTR:
                CLIENT_COMMON_RSP_CLEANUP(rsp, fsetxattr, i);
                break;
            case GF_FOP_FREMOVEXATTR:
                CLIENT_COMMON_RSP_CLEANUP(rsp, fremovexattr, i);
                break;
            case GF_FOP_FSYNCDIR:
                CLIENT_COMMON_RSP_CLEANUP(rsp, fsyncdir, i);
                break;
            case GF_FOP_ACCESS:
                CLIENT_COMMON_RSP_CLEANUP(rsp, access, i);
                break;
            case GF_FOP_INODELK:
                CLIENT_COMMON_RSP_CLEANUP(rsp, inodelk, i);
                break;
            case GF_FOP_FINODELK:
                CLIENT_COMMON_RSP_CLEANUP(rsp, finodelk, i);
                break;
            case GF_FOP_ENTRYLK:
                CLIENT_COMMON_RSP_CLEANUP(rsp, entrylk, i);
                break;
            case GF_FOP_FENTRYLK:
                CLIENT_COMMON_RSP_CLEANUP(rsp, fentrylk, i);
                break;
            /* fops that need extra cleanup */
            case GF_FOP_LK: {
                CLIENT_FOP_RSP_CLEANUP(rsp, lk, i);
                gfs3_lk_rsp *tmp_rsp = &CPD_RSP_FIELD(this_rsp, lk);
                free(tmp_rsp->flock.lk_owner.lk_owner_val);
                break;
            }
            case GF_FOP_READLINK: {
                CLIENT_FOP_RSP_CLEANUP(rsp, readlink, i);
                gfs3_readlink_rsp *tmp_rsp = &CPD_RSP_FIELD(this_rsp, readlink);
                free(tmp_rsp->path);
                break;
            }
            case GF_FOP_XATTROP: {
                CLIENT_FOP_RSP_CLEANUP(rsp, xattrop, i);
                gfs3_xattrop_rsp *tmp_rsp = &CPD_RSP_FIELD(this_rsp, xattrop);
                free(tmp_rsp->dict.dict_val);
                break;
            }
            case GF_FOP_FXATTROP: {
                CLIENT_FOP_RSP_CLEANUP(rsp, fxattrop, i);
                gfs3_fxattrop_rsp *tmp_rsp = &CPD_RSP_FIELD(this_rsp, fxattrop);
                free(tmp_rsp->dict.dict_val);
                break;
            }
            case GF_FOP_READDIR: {
                CLIENT_FOP_RSP_CLEANUP(rsp, readdir, i);
                gfs3_readdir_rsp *tmp_rsp = &CPD_RSP_FIELD(this_rsp, readdir);
                clnt_readdir_rsp_cleanup(tmp_rsp);
                break;
            }
            case GF_FOP_READDIRP: {
                CLIENT_FOP_RSP_CLEANUP(rsp, readdirp, i);
                gfs3_readdirp_rsp *tmp_rsp = &CPD_RSP_FIELD(this_rsp, readdirp);
                clnt_readdirp_rsp_cleanup(tmp_rsp);
                break;
            }
            case GF_FOP_GETXATTR: {
                CLIENT_FOP_RSP_CLEANUP(rsp, getxattr, i);
                gfs3_getxattr_rsp *tmp_rsp = &CPD_RSP_FIELD(this_rsp, getxattr);
                free(tmp_rsp->dict.dict_val);
                break;
            }
            case GF_FOP_FGETXATTR: {
                CLIENT_FOP_RSP_CLEANUP(rsp, fgetxattr, i);
                gfs3_fgetxattr_rsp *tmp_rsp = &CPD_RSP_FIELD(this_rsp,
                                                             fgetxattr);
                free(tmp_rsp->dict.dict_val);
                break;
            }
            case GF_FOP_RCHECKSUM: {
                CLIENT_FOP_RSP_CLEANUP(rsp, rchecksum, i);
                gfs3_rchecksum_rsp *rck = &CPD_RSP_FIELD(this_rsp, rchecksum);
                if (rck->strong_checksum.strong_checksum_val) {
                    free(rck->strong_checksum.strong_checksum_val);
                }
                break;
            }
            default:
                break;
        }
    }
    return;
}

/* compound v2 */
int
client_handle_fop_requirements_v2(
    xlator_t *this, call_frame_t *frame, gfx_compound_req *req,
    clnt_local_t *local, struct iobref **req_iobref, struct iobref **rsp_iobref,
    struct iovec *req_vector, struct iovec *rsp_vector, int *req_count,
    int *rsp_count, default_args_t *args, int fop_enum, int index)
{
    int ret = 0;
    int op_errno = ENOMEM;
    struct iobuf *rsp_iobuf = NULL;
    int64_t remote_fd = -1;
    compound_req_v2 *this_req = &req->compound_req_array
                                     .compound_req_array_val[index];

    this_req->fop_enum = fop_enum;

    switch (fop_enum) {
        case GF_FOP_STAT:
            CLIENT4_PRE_FOP(stat, this,
                            &this_req->compound_req_v2_u.compound_stat_req,
                            op_errno, out, &args->loc, args->xdata);
            break;
        case GF_FOP_READLINK:
            CLIENT4_PRE_FOP(readlink, this,
                            &this_req->compound_req_v2_u.compound_readlink_req,
                            op_errno, out, &args->loc, args->size, args->xdata);
            break;
        case GF_FOP_MKNOD:
            CLIENT4_PRE_FOP(mknod, this,
                            &this_req->compound_req_v2_u.compound_mknod_req,
                            op_errno, out, &args->loc, args->mode, args->rdev,
                            args->umask, args->xdata);
            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_MKDIR:
            CLIENT4_PRE_FOP(mkdir, this,
                            &this_req->compound_req_v2_u.compound_mkdir_req,
                            op_errno, out, &args->loc, args->mode, args->umask,
                            args->xdata);
            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_UNLINK:
            CLIENT4_PRE_FOP(
                unlink, this, &this_req->compound_req_v2_u.compound_unlink_req,
                op_errno, out, &args->loc, args->xflag, args->xdata);
            break;
        case GF_FOP_RMDIR:
            CLIENT4_PRE_FOP(
                rmdir, this, &this_req->compound_req_v2_u.compound_rmdir_req,
                op_errno, out, &args->loc, args->flags, args->xdata);
            break;
        case GF_FOP_SYMLINK:
            CLIENT4_PRE_FOP(symlink, this,
                            &this_req->compound_req_v2_u.compound_symlink_req,
                            op_errno, out, &args->loc, args->linkname,
                            args->umask, args->xdata);
            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_RENAME:
            CLIENT4_PRE_FOP(
                rename, this, &this_req->compound_req_v2_u.compound_rename_req,
                op_errno, out, &args->loc, &args->loc2, args->xdata);
            break;
        case GF_FOP_LINK:
            CLIENT4_PRE_FOP(
                link, this, &this_req->compound_req_v2_u.compound_link_req,
                op_errno, out, &args->loc, &args->loc2, args->xdata);
            break;
        case GF_FOP_TRUNCATE:
            CLIENT4_PRE_FOP(truncate, this,
                            &this_req->compound_req_v2_u.compound_truncate_req,
                            op_errno, out, &args->loc, args->offset,
                            args->xdata);
            break;
        case GF_FOP_OPEN:
            CLIENT4_PRE_FOP(
                open, this, &this_req->compound_req_v2_u.compound_open_req,
                op_errno, out, &args->loc, args->fd, args->flags, args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            break;
        case GF_FOP_READ:
            op_errno = client_pre_readv_v2(
                this, &this_req->compound_req_v2_u.compound_read_req, args->fd,
                args->size, args->offset, args->flags, args->xdata);

            if (op_errno) {
                op_errno = -op_errno;
                goto out;
            }
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            local->attempt_reopen = client_is_reopen_needed(args->fd, this,
                                                            remote_fd);
            rsp_iobuf = iobuf_get2(this->ctx->iobuf_pool, args->size);
            if (rsp_iobuf == NULL) {
                op_errno = ENOMEM;
                goto out;
            }

            if (!*rsp_iobref) {
                *rsp_iobref = iobref_new();
                if (*rsp_iobref == NULL) {
                    op_errno = ENOMEM;
                    goto out;
                }
            }

            if (*rsp_count + 1 >= MAX_IOVEC) {
                op_errno = ENOMEM;
                goto out;
            }
            rsp_vector[*rsp_count].iov_base = iobuf_ptr(rsp_iobuf);
            rsp_vector[*rsp_count].iov_len = iobuf_pagesize(rsp_iobuf);
            iobref_add(*rsp_iobref, rsp_iobuf);
            iobuf_unref(rsp_iobuf);
            rsp_iobuf = NULL;
            if (args->size > rsp_vector[*rsp_count].iov_len) {
                gf_msg(this->name, GF_LOG_WARNING, ENOMEM, PC_MSG_NO_MEMORY,
                       "read-size (%lu) is bigger than iobuf size "
                       "(%lu)",
                       (unsigned long)args->size,
                       (unsigned long)rsp_vector[*rsp_count].iov_len);
                op_errno = EINVAL;
                goto out;
            }
            *rsp_count += 1;

            break;
        case GF_FOP_WRITE:
            op_errno = client_pre_writev_v2(
                this, &this_req->compound_req_v2_u.compound_write_req, args->fd,
                iov_length(args->vector, args->count), args->offset,
                args->flags, &args->xdata);

            if (op_errno) {
                op_errno = -op_errno;
                goto out;
            }
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            local->attempt_reopen = client_is_reopen_needed(args->fd, this,
                                                            remote_fd);

            if (*req_count + args->count >= MAX_IOVEC) {
                op_errno = ENOMEM;
                goto out;
            }
            memcpy(&req_vector[*req_count], args->vector,
                   (args->count * sizeof(req_vector[0])));
            *req_count += args->count;

            if (!*req_iobref)
                *req_iobref = args->iobref;
            else if (iobref_merge(*req_iobref, args->iobref))
                goto out;
            break;
        case GF_FOP_STATFS:
            CLIENT4_PRE_FOP(statfs, this,
                            &this_req->compound_req_v2_u.compound_statfs_req,
                            op_errno, out, &args->loc, args->xdata);
            break;
        case GF_FOP_FLUSH:
            CLIENT4_PRE_FOP(flush, this,
                            &this_req->compound_req_v2_u.compound_flush_req,
                            op_errno, out, args->fd, args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            local->owner = frame->root->lk_owner;
            break;
        case GF_FOP_FSYNC:
            CLIENT4_PRE_FOP(
                fsync, this, &this_req->compound_req_v2_u.compound_fsync_req,
                op_errno, out, args->fd, args->datasync, args->xdata);
            break;
        case GF_FOP_SETXATTR:
            CLIENT4_PRE_FOP(setxattr, this,
                            &this_req->compound_req_v2_u.compound_setxattr_req,
                            op_errno, out, &args->loc, args->xattr, args->flags,
                            args->xdata);
            break;
        case GF_FOP_GETXATTR:
            CLIENT4_PRE_FOP(getxattr, this,
                            &this_req->compound_req_v2_u.compound_getxattr_req,
                            op_errno, out, &args->loc, args->name, args->xdata);
            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_REMOVEXATTR:
            CLIENT4_PRE_FOP(
                removexattr, this,
                &this_req->compound_req_v2_u.compound_removexattr_req, op_errno,
                out, &args->loc, args->name, args->xdata);
            break;
        case GF_FOP_OPENDIR:
            CLIENT4_PRE_FOP(opendir, this,
                            &this_req->compound_req_v2_u.compound_opendir_req,
                            op_errno, out, &args->loc, args->fd, args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_FSYNCDIR:
            CLIENT4_PRE_FOP(fsyncdir, this,
                            &this_req->compound_req_v2_u.compound_fsyncdir_req,
                            op_errno, out, args->fd, args->datasync,
                            args->xdata);
            break;
        case GF_FOP_ACCESS:
            CLIENT4_PRE_FOP(access, this,
                            &this_req->compound_req_v2_u.compound_access_req,
                            op_errno, out, &args->loc, args->mask, args->xdata);
            break;
        case GF_FOP_CREATE:
            CLIENT4_PRE_FOP(create, this,
                            &this_req->compound_req_v2_u.compound_create_req,
                            op_errno, out, &args->loc, args->fd, args->mode,
                            args->flags, args->umask, args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);

            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_FTRUNCATE:
            CLIENT4_PRE_FOP(ftruncate, this,
                            &this_req->compound_req_v2_u.compound_ftruncate_req,
                            op_errno, out, args->fd, args->offset, args->xdata);
            break;
        case GF_FOP_FSTAT:
            CLIENT4_PRE_FOP(fstat, this,
                            &this_req->compound_req_v2_u.compound_fstat_req,
                            op_errno, out, args->fd, args->xdata);
            break;
        case GF_FOP_LK:
            CLIENT4_PRE_FOP(
                lk, this, &this_req->compound_req_v2_u.compound_lk_req,
                op_errno, out, args->cmd, &args->lock, args->fd, args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            local->owner = frame->root->lk_owner;
            break;
        case GF_FOP_LOOKUP:
            CLIENT4_PRE_FOP(lookup, this,
                            &this_req->compound_req_v2_u.compound_lookup_req,
                            op_errno, out, &args->loc, args->xdata);
            loc_copy(&local->loc, &args->loc);
            loc_path(&local->loc, NULL);
            break;
        case GF_FOP_READDIR:
            CLIENT4_PRE_FOP(readdir, this,
                            &this_req->compound_req_v2_u.compound_readdir_req,
                            op_errno, out, args->fd, args->size, args->offset,
                            args->xdata);
            break;
        case GF_FOP_INODELK:
            CLIENT4_PRE_FOP(inodelk, this,
                            &this_req->compound_req_v2_u.compound_inodelk_req,
                            op_errno, out, &args->loc, args->cmd, &args->lock,
                            args->volume, args->xdata);
            break;
        case GF_FOP_FINODELK:
            CLIENT4_PRE_FOP(finodelk, this,
                            &this_req->compound_req_v2_u.compound_finodelk_req,
                            op_errno, out, args->fd, args->cmd, &args->lock,
                            args->volume, args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            local->attempt_reopen = client_is_reopen_needed(args->fd, this,
                                                            remote_fd);
            break;
        case GF_FOP_ENTRYLK:
            CLIENT4_PRE_FOP(entrylk, this,
                            &this_req->compound_req_v2_u.compound_entrylk_req,
                            op_errno, out, &args->loc, args->entrylkcmd,
                            args->entrylktype, args->volume, args->name,
                            args->xdata);
            break;
        case GF_FOP_FENTRYLK:
            CLIENT4_PRE_FOP(fentrylk, this,
                            &this_req->compound_req_v2_u.compound_fentrylk_req,
                            op_errno, out, args->fd, args->entrylkcmd,
                            args->entrylktype, args->volume, args->name,
                            args->xdata);
            break;
        case GF_FOP_XATTROP:
            CLIENT4_PRE_FOP(xattrop, this,
                            &this_req->compound_req_v2_u.compound_xattrop_req,
                            op_errno, out, &args->loc, args->xattr,
                            args->optype, args->xdata);
            break;
        case GF_FOP_FXATTROP:
            CLIENT4_PRE_FOP(fxattrop, this,
                            &this_req->compound_req_v2_u.compound_fxattrop_req,
                            op_errno, out, args->fd, args->xattr, args->optype,
                            args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            local->attempt_reopen = client_is_reopen_needed(args->fd, this,
                                                            remote_fd);
            break;
        case GF_FOP_FGETXATTR:
            CLIENT4_PRE_FOP(fgetxattr, this,
                            &this_req->compound_req_v2_u.compound_fgetxattr_req,
                            op_errno, out, args->fd, args->name, args->xdata);
            break;
        case GF_FOP_FSETXATTR:
            CLIENT4_PRE_FOP(fsetxattr, this,
                            &this_req->compound_req_v2_u.compound_fsetxattr_req,
                            op_errno, out, args->fd, args->flags, args->xattr,
                            args->xdata);
            break;
        case GF_FOP_RCHECKSUM:
            CLIENT4_PRE_FOP(rchecksum, this,
                            &this_req->compound_req_v2_u.compound_rchecksum_req,
                            op_errno, out, args->fd, args->size, args->offset,
                            args->xdata);
            break;
        case GF_FOP_SETATTR:
            CLIENT4_PRE_FOP(setattr, this,
                            &this_req->compound_req_v2_u.compound_setattr_req,
                            op_errno, out, &args->loc, args->valid, &args->stat,
                            args->xdata);
            break;
        case GF_FOP_FSETATTR:
            CLIENT4_PRE_FOP(fsetattr, this,
                            &this_req->compound_req_v2_u.compound_fsetattr_req,
                            op_errno, out, args->fd, args->valid, &args->stat,
                            args->xdata);
            break;
        case GF_FOP_READDIRP:
            CLIENT4_PRE_FOP(readdirp, this,
                            &this_req->compound_req_v2_u.compound_readdirp_req,
                            op_errno, out, args->fd, args->size, args->offset,
                            args->xdata);
            if (!local->fd)
                local->fd = fd_ref(args->fd);
            break;
        case GF_FOP_FREMOVEXATTR:
            CLIENT4_PRE_FOP(
                fremovexattr, this,
                &this_req->compound_req_v2_u.compound_fremovexattr_req,
                op_errno, out, args->fd, args->name, args->xdata);
            break;
        case GF_FOP_FALLOCATE:
            CLIENT4_PRE_FOP(fallocate, this,
                            &this_req->compound_req_v2_u.compound_fallocate_req,
                            op_errno, out, args->fd, args->flags, args->offset,
                            args->size, args->xdata);
            break;
        case GF_FOP_DISCARD:
            CLIENT4_PRE_FOP(discard, this,
                            &this_req->compound_req_v2_u.compound_discard_req,
                            op_errno, out, args->fd, args->offset, args->size,
                            args->xdata);
            break;
        case GF_FOP_ZEROFILL:
            CLIENT4_PRE_FOP(zerofill, this,
                            &this_req->compound_req_v2_u.compound_zerofill_req,
                            op_errno, out, args->fd, args->offset, args->size,
                            args->xdata);
            break;
        case GF_FOP_IPC:
            CLIENT4_PRE_FOP(ipc, this,
                            &this_req->compound_req_v2_u.compound_ipc_req,
                            op_errno, out, args->cmd, args->xdata);
            break;
        case GF_FOP_SEEK:
            CLIENT4_PRE_FOP(
                seek, this, &this_req->compound_req_v2_u.compound_seek_req,
                op_errno, out, args->fd, args->offset, args->what, args->xdata);
            break;
        case GF_FOP_LEASE:
            CLIENT4_PRE_FOP(
                lease, this, &this_req->compound_req_v2_u.compound_lease_req,
                op_errno, out, &args->loc, &args->lease, args->xdata);
            break;
        case GF_FOP_COPY_FILE_RANGE:
            /*
             * Not going to handle the copy_file_range fop in compound
             * operation. This is because, compound operation is going
             * to be removed. In fact, AFR one of the heavy consumer of
             * compound operations has stopped using that.
             * https://github.com/gluster/glusterfs/issues/414
             * Therefore, sending ENOTSUP error for this fop coming as
             * comound request. Though, there was no need of handling
             * "case GF_FOP_COPY_FILE_RANGE" technically, this comment
             * under the label of GF_FOP_COPY_FILE_RANGE will help in
             * understanding that this fop does not handle the compund
             * request and why.
             */
        default:
            return ENOTSUP;
    }
    return 0;
out:
    return op_errno;
}

void
compound_request_cleanup_v2(gfx_compound_req *req)
{
    int i = 0;
    int length = req->compound_req_array.compound_req_array_len;
    compound_req_v2 *curr_req = NULL;

    if (!req->compound_req_array.compound_req_array_val)
        return;

    for (i = 0; i < length; i++) {
        curr_req = &req->compound_req_array.compound_req_array_val[i];

        switch (curr_req->fop_enum) {
            case GF_FOP_STAT:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, stat);
                break;
            case GF_FOP_READLINK:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, readlink);
                break;
            case GF_FOP_MKNOD:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, mknod);
                break;
            case GF_FOP_MKDIR:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, mkdir);
                break;
            case GF_FOP_UNLINK:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, unlink);
                break;
            case GF_FOP_RMDIR:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, rmdir);
                break;
            case GF_FOP_SYMLINK:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, symlink);
                break;
            case GF_FOP_RENAME:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, rename);
                break;
            case GF_FOP_LINK:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, link);
                break;
            case GF_FOP_TRUNCATE:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, truncate);
                break;
            case GF_FOP_OPEN:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, open);
                break;
            case GF_FOP_READ:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, read);
                break;
            case GF_FOP_WRITE:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, write);
                break;
            case GF_FOP_STATFS:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, statfs);
                break;
            case GF_FOP_FLUSH:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, flush);
                break;
            case GF_FOP_FSYNC:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, fsync);
                break;
            case GF_FOP_SETXATTR: {
                gfx_setxattr_req *args = &CPD4_REQ_FIELD(curr_req, setxattr);
                GF_FREE(args->dict.pairs.pairs_val);
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, setxattr);
                break;
            }
            case GF_FOP_GETXATTR:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, getxattr);
                break;
            case GF_FOP_REMOVEXATTR:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, removexattr);
                break;
            case GF_FOP_OPENDIR:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, opendir);
                break;
            case GF_FOP_FSYNCDIR:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, fsyncdir);
                break;
            case GF_FOP_ACCESS:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, access);
                break;
            case GF_FOP_CREATE:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, create);
                break;
            case GF_FOP_FTRUNCATE:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, ftruncate);
                break;
            case GF_FOP_FSTAT:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, fstat);
                break;
            case GF_FOP_LK:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, lk);
                break;
            case GF_FOP_LOOKUP:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, lookup);
                break;
            case GF_FOP_READDIR:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, readdir);
                break;
            case GF_FOP_INODELK:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, inodelk);
                break;
            case GF_FOP_FINODELK:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, finodelk);
                break;
            case GF_FOP_ENTRYLK:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, entrylk);
                break;
            case GF_FOP_FENTRYLK:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, fentrylk);
                break;
            case GF_FOP_XATTROP: {
                gfx_xattrop_req *args = &CPD4_REQ_FIELD(curr_req, xattrop);
                GF_FREE(args->dict.pairs.pairs_val);
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, xattrop);
                break;
            }
            case GF_FOP_FXATTROP: {
                gfx_fxattrop_req *args = &CPD4_REQ_FIELD(curr_req, fxattrop);
                GF_FREE(args->dict.pairs.pairs_val);
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, fxattrop);
                break;
            }
            case GF_FOP_FGETXATTR:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, fgetxattr);
                break;
            case GF_FOP_FSETXATTR: {
                gfx_fsetxattr_req *args = &CPD4_REQ_FIELD(curr_req, fsetxattr);
                GF_FREE(args->dict.pairs.pairs_val);
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, fsetxattr);
                break;
            }
            case GF_FOP_RCHECKSUM:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, rchecksum);
                break;
            case GF_FOP_SETATTR:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, setattr);
                break;
            case GF_FOP_FSETATTR:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, fsetattr);
                break;
            case GF_FOP_READDIRP:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, readdirp);
                break;
            case GF_FOP_FREMOVEXATTR:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, fremovexattr);
                break;
            case GF_FOP_FALLOCATE:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, fallocate);
                break;
            case GF_FOP_DISCARD:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, discard);
                break;
            case GF_FOP_ZEROFILL:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, zerofill);
                break;
            case GF_FOP_IPC:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, ipc);
                break;
            case GF_FOP_SEEK:
                CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, seek);
                break;
            case GF_FOP_COPY_FILE_RANGE:
                /*
                 * This fop is not handled in compund operations.
                 * Check the comment added under this fop's section
                 * in the compound_request_cleanup_v2. Therefore
                 * keeping this label only as a placeholder with
                 * a message that, this fop is not handled.
                 */
            default:
                break;
        }
    }

    GF_FREE(req->compound_req_array.compound_req_array_val);
    return;
}

void
client_compound_rsp_cleanup_v2(gfx_compound_rsp *rsp, int len)
{
    int i = 0;
    compound_rsp_v2 *this_rsp = NULL;

    for (i = 0; i < len; i++) {
        this_rsp = &rsp->compound_rsp_array.compound_rsp_array_val[i];
        switch (this_rsp->fop_enum) {
            /* fops that need extra cleanup */
            case GF_FOP_LK: {
                gfx_lk_rsp *tmp_rsp = &CPD4_RSP_FIELD(this_rsp, lk);
                free(tmp_rsp->flock.lk_owner.lk_owner_val);
                break;
            }
            case GF_FOP_READLINK: {
                gfx_readlink_rsp *tmp_rsp = &CPD4_RSP_FIELD(this_rsp, readlink);
                free(tmp_rsp->path);
                break;
            }
            case GF_FOP_READDIR: {
                gfx_readdir_rsp *tmp_rsp = &CPD4_RSP_FIELD(this_rsp, readdir);
                clnt_readdir_rsp_cleanup_v2(tmp_rsp);
                break;
            }
            case GF_FOP_READDIRP: {
                gfx_readdirp_rsp *tmp_rsp = &CPD4_RSP_FIELD(this_rsp, readdirp);
                clnt_readdirp_rsp_cleanup_v2(tmp_rsp);
                break;
            }
            case GF_FOP_RCHECKSUM: {
                gfx_rchecksum_rsp *rck = &CPD4_RSP_FIELD(this_rsp, rchecksum);
                if (rck->strong_checksum.strong_checksum_val) {
                    free(rck->strong_checksum.strong_checksum_val);
                }
                break;
            }
            default:
                break;
        }
    }
    return;
}

int
client_process_response_v2(call_frame_t *frame, xlator_t *this,
                           struct rpc_req *req, gfx_compound_rsp *rsp,
                           compound_args_cbk_t *args_cbk, int index)
{
    int ret = 0;
    dict_t *xdata = NULL;
    dict_t *xattr = NULL;
    struct iovec vector[MAX_IOVEC] = {
        {0},
    };
    gf_dirent_t entries;
    default_args_cbk_t *this_args_cbk = &args_cbk->rsp_list[index];
    clnt_local_t *local = frame->local;
    compound_rsp_v2 *this_rsp = NULL;
    compound_args_t *args = local->compound_args;

    this_rsp = &rsp->compound_rsp_array.compound_rsp_array_val[index];
    args_cbk->enum_list[index] = this_rsp->fop_enum;

    INIT_LIST_HEAD(&entries.list);

    switch (args_cbk->enum_list[index]) {
        case GF_FOP_STAT:
        case GF_FOP_FSTAT: {
            gfx_common_iatt_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_stat_rsp;

            client_post_common_iatt(this, tmp_rsp, &this_args_cbk->stat,
                                    &xdata);

            CLIENT4_POST_FOP_TYPE(stat, common_iatt, this_rsp, this_args_cbk,
                                  &this_args_cbk->stat, xdata);
            break;
        }
        case GF_FOP_READLINK: {
            gfx_readlink_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_readlink_rsp;

            gfx_stat_to_iattx(&tmp_rsp->buf, &this_args_cbk->stat);
            xdr_to_dict(&tmp_rsp->xdata, &xdata);

            CLIENT4_POST_FOP_TYPE(readlink, readlink, this_rsp, this_args_cbk,
                                  tmp_rsp->path, &this_args_cbk->stat, xdata);
            break;
        }
        case GF_FOP_MKDIR:
        case GF_FOP_MKNOD:
        case GF_FOP_SYMLINK:
        case GF_FOP_LINK: {
            gfx_common_3iatt_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_mknod_rsp;

            client_post_common_3iatt(this, tmp_rsp, &this_args_cbk->stat,
                                     &this_args_cbk->preparent,
                                     &this_args_cbk->postparent, &xdata);
            CLIENT4_POST_FOP_TYPE(mknod, common_3iatt, this_rsp, this_args_cbk,
                                  local->loc.inode, &this_args_cbk->stat,
                                  &this_args_cbk->preparent,
                                  &this_args_cbk->postparent, xdata);
            break;
        }
        case GF_FOP_UNLINK:
        case GF_FOP_RMDIR: {
            gfx_common_2iatt_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_unlink_rsp;

            client_post_common_2iatt(this, tmp_rsp, &this_args_cbk->preparent,
                                     &this_args_cbk->postparent, &xdata);
            CLIENT4_POST_FOP_TYPE(unlink, common_2iatt, this_rsp, this_args_cbk,
                                  &this_args_cbk->preparent,
                                  &this_args_cbk->postparent, xdata);
            break;
        }
        case GF_FOP_RENAME: {
            gfx_rename_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_rename_rsp;

            client_post_rename_v2(
                this, tmp_rsp, &this_args_cbk->stat, &this_args_cbk->preparent,
                &this_args_cbk->postparent, &this_args_cbk->preparent2,
                &this_args_cbk->postparent2, &xdata);
            CLIENT4_POST_FOP_TYPE(
                rename, rename, this_rsp, this_args_cbk, &this_args_cbk->stat,
                &this_args_cbk->preparent, &this_args_cbk->postparent,
                &this_args_cbk->preparent2, &this_args_cbk->postparent2, xdata);
            break;
        }
        case GF_FOP_WRITE:
        case GF_FOP_TRUNCATE:
        case GF_FOP_FTRUNCATE:
        case GF_FOP_FSYNC:
        case GF_FOP_ZEROFILL:
        case GF_FOP_DISCARD:
        case GF_FOP_FALLOCATE:
        case GF_FOP_FSETATTR:
        case GF_FOP_SETATTR: {
            gfx_common_2iatt_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_truncate_rsp;

            client_post_common_2iatt(this, tmp_rsp, &this_args_cbk->prestat,
                                     &this_args_cbk->poststat, &xdata);
            CLIENT4_POST_FOP_TYPE(truncate, common_2iatt, this_rsp,
                                  this_args_cbk, &this_args_cbk->prestat,
                                  &this_args_cbk->poststat, xdata);
            break;
        }
        case GF_FOP_OPEN: {
            gfx_open_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_open_rsp;

            xdr_to_dict(&tmp_rsp->xdata, &xdata);
            CLIENT4_POST_FOP_TYPE(open, open, this_rsp, this_args_cbk,
                                  local->fd, xdata);
            if (-1 != this_args_cbk->op_ret)
                ret = client_add_fd_to_saved_fds(this, local->fd, &local->loc,
                                                 args->req_list[index].flags,
                                                 tmp_rsp->fd, 0);
            break;
        }
        case GF_FOP_READ: {
            gfx_read_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_read_rsp;

            client_post_readv_v2(this, tmp_rsp, &this_args_cbk->iobref,
                                 req->rsp_iobref, &this_args_cbk->stat, vector,
                                 &req->rsp[1], &this_args_cbk->count, &xdata);

            /* Each read should be given read response that only
             * corresponds to its request.
             * Modify the iovecs accordingly.
             * After each read, store the length of data already read
             * so that the next ones can continue from there.
             */
            if (local->read_length) {
                vector[0].iov_base += local->read_length;
                local->read_length += tmp_rsp->op_ret;
            } else {
                local->read_length = tmp_rsp->op_ret;
            }

            args_readv_cbk_store(this_args_cbk, tmp_rsp->op_ret,
                                 gf_error_to_errno(tmp_rsp->op_errno), vector,
                                 this_args_cbk->count, &this_args_cbk->stat,
                                 this_args_cbk->iobref, xdata);

            if (tmp_rsp->op_ret >= 0)
                if (local->attempt_reopen)
                    client_attempt_reopen(local->fd, this);

            break;
        }
        case GF_FOP_STATFS: {
            gfx_statfs_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_statfs_rsp;

            gf_statfs_to_statfs(&tmp_rsp->statfs, &this_args_cbk->statvfs);
            xdr_to_dict(&tmp_rsp->xdata, &xdata);

            CLIENT4_POST_FOP_TYPE(statfs, statfs, this_rsp, this_args_cbk,
                                  &this_args_cbk->statvfs, xdata);
            break;
        }
        case GF_FOP_FLUSH: {
            gfx_common_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_flush_rsp;

            xdr_to_dict(&tmp_rsp->xdata, &xdata);

            CLIENT4_POST_FOP(flush, this_rsp, this_args_cbk, xdata);
            if (this_args_cbk->op_ret >= 0 && !fd_is_anonymous(local->fd)) {
                /* Delete all saved locks of the owner issuing flush */
                ret = delete_granted_locks_owner(local->fd, &local->owner);
                gf_msg_trace(this->name, 0,
                             "deleting locks of owner (%s) returned %d",
                             lkowner_utoa(&local->owner), ret);
            }
            break;
        }
        case GF_FOP_FSYNCDIR:
        case GF_FOP_ACCESS:
        case GF_FOP_REMOVEXATTR:
        case GF_FOP_FREMOVEXATTR:
        case GF_FOP_FSETXATTR:
        case GF_FOP_SETXATTR:
        case GF_FOP_INODELK:
        case GF_FOP_FINODELK:
        case GF_FOP_ENTRYLK:
        case GF_FOP_FENTRYLK:
        case GF_FOP_IPC: {
            gfx_common_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_setxattr_rsp;

            xdr_to_dict(&tmp_rsp->xdata, &xdata);

            CLIENT4_POST_FOP(setxattr, this_rsp, this_args_cbk, xdata);
            break;
        }
        case GF_FOP_GETXATTR:
        case GF_FOP_FGETXATTR:
        case GF_FOP_XATTROP:
        case GF_FOP_FXATTROP: {
            gfx_common_dict_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_getxattr_rsp;

            ret = client_post_common_dict(this, tmp_rsp, &xattr, &xdata);
            if (ret) {
                tmp_rsp->op_errno = -ret;
                goto out;
            }

            CLIENT4_POST_FOP_TYPE(getxattr, common_dict, this_rsp,
                                  this_args_cbk, xattr, xdata);
            break;
        }
        case GF_FOP_OPENDIR: {
            gfx_open_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_opendir_rsp;

            xdr_to_dict(&tmp_rsp->xdata, &xdata);

            CLIENT4_POST_FOP_TYPE(opendir, open, this_rsp, this_args_cbk,
                                  local->fd, xdata);
            if (-1 != this_args_cbk->op_ret)
                ret = client_add_fd_to_saved_fds(this, local->fd, &local->loc,
                                                 args->req_list[index].flags,
                                                 tmp_rsp->fd, 0);
            break;
        }
        case GF_FOP_CREATE: {
            gfx_create_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_create_rsp;

            client_post_create_v2(this, tmp_rsp, &this_args_cbk->stat,
                                  &this_args_cbk->preparent,
                                  &this_args_cbk->postparent, local, &xdata);

            CLIENT4_POST_FOP_TYPE(
                create, create, this_rsp, this_args_cbk, local->fd,
                local->loc.inode, &this_args_cbk->stat,
                &this_args_cbk->preparent, &this_args_cbk->postparent, xdata);
            if (-1 != this_args_cbk->op_ret)
                ret = client_add_fd_to_saved_fds(this, local->fd, &local->loc,
                                                 args->req_list[index].flags,
                                                 tmp_rsp->fd, 0);
            break;
        }
        case GF_FOP_LK: {
            gfx_lk_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_lk_rsp;

            client_post_lk_v2(this, tmp_rsp, &this_args_cbk->lock, &xdata);

            CLIENT4_POST_FOP_TYPE(lk, lk, this_rsp, this_args_cbk,
                                  &this_args_cbk->lock, xdata);
            break;
        }
        case GF_FOP_LOOKUP: {
            gfx_common_2iatt_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_lookup_rsp;

            client_post_common_2iatt(this, tmp_rsp, &this_args_cbk->stat,
                                     &this_args_cbk->postparent, &xdata);
            CLIENT4_POST_FOP_TYPE(lookup, common_2iatt, this_rsp, this_args_cbk,
                                  local->loc.inode, &this_args_cbk->stat, xdata,
                                  &this_args_cbk->postparent);
            break;
        }
        case GF_FOP_READDIR: {
            gfx_readdir_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_readdir_rsp;

            client_post_readdir_v2(this, tmp_rsp, &entries, &xdata);

            CLIENT4_POST_FOP_TYPE(readdir, readdir, this_rsp, this_args_cbk,
                                  &entries, xdata);
            break;
        }
        case GF_FOP_RCHECKSUM: {
            gfx_rchecksum_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_rchecksum_rsp;

            xdr_to_dict(&tmp_rsp->xdata, &xdata);

            CLIENT4_POST_FOP_TYPE(
                rchecksum, rchecksum, this_rsp, this_args_cbk,
                tmp_rsp->weak_checksum,
                (uint8_t *)tmp_rsp->strong_checksum.strong_checksum_val, xdata);
            break;
        }
        case GF_FOP_READDIRP: {
            gfx_readdirp_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_readdirp_rsp;

            client_post_readdirp_v2(this, tmp_rsp, local->fd, &entries, &xdata);

            CLIENT4_POST_FOP_TYPE(readdirp, readdirp, this_rsp, this_args_cbk,
                                  &entries, xdata);
            break;
        }
        case GF_FOP_SEEK: {
            gfx_seek_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_seek_rsp;

            xdr_to_dict(&tmp_rsp->xdata, &xdata);

            CLIENT4_POST_FOP_TYPE(seek, seek, this_rsp, this_args_cbk,
                                  tmp_rsp->offset, xdata);
            break;
        }
        case GF_FOP_LEASE: {
            gfx_lease_rsp *tmp_rsp = NULL;
            tmp_rsp = &this_rsp->compound_rsp_v2_u.compound_lease_rsp;

            client_post_lease_v2(this, tmp_rsp, &this_args_cbk->lease, &xdata);

            CLIENT4_POST_FOP_TYPE(lease, lease, this_rsp, this_args_cbk,
                                  &this_args_cbk->lease, xdata);
            break;
        }
        case GF_FOP_COPY_FILE_RANGE:
            /*
             * Not handling this fop. Returning ENOTSUP. Check
             * the comment added for this fop in the function
             * client_handle_fop_requirements_v2.
             */
        default:
            return -ENOTSUP;
    }

out:
    if (xdata)
        dict_unref(xdata);
    if (xattr)
        dict_unref(xattr);
    gf_dirent_free(&entries);
    return 0;
}

extern int
client3_3_releasedir_cbk(struct rpc_req *req, struct iovec *iov, int count,
                         void *myframe);
extern int
client3_3_release_cbk(struct rpc_req *req, struct iovec *iov, int count,
                      void *myframe);
extern int
client4_0_releasedir_cbk(struct rpc_req *req, struct iovec *iov, int count,
                         void *myframe);
extern int
client4_0_release_cbk(struct rpc_req *req, struct iovec *iov, int count,
                      void *myframe);

static int
send_release4_0_over_wire(xlator_t *this, clnt_fd_ctx_t *fdctx,
                          call_frame_t *fr)
{
    clnt_conf_t *conf = NULL;
    conf = (clnt_conf_t *)this->private;
    if (fdctx->is_dir) {
        gfx_releasedir_req req = {
            {
                0,
            },
        };
        memcpy(req.gfid, fdctx->gfid, 16);
        req.fd = fdctx->remote_fd;

        gf_msg_trace(this->name, 0, "sending releasedir on fd");
        (void)client_submit_request(
            this, &req, fr, conf->fops, GFS3_OP_RELEASEDIR,
            client4_0_releasedir_cbk, NULL, (xdrproc_t)xdr_gfx_releasedir_req);
    } else {
        gfx_release_req req = {
            {
                0,
            },
        };
        memcpy(req.gfid, fdctx->gfid, 16);
        req.fd = fdctx->remote_fd;
        gf_msg_trace(this->name, 0, "sending release on fd");
        (void)client_submit_request(this, &req, fr, conf->fops, GFS3_OP_RELEASE,
                                    client4_0_release_cbk, NULL,
                                    (xdrproc_t)xdr_gfx_release_req);
    }

    return 0;
}

static int
send_release3_3_over_wire(xlator_t *this, clnt_fd_ctx_t *fdctx,
                          call_frame_t *fr)
{
    clnt_conf_t *conf = NULL;
    conf = (clnt_conf_t *)this->private;
    if (fdctx->is_dir) {
        gfs3_releasedir_req req = {
            {
                0,
            },
        };
        memcpy(req.gfid, fdctx->gfid, 16);
        req.fd = fdctx->remote_fd;
        gf_msg_trace(this->name, 0, "sending releasedir on fd");
        (void)client_submit_request(
            this, &req, fr, conf->fops, GFS3_OP_RELEASEDIR,
            client3_3_releasedir_cbk, NULL, (xdrproc_t)xdr_gfs3_releasedir_req);
    } else {
        gfs3_release_req req = {
            {
                0,
            },
        };
        memcpy(req.gfid, fdctx->gfid, 16);
        req.fd = fdctx->remote_fd;
        gf_msg_trace(this->name, 0, "sending release on fd");
        (void)client_submit_request(this, &req, fr, conf->fops, GFS3_OP_RELEASE,
                                    client3_3_release_cbk, NULL,
                                    (xdrproc_t)xdr_gfs3_release_req);
    }

    return 0;
}

int
client_fdctx_destroy(xlator_t *this, clnt_fd_ctx_t *fdctx)
{
    clnt_conf_t *conf = NULL;
    call_frame_t *fr = NULL;
    int32_t ret = -1;
    char parent_down = 0;
    fd_lk_ctx_t *lk_ctx = NULL;

    GF_VALIDATE_OR_GOTO("client", this, out);
    GF_VALIDATE_OR_GOTO(this->name, fdctx, out);

    conf = (clnt_conf_t *)this->private;

    if (fdctx->remote_fd == -1) {
        gf_msg_debug(this->name, 0, "not a valid fd");
        goto out;
    }

    pthread_mutex_lock(&conf->lock);
    {
        parent_down = conf->parent_down;
    }
    pthread_mutex_unlock(&conf->lock);
    lk_ctx = fdctx->lk_ctx;
    fdctx->lk_ctx = NULL;

    if (lk_ctx)
        fd_lk_ctx_unref(lk_ctx);

    if (!parent_down)
        rpc_clnt_ref(conf->rpc);
    else
        goto out;

    fr = create_frame(this, this->ctx->pool);
    if (fr == NULL) {
        goto out;
    }

    ret = 0;

    if (conf->fops->progver == GLUSTER_FOP_VERSION)
        send_release3_3_over_wire(this, fdctx, fr);
    else
        send_release4_0_over_wire(this, fdctx, fr);

    rpc_clnt_unref(conf->rpc);
out:
    if (fdctx) {
        fdctx->remote_fd = -1;
        GF_FREE(fdctx);
    }

    return ret;
}
