diff options
Diffstat (limited to 'xlators/nfs/server/src/nfs-fops.c')
-rw-r--r-- | xlators/nfs/server/src/nfs-fops.c | 1441 |
1 files changed, 1441 insertions, 0 deletions
diff --git a/xlators/nfs/server/src/nfs-fops.c b/xlators/nfs/server/src/nfs-fops.c new file mode 100644 index 000000000..3d4968a8b --- /dev/null +++ b/xlators/nfs/server/src/nfs-fops.c @@ -0,0 +1,1441 @@ +/* + Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "dict.h" +#include "xlator.h" +#include "iobuf.h" +#include "call-stub.h" +#include "stack.h" +#include "nfs.h" +#include "nfs-fops.h" +#include "inode.h" +#include "nfs-common.h" + +#include <libgen.h> +#include <semaphore.h> + +#define nfs_stack_destroy(fram) \ + do { \ + (fram)->local = NULL; \ + STACK_DESTROY ((fram)->root); \ + } while (0) \ + + +struct nfs_fop_local * +nfs_fop_local_init (xlator_t *xl) +{ + struct nfs_fop_local *l = NULL; + struct nfs_state *nfs = NULL; + if (!xl) + return NULL; + + nfs = xlator_top_private (xl); + l = mem_get (nfs->foppool); + + memset (l, 0, sizeof (*l)); + return l; +} + +void +nfs_fop_local_wipe (xlator_t *xl, struct nfs_fop_local *l) +{ + struct nfs_state *nfs = NULL; + + if ((!xl) || (!l)) + return; + + nfs = xlator_top_private (xl); + + if (l->iobref) + iobref_unref (l->iobref); + + if (l->parent) + inode_unref (l->parent); + + if (l->inode) + inode_unref (l->inode); + + if (l->newparent) + inode_unref (l->newparent); + + mem_put (nfs->foppool, l); + + return; +} + +call_frame_t * +nfs_create_frame (xlator_t *xl, nfs_user_t *nfu) +{ + call_frame_t *frame = NULL; + int x = 0; + int y = 0; + + if ((!xl) || (!nfu) || (nfu->ngrps > NFS_NGROUPS)) + return NULL; + + frame = create_frame (xl, (call_pool_t *)xl->ctx->pool); + if (!frame) + goto err; + frame->root->uid = nfu->uid; + frame->root->gid = nfu->gids[NFS_PRIMGID_IDX]; + if (nfu->ngrps == 1) + goto err; /* Done, we only got primary gid */ + + frame->root->ngrps = nfu->ngrps - 1; + + gf_log (GF_NFS, GF_LOG_TRACE,"uid: %d, gid %d, gids: %d", + frame->root->uid, frame->root->gid, frame->root->ngrps); + for(y = 0, x = 1; y < frame->root->ngrps; x++,y++) { + gf_log (GF_NFS, GF_LOG_TRACE, "gid: %d", nfu->gids[x]); + frame->root->groups[y] = nfu->gids[x]; + } + +err: + return frame; +} + +#define nfs_fop_handle_frame_create(fram, xla, nfuser, retval, errlabel) \ + do { \ + fram = nfs_create_frame (xla, (nfuser)); \ + if (!fram) { \ + retval = (-ENOMEM); \ + gf_log (GF_NFS, GF_LOG_ERROR,"Frame creation failed");\ + goto errlabel; \ + } \ + } while (0) \ + +/* Look into the inode and parent inode of a loc and save enough state + * for us to determine in the callback whether to funge the ino in the stat buf + * with 1 for the parent. + */ +#define nfs_fop_save_root_ino(locl, loc) \ + do { \ + if ((loc)->ino == 1) \ + (locl)->rootinode = 1; \ + else if (((loc)->parent) && ((loc)->parent->ino == 1)) \ + (locl)->rootparentinode = 1; \ + } while (0) \ + +/* Do the same for an fd */ +#define nfs_fop_save_root_fd_ino(locl, fdesc) \ + do { \ + if ((fdesc)->inode->ino == 1) \ + (locl)->rootinode = 1; \ + } while (0) \ + + + +/* Use the state saved by the previous macro to funge the ino in the appropriate + * structure. + */ +#define nfs_fop_restore_root_ino(locl, preattr, postattr, prepar, postpar) \ + do { \ + if ((locl)->rootinode) { \ + if ((preattr)) { \ + ((struct iatt *)(preattr))->ia_ino = 1; \ + ((struct iatt *)(preattr))->ia_dev = 0; \ + } \ + if ((postattr)) { \ + ((struct iatt *)(postattr))->ia_ino = 1; \ + ((struct iatt *)(postattr))->ia_dev = 0; \ + } \ + } else if ((locl)->rootparentinode) { \ + if ((prepar)) { \ + ((struct iatt *)(prepar))->ia_ino = 1; \ + ((struct iatt *)(prepar))->ia_dev = 0; \ + } \ + if ((postpar)) { \ + ((struct iatt *)(postpar))->ia_ino = 1; \ + ((struct iatt *)(postpar))->ia_dev = 0; \ + } \ + } \ + } while (0) \ + +/* If the newly created, inode's parent is root, we'll need to funge the ino + * in the parent attr when we receive them in the callback. + */ +#define nfs_fop_newloc_save_root_ino(locl, newloc) \ + do { \ + if ((newloc)->ino == 1) \ + (locl)->newrootinode = 1; \ + else if (((newloc)->parent) && ((newloc)->parent->ino == 1)) \ + (locl)->newrootparentinode = 1; \ + } while (0) \ + + +#define nfs_fop_newloc_restore_root_ino(locl, preattr, postattr, prepar, postpar) \ + do { \ + if ((locl)->newrootinode) { \ + if ((preattr)) \ + ((struct iatt *)(preattr))->ia_ino = 1; \ + if ((postattr)) \ + ((struct iatt *)(postattr))->ia_ino = 1; \ + } else if ((locl)->newrootparentinode) { \ + if ((prepar)) \ + ((struct iatt *)(prepar))->ia_ino = 1; \ + if ((postpar)) \ + ((struct iatt *)(postpar))->ia_ino = 1; \ + } \ + } while (0) \ + +/* Fops Layer Explained + * The fops layer has three types of functions. They can all be identified by + * their names. Here are the three patterns: + * + * nfs_fop_<fopname> + * This is the lowest level function that knows nothing about states and + * callbacks. At most this is required to create a frame and call the + * fop. The idea here is to provide a convenient way to call fops than + * directly use STACK_WINDs. If this type of interface is used, the caller's + * callback is responsible for doing the relevant GlusterFS state + * maintenance operations on the data returned in the callbacks. + * + * nfs_fop_<fopname>_sync + * These are synchronous versions of the above fops. The idea is that + * if the user wants to wait for the fop to complete, this is the interface to + * use. The caller is responsible for doing the relevant GlusterFS + * state maintenance operations on the call_stub_t that is returned, including + * calling call_stub_destroy. + * + * nfs_<fopname>_sync + * This is help callers avoid the need to pass a pathloc to the + * nfs_fop_<fopname>_sync versions of the same fops. + * + * nfs_<fopname> + * Unlike the nfs_fop_<fopname> variety, this is the stateful type of fop, in + * that it silently performs all the relevant GlusterFS state maintainence + * operations on the data returned to the callbacks, leaving the caller's + * callback to just use the data returned for whatever it needs to do with that + * data, for eg. the nfs_lookup, will take care of looking up the inodes, + * revalidating them if needed and linking new inodes into the table, while + * the caller's callback, for eg, the NFSv3 LOOKUP callback can just use + * the stat bufs returned to create file handle, map the file handle into the + * fh cache and finally encode the fh and the stat bufs into a NFS reply. + * + */ + +int32_t +nfs_fop_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, dict_t *xattr, struct iatt *postparent) +{ + struct nfs_fop_local *local = NULL; + fop_lookup_cbk_t progcbk; + + nfl_to_prog_data (this, local, progcbk, frame); + nfs_fop_restore_root_ino (local, buf, NULL, NULL, postparent); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, + xattr, postparent); + + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_lookup (xlator_t *xl, nfs_user_t *nfu, loc_t *loc, + fop_lookup_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!loc) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Lookup: %s", loc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, loc); + + STACK_WIND_COOKIE (frame, nfs_fop_lookup_cbk, xl, xl, xl->fops->lookup, + loc, NULL); + + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf) +{ + struct nfs_fop_local *nfl = NULL; + fop_stat_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, buf, NULL, NULL, NULL); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, buf); + + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_stat (xlator_t *xl, nfs_user_t *nfu, loc_t *loc, + fop_stat_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!loc) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Stat: %s", loc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, loc); + + STACK_WIND_COOKIE (frame, nfs_fop_stat_cbk, xl, xl, xl->fops->stat, + loc); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_fstat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf) +{ + struct nfs_fop_local *nfl = NULL; + fop_fstat_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, buf, NULL, NULL, NULL); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, buf); + + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_fstat (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, + fop_fstat_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!fd) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "FStat"); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_fd_ino (nfl, fd); + + STACK_WIND_COOKIE (frame, nfs_fop_fstat_cbk, xl, xl, xl->fops->fstat, + fd); + + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_opendir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd) +{ + struct nfs_fop_local *nfl = NULL; + fop_opendir_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, fd); + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_opendir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,fd_t *dirfd, + fop_opendir_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!pathloc) || (!dirfd) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Opendir: %s", pathloc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + + STACK_WIND_COOKIE (frame, nfs_fop_opendir_cbk, xl, xl, + xl->fops->opendir, pathloc, dirfd); + ret = 0; + +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + +int +nfs_fop_flush_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + struct nfs_fop_local *nfl = NULL; + fop_flush_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno); + + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_flush (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, + fop_flush_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!fd) || (!nfu)) + return ret; + + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + + STACK_WIND_COOKIE (frame, nfs_fop_flush_cbk, xl, xl, xl->fops->flush, + fd); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_readdirp_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries) +{ + struct nfs_fop_local *nfl = NULL; + fop_readdirp_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, entries); + + nfs_stack_destroy (frame); + + return 0; +} + + +int +nfs_fop_readdirp (xlator_t *xl, nfs_user_t *nfu, fd_t *dirfd, + size_t bufsize, off_t offset, fop_readdirp_cbk_t cbk, + void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!dirfd) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "readdir"); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + + STACK_WIND_COOKIE (frame, nfs_fop_readdirp_cbk, xl, xl, + xl->fops->readdirp, dirfd, bufsize, offset); + + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct statvfs *buf) +{ + + struct nfs_fop_local *nfl = NULL; + fop_statfs_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, buf); + + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_statfs (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, + fop_statfs_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!pathloc) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Statfs: %s", pathloc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + + STACK_WIND_COOKIE (frame, nfs_fop_statfs_cbk, xl, xl, xl->fops->statfs + ,pathloc); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent) +{ + struct nfs_fop_local *nfl = NULL; + fop_create_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, fd, inode, buf, + preparent, postparent); + + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_create (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int flags, + mode_t mode, fd_t *fd, fop_create_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!pathloc) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Create: %s", pathloc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, pathloc); + + STACK_WIND_COOKIE (frame, nfs_fop_create_cbk, xl, xl, xl->fops->create + , pathloc, flags, mode, fd); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *pre, + struct iatt *post) +{ + struct nfs_fop_local *nfl = NULL; + fop_setattr_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, pre, post, NULL, NULL); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, pre, post); + nfs_stack_destroy (frame); + return 0; +} + + + +int +nfs_fop_setattr (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, + struct iatt *buf, int32_t valid, fop_setattr_cbk_t cbk, + void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!pathloc) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Setattr: %s", pathloc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, pathloc); + + STACK_WIND_COOKIE (frame, nfs_fop_setattr_cbk, xl, xl, + xl->fops->setattr, pathloc, buf, valid); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent) +{ + struct nfs_fop_local *nfl = NULL; + fop_mkdir_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, + preparent, postparent); + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_mkdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, mode_t mode, + fop_mkdir_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!pathloc) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Mkdir: %s", pathloc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, pathloc); + + STACK_WIND_COOKIE (frame, nfs_fop_mkdir_cbk, xl, xl, xl->fops->mkdir, + pathloc, mode); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_symlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent) +{ + struct nfs_fop_local *nfl = NULL; + fop_symlink_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, + preparent, postparent); + nfs_stack_destroy (frame); + return 0; +} + +int +nfs_fop_symlink (xlator_t *xl, nfs_user_t *nfu, char *target, + loc_t *pathloc, fop_symlink_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!pathloc) || (!target) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Symlink: %s", pathloc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, pathloc); + + STACK_WIND_COOKIE (frame, nfs_fop_symlink_cbk, xl, xl, + xl->fops->symlink, target, pathloc); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, const char *path, + struct iatt *buf) +{ + struct nfs_fop_local *nfl = NULL; + fop_readlink_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, buf, NULL, NULL, NULL); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, path, buf); + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_readlink (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, + size_t size, fop_readlink_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!pathloc) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Readlink: %s", pathloc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, pathloc); + + STACK_WIND_COOKIE (frame, nfs_fop_readlink_cbk, xl, xl, + xl->fops->readlink, pathloc, size); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent) +{ + struct nfs_fop_local *nfl = NULL; + fop_mknod_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, + preparent, postparent); + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_mknod (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, mode_t mode, + dev_t dev, fop_mknod_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!pathloc) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Mknod: %s", pathloc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, pathloc); + + STACK_WIND_COOKIE (frame, nfs_fop_mknod_cbk, xl, xl, xl->fops->mknod, + pathloc, mode, dev); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; + +} + +int32_t +nfs_fop_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *preparent, + struct iatt *postparent) +{ + struct nfs_fop_local *nfl = frame->local; + fop_rmdir_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, NULL, NULL, preparent, postparent); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, preparent, + postparent); + nfs_stack_destroy (frame); + return 0; +} + + + +int +nfs_fop_rmdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, + fop_rmdir_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!pathloc) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Rmdir: %s", pathloc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, pathloc); + + STACK_WIND_COOKIE (frame, nfs_fop_rmdir_cbk, xl, xl, xl->fops->rmdir, + pathloc); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; + +} + + +int32_t +nfs_fop_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *preparent, + struct iatt *postparent) +{ + struct nfs_fop_local *nfl = frame->local; + fop_unlink_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, NULL, NULL, preparent, postparent); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, preparent, + postparent); + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_unlink (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, + fop_unlink_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!pathloc) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Unlink: %s", pathloc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, pathloc); + + STACK_WIND_COOKIE (frame, nfs_fop_unlink_cbk, xl, xl, xl->fops->unlink, + pathloc); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; + +} + + +int32_t +nfs_fop_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent) +{ + struct nfs_fop_local *nfl = NULL; + fop_link_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, + preparent, postparent); + + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_link (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc, loc_t *newloc, + fop_link_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!oldloc) || (!newloc) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Link: %s -> %s", newloc->path, + oldloc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, newloc); + + STACK_WIND_COOKIE (frame, nfs_fop_link_cbk, xl, xl, xl->fops->link, + oldloc, newloc); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent) +{ + + struct nfs_fop_local *nfl = NULL; + fop_rename_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + /* The preattr arg needs to be NULL instead of @buf because it is + * possible that the new parent is not root whereas the source dir + * could've been. That is handled in the next macro. + */ + nfs_fop_restore_root_ino (nfl, NULL, NULL, preoldparent, postoldparent); + nfs_fop_newloc_restore_root_ino (nfl, buf, NULL, prenewparent, + postnewparent); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, buf, + preoldparent, postoldparent, prenewparent, + postnewparent); + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_rename (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc, + loc_t *newloc, fop_rename_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!oldloc) || (!newloc) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Rename: %s -> %s", oldloc->path, + newloc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, oldloc); + nfs_fop_newloc_save_root_ino (nfl, newloc); + + STACK_WIND_COOKIE (frame, nfs_fop_rename_cbk, xl, xl, xl->fops->rename, + oldloc, newloc); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd) +{ + struct nfs_fop_local *nfl = NULL; + fop_open_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, fd); + nfs_stack_destroy (frame); + + return 0; +} + +int +nfs_fop_open (xlator_t *xl, nfs_user_t *nfu, loc_t *loc, int32_t flags, + fd_t *fd, int32_t wbflags, fop_open_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!loc) || (!fd) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Open: %s", loc->path); + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + + STACK_WIND_COOKIE (frame, nfs_fop_open_cbk, xl, xl, xl->fops->open, + loc, flags, fd, wbflags); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; + +} + + +int32_t +nfs_fop_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + struct nfs_fop_local *nfl = NULL; + fop_writev_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, prebuf, postbuf, NULL, NULL); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, prebuf,postbuf); + + nfs_stack_destroy (frame); + + return 0; +} + + +int +nfs_fop_write (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, struct iobuf *srciob, + struct iovec *vector, int32_t count, off_t offset, + fop_writev_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!fd) || (!vector) || (!nfu) || (!srciob)) + return ret; + + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_fd_ino (nfl, fd); + + nfl->iobref = iobref_new (); + if (!nfl->iobref) { + gf_log (GF_NFS, GF_LOG_ERROR, "iobref creation failed"); + ret = -ENOMEM; + goto err; + } + + iobref_add (nfl->iobref, srciob); + STACK_WIND_COOKIE (frame, nfs_fop_writev_cbk, xl, xl, xl->fops->writev + , fd, vector, count, offset, nfl->iobref); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + nfs_fop_local_wipe (xl, nfl); + } + + return ret; +} + + +int32_t +nfs_fop_fsync_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + struct nfs_fop_local *nfl = NULL; + fop_fsync_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, prebuf, postbuf, NULL, NULL); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, prebuf,postbuf); + nfs_stack_destroy (frame); + return 0; +} + + + +int +nfs_fop_fsync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, int32_t datasync, + fop_fsync_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!fd)) + return ret; + + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_fd_ino (nfl, fd); + + STACK_WIND_COOKIE (frame, nfs_fop_fsync_cbk, xl, xl, + xl->fops->fsync, fd, datasync); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_readv_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iovec *vector, + int32_t count, struct iatt *stbuf, struct iobref *iobref) +{ + struct nfs_fop_local *nfl = NULL; + fop_readv_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, stbuf, NULL, NULL, NULL); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, vector, count, + stbuf, iobref); + + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_read (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, size_t size, + off_t offset, fop_readv_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!fd) || (!nfu)) + return ret; + + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_fd_ino (nfl, fd); + + STACK_WIND_COOKIE (frame, nfs_fop_readv_cbk, xl, xl, xl->fops->readv, fd + , size, offset); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int32_t +nfs_fop_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + struct nfs_fop_local *nfl = NULL; + fop_truncate_cbk_t progcbk = NULL; + + nfl_to_prog_data (this, nfl, progcbk, frame); + nfs_fop_restore_root_ino (nfl, prebuf, postbuf, NULL, NULL); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, prebuf,postbuf); + + nfs_stack_destroy (frame); + return 0; +} + + +int +nfs_fop_truncate (xlator_t *xl, nfs_user_t *nfu, loc_t *loc, off_t offset, + fop_truncate_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!loc) || (!nfu)) + return ret; + + nfs_fop_handle_frame_create (frame, xl, nfu, ret, err); + nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, loc); + + STACK_WIND_COOKIE (frame, nfs_fop_truncate_cbk, xl, xl, + xl->fops->truncate, loc, offset); + + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (frame); + } + + return ret; +} + + +int +nfs_fop_lookup_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, dict_t *xattr, + struct iatt *postparent) +{ + nfs_syncfop_t *sf = frame->local; + + if (!sf) + return -1; + + if (op_ret == -1) + gf_log (GF_NFS, GF_LOG_TRACE, "Sync lookup failed: %s", + strerror (op_errno)); + else + gf_log (GF_NFS, GF_LOG_TRACE, "Sync lookup done"); + + sf->replystub = fop_lookup_cbk_stub (frame, NULL, op_ret, op_errno, + inode, buf, xattr, postparent); + nfs_syncfop_notify (sf); + return 0; +} + + +call_stub_t * +nfs_fop_lookup_sync (xlator_t *xl, nfs_user_t *nfu, loc_t *loc) +{ + nfs_syncfop_t *sf = NULL; + call_stub_t *reply = NULL; + int ret = -1; + + if ((!xl) || (!loc) || (!nfu)) + return NULL; + + sf = nfs_syncfop_init (); + if (!sf) { + gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed"); + goto err; + } + + ret = nfs_fop_lookup (xl, nfu, loc, nfs_fop_lookup_sync_cbk, sf); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "Sync lookup failed"); + goto err; + } + + reply = nfs_syncfop_wait (sf); + +err: + return reply; +} + + + +int32_t +nfs_fop_readdirp_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + gf_dirent_t *entries) +{ + nfs_syncfop_t *sf = frame->local; + + if (op_ret == -1) + gf_log (GF_NFS, GF_LOG_TRACE, "Sync readdir failed: %s", + strerror (op_errno)); + else + gf_log (GF_NFS, GF_LOG_TRACE, "Sync readdir done"); + + sf->replystub = fop_readdirp_cbk_stub (frame, NULL, op_ret, op_errno, + entries); + + nfs_syncfop_notify (sf); + return 0; +} + + +/* This function does not update or map the st_dev in the d_stat of all the + * entries that were read. That mapping for the sync version of readdiring + * happens in the dcache. + */ +call_stub_t * +nfs_fop_readdirp_sync (xlator_t *fopxl, nfs_user_t *nfu, fd_t *dirfd, + off_t offset, size_t bufsize) +{ + nfs_syncfop_t *sf = NULL; + call_stub_t *reply = NULL; + int ret = -1; + + if ((!fopxl) || (!nfu) || (!dirfd)) + return NULL; + + sf = nfs_syncfop_init (); + if (!sf) { + gf_log (GF_NFS, GF_LOG_ERROR, "sync fop local init failed"); + goto ret; + } + + ret = nfs_fop_readdirp (fopxl, nfu, dirfd, bufsize, offset, + nfs_fop_readdirp_sync_cbk, sf); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "Fop readdir failed: %s", + strerror (-ret)); + goto ret; + } + + reply = nfs_syncfop_wait (sf); + +ret: + return reply; +} + + + +nfs_syncfop_t * +nfs_syncfop_init () +{ + nfs_syncfop_t *sfl = NULL; + + sfl = CALLOC (1, sizeof (*sfl)); + if (!sfl) { + gf_log (GF_NFS, GF_LOG_ERROR, "Memory allocation failed"); + return NULL; + } + + sem_init (&sfl->replysig, 0, 0); + + return sfl; +} + + +call_stub_t * +nfs_syncfop_wait (nfs_syncfop_t *s) +{ + call_stub_t *replystub = NULL; + + gf_log (GF_NFS, GF_LOG_TRACE, "Waiting for sync fop"); + sem_wait (&s->replysig); + gf_log (GF_NFS, GF_LOG_TRACE, "Sync fop notification received"); + replystub = s->replystub; + FREE (s); + return replystub; +} + + +void +nfs_syncfop_notify (nfs_syncfop_t *s) +{ + sem_post (&s->replysig); + gf_log (GF_NFS, GF_LOG_TRACE, "Sync fop notified"); +} + + + |