diff options
Diffstat (limited to 'xlators/nfs')
40 files changed, 10122 insertions, 11716 deletions
diff --git a/xlators/nfs/lib/src/auth-null.c b/xlators/nfs/lib/src/auth-null.c deleted file mode 100644 index 0c8e335db..000000000 --- a/xlators/nfs/lib/src/auth-null.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero 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 "rpcsvc.h" -#include "list.h" -#include "dict.h" - - -int -nfs_auth_null_request_init (rpcsvc_request_t *req, void *priv) -{ - if (!req) - return -1; - - memset (req->cred.authdata, 0, RPCSVC_MAX_AUTH_BYTES); - req->cred.datalen = 0; - - memset (req->verf.authdata, 0, RPCSVC_MAX_AUTH_BYTES); - req->verf.datalen = 0; - - return 0; -} - -int -nfs_auth_null_authenticate (rpcsvc_request_t *req, void *priv) -{ - /* Always succeed. */ - return RPCSVC_AUTH_ACCEPT; -} - -rpcsvc_auth_ops_t nfs_auth_null_ops = { - .conn_init = NULL, - .request_init = nfs_auth_null_request_init, - .authenticate = nfs_auth_null_authenticate -}; - -rpcsvc_auth_t nfs_rpcsvc_auth_null = { - .authname = "AUTH_NULL", - .authnum = AUTH_NULL, - .authops = &nfs_auth_null_ops, - .authprivate = NULL -}; - - -rpcsvc_auth_t * -nfs_rpcsvc_auth_null_init (rpcsvc_t *svc, dict_t *options) -{ - return &nfs_rpcsvc_auth_null; -} - diff --git a/xlators/nfs/lib/src/auth-unix.c b/xlators/nfs/lib/src/auth-unix.c deleted file mode 100644 index 10000c385..000000000 --- a/xlators/nfs/lib/src/auth-unix.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero 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 "rpcsvc.h" -#include "list.h" -#include "dict.h" -#include "xdr-rpc.h" - - -int -nfs_auth_unix_request_init (rpcsvc_request_t *req, void *priv) -{ - if (!req) - return -1; - memset (req->verf.authdata, 0, RPCSVC_MAX_AUTH_BYTES); - req->verf.datalen = 0; - req->verf.flavour = AUTH_NULL; - - return 0; -} - -int -nfs_auth_unix_authenticate (rpcsvc_request_t *req, void *priv) -{ - int ret = RPCSVC_AUTH_REJECT; - struct authunix_parms aup; - char machname[MAX_MACHINE_NAME]; - - if (!req) - return ret; - - ret = nfs_xdr_to_auth_unix_cred (req->cred.authdata, req->cred.datalen, - &aup, machname, req->auxgids); - if (ret == -1) { - ret = RPCSVC_AUTH_REJECT; - goto err; - } - - req->uid = aup.aup_uid; - req->gid = aup.aup_gid; - req->auxgidcount = aup.aup_len; - - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Auth Info: machine name: %s, uid: %d" - ", gid: %d", machname, req->uid, req->gid); - ret = RPCSVC_AUTH_ACCEPT; -err: - return ret; -} - -rpcsvc_auth_ops_t nfs_auth_unix_ops = { - .conn_init = NULL, - .request_init = nfs_auth_unix_request_init, - .authenticate = nfs_auth_unix_authenticate -}; - -rpcsvc_auth_t nfs_rpcsvc_auth_unix = { - .authname = "AUTH_UNIX", - .authnum = AUTH_UNIX, - .authops = &nfs_auth_unix_ops, - .authprivate = NULL -}; - - -rpcsvc_auth_t * -nfs_rpcsvc_auth_unix_init (rpcsvc_t *svc, dict_t *options) -{ - return &nfs_rpcsvc_auth_unix; -} - diff --git a/xlators/nfs/lib/src/msg-nfs3.c b/xlators/nfs/lib/src/msg-nfs3.c deleted file mode 100644 index e6e722051..000000000 --- a/xlators/nfs/lib/src/msg-nfs3.c +++ /dev/null @@ -1,554 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero 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 <sys/uio.h> -#include <rpc/rpc.h> -#include <rpc/xdr.h> -#include <sys/types.h> - -#include "xdr-nfs3.h" -#include "msg-nfs3.h" -#include "xdr-common.h" - - -/* Decode the mount path from the network message in inmsg - * into the memory referenced by outpath.iov_base. - * The size allocated for outpath.iov_base is outpath.iov_len. - * The size of the path extracted from the message is returned. - */ -ssize_t -xdr_to_mountpath (struct iovec outpath, struct iovec inmsg) -{ - XDR xdr; - ssize_t ret = -1; - char *mntpath = NULL; - - if ((!outpath.iov_base) || (!inmsg.iov_base)) - return -1; - - xdrmem_create (&xdr, inmsg.iov_base, (unsigned int)inmsg.iov_len, - XDR_DECODE); - - mntpath = outpath.iov_base; - if (!xdr_dirpath (&xdr, (dirpath *)&mntpath)) { - ret = -1; - goto ret; - } - - ret = nfs_xdr_decoded_length (xdr); - -ret: - return ret; -} - - -ssize_t -nfs_xdr_serialize_generic (struct iovec outmsg, void *res, xdrproc_t proc) -{ - ssize_t ret = -1; - XDR xdr; - - if ((!outmsg.iov_base) || (!res) || (!proc)) - return -1; - - xdrmem_create (&xdr, outmsg.iov_base, (unsigned int)outmsg.iov_len, - XDR_ENCODE); - - if (!proc (&xdr, res)) { - ret = -1; - goto ret; - } - - ret = nfs_xdr_encoded_length (xdr); - -ret: - return ret; -} - - -ssize_t -nfs_xdr_to_generic (struct iovec inmsg, void *args, xdrproc_t proc) -{ - XDR xdr; - ssize_t ret = -1; - - if ((!inmsg.iov_base) || (!args) || (!proc)) - return -1; - - xdrmem_create (&xdr, inmsg.iov_base, (unsigned int)inmsg.iov_len, - XDR_DECODE); - - if (!proc (&xdr, args)) { - ret = -1; - goto ret; - } - - ret = nfs_xdr_decoded_length (xdr); -ret: - return ret; -} - - -ssize_t -nfs_xdr_to_generic_payload (struct iovec inmsg, void *args, xdrproc_t proc, - struct iovec *pendingpayload) -{ - XDR xdr; - ssize_t ret = -1; - - if ((!inmsg.iov_base) || (!args) || (!proc)) - return -1; - - xdrmem_create (&xdr, inmsg.iov_base, (unsigned int)inmsg.iov_len, - XDR_DECODE); - - if (!proc (&xdr, args)) { - ret = -1; - goto ret; - } - - ret = nfs_xdr_decoded_length (xdr); - - if (pendingpayload) { - pendingpayload->iov_base = nfs_xdr_decoded_remaining_addr (xdr); - pendingpayload->iov_len = nfs_xdr_decoded_remaining_len (xdr); - } - -ret: - return ret; -} - - -/* Translate the mountres3 structure in res into XDR format into memory - * referenced by outmsg.iov_base. - * Returns the number of bytes used in encoding into XDR format. - */ -ssize_t -xdr_serialize_mountres3 (struct iovec outmsg, mountres3 *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_mountres3); -} - - -ssize_t -xdr_serialize_mountbody (struct iovec outmsg, mountbody *mb) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)mb, - (xdrproc_t)xdr_mountbody); -} - -ssize_t -xdr_serialize_mountlist (struct iovec outmsg, mountlist *ml) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)ml, - (xdrproc_t)xdr_mountlist); -} - - -ssize_t -xdr_serialize_mountstat3 (struct iovec outmsg, mountstat3 *m) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)m, - (xdrproc_t)xdr_mountstat3); -} - - -ssize_t -xdr_to_getattr3args (struct iovec inmsg, getattr3args *ga) -{ - return nfs_xdr_to_generic (inmsg, (void *)ga, - (xdrproc_t)xdr_getattr3args); -} - - -ssize_t -xdr_serialize_getattr3res (struct iovec outmsg, getattr3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_getattr3res); -} - - -ssize_t -xdr_serialize_setattr3res (struct iovec outmsg, setattr3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_setattr3res); -} - - -ssize_t -xdr_to_setattr3args (struct iovec inmsg, setattr3args *sa) -{ - return nfs_xdr_to_generic (inmsg, (void *)sa, - (xdrproc_t)xdr_setattr3args); -} - - -ssize_t -xdr_serialize_lookup3res (struct iovec outmsg, lookup3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_lookup3res); -} - - -ssize_t -xdr_to_lookup3args (struct iovec inmsg, lookup3args *la) -{ - return nfs_xdr_to_generic (inmsg, (void *)la, - (xdrproc_t)xdr_lookup3args); -} - - -ssize_t -xdr_to_access3args (struct iovec inmsg, access3args *ac) -{ - return nfs_xdr_to_generic (inmsg,(void *)ac, - (xdrproc_t)xdr_access3args); -} - - -ssize_t -xdr_serialize_access3res (struct iovec outmsg, access3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_access3res); -} - - -ssize_t -xdr_to_readlink3args (struct iovec inmsg, readlink3args *ra) -{ - return nfs_xdr_to_generic (inmsg, (void *)ra, - (xdrproc_t)xdr_readlink3args); -} - - -ssize_t -xdr_serialize_readlink3res (struct iovec outmsg, readlink3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_readlink3res); -} - - -ssize_t -xdr_to_read3args (struct iovec inmsg, read3args *ra) -{ - return nfs_xdr_to_generic (inmsg, (void *)ra, (xdrproc_t)xdr_read3args); -} - - -ssize_t -xdr_serialize_read3res (struct iovec outmsg, read3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_read3res); -} - -ssize_t -xdr_serialize_read3res_nocopy (struct iovec outmsg, read3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_read3res_nocopy); -} - - -ssize_t -xdr_to_write3args (struct iovec inmsg, write3args *wa) -{ - return nfs_xdr_to_generic (inmsg, (void *)wa,(xdrproc_t)xdr_write3args); -} - - -ssize_t -xdr_to_write3args_nocopy (struct iovec inmsg, write3args *wa, - struct iovec *payload) -{ - return nfs_xdr_to_generic_payload (inmsg, (void *)wa, - (xdrproc_t)xdr_write3args, payload); -} - - -ssize_t -xdr_serialize_write3res (struct iovec outmsg, write3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_write3res); -} - - -ssize_t -xdr_to_create3args (struct iovec inmsg, create3args *ca) -{ - return nfs_xdr_to_generic (inmsg, (void *)ca, - (xdrproc_t)xdr_create3args); -} - - -ssize_t -xdr_serialize_create3res (struct iovec outmsg, create3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_create3res); -} - - -ssize_t -xdr_serialize_mkdir3res (struct iovec outmsg, mkdir3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_mkdir3res); -} - - -ssize_t -xdr_to_mkdir3args (struct iovec inmsg, mkdir3args *ma) -{ - return nfs_xdr_to_generic (inmsg, (void *)ma, - (xdrproc_t)xdr_mkdir3args); -} - - -ssize_t -xdr_to_symlink3args (struct iovec inmsg, symlink3args *sa) -{ - return nfs_xdr_to_generic (inmsg, (void *)sa, - (xdrproc_t)xdr_symlink3args); -} - - -ssize_t -xdr_serialize_symlink3res (struct iovec outmsg, symlink3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_symlink3res); -} - - -ssize_t -xdr_to_mknod3args (struct iovec inmsg, mknod3args *ma) -{ - return nfs_xdr_to_generic (inmsg, (void *)ma, - (xdrproc_t)xdr_mknod3args); -} - - -ssize_t -xdr_serialize_mknod3res (struct iovec outmsg, mknod3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_mknod3res); -} - - -ssize_t -xdr_to_remove3args (struct iovec inmsg, remove3args *ra) -{ - return nfs_xdr_to_generic (inmsg, (void *)ra, - (xdrproc_t)xdr_remove3args); -} - - -ssize_t -xdr_serialize_remove3res (struct iovec outmsg, remove3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_remove3res); -} - - -ssize_t -xdr_to_rmdir3args (struct iovec inmsg, rmdir3args *ra) -{ - return nfs_xdr_to_generic (inmsg, (void *)ra, - (xdrproc_t)xdr_rmdir3args); -} - - -ssize_t -xdr_serialize_rmdir3res (struct iovec outmsg, rmdir3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_rmdir3res); -} - - -ssize_t -xdr_serialize_rename3res (struct iovec outmsg, rename3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_rename3res); -} - - -ssize_t -xdr_to_rename3args (struct iovec inmsg, rename3args *ra) -{ - return nfs_xdr_to_generic (inmsg, (void *)ra, - (xdrproc_t)xdr_rename3args); -} - - -ssize_t -xdr_serialize_link3res (struct iovec outmsg, link3res *li) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)li, - (xdrproc_t)xdr_link3res); -} - - -ssize_t -xdr_to_link3args (struct iovec inmsg, link3args *la) -{ - return nfs_xdr_to_generic (inmsg, (void *)la, (xdrproc_t)xdr_link3args); -} - - -ssize_t -xdr_to_readdir3args (struct iovec inmsg, readdir3args *rd) -{ - return nfs_xdr_to_generic (inmsg, (void *)rd, - (xdrproc_t)xdr_readdir3args); -} - - -ssize_t -xdr_serialize_readdir3res (struct iovec outmsg, readdir3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_readdir3res); -} - - -ssize_t -xdr_to_readdirp3args (struct iovec inmsg, readdirp3args *rp) -{ - return nfs_xdr_to_generic (inmsg, (void *)rp, - (xdrproc_t)xdr_readdirp3args); -} - - -ssize_t -xdr_serialize_readdirp3res (struct iovec outmsg, readdirp3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_readdirp3res); -} - - -ssize_t -xdr_to_fsstat3args (struct iovec inmsg, fsstat3args *fa) -{ - return nfs_xdr_to_generic (inmsg, (void *)fa, - (xdrproc_t)xdr_fsstat3args); -} - - -ssize_t -xdr_serialize_fsstat3res (struct iovec outmsg, fsstat3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_fsstat3res); -} - -ssize_t -xdr_to_fsinfo3args (struct iovec inmsg, fsinfo3args *fi) -{ - return nfs_xdr_to_generic (inmsg, (void *)fi, - (xdrproc_t)xdr_fsinfo3args); -} - - -ssize_t -xdr_serialize_fsinfo3res (struct iovec outmsg, fsinfo3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_fsinfo3res); -} - - -ssize_t -xdr_to_pathconf3args (struct iovec inmsg, pathconf3args *pc) -{ - return nfs_xdr_to_generic (inmsg, (void *)pc, - (xdrproc_t)xdr_pathconf3args);} - - -ssize_t -xdr_serialize_pathconf3res (struct iovec outmsg, pathconf3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_pathconf3res); -} - - -ssize_t -xdr_to_commit3args (struct iovec inmsg, commit3args *ca) -{ - return nfs_xdr_to_generic (inmsg, (void *)ca, - (xdrproc_t)xdr_commit3args); -} - - -ssize_t -xdr_serialize_commit3res (struct iovec outmsg, commit3res *res) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)res, - (xdrproc_t)xdr_commit3res); -} - - -ssize_t -xdr_serialize_exports (struct iovec outmsg, exports *elist) -{ - XDR xdr; - ssize_t ret = -1; - - if ((!outmsg.iov_base) || (!elist)) - return -1; - - xdrmem_create (&xdr, outmsg.iov_base, (unsigned int)outmsg.iov_len, - XDR_ENCODE); - - if (!xdr_exports (&xdr, elist)) - goto ret; - - ret = nfs_xdr_decoded_length (xdr); - -ret: - return ret; -} - - -ssize_t -xdr_serialize_nfsstat3 (struct iovec outmsg, nfsstat3 *s) -{ - return nfs_xdr_serialize_generic (outmsg, (void *)s, - (xdrproc_t)xdr_nfsstat3); -} - - diff --git a/xlators/nfs/lib/src/msg-nfs3.h b/xlators/nfs/lib/src/msg-nfs3.h deleted file mode 100644 index f0d57c646..000000000 --- a/xlators/nfs/lib/src/msg-nfs3.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _MSG_NFS3_H_ -#define _MSG_NFS3_H_ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "xdr-nfs3.h" - -#include <sys/types.h> -#include <sys/uio.h> - -extern ssize_t -xdr_to_mountpath (struct iovec outpath, struct iovec inmsg); - -extern ssize_t -xdr_serialize_mountres3 (struct iovec outmsg, mountres3 *res); - -extern ssize_t -xdr_serialize_mountbody (struct iovec outmsg, mountbody *mb); - -extern ssize_t -xdr_to_getattr3args (struct iovec inmsg, getattr3args *ga); - -extern ssize_t -xdr_serialize_getattr3res (struct iovec outmsg, getattr3res *res); - -extern ssize_t -xdr_serialize_setattr3res (struct iovec outmsg, setattr3res *res); - -extern ssize_t -xdr_to_setattr3args (struct iovec inmsg, setattr3args *sa); - -extern ssize_t -xdr_serialize_lookup3res (struct iovec outmsg, lookup3res *res); - -extern ssize_t -xdr_to_lookup3args (struct iovec inmsg, lookup3args *la); - -extern ssize_t -xdr_to_access3args (struct iovec inmsg, access3args *ac); - -extern ssize_t -xdr_serialize_access3res (struct iovec outmsg, access3res *res); - -extern ssize_t -xdr_to_readlink3args (struct iovec inmsg, readlink3args *ra); - -extern ssize_t -xdr_serialize_readlink3res (struct iovec outmsg, readlink3res *res); - -extern ssize_t -xdr_to_read3args (struct iovec inmsg, read3args *ra); - -extern ssize_t -xdr_serialize_read3res (struct iovec outmsg, read3res *res); - -extern ssize_t -xdr_serialize_read3res_nocopy (struct iovec outmsg, read3res *res); - -extern ssize_t -xdr_to_write3args (struct iovec inmsg, write3args *wa); - -extern ssize_t -xdr_to_write3args_nocopy (struct iovec inmsg, write3args *wa, - struct iovec *payload); - -extern ssize_t -xdr_serialize_write3res (struct iovec outmsg, write3res *res); - -extern ssize_t -xdr_to_create3args (struct iovec inmsg, create3args *ca); - -extern ssize_t -xdr_serialize_create3res (struct iovec outmsg, create3res *res); - -extern ssize_t -xdr_serialize_mkdir3res (struct iovec outmsg, mkdir3res *res); - -extern ssize_t -xdr_to_mkdir3args (struct iovec inmsg, mkdir3args *ma); - -extern ssize_t -xdr_to_symlink3args (struct iovec inmsg, symlink3args *sa); - -extern ssize_t -xdr_serialize_symlink3res (struct iovec outmsg, symlink3res *res); - -extern ssize_t -xdr_to_mknod3args (struct iovec inmsg, mknod3args *ma); - -extern ssize_t -xdr_serialize_mknod3res (struct iovec outmsg, mknod3res *res); - -extern ssize_t -xdr_to_remove3args (struct iovec inmsg, remove3args *ra); - -extern ssize_t -xdr_serialize_remove3res (struct iovec outmsg, remove3res *res); - -extern ssize_t -xdr_to_rmdir3args (struct iovec inmsg, rmdir3args *ra); - -extern ssize_t -xdr_serialize_rmdir3res (struct iovec outmsg, rmdir3res *res); - -extern ssize_t -xdr_serialize_rename3res (struct iovec outmsg, rename3res *res); - -extern ssize_t -xdr_to_rename3args (struct iovec inmsg, rename3args *ra); - -extern ssize_t -xdr_serialize_link3res (struct iovec outmsg, link3res *li); - -extern ssize_t -xdr_to_link3args (struct iovec inmsg, link3args *la); - -extern ssize_t -xdr_to_readdir3args (struct iovec inmsg, readdir3args *rd); - -extern ssize_t -xdr_serialize_readdir3res (struct iovec outmsg, readdir3res *res); - -extern ssize_t -xdr_to_readdirp3args (struct iovec inmsg, readdirp3args *rp); - -extern ssize_t -xdr_serialize_readdirp3res (struct iovec outmsg, readdirp3res *res); - -extern ssize_t -xdr_to_fsstat3args (struct iovec inmsg, fsstat3args *fa); - -extern ssize_t -xdr_serialize_fsstat3res (struct iovec outmsg, fsstat3res *res); - -extern ssize_t -xdr_to_fsinfo3args (struct iovec inmsg, fsinfo3args *fi); - -extern ssize_t -xdr_serialize_fsinfo3res (struct iovec outmsg, fsinfo3res *res); - -extern ssize_t -xdr_to_pathconf3args (struct iovec inmsg, pathconf3args *pc); - -extern ssize_t -xdr_serialize_pathconf3res (struct iovec outmsg, pathconf3res *res); - -extern ssize_t -xdr_to_commit3args (struct iovec inmsg, commit3args *ca); - -extern ssize_t -xdr_serialize_commit3res (struct iovec outmsg, commit3res *res); - -extern ssize_t -xdr_serialize_exports (struct iovec outmsg, exports *elist); - -extern ssize_t -xdr_serialize_mountlist (struct iovec outmsg, mountlist *ml); - -extern ssize_t -xdr_serialize_mountstat3 (struct iovec outmsg, mountstat3 *m); - -extern ssize_t -xdr_serialize_nfsstat3 (struct iovec outmsg, nfsstat3 *s); -#endif diff --git a/xlators/nfs/lib/src/rpc-socket.c b/xlators/nfs/lib/src/rpc-socket.c deleted file mode 100644 index 9d6aca33b..000000000 --- a/xlators/nfs/lib/src/rpc-socket.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero 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 "rpc-socket.h" -#include "rpcsvc.h" -#include "dict.h" -#include "logging.h" -#include "byte-order.h" -#include "common-utils.h" -#include "compat-errno.h" - -#include <fcntl.h> -#include <errno.h> -#include <sys/socket.h> -#include <netdb.h> -#include <netinet/in.h> -#include <netinet/tcp.h> - -static int -nfs_rpcsvc_socket_server_get_local_socket (int addrfam, char *listenhost, - uint16_t listenport, - struct sockaddr *addr, - socklen_t *addr_len) -{ - struct addrinfo hints, *res = 0; - char service[NI_MAXSERV]; - int ret = -1; - - memset (service, 0, sizeof (service)); - sprintf (service, "%d", listenport); - - memset (&hints, 0, sizeof (hints)); - addr->sa_family = hints.ai_family = addrfam; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; - - ret = getaddrinfo(listenhost, service, &hints, &res); - if (ret != 0) { - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, - "getaddrinfo failed for host %s, service %s (%s)", - listenhost, service, gai_strerror (ret)); - ret = -1; - goto err; - } - - memcpy (addr, res->ai_addr, res->ai_addrlen); - *addr_len = res->ai_addrlen; - - freeaddrinfo (res); - ret = 0; - -err: - return ret; -} - - -int -nfs_rpcsvc_socket_listen (int addrfam, char *listenhost, uint16_t listenport) -{ - int sock = -1; - struct sockaddr_storage sockaddr; - socklen_t sockaddr_len; - int flags = 0; - int ret = -1; - int opt = 1; - - ret = nfs_rpcsvc_socket_server_get_local_socket (addrfam, listenhost, - listenport, - SA (&sockaddr), - &sockaddr_len); - - if (ret == -1) - return ret; - - sock = socket (SA (&sockaddr)->sa_family, SOCK_STREAM, 0); - if (sock == -1) { - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "socket creation failed" - " (%s)", strerror (errno)); - goto err; - } - - flags = fcntl (sock, F_GETFL); - if (flags == -1) { - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot get socket flags" - " (%s)", strerror(errno)); - goto close_err; - } - - ret = fcntl (sock, F_SETFL, flags | O_NONBLOCK); - if (ret == -1) { - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot set socket " - "non-blocking (%s)", strerror (errno)); - goto close_err; - } - - ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); - if (ret == -1) { - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "setsockopt() for " - "SO_REUSEADDR failed (%s)", strerror (errno)); - goto close_err; - } - - ret = bind (sock, (struct sockaddr *)&sockaddr, sockaddr_len); - if (ret == -1) { - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "binding socket failed:" - " %s", strerror (errno)); - if (errno == EADDRINUSE) - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "Port is already" - " in use"); - goto close_err; - } - - ret = listen (sock, 10); - if (ret == -1) { - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "could not listen on" - " socket (%s)", strerror (errno)); - goto close_err; - } - - return sock; - -close_err: - close (sock); - sock = -1; - -err: - return sock; -} - - -int -nfs_rpcsvc_socket_accept (int listenfd) -{ - int new_sock = -1; - struct sockaddr_storage new_sockaddr = {0, }; - socklen_t addrlen = sizeof (new_sockaddr); - int flags = 0; - int ret = -1; - int on = 1; - - new_sock = accept (listenfd, SA (&new_sockaddr), &addrlen); - if (new_sock == -1) { - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR,"accept on socket failed"); - goto err; - } - - flags = fcntl (new_sock, F_GETFL); - if (flags == -1) { - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot get socket flags" - " (%s)", strerror(errno)); - goto close_err; - } - - ret = fcntl (new_sock, F_SETFL, flags | O_NONBLOCK); - if (ret == -1) { - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot set socket " - "non-blocking (%s)", strerror (errno)); - goto close_err; - } - -#ifdef TCP_NODELAY - ret = setsockopt(new_sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); - if (ret == -1) { - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot set no-delay " - " socket option"); - } -#endif - - return new_sock; - -close_err: - close (new_sock); - new_sock = -1; - -err: - return new_sock; -} - -ssize_t -nfs_rpcsvc_socket_read (int sockfd, char *readaddr, size_t readsize) -{ - ssize_t dataread = 0; - ssize_t readlen = -1; - - if (!readaddr) - return -1; - - while (readsize > 0) { - readlen = read (sockfd, readaddr, readsize); - if (readlen == -1) { - if (errno != EAGAIN) { - dataread = -1; - break; - } else - break; - } else if (readlen == 0) - break; - - dataread += readlen; - readaddr += readlen; - readsize -= readlen; - } - - return dataread; -} - - -ssize_t -nfs_rpcsvc_socket_write (int sockfd, char *buffer, size_t size) -{ - size_t writelen = -1; - ssize_t written = 0; - - if (!buffer) - return -1; - - while (size > 0) { - writelen = write (sockfd, buffer, size); - if (writelen == -1) { - if (errno != EAGAIN) { - written = -1; - break; - } else - break; - } else if (writelen == 0) - break; - - written += writelen; - size -= writelen; - buffer += writelen; - } - - return written; -} - - -int -nfs_rpcsvc_socket_peername (int sockfd, char *hostname, int hostlen) -{ - struct sockaddr sa; - socklen_t sl = sizeof (sa); - int ret = EAI_FAIL; - - if (!hostname) - return ret; - - ret = getpeername (sockfd, &sa, &sl); - if (ret == -1) { - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "Failed to get peer name:" - " %s", strerror (errno)); - ret = EAI_FAIL; - goto err; - } - - ret = getnameinfo (&sa, sl, hostname, hostlen, NULL, 0, 0); - if (ret != 0) - goto err; - -err: - return ret; -} - - -int -nfs_rpcsvc_socket_peeraddr (int sockfd, char *addrstr, int addrlen, - struct sockaddr *returnsa, socklen_t sasize) -{ - struct sockaddr sa; - int ret = EAI_FAIL; - - if (returnsa) - ret = getpeername (sockfd, returnsa, &sasize); - else { - sasize = sizeof (sa); - ret = getpeername (sockfd, &sa, &sasize); - } - - if (ret == -1) { - gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "Failed to get peer addr:" - " %s", strerror (errno)); - ret = EAI_FAIL; - goto err; - } - - /* If caller did not specify a string into which the address can be - * stored, dont bother getting it. - */ - if (!addrstr) { - ret = 0; - goto err; - } - - if (returnsa) - ret = getnameinfo (returnsa, sasize, addrstr, addrlen, NULL, 0, - NI_NUMERICHOST); - else - ret = getnameinfo (&sa, sasize, addrstr, addrlen, NULL, 0, - NI_NUMERICHOST); - -err: - return ret; -} - - -int -nfs_rpcsvc_socket_block_tx (int sockfd) -{ - - int ret = -1; - int on = 1; - -#ifdef TCP_CORK - ret = setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, &on, sizeof(on)); -#endif - -#ifdef TCP_NOPUSH - ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NOPUSH, &on, sizeof(on)); -#endif - - return ret; -} - - -int -nfs_rpcsvc_socket_unblock_tx (int sockfd) -{ - int ret = -1; - int off = 0; - -#ifdef TCP_CORK - ret = setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, &off, sizeof(off)); -#endif - -#ifdef TCP_NOPUSH - ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NOPUSH, &off, sizeof(off)); -#endif - return ret; -} - diff --git a/xlators/nfs/lib/src/rpc-socket.h b/xlators/nfs/lib/src/rpc-socket.h deleted file mode 100644 index 0f9172977..000000000 --- a/xlators/nfs/lib/src/rpc-socket.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _NFS_RPCSVC_SOCKET_H_ -#define _NFS_RPCSVC_SOCKET_H_ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "rpcsvc.h" -#include "dict.h" -#include "logging.h" -#include "byte-order.h" -#include "common-utils.h" -#include "compat-errno.h" - -#include <fcntl.h> -#include <errno.h> -#include <sys/socket.h> -#include <netdb.h> - -#define SA(ptr) ((struct sockaddr *)ptr) -#define GF_RPCSVC_SOCK "rpc-socket" -extern int -nfs_rpcsvc_socket_listen (int addrfam, char *listenhost, uint16_t listenport); - -extern int -nfs_rpcsvc_socket_accept (int listenfd); - -extern ssize_t -nfs_rpcsvc_socket_read (int sockfd, char *readaddr, size_t readsize); - -extern ssize_t -nfs_rpcsvc_socket_write (int sockfd, char *buffer, size_t size); - -extern int -nfs_rpcsvc_socket_peername (int sockfd, char *hostname, int hostlen); - -extern int -nfs_rpcsvc_socket_peeraddr (int sockfd, char *addrstr, int addrlen, - struct sockaddr *returnsa, socklen_t sasize); -extern int -nfs_rpcsvc_socket_block_tx (int sockfd); - -extern int -nfs_rpcsvc_socket_unblock_tx (int sockfd); -#endif diff --git a/xlators/nfs/lib/src/rpcsvc-auth.c b/xlators/nfs/lib/src/rpcsvc-auth.c deleted file mode 100644 index 6d07619e4..000000000 --- a/xlators/nfs/lib/src/rpcsvc-auth.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#include "rpcsvc.h" -#include "logging.h" -#include "dict.h" - -extern rpcsvc_auth_t * -nfs_rpcsvc_auth_null_init (rpcsvc_t *svc, dict_t *options); - -extern rpcsvc_auth_t * -nfs_rpcsvc_auth_unix_init (rpcsvc_t *svc, dict_t *options); - -int -nfs_rpcsvc_auth_add_initer (struct list_head *list, char *idfier, - rpcsvc_auth_initer_t init) -{ - struct rpcsvc_auth_list *new = NULL; - - if ((!list) || (!init) || (!idfier)) - return -1; - - new = GF_CALLOC (1, sizeof (*new), gf_common_mt_rpcsvc_auth_list); - if (!new) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Memory allocation failed"); - return -1; - } - - new->init = init; - strcpy (new->name, idfier); - INIT_LIST_HEAD (&new->authlist); - list_add_tail (&new->authlist, list); - return 0; -} - - - -int -nfs_rpcsvc_auth_add_initers (rpcsvc_t *svc) -{ - int ret = -1; - - ret = nfs_rpcsvc_auth_add_initer (&svc->authschemes, "auth-unix", - (rpcsvc_auth_initer_t) - nfs_rpcsvc_auth_unix_init); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to add AUTH_UNIX"); - goto err; - } - - ret = nfs_rpcsvc_auth_add_initer (&svc->authschemes, "auth-null", - (rpcsvc_auth_initer_t) - nfs_rpcsvc_auth_null_init); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to add AUTH_NULL"); - goto err; - } - -err: - return ret; -} - - -int -nfs_rpcsvc_auth_init_auth (rpcsvc_t *svc, dict_t *options, - struct rpcsvc_auth_list *authitem) -{ - int ret = -1; - - if ((!svc) || (!options) || (!authitem)) - return -1; - - if (!authitem->init) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "No init function defined"); - ret = -1; - goto err; - } - - authitem->auth = authitem->init (svc, options); - if (!authitem->auth) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Registration of auth failed:" - " %s", authitem->name); - ret = -1; - goto err; - } - - authitem->enable = 1; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Authentication enabled: %s", - authitem->auth->authname); - - ret = 0; -err: - return ret; -} - - -int -nfs_rpcsvc_auth_init_auths (rpcsvc_t *svc, dict_t *options) -{ - int ret = -1; - struct rpcsvc_auth_list *auth = NULL; - struct rpcsvc_auth_list *tmp = NULL; - - if (!svc) - return -1; - - if (list_empty (&svc->authschemes)) { - gf_log (GF_RPCSVC, GF_LOG_WARNING, "No authentication!"); - ret = 0; - goto err; - } - - /* If auth null and sys are not disabled by the user, we must enable - * it by default. This is a globally default rule, the user is still - * allowed to disable the two for particular subvolumes. - */ - if (!dict_get (options, "rpc-auth.auth-null")) { - ret = dict_set_dynstr (options, "rpc-auth.auth-null", "on"); - if (ret < 0) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, - "Failed to set dict value."); - goto err; - } - } - - if (!dict_get (options, "rpc-auth.auth-unix")) { - ret = dict_set_dynstr (options, "rpc-auth.auth-unix", "on"); - if (ret < 0) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, - "Failed to set dict value."); - goto err; - } - } - - list_for_each_entry_safe (auth, tmp, &svc->authschemes, authlist) { - ret = nfs_rpcsvc_auth_init_auth (svc, options, auth); - if (ret == -1) - goto err; - } - - ret = 0; -err: - return ret; - -} - -int -nfs_rpcsvc_auth_init (rpcsvc_t *svc, dict_t *options) -{ - int ret = -1; - - if ((!svc) || (!options)) - return -1; - - ret = nfs_rpcsvc_auth_add_initers (svc); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to add initers"); - goto out; - } - - ret = nfs_rpcsvc_auth_init_auths (svc, options); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to init auth schemes"); - goto out; - } - -out: - return ret; -} - - -rpcsvc_auth_t * -__nfs_rpcsvc_auth_get_handler (rpcsvc_request_t *req) -{ - struct rpcsvc_auth_list *auth = NULL; - struct rpcsvc_auth_list *tmp = NULL; - rpcsvc_t *svc = NULL; - - if (!req) - return NULL; - - svc = nfs_rpcsvc_request_service (req); - if (list_empty (&svc->authschemes)) { - gf_log (GF_RPCSVC, GF_LOG_WARNING, "No authentication!"); - goto err; - } - - list_for_each_entry_safe (auth, tmp, &svc->authschemes, authlist) { - if (!auth->enable) - continue; - if (auth->auth->authnum == req->cred.flavour) - goto err; - - } - - auth = NULL; -err: - if (auth) - return auth->auth; - else - return NULL; -} - -rpcsvc_auth_t * -nfs_rpcsvc_auth_get_handler (rpcsvc_request_t *req) -{ - rpcsvc_auth_t *auth = NULL; - - auth = __nfs_rpcsvc_auth_get_handler (req); - if (auth) - goto ret; - - gf_log (GF_RPCSVC, GF_LOG_TRACE, "No auth handler: %d", - req->cred.flavour); - - /* The requested scheme was not available so fall back the to one - * scheme that will always be present. - */ - req->cred.flavour = AUTH_NULL; - req->verf.flavour = AUTH_NULL; - auth = __nfs_rpcsvc_auth_get_handler (req); -ret: - return auth; -} - - -int -nfs_rpcsvc_auth_request_init (rpcsvc_request_t *req) -{ - int ret = -1; - rpcsvc_auth_t *auth = NULL; - - if (!req) - return -1; - - auth = nfs_rpcsvc_auth_get_handler (req); - if (!auth) - goto err; - ret = 0; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Auth handler: %s", auth->authname); - if (!auth->authops->request_init) - ret = auth->authops->request_init (req, auth->authprivate); - -err: - return ret; -} - - -int -nfs_rpcsvc_authenticate (rpcsvc_request_t *req) -{ - int ret = RPCSVC_AUTH_REJECT; - rpcsvc_auth_t *auth = NULL; - int minauth = 0; - - if (!req) - return ret; - - minauth = nfs_rpcsvc_request_prog_minauth (req); - if (minauth > nfs_rpcsvc_request_cred_flavour (req)) { - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Auth too weak"); - nfs_rpcsvc_request_set_autherr (req, AUTH_TOOWEAK); - goto err; - } - - auth = nfs_rpcsvc_auth_get_handler (req); - if (!auth) { - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "No auth handler found"); - goto err; - } - - if (auth->authops->authenticate) - ret = auth->authops->authenticate (req, auth->authprivate); - -err: - return ret; -} - - -int -nfs_rpcsvc_auth_array (rpcsvc_t *svc, char *volname, int *autharr, int arrlen) -{ - int count = 0; - int gen = RPCSVC_AUTH_REJECT; - int spec = RPCSVC_AUTH_REJECT; - int final = RPCSVC_AUTH_REJECT; - char *srchstr = NULL; - char *valstr = NULL; - gf_boolean_t boolval = _gf_false; - int ret = 0; - - struct rpcsvc_auth_list *auth = NULL; - struct rpcsvc_auth_list *tmp = NULL; - - if ((!svc) || (!autharr) || (!volname)) - return -1; - - memset (autharr, 0, arrlen * sizeof(int)); - if (list_empty (&svc->authschemes)) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "No authentication!"); - goto err; - } - - list_for_each_entry_safe (auth, tmp, &svc->authschemes, authlist) { - if (count >= arrlen) - break; - - gen = gf_asprintf (&srchstr, "rpc-auth.%s", auth->name); - if (gen == -1) { - count = -1; - goto err; - } - - gen = RPCSVC_AUTH_REJECT; - if (dict_get (svc->options, srchstr)) { - ret = dict_get_str (svc->options, srchstr, &valstr); - if (ret == 0) { - ret = gf_string2boolean (valstr, &boolval); - if (ret == 0) { - if (boolval == _gf_true) - gen = RPCSVC_AUTH_ACCEPT; - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Faile" - "d to read auth val"); - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Faile" - "d to read auth val"); - } - - GF_FREE (srchstr); - spec = gf_asprintf (&srchstr, "rpc-auth.%s.%s", auth->name, - volname); - if (spec == -1) { - count = -1; - goto err; - } - - spec = RPCSVC_AUTH_DONTCARE; - if (dict_get (svc->options, srchstr)) { - ret = dict_get_str (svc->options, srchstr, &valstr); - if (ret == 0) { - ret = gf_string2boolean (valstr, &boolval); - if (ret == 0) { - if (boolval == _gf_true) - spec = RPCSVC_AUTH_ACCEPT; - else - spec = RPCSVC_AUTH_REJECT; - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Faile" - "d to read auth val"); - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Faile" - "d to read auth val"); - } - - GF_FREE (srchstr); - final = nfs_rpcsvc_combine_gen_spec_volume_checks (gen, spec); - if (final == RPCSVC_AUTH_ACCEPT) { - autharr[count] = auth->auth->authnum; - ++count; - } - } - -err: - return count; -} - - -gid_t * -nfs_rpcsvc_auth_unix_auxgids (rpcsvc_request_t *req, int *arrlen) -{ - if ((!req) || (!arrlen)) - return NULL; - - if (req->cred.flavour != AUTH_UNIX) - return NULL; - - *arrlen = req->auxgidcount; - if (*arrlen == 0) - return NULL; - - return &req->auxgids[0]; -} - diff --git a/xlators/nfs/lib/src/rpcsvc.c b/xlators/nfs/lib/src/rpcsvc.c deleted file mode 100644 index 112bf6326..000000000 --- a/xlators/nfs/lib/src/rpcsvc.c +++ /dev/null @@ -1,2835 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero 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 "rpcsvc.h" -#include "rpc-socket.h" -#include "dict.h" -#include "logging.h" -#include "byte-order.h" -#include "common-utils.h" -#include "compat-errno.h" -#include "list.h" -#include "xdr-rpc.h" -#include "iobuf.h" -#include "globals.h" - -#include <errno.h> -#include <pthread.h> -#include <stdlib.h> -#include <rpc/rpc.h> -#include <rpc/pmap_clnt.h> -#include <arpa/inet.h> -#include <rpc/xdr.h> -#include <fnmatch.h> -#include <stdarg.h> -#include <stdio.h> - - -#define nfs_rpcsvc_alloc_request(con, request) \ - do { \ - request = (rpcsvc_request_t *) mem_get ((con)->rxpool); \ - memset (request, 0, sizeof (rpcsvc_request_t)); \ - } while (0) \ - -/* The generic event handler for every stage */ -void * -nfs_rpcsvc_stage_proc (void *arg) -{ - rpcsvc_stage_t *stg = (rpcsvc_stage_t *)arg; - - if (!stg) - return NULL; - - event_dispatch (stg->eventpool); - return NULL; -} - - -rpcsvc_stage_t * -nfs_rpcsvc_stage_init (rpcsvc_t *svc) -{ - rpcsvc_stage_t *stg = NULL; - int ret = -1; - size_t stacksize = RPCSVC_THREAD_STACK_SIZE; - pthread_attr_t stgattr; - unsigned int eventpoolsize = 0; - - if (!svc) - return NULL; - - stg = GF_CALLOC (1, sizeof(*stg), gf_common_mt_rpcsvc_stage_t); - if (!stg) - return NULL; - - eventpoolsize = svc->memfactor * RPCSVC_EVENTPOOL_SIZE_MULT; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "event pool size: %d", eventpoolsize); - stg->eventpool = event_pool_new (eventpoolsize); - if (!stg->eventpool) - goto free_stg; - - pthread_attr_init (&stgattr); - ret = pthread_attr_setstacksize (&stgattr, stacksize); - if (ret == EINVAL) - gf_log (GF_RPCSVC, GF_LOG_WARNING, - "Using default thread stack size"); - - ret = pthread_create (&stg->tid, &stgattr, nfs_rpcsvc_stage_proc, - (void *)stg); - if (ret != 0) { - ret = -1; - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Stage creation failed"); - goto free_stg; - } - - stg->svc = svc; - ret = 0; -free_stg: - if (ret == -1) { - GF_FREE (stg); - stg = NULL; - } - - return stg; -} - - -int -nfs_rpcsvc_init_options (rpcsvc_t *svc, dict_t *options) -{ - char *optstr = NULL; - int ret = -1; - - if ((!svc) || (!options)) - return -1; - - svc->memfactor = RPCSVC_DEFAULT_MEMFACTOR; - - svc->register_portmap = _gf_true; - if (dict_get (options, "rpc.register-with-portmap")) { - ret = dict_get_str (options, "rpc.register-with-portmap", - &optstr); - if (ret < 0) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to parse " - "dict"); - goto out; - } - - ret = gf_string2boolean (optstr, &svc->register_portmap); - if (ret < 0) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to parse bool " - "string"); - goto out; - } - } - - if (!svc->register_portmap) - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Portmap registration " - "disabled"); - - ret = 0; -out: - return ret; -} - - -/* The global RPC service initializer. - * Starts up the stages and then waits for RPC program registrations - * to come in. - */ -rpcsvc_t * -nfs_rpcsvc_init (glusterfs_ctx_t *ctx, dict_t *options) -{ - rpcsvc_t *svc = NULL; - int ret = -1; - - if ((!ctx) || (!options)) - return NULL; - - svc = GF_CALLOC (1, sizeof (*svc), gf_common_mt_rpcsvc_t); - if (!svc) - return NULL; - - pthread_mutex_init (&svc->rpclock, NULL); - INIT_LIST_HEAD (&svc->stages); - INIT_LIST_HEAD (&svc->authschemes); - - ret = nfs_rpcsvc_init_options (svc, options); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to init options"); - goto free_svc; - } - - ret = nfs_rpcsvc_auth_init (svc, options); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to init " - "authentication"); - goto free_svc; - } - - ret = -1; - svc->defaultstage = nfs_rpcsvc_stage_init (svc); - if (!svc->defaultstage) { - gf_log (GF_RPCSVC, GF_LOG_ERROR,"RPC service init failed."); - goto free_svc; - } - svc->options = options; - svc->ctx = ctx; - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "RPC service inited."); - - ret = 0; -free_svc: - if (ret == -1) { - GF_FREE (svc); - svc = NULL; - } - - return svc; -} - - -/* Once multi-threaded support is complete, we'll be able to round-robin - * the various incoming connections over the many available stages. This - * function selects one from among all the stages. - */ -rpcsvc_stage_t * -nfs_rpcsvc_select_stage (rpcsvc_t *rpcservice) -{ - if (!rpcservice) - return NULL; - - return rpcservice->defaultstage; -} - - -int -nfs_rpcsvc_conn_peer_check_search (dict_t *options, char *pattern, char *clstr) -{ - int ret = -1; - char *addrtok = NULL; - char *addrstr = NULL; - char *svptr = NULL; - - if ((!options) || (!clstr)) - return -1; - - if (!dict_get (options, pattern)) - return -1; - - ret = dict_get_str (options, pattern, &addrstr); - if (ret < 0) { - ret = -1; - goto err; - } - - if (!addrstr) { - ret = -1; - goto err; - } - - addrtok = strtok_r (addrstr, ",", &svptr); - while (addrtok) { - - /* CASEFOLD not present on Solaris */ -#ifdef FNM_CASEFOLD - ret = fnmatch (addrtok, clstr, FNM_CASEFOLD); -#else - ret = fnmatch (addrtok, clstr, 0); -#endif - if (ret == 0) - goto err; - - addrtok = strtok_r (NULL, ",", &svptr); - } - - ret = -1; -err: - - return ret; -} - - -int -nfs_rpcsvc_conn_peer_check_allow (dict_t *options, char *volname, char *clstr) -{ - int ret = RPCSVC_AUTH_DONTCARE; - char *srchstr = NULL; - char globalrule[] = "rpc-auth.addr.allow"; - - if ((!options) || (!clstr)) - return ret; - - /* If volname is NULL, then we're searching for the general rule to - * determine the current address in clstr is allowed or not for all - * subvolumes. - */ - if (volname) { - ret = gf_asprintf (&srchstr, "rpc-auth.addr.%s.allow", volname); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); - ret = RPCSVC_AUTH_DONTCARE; - goto out; - } - } else - srchstr = globalrule; - - ret = nfs_rpcsvc_conn_peer_check_search (options, srchstr, clstr); - if (volname) - GF_FREE (srchstr); - - if (ret == 0) - ret = RPCSVC_AUTH_ACCEPT; - else - ret = RPCSVC_AUTH_DONTCARE; -out: - return ret; -} - -int -nfs_rpcsvc_conn_peer_check_reject (dict_t *options, char *volname, char *clstr) -{ - int ret = RPCSVC_AUTH_DONTCARE; - char *srchstr = NULL; - char generalrule[] = "rpc-auth.addr.reject"; - - if ((!options) || (!clstr)) - return ret; - - if (volname) { - ret = gf_asprintf (&srchstr, "rpc-auth.addr.%s.reject", - volname); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); - ret = RPCSVC_AUTH_REJECT; - goto out; - } - } else - srchstr = generalrule; - - ret = nfs_rpcsvc_conn_peer_check_search (options, srchstr, clstr); - if (volname) - GF_FREE (srchstr); - - if (ret == 0) - ret = RPCSVC_AUTH_REJECT; - else - ret = RPCSVC_AUTH_DONTCARE; -out: - return ret; -} - - -/* This function tests the results of the allow rule and the reject rule to - * combine them into a single result that can be used to determine if the - * connection should be allowed to proceed. - * Heres the test matrix we need to follow in this function. - * - * A - Allow, the result of the allow test. Never returns R. - * R - Reject, result of the reject test. Never returns A. - * Both can return D or dont care if no rule was given. - * - * | @allow | @reject | Result | - * | A | R | R | - * | D | D | D | - * | A | D | A | - * | D | R | R | - */ -int -nfs_rpcsvc_combine_allow_reject_volume_check (int allow, int reject) -{ - int final = RPCSVC_AUTH_REJECT; - - /* If allowed rule allows but reject rule rejects, we stay cautious - * and reject. */ - if ((allow == RPCSVC_AUTH_ACCEPT) && (reject == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - /* if both are dont care, that is user did not specify for either allow - * or reject, we leave it up to the general rule to apply, in the hope - * that there is one. - */ - else if ((allow == RPCSVC_AUTH_DONTCARE) && - (reject == RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_DONTCARE; - /* If one is dont care, the other one applies. */ - else if ((allow == RPCSVC_AUTH_ACCEPT) && - (reject == RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_ACCEPT; - else if ((allow == RPCSVC_AUTH_DONTCARE) && - (reject == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - - return final; -} - - -/* Combines the result of the general rule test against, the specific rule - * to determine final permission for the client's address. - * - * | @gen | @spec | Result | - * | A | A | A | - * | A | R | R | - * | A | D | A | - * | D | A | A | - * | D | R | R | - * | D | D | D | - * | R | A | A | - * | R | D | R | - * | R | R | R | - */ -int -nfs_rpcsvc_combine_gen_spec_addr_checks (int gen, int spec) -{ - int final = RPCSVC_AUTH_REJECT; - - if ((gen == RPCSVC_AUTH_ACCEPT) && (spec == RPCSVC_AUTH_ACCEPT)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_ACCEPT) && (spec == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - else if ((gen == RPCSVC_AUTH_ACCEPT) && (spec == RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_DONTCARE) && (spec == RPCSVC_AUTH_ACCEPT)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_DONTCARE) && (spec == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - else if ((gen == RPCSVC_AUTH_DONTCARE) && (spec== RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_DONTCARE; - else if ((gen == RPCSVC_AUTH_REJECT) && (spec == RPCSVC_AUTH_ACCEPT)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_REJECT) && (spec == RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_REJECT; - else if ((gen == RPCSVC_AUTH_REJECT) && (spec == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - - return final; -} - - - -/* Combines the result of the general rule test against, the specific rule - * to determine final test for the connection coming in for a given volume. - * - * | @gen | @spec | Result | - * | A | A | A | - * | A | R | R | - * | A | D | A | - * | D | A | A | - * | D | R | R | - * | D | D | R |, special case, we intentionally disallow this. - * | R | A | A | - * | R | D | R | - * | R | R | R | - */ -int -nfs_rpcsvc_combine_gen_spec_volume_checks (int gen, int spec) -{ - int final = RPCSVC_AUTH_REJECT; - - if ((gen == RPCSVC_AUTH_ACCEPT) && (spec == RPCSVC_AUTH_ACCEPT)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_ACCEPT) && (spec == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - else if ((gen == RPCSVC_AUTH_ACCEPT) && (spec == RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_DONTCARE) && (spec == RPCSVC_AUTH_ACCEPT)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_DONTCARE) && (spec == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - /* On no rule, we reject. */ - else if ((gen == RPCSVC_AUTH_DONTCARE) && (spec== RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_REJECT; - else if ((gen == RPCSVC_AUTH_REJECT) && (spec == RPCSVC_AUTH_ACCEPT)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_REJECT) && (spec == RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_REJECT; - else if ((gen == RPCSVC_AUTH_REJECT) && (spec == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - - return final; -} - - -int -nfs_rpcsvc_conn_peer_check_name (dict_t *options, char *volname, - rpcsvc_conn_t *conn) -{ - int ret = RPCSVC_AUTH_REJECT; - int aret = RPCSVC_AUTH_REJECT; - int rjret = RPCSVC_AUTH_REJECT; - char clstr[RPCSVC_PEER_STRLEN]; - - if (!conn) - return ret; - - ret = nfs_rpcsvc_conn_peername (conn, clstr, RPCSVC_PEER_STRLEN); - if (ret != 0) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get remote addr: " - "%s", gai_strerror (ret)); - ret = RPCSVC_AUTH_REJECT; - goto err; - } - - aret = nfs_rpcsvc_conn_peer_check_allow (options, volname, clstr); - rjret = nfs_rpcsvc_conn_peer_check_reject (options, volname, clstr); - - ret = nfs_rpcsvc_combine_allow_reject_volume_check (aret, rjret); - -err: - return ret; -} - - -int -nfs_rpcsvc_conn_peer_check_addr (dict_t *options, char *volname, - rpcsvc_conn_t *conn) -{ - int ret = RPCSVC_AUTH_REJECT; - int aret = RPCSVC_AUTH_DONTCARE; - int rjret = RPCSVC_AUTH_REJECT; - char clstr[RPCSVC_PEER_STRLEN]; - - if (!conn) - return ret; - - ret = nfs_rpcsvc_conn_peeraddr (conn, clstr, RPCSVC_PEER_STRLEN, NULL, - 0); - if (ret != 0) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get remote addr: " - "%s", gai_strerror (ret)); - ret = RPCSVC_AUTH_REJECT; - goto err; - } - - aret = nfs_rpcsvc_conn_peer_check_allow (options, volname, clstr); - rjret = nfs_rpcsvc_conn_peer_check_reject (options, volname, clstr); - - ret = nfs_rpcsvc_combine_allow_reject_volume_check (aret, rjret); -err: - return ret; -} - - -int -nfs_rpcsvc_conn_check_volume_specific (dict_t *options, char *volname, - rpcsvc_conn_t *conn) -{ - int namechk = RPCSVC_AUTH_REJECT; - int addrchk = RPCSVC_AUTH_REJECT; - gf_boolean_t namelookup = _gf_true; - char *namestr = NULL; - int ret = 0; - - if ((!options) || (!volname) || (!conn)) - return RPCSVC_AUTH_REJECT; - - /* Enabled by default */ - if ((dict_get (options, "rpc-auth.addr.namelookup"))) { - ret = dict_get_str (options, "rpc-auth.addr.namelookup" - , &namestr); - if (ret == 0) - ret = gf_string2boolean (namestr, &namelookup); - } - - /* We need two separate checks because the rules with addresses in them - * can be network addresses which can be general and names can be - * specific which will over-ride the network address rules. - */ - if (namelookup) - namechk = nfs_rpcsvc_conn_peer_check_name (options, volname, - conn); - addrchk = nfs_rpcsvc_conn_peer_check_addr (options, volname, conn); - - if (namelookup) - ret = nfs_rpcsvc_combine_gen_spec_addr_checks (addrchk, - namechk); - else - ret = addrchk; - - return ret; -} - - -int -nfs_rpcsvc_conn_check_volume_general (dict_t *options, rpcsvc_conn_t *conn) -{ - int addrchk = RPCSVC_AUTH_REJECT; - int namechk = RPCSVC_AUTH_REJECT; - gf_boolean_t namelookup = _gf_true; - char *namestr = NULL; - int ret = 0; - - if ((!options) || (!conn)) - return RPCSVC_AUTH_REJECT; - - /* Enabled by default */ - if ((dict_get (options, "rpc-auth.addr.namelookup"))) { - ret = dict_get_str (options, "rpc-auth.addr.namelookup" - , &namestr); - if (ret == 0) - ret = gf_string2boolean (namestr, &namelookup); - } - - /* We need two separate checks because the rules with addresses in them - * can be network addresses which can be general and names can be - * specific which will over-ride the network address rules. - */ - if (namelookup) - namechk = nfs_rpcsvc_conn_peer_check_name (options, NULL, conn); - addrchk = nfs_rpcsvc_conn_peer_check_addr (options, NULL, conn); - - if (namelookup) - ret = nfs_rpcsvc_combine_gen_spec_addr_checks (addrchk, - namechk); - else - ret = addrchk; - - return ret; -} - -int -nfs_rpcsvc_conn_peer_check (dict_t *options, char *volname, rpcsvc_conn_t *conn) -{ - int general_chk = RPCSVC_AUTH_REJECT; - int specific_chk = RPCSVC_AUTH_REJECT; - - if ((!options) || (!volname) || (!conn)) - return RPCSVC_AUTH_REJECT; - - general_chk = nfs_rpcsvc_conn_check_volume_general (options, conn); - specific_chk = nfs_rpcsvc_conn_check_volume_specific (options, volname, - conn); - - return nfs_rpcsvc_combine_gen_spec_volume_checks (general_chk, - specific_chk); -} - - -char * -nfs_rpcsvc_volume_allowed (dict_t *options, char *volname) -{ - char globalrule[] = "rpc-auth.addr.allow"; - char *srchstr = NULL; - char *addrstr = NULL; - int ret = -1; - - if ((!options) || (!volname)) - return NULL; - - ret = gf_asprintf (&srchstr, "rpc-auth.addr.%s.allow", volname); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); - goto out; - } - - if (!dict_get (options, srchstr)) { - GF_FREE (srchstr); - srchstr = globalrule; - ret = dict_get_str (options, srchstr, &addrstr); - } else - ret = dict_get_str (options, srchstr, &addrstr); - -out: - return addrstr; -} - - -/* Initialize the core of a connection */ -rpcsvc_conn_t * -nfs_rpcsvc_conn_init (rpcsvc_t *svc, rpcsvc_program_t *prog, int sockfd) -{ - rpcsvc_conn_t *conn = NULL; - int ret = -1; - unsigned int poolcount = 0; - - conn = GF_CALLOC (1, sizeof(*conn), gf_common_mt_rpcsvc_conn_t); - if (!conn) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "memory allocation failed"); - return NULL; - } - - conn->sockfd = sockfd; - conn->program = (void *)prog; - INIT_LIST_HEAD (&conn->txbufs); - poolcount = RPCSVC_POOLCOUNT_MULT * svc->memfactor; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "tx pool: %d", poolcount); - conn->txpool = mem_pool_new (rpcsvc_txbuf_t, poolcount); - if (!conn->txpool) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "mem pool allocation failed"); - goto free_conn; - } - - gf_log (GF_RPCSVC, GF_LOG_TRACE, "rx pool: %d", poolcount); - conn->rxpool = mem_pool_new (rpcsvc_request_t, poolcount); - if (!conn->rxpool) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "mem pool allocation failed"); - goto free_txp; - } - - /* Cannot consider a connection connected unless the user of this - * connection decides it is ready to use. It is possible that we have - * to free this connection soon after. That free will not happpen - * unless the state is disconnected. - */ - conn->connstate = RPCSVC_CONNSTATE_DISCONNECTED; - pthread_mutex_init (&conn->connlock, NULL); - conn->connref = 0; - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "New connection inited: sockfd: %d", - sockfd); - - ret = 0; -free_txp: - if (ret == -1) - mem_pool_destroy (conn->txpool); - -free_conn: - if (ret == -1) { - GF_FREE (conn); - conn = NULL; - } - - return conn; -} - - -void -nfs_rpcsvc_conn_destroy (rpcsvc_conn_t *conn) -{ - mem_pool_destroy (conn->txpool); - mem_pool_destroy (conn->rxpool); - - /* Need to destory record state, txlists etc. */ - GF_FREE (conn); - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Connection destroyed"); -} - - -int -__nfs_rpcsvc_conn_unref (rpcsvc_conn_t *conn) -{ - --conn->connref; - return conn->connref; -} - - -void -__nfs_rpcsvc_conn_deinit (rpcsvc_conn_t *conn) -{ - if (!conn) - return; - - if ((conn->stage) && (conn->stage->eventpool)) { - event_unregister (conn->stage->eventpool, conn->sockfd, - conn->eventidx); - } - - if (nfs_rpcsvc_conn_check_active (conn)) { - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Connection de-activated:" - " sockfd: %d", conn->sockfd); - conn->connstate = RPCSVC_CONNSTATE_DISCONNECTED; - } - - if (conn->sockfd != -1) { - close (conn->sockfd); - conn->sockfd = -1; - } -} - - -void -nfs_rpcsvc_conn_deinit (rpcsvc_conn_t *conn) -{ - int ref = 0; - - if (!conn) - return; - - pthread_mutex_lock (&conn->connlock); - { - __nfs_rpcsvc_conn_deinit (conn); - ref = __nfs_rpcsvc_conn_unref (conn); - } - pthread_mutex_unlock (&conn->connlock); - - if (ref == 0) - nfs_rpcsvc_conn_destroy (conn); - - return; -} - - -void -nfs_rpcsvc_conn_unref (rpcsvc_conn_t *conn) -{ - int ref = 0; - if (!conn) - return; - - pthread_mutex_lock (&conn->connlock); - { - ref = __nfs_rpcsvc_conn_unref (conn); - } - pthread_mutex_unlock (&conn->connlock); - - if (ref == 0) - nfs_rpcsvc_conn_destroy (conn); -} - - -int -nfs_rpcsvc_conn_active (rpcsvc_conn_t *conn) -{ - int status = 0; - - if (!conn) - return 0; - - pthread_mutex_lock (&conn->connlock); - { - status = nfs_rpcsvc_conn_check_active (conn); - } - pthread_mutex_unlock (&conn->connlock); - - return status; -} - - - -void -nfs_rpcsvc_conn_ref (rpcsvc_conn_t *conn) -{ - if (!conn) - return; - - pthread_mutex_lock (&conn->connlock); - { - ++conn->connref; - } - pthread_mutex_unlock (&conn->connlock); - - return; -} - - -void -nfs_rpcsvc_conn_state_init (rpcsvc_conn_t *conn) -{ - if (!conn) - return; - - ++conn->connref; - conn->connstate = RPCSVC_CONNSTATE_CONNECTED; -} - -/* Builds a rpcsvc_conn_t with the aim of listening on it. - */ -rpcsvc_conn_t * -nfs_rpcsvc_conn_listen_init (rpcsvc_t *svc, rpcsvc_program_t *newprog) -{ - rpcsvc_conn_t *conn = NULL; - int sock = -1; - - if (!newprog) - return NULL; - - sock = nfs_rpcsvc_socket_listen (newprog->progaddrfamily, - newprog->proghost, newprog->progport); - if (sock == -1) - goto err; - - conn = nfs_rpcsvc_conn_init (svc, newprog, sock); - if (!conn) - goto sock_close_err; - - nfs_rpcsvc_conn_state_init (conn); -sock_close_err: - if (!conn) - close (sock); - -err: - return conn; -} - -void -nfs_rpcsvc_record_init (rpcsvc_record_state_t *rs, struct iobuf_pool *pool) -{ - if (!rs) - return; - - rs->state = RPCSVC_READ_FRAGHDR; - rs->vecstate = 0; - rs->remainingfraghdr = RPCSVC_FRAGHDR_SIZE; - rs->remainingfrag = 0; - rs->fragsize = 0; - rs->recordsize = 0; - rs->islastfrag = 0; - - /* If the rs preserves a ref to the iob used by the previous request, - * we must unref it here to prevent memory leak. - * If program actor wanted to keep that memory around, it should've - * refd it on entry into the actor. - */ - if (rs->activeiob) - iobuf_unref (rs->activeiob); - - if (rs->vectoriob) { - iobuf_unref (rs->vectoriob); - rs->vectoriob = NULL; - } - - rs->activeiob = iobuf_get (pool); - rs->fragcurrent = iobuf_ptr (rs->activeiob); - - memset (rs->fragheader, 0, RPCSVC_FRAGHDR_SIZE); - rs->hdrcurrent = &rs->fragheader[0]; - -} - - -int -nfs_rpcsvc_conn_privport_check (rpcsvc_t *svc, char *volname, - rpcsvc_conn_t *conn) -{ - struct sockaddr_in sa; - int ret = RPCSVC_AUTH_REJECT; - socklen_t sasize = sizeof (sa); - char *srchstr = NULL; - char *valstr = NULL; - int globalinsecure = RPCSVC_AUTH_REJECT; - int exportinsecure = RPCSVC_AUTH_DONTCARE; - uint16_t port = 0; - gf_boolean_t insecure = _gf_false; - - if ((!svc) || (!volname) || (!conn)) - return ret; - - ret = nfs_rpcsvc_conn_peeraddr (conn, NULL, 0, (struct sockaddr *)&sa, - sasize); - if (ret != 0) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get peer addr: %s", - gai_strerror (ret)); - ret = RPCSVC_AUTH_REJECT; - goto err; - } - - port = ntohs (sa.sin_port); - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Client port: %d", (int)port); - /* If the port is already a privileged one, dont bother with checking - * options. - */ - if (port <= 1024) { - ret = RPCSVC_AUTH_ACCEPT; - goto err; - } - - /* Disabled by default */ - if ((dict_get (svc->options, "rpc-auth.ports.insecure"))) { - ret = dict_get_str (svc->options, "rpc-auth.ports.insecure" - , &srchstr); - if (ret == 0) { - ret = gf_string2boolean (srchstr, &insecure); - if (ret == 0) { - if (insecure == _gf_true) - globalinsecure = RPCSVC_AUTH_ACCEPT; - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to" - " read rpc-auth.ports.insecure value"); - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to" - " read rpc-auth.ports.insecure value"); - } - - /* Disabled by default */ - ret = gf_asprintf (&srchstr, "rpc-auth.ports.%s.insecure", volname); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); - ret = RPCSVC_AUTH_REJECT; - goto err; - } - - if (dict_get (svc->options, srchstr)) { - ret = dict_get_str (svc->options, srchstr, &valstr); - if (ret == 0) { - ret = gf_string2boolean (srchstr, &insecure); - if (ret == 0) { - if (insecure == _gf_true) - exportinsecure = RPCSVC_AUTH_ACCEPT; - else - exportinsecure = RPCSVC_AUTH_REJECT; - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to" - " read rpc-auth.ports.insecure value"); - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to" - " read rpc-auth.ports.insecure value"); - } - - ret = nfs_rpcsvc_combine_gen_spec_volume_checks (globalinsecure, - exportinsecure); - if (ret == RPCSVC_AUTH_ACCEPT) - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Unprivileged port allowed"); - else - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Unprivileged port not" - " allowed"); - -err: - return ret; -} - -/* Inits a rpcsvc_conn_t after accepting the connection. - */ -rpcsvc_conn_t * -nfs_rpcsvc_conn_accept_init (rpcsvc_t *svc, int listenfd, - rpcsvc_program_t *destprog) -{ - rpcsvc_conn_t *newconn = NULL; - int sock = -1; - int ret = -1; - - sock = nfs_rpcsvc_socket_accept (listenfd); - if (sock == -1) - goto err; - - newconn = nfs_rpcsvc_conn_init (svc, destprog, sock); - if (!newconn) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to init conn object"); - ret = -1; - goto err; - } - - nfs_rpcsvc_record_init (&newconn->rstate, svc->ctx->iobuf_pool); - nfs_rpcsvc_conn_state_init (newconn); - ret = 0; - -err: - if (ret == -1) - close (sock); - - return newconn; -} - - -/* Once the connection has been created, we need to associate it with - * a stage so that the selected stage will handle the event on this connection. - * This function also allows the caller to decide which handler should - * be executed in the context of the stage, and also which specific events - * should be handed to the handler when running in this particular stage. - */ -int -nfs_rpcsvc_stage_conn_associate (rpcsvc_stage_t *stg, rpcsvc_conn_t *conn, - event_handler_t handler, void *data) -{ - int ret = -1; - - if ((!stg) || (!conn)) - return -1; - - conn->stage = stg; - conn->eventidx = event_register (stg->eventpool, conn->sockfd, handler, - data, 1, 0); - if (conn->eventidx == -1) - goto err; - - ret = 0; -err: - return ret; -} - - -/* Depending on the state we're in, return the size of the next read request. */ -size_t -nfs_rpcsvc_record_read_size (rpcsvc_record_state_t *rs) -{ - size_t toread = -1; - - if (!rs) - return -1; - - if (nfs_rpcsvc_record_readfraghdr (rs)) - toread = rs->remainingfraghdr; - else if (nfs_rpcsvc_record_readfrag (rs)) - toread = rs->remainingfrag; - else - toread = RPCSVC_CONN_READ; - - return toread; -} - - -uint32_t -nfs_rpcsvc_record_extract_fraghdr (char *fraghdr) -{ - uint32_t hdr = 0; - if (!fraghdr) - return 0; - - memcpy ((void *)&hdr, fraghdr, sizeof (hdr)); - - hdr = ntohl (hdr); - return hdr; -} - - -ssize_t -nfs_rpcsvc_record_read_complete_fraghdr (rpcsvc_record_state_t *rs, - ssize_t dataread) -{ - uint32_t remhdr = 0; - char *fraghdrstart = NULL; - uint32_t fraghdr = 0; - - fraghdrstart = &rs->fragheader[0]; - remhdr = rs->remainingfraghdr; - fraghdr = nfs_rpcsvc_record_extract_fraghdr (fraghdrstart); - rs->fragsize = RPCSVC_FRAGSIZE (fraghdr); - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Received fragment size: %d", - rs->fragsize); - if (nfs_rpcsvc_record_vectored (rs)) { - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Vectored RPC header," - " remaining: %d", RPCSVC_BARERPC_MSGSZ); - rs->remainingfrag = RPCSVC_BARERPC_MSGSZ; - } else { - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Regular RPC header," - " remaining: %d", rs->fragsize); - rs->remainingfrag = rs->fragsize; - } - - rs->state = RPCSVC_READ_FRAG; - dataread -= remhdr; - rs->remainingfraghdr -= remhdr; - rs->islastfrag = RPCSVC_LASTFRAG (fraghdr); - - return dataread; -} - - -ssize_t -nfs_rpcsvc_record_read_partial_fraghdr (rpcsvc_record_state_t *rs, - ssize_t dataread) -{ - - /* In case we got less than even the remaining header size, - * we need to consume it all and wait for remaining frag hdr - * bytes to come in. - */ - rs->remainingfraghdr -= dataread; - nfs_rpcsvc_record_update_currenthdr (rs, dataread); - dataread = 0; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Fragment header remaining: %d", - rs->remainingfraghdr); - - return dataread; -} - - -ssize_t -nfs_rpcsvc_record_update_fraghdr (rpcsvc_record_state_t *rs, ssize_t dataread) -{ - if ((!rs) || (dataread <= 0)) - return -1; - - /* Why are we even here, we're not supposed to be in the fragment - * header processing state. - */ - if (!nfs_rpcsvc_record_readfraghdr(rs)) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "record state inconsistent" - ": request to update frag header when state is not" - "RPCSVC_READ_FRAGHDR"); - return -1; - } - - /* Again, if header has been read then the state member above should've - * been different, this is crazy. We should not be here. - */ - if (rs->remainingfraghdr == 0) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "record state inconsistent" - ": request to update frag header when frag header" - "remaining is 0."); - return -1; - } - - /* We've definitely got the full header now and may be even more. */ - if (dataread >= rs->remainingfraghdr) - dataread = nfs_rpcsvc_record_read_complete_fraghdr (rs, - dataread); - else - dataread = nfs_rpcsvc_record_read_partial_fraghdr (rs, - dataread); - - return dataread; -} - -ssize_t -nfs_rpcsvc_record_read_complete_frag (rpcsvc_record_state_t *rs, - ssize_t dataread) -{ - uint32_t remfrag; - - /* Since the frag is now complete, change the state to the next - * one, i.e. to read the header of the next fragment. - */ - remfrag = rs->remainingfrag; - rs->state = RPCSVC_READ_FRAGHDR; - dataread -= remfrag; - - /* This will be 0 now. */ - rs->remainingfrag -= remfrag; - - /* Now that the fragment is complete, we must update the - * record size. Recall that fragsize was got from the frag - * header. - */ - rs->recordsize += rs->fragsize; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Fragment remaining: %d", - rs->remainingfrag); - - return dataread; -} - - -ssize_t -nfs_rpcsvc_record_read_partial_frag (rpcsvc_record_state_t *rs, - ssize_t dataread) -{ - /* Just take whatever has come through the current network buffer. */ - rs->remainingfrag -= dataread; - - nfs_rpcsvc_record_update_currentfrag (rs, dataread); - /* Since we know we're consuming the whole buffer from dataread - * simply setting to 0 zero is fine. - */ - dataread = 0; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Fragment remaining: %d", - rs->remainingfrag); - return dataread; -} - - -ssize_t -nfs_rpcsvc_record_update_frag (rpcsvc_record_state_t *rs, ssize_t dataread) -{ - if ((!rs) || (dataread <= 0)) - return -1; - - if (!nfs_rpcsvc_record_readfrag (rs)) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "record state inconsistent" - ": request to update fragment when record state is not" - "RPCSVC_READ_FRAG."); - return -1; - } - - if (rs->remainingfrag == 0) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "record state inconsistent" - ": request to update fragment when there is no fragment" - " data remaining to be read."); - return -1; - } - - /* We've read in more data than the current fragment requires. */ - if (dataread >= rs->remainingfrag) - dataread = nfs_rpcsvc_record_read_complete_frag (rs, dataread); - else - dataread = nfs_rpcsvc_record_read_partial_frag (rs, dataread); - - return dataread; -} - - -/* This needs to change to returning errors, since - * we need to return RPC specific error messages when some - * of the pointers below are NULL. - */ -rpcsvc_actor_t * -nfs_rpcsvc_program_actor (rpcsvc_conn_t *conn, rpcsvc_request_t *req) -{ - rpcsvc_program_t *program = NULL; - int err = SYSTEM_ERR; - rpcsvc_actor_t *actor = NULL; - - if ((!conn) || (!req)) - goto err; - - program = (rpcsvc_program_t *)conn->program; - if (!program) - goto err; - - if (req->prognum != program->prognum) { - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "RPC program not available"); - err = PROG_UNAVAIL; - goto err; - } - - if (!program->actors) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC System error"); - err = SYSTEM_ERR; - goto err; - } - - if (req->progver != program->progver) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC program version not" - " available"); - err = PROG_MISMATCH; - goto err; - } - - if ((req->procnum < 0) || (req->procnum >= program->numactors)) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC Program procedure not" - " available"); - err = PROC_UNAVAIL; - goto err; - } - - actor = &program->actors[req->procnum]; - if (!actor->actor) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC Program procedure not" - " available"); - err = PROC_UNAVAIL; - actor = NULL; - goto err; - } - - err = SUCCESS; - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Actor found: %s - %s", - program->progname, actor->procname); -err: - if (req) - req->rpc_err = err; - - return actor; -} - - -rpcsvc_txbuf_t * -nfs_rpcsvc_init_txbuf (rpcsvc_conn_t *conn, struct iovec msg, struct iobuf *iob, - struct iobref *iobref, int txflags) -{ - rpcsvc_txbuf_t *txbuf = NULL; - - txbuf = (rpcsvc_txbuf_t *) mem_get(conn->txpool); - if (!txbuf) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get txbuf"); - return NULL; - } - - memset (txbuf, 0, sizeof (*txbuf)); - INIT_LIST_HEAD (&txbuf->txlist); - txbuf->buf = msg; - - /* If it was required, this iob must've been ref'd already - * so I dont have to bother here. - */ - txbuf->iob = iob; - txbuf->iobref = iobref; - txbuf->offset = 0; - txbuf->txbehave = txflags; - - return txbuf; -} - - -int -nfs_rpcsvc_conn_append_txlist (rpcsvc_conn_t *conn, struct iovec msg, - struct iobuf *iob, int txflags) -{ - rpcsvc_txbuf_t *txbuf = NULL; - - if ((!conn) || (!msg.iov_base) || (!iob)) - return -1; - - txbuf = nfs_rpcsvc_init_txbuf (conn, msg, iob, NULL, txflags); - if (!txbuf) - return -1; - - list_add_tail (&txbuf->txlist, &conn->txbufs); - return 0; -} - - -void -nfs_rpcsvc_set_lastfrag (uint32_t *fragsize) { - (*fragsize) |= 0x80000000U; -} - -void -nfs_rpcsvc_set_frag_header_size (uint32_t size, char *haddr) -{ - size = htonl (size); - memcpy (haddr, &size, sizeof (size)); -} - -void -nfs_rpcsvc_set_last_frag_header_size (uint32_t size, char *haddr) -{ - nfs_rpcsvc_set_lastfrag (&size); - nfs_rpcsvc_set_frag_header_size (size, haddr); -} - - -/* Given the RPC reply structure and the payload handed by the RPC program, - * encode the RPC record header into the buffer pointed by recordstart. - */ -struct iovec -nfs_rpcsvc_record_build_header (char *recordstart, size_t rlen, - struct rpc_msg reply, size_t payload) -{ - struct iovec replyhdr; - struct iovec txrecord = {0, 0}; - size_t fraglen = 0; - int ret = -1; - - /* After leaving aside the 4 bytes for the fragment header, lets - * encode the RPC reply structure into the buffer given to us. - */ - ret = nfs_rpc_reply_to_xdr (&reply,(recordstart + RPCSVC_FRAGHDR_SIZE), - rlen, &replyhdr); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to create RPC reply"); - goto err; - } - - fraglen = payload + replyhdr.iov_len; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Reply fraglen %zu, payload: %zu, " - "rpc hdr: %zu", fraglen, payload, replyhdr.iov_len); - - /* Since we're not spreading RPC records over mutiple fragments - * we just set this fragment as the first and last fragment for this - * record. - */ - nfs_rpcsvc_set_last_frag_header_size (fraglen, recordstart); - - /* Even though the RPC record starts at recordstart+RPCSVC_FRAGHDR_SIZE - * we need to transmit the record with the fragment header, which starts - * at recordstart. - */ - txrecord.iov_base = recordstart; - - /* Remember, this is only the vec for the RPC header and does not - * include the payload above. We needed the payload only to calculate - * the size of the full fragment. This size is sent in the fragment - * header. - */ - txrecord.iov_len = RPCSVC_FRAGHDR_SIZE + replyhdr.iov_len; - -err: - return txrecord; -} - - -int -nfs_rpcsvc_conn_submit (rpcsvc_conn_t *conn, struct iovec hdr, - struct iobuf *hdriob, struct iovec msgvec, - struct iobuf *msgiob) -{ - int ret = -1; - - if ((!conn) || (!hdr.iov_base) || (!hdriob)) - return -1; - - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Tx Header: %zu, payload: %zu", - hdr.iov_len, msgvec.iov_len); - /* Now that we have both the RPC and Program buffers in xdr format - * lets hand it to the transmission layer. - */ - pthread_mutex_lock (&conn->connlock); - { - if (!nfs_rpcsvc_conn_check_active (conn)) { - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Connection inactive"); - goto unlock_err; - } - - ret = nfs_rpcsvc_conn_append_txlist (conn, hdr, hdriob, - RPCSVC_TXB_FIRST); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to append " - "header to transmission list"); - goto unlock_err; - } - - /* It is possible that this RPC reply is an error reply. In that - * case we might not have been handed a payload. - */ - ret = 0; - if (msgiob) - ret = nfs_rpcsvc_conn_append_txlist (conn, msgvec, - msgiob, - RPCSVC_TXB_LAST); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to append" - " payload to transmission list"); - goto unlock_err; - } - } -unlock_err: - pthread_mutex_unlock (&conn->connlock); - - if (ret == -1) - goto err; - - /* Tell event pool, we're interested in poll_out to trigger flush - * of our tx buffers. - */ - conn->eventidx = event_select_on (conn->stage->eventpool, conn->sockfd, - conn->eventidx, -1, 1); - ret = 0; -err: - - return ret; -} - - -int -nfs_rpcsvc_fill_reply (rpcsvc_request_t *req, struct rpc_msg *reply) -{ - rpcsvc_program_t *prog = NULL; - if ((!req) || (!reply)) - return -1; - - prog = nfs_rpcsvc_request_program (req); - nfs_rpc_fill_empty_reply (reply, req->xid); - - if (req->rpc_stat == MSG_DENIED) - nfs_rpc_fill_denied_reply (reply, req->rpc_err, req->auth_err); - else if (req->rpc_stat == MSG_ACCEPTED) - nfs_rpc_fill_accepted_reply (reply, req->rpc_err, - prog->proglowvers, - prog->proghighvers, - req->verf.flavour, - req->verf.datalen, - req->verf.authdata); - else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Invalid rpc_stat value"); - - return 0; -} - - -/* Given a request and the reply payload, build a reply and encodes the reply - * into a record header. This record header is encoded into the vector pointed - * to be recbuf. - * msgvec is the buffer that points to the payload of the RPC program. - * This buffer can be NULL, if an RPC error reply is being constructed. - * The only reason it is needed here is that in case the buffer is provided, - * we should account for the length of that buffer in the RPC fragment header. - */ -struct iobuf * -nfs_rpcsvc_record_build_record (rpcsvc_request_t *req, size_t payload, - struct iovec *recbuf) -{ - struct rpc_msg reply; - struct iobuf *replyiob = NULL; - char *record = NULL; - struct iovec recordhdr = {0, }; - size_t pagesize = 0; - rpcsvc_conn_t *conn = NULL; - rpcsvc_t *svc = NULL; - - if ((!req) || (!req->conn) || (!recbuf)) - return NULL; - - /* First, try to get a pointer into the buffer which the RPC - * layer can use. - */ - conn = req->conn; - svc = nfs_rpcsvc_conn_rpcsvc (conn); - replyiob = iobuf_get (svc->ctx->iobuf_pool); - pagesize = iobpool_pagesize ((struct iobuf_pool *)svc->ctx->iobuf_pool); - if (!replyiob) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get iobuf"); - goto err_exit; - } - - record = iobuf_ptr (replyiob); /* Now we have it. */ - - /* Fill the rpc structure and XDR it into the buffer got above. */ - nfs_rpcsvc_fill_reply (req, &reply); - recordhdr = nfs_rpcsvc_record_build_header (record, pagesize, reply, - payload); - if (!recordhdr.iov_base) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to build record " - " header"); - iobuf_unref (replyiob); - replyiob = NULL; - recbuf->iov_base = NULL; - goto err_exit; - } - - recbuf->iov_base = recordhdr.iov_base; - recbuf->iov_len = recordhdr.iov_len; -err_exit: - return replyiob; -} - - -/* - * The function to submit a program message to the RPC service. - * This message is added to the transmission queue of the - * conn. - * - * Program callers are not expected to use the msgvec->iov_base - * address for anything else. - * Nor are they expected to free it once this function returns. - * Once the transmission of the buffer is completed by the RPC service, - * the memory area as referenced through @msg will be unrefed. - * If a higher layer does not want anything to do with this iobuf - * after this function returns, it should call unref on it. For keeping - * it around till the transmission is actually complete, rpcsvc also refs it. - * * - * If this function returns an error by returning -1, the - * higher layer programs should assume that a disconnection happened - * and should know that the conn memory area as well as the req structure - * has been freed internally. - * - * For now, this function assumes that a submit is always called - * to send a new record. Later, if there is a situation where different - * buffers for the same record come from different sources, then we'll - * need to change this code to account for multiple submit calls adding - * the buffers into a single record. - */ - -int -nfs_rpcsvc_submit_generic (rpcsvc_request_t *req, struct iovec msgvec, - struct iobuf *msg) -{ - int ret = -1; - struct iobuf *replyiob = NULL; - struct iovec recordhdr = {0, }; - rpcsvc_conn_t *conn = NULL; - - if ((!req) || (!req->conn)) - return -1; - - conn = req->conn; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Tx message: %zu", msgvec.iov_len); - /* Build the buffer containing the encoded RPC reply. */ - replyiob = nfs_rpcsvc_record_build_record (req, msgvec.iov_len, - &recordhdr); - if (!replyiob) { - gf_log (GF_RPCSVC, GF_LOG_ERROR,"Reply record creation failed"); - goto disconnect_exit; - } - - /* Must ref the iobuf got from higher layer so that the higher layer - * can rest assured that it can unref it and leave the final freeing - * of the buffer to us. Note msg can be NULL if an RPC-only message - * was being sent. Happens when an RPC error reply is being sent. - */ - if (msg) - iobuf_ref (msg); - ret = nfs_rpcsvc_conn_submit (conn, recordhdr, replyiob, msgvec, msg); - mem_put (conn->rxpool, req); - - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to submit message"); - iobuf_unref (replyiob); - } - -disconnect_exit: - /* Note that a unref is called everytime a reply is sent. This is in - * response to the ref that is performed on the conn when a request is - * handed to the RPC program. - * - * The catch, however, is that if the reply is an rpc error, we must - * not unref. This is because the ref only contains - * references for the actors to which the request was handed plus one - * reference maintained by the RPC layer. By unrefing for a case where - * no actor was called, we will be losing the ref held for the RPC - * layer. - */ - if ((nfs_rpcsvc_request_accepted (req)) && - (nfs_rpcsvc_request_accepted_success (req))) - nfs_rpcsvc_conn_unref (conn); - - return ret; -} - - -int -nfs_rpcsvc_request_attach_vector (rpcsvc_request_t *req, struct iovec msgvec, - struct iobuf *iob, struct iobref *iobref, - int finalvector) -{ - rpcsvc_txbuf_t *txb = NULL; - int txflags = 0; - - if ((!req) || (!msgvec.iov_base)) - return -1; - - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Tx Vector: %zu", msgvec.iov_len); - if (finalvector) - txflags |= RPCSVC_TXB_LAST; - /* We only let the user decide whether this is the last vector for the - * record, since the first vector is always the RPC header. - */ - txb = nfs_rpcsvc_init_txbuf (req->conn, msgvec, iob, iobref, txflags); - if (!txb) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Could not init tx buf"); - return -1; - } - - req->payloadsize += msgvec.iov_len; - if (iob) - iobuf_ref (iob); - if (iobref) - iobref_ref (iobref); - list_add_tail (&txb->txlist, &req->txlist); - - return 0; -} - - -int -nfs_rpcsvc_request_attach_vectors (rpcsvc_request_t *req, struct iovec *payload, - int vcount, struct iobref *piobref) -{ - int c = 0; - int ret = -1; - - for (;c < (vcount-1); c++) { - ret = nfs_rpcsvc_request_attach_vector (req, payload[c], NULL, - piobref, 0); - if (ret < 0) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to attach " - "vector"); - goto out; - } - } - - ret = nfs_rpcsvc_request_attach_vector (req, payload[vcount-1], NULL, - piobref, 1); - if (ret < 0) - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to attach final vec"); - -out: - return ret; -} - - -int -nfs_rpcsvc_submit_vectors (rpcsvc_request_t *req) -{ - int ret = -1; - struct iobuf *replyiob = NULL; - struct iovec recordhdr = {0, }; - rpcsvc_txbuf_t *rpctxb = NULL; - - if ((!req) || (!req->conn)) - return -1; - - /* Build the buffer containing the encoded RPC reply. */ - replyiob = nfs_rpcsvc_record_build_record (req, req->payloadsize, - &recordhdr); - if (!replyiob) { - gf_log (GF_RPCSVC, GF_LOG_ERROR,"Reply record creation failed"); - goto disconnect_exit; - } - - rpctxb = nfs_rpcsvc_init_txbuf (req->conn, recordhdr, replyiob, NULL, - RPCSVC_TXB_FIRST); - if (!rpctxb) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to create tx buf"); - goto disconnect_exit; - } - - pthread_mutex_lock (&req->conn->connlock); - { - list_splice_init (&req->txlist, &req->conn->txbufs); - list_add (&rpctxb->txlist, &req->conn->txbufs); - } - pthread_mutex_unlock (&req->conn->connlock); - - ret = 0; - req->conn->eventidx = event_select_on (req->conn->stage->eventpool, - req->conn->sockfd, - req->conn->eventidx, -1, 1); -disconnect_exit: - /* Note that a unref is called everytime a reply is sent. This is in - * response to the ref that is performed on the conn when a request is - * handed to the RPC program. - */ - nfs_rpcsvc_conn_unref (req->conn); - if (ret == -1) - iobuf_unref (replyiob); - - mem_put (req->conn->rxpool, req); - return ret; -} - - -int -nfs_rpcsvc_error_reply (rpcsvc_request_t *req) -{ - struct iovec dummyvec = {0, }; - - if (!req) - return -1; - - /* At this point the req should already have been filled with the - * appropriate RPC error numbers. - */ - return nfs_rpcsvc_submit_generic (req, dummyvec, NULL); -} - - -rpcsvc_request_t * -nfs_rpcsvc_request_init (rpcsvc_conn_t *conn, struct rpc_msg *callmsg, - struct iovec progmsg, rpcsvc_request_t *req) -{ - if ((!conn) || (!callmsg)|| (!req)) - return NULL; - - - /* We start a RPC request as always denied. */ - req->rpc_stat = MSG_DENIED; - req->xid = nfs_rpc_call_xid (callmsg); - req->prognum = nfs_rpc_call_program (callmsg); - req->progver = nfs_rpc_call_progver (callmsg); - req->procnum = nfs_rpc_call_progproc (callmsg); - req->conn = conn; - req->msg = progmsg; - req->recordiob = conn->rstate.activeiob; - INIT_LIST_HEAD (&req->txlist); - req->payloadsize = 0; - - /* By this time, the data bytes for the auth scheme would have already - * been copied into the required sections of the req structure, - * we just need to fill in the meta-data about it now. - */ - req->cred.flavour = nfs_rpc_call_cred_flavour (callmsg); - req->cred.datalen = nfs_rpc_call_cred_len (callmsg); - req->verf.flavour = nfs_rpc_call_verf_flavour (callmsg); - req->verf.datalen = nfs_rpc_call_verf_len (callmsg); - - /* AUTH */ - nfs_rpcsvc_auth_request_init (req); - return req; -} - - -rpcsvc_request_t * -nfs_rpcsvc_request_create (rpcsvc_conn_t *conn) -{ - char *msgbuf = NULL; - struct rpc_msg rpcmsg; - struct iovec progmsg; /* RPC Program payload */ - rpcsvc_request_t *req = NULL; - int ret = -1; - - if (!conn) - return NULL; - - /* We need to allocate the request before actually calling - * rpcsvc_request_init on the request so that we, can fill the auth - * data directly into the request structure from the message iobuf. - * This avoids a need to keep a temp buffer into which the auth data - * would've been copied otherwise. - */ - nfs_rpcsvc_alloc_request (conn, req); - if (!req) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to alloc request"); - goto err; - } - - msgbuf = iobuf_ptr (conn->rstate.activeiob); - ret = nfs_xdr_to_rpc_call (msgbuf, conn->rstate.recordsize, &rpcmsg, - &progmsg, req->cred.authdata, - req->verf.authdata); - - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC call decoding failed"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); - goto err; - } - - ret = -1; - nfs_rpcsvc_request_init (conn, &rpcmsg, progmsg, req); - - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "RPC XID: %lx, Ver: %ld, Program: %ld," - " ProgVers: %ld, Proc: %ld", nfs_rpc_call_xid (&rpcmsg), - nfs_rpc_call_rpcvers (&rpcmsg), nfs_rpc_call_program (&rpcmsg), - nfs_rpc_call_progver (&rpcmsg), - nfs_rpc_call_progproc (&rpcmsg)); - - if (nfs_rpc_call_rpcvers (&rpcmsg) != 2) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC version not supported"); - nfs_rpcsvc_request_seterr (req, RPC_MISMATCH); - goto err; - } - - ret = nfs_rpcsvc_authenticate (req); - if (ret == RPCSVC_AUTH_REJECT) { - /* No need to set auth_err, that is the responsibility of - * the authentication handler since only that know what exact - * error happened. - */ - nfs_rpcsvc_request_seterr (req, AUTH_ERROR); - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed authentication"); - ret = -1; - goto err; - } - - - /* If the error is not RPC_MISMATCH, we consider the call as accepted - * since we are not handling authentication failures for now. - */ - req->rpc_stat = MSG_ACCEPTED; - ret = 0; -err: - if (ret == -1) { - ret = nfs_rpcsvc_error_reply (req); - req = NULL; - } - - return req; -} - - -int -nfs_rpcsvc_handle_rpc_call (rpcsvc_conn_t *conn) -{ - rpcsvc_actor_t *actor = NULL; - rpcsvc_request_t *req = NULL; - int ret = -1; - - if (!conn) - return -1; - - req = nfs_rpcsvc_request_create (conn); - if (!req) - goto err; - - if (!nfs_rpcsvc_request_accepted (req)) - goto err_reply; - - actor = nfs_rpcsvc_program_actor (conn, req); - if (!actor) - goto err_reply; - - if ((actor) && (actor->actor)) { - THIS = nfs_rpcsvc_request_actorxl (req); - nfs_rpcsvc_conn_ref (conn); - ret = actor->actor (req); - } - -err_reply: - if (ret == RPCSVC_ACTOR_ERROR) - ret = nfs_rpcsvc_error_reply (req); - - /* No need to propagate error beyond this function since the reply - * has now been queued. */ - ret = 0; -err: - return ret; -} - -#define nfs_rpc_call_cred_addr(rs) (iobuf_ptr ((rs)->activeiob) + RPCSVC_BARERPC_MSGSZ - 4) - -uint32_t -nfs_rpcsvc_call_credlen (rpcsvc_record_state_t *rs) -{ - char *credaddr = NULL; - uint32_t credlen_nw = 0; - uint32_t credlen_host = 0; - - /* Position to the start of the credential length field. */ - credaddr = nfs_rpc_call_cred_addr (rs); - credlen_nw = *(uint32_t *)credaddr; - credlen_host = ntohl (credlen_nw); - - return credlen_host; -} - -uint32_t -nfs_rpcsvc_call_verflen (rpcsvc_record_state_t *rs) -{ - char *verfaddr = NULL; - uint32_t verflen_nw = 0; - uint32_t verflen_host = 0; - uint32_t credlen = 0; - - /* Position to the start of the verifier length field. */ - credlen = nfs_rpcsvc_call_credlen (rs); - verfaddr = (nfs_rpc_call_cred_addr (rs) + 4 + credlen); - verflen_nw = *(uint32_t *)verfaddr; - verflen_host = ntohl (verflen_nw); - - return verflen_host; -} - - -void -nfs_rpcsvc_update_vectored_verf (rpcsvc_record_state_t *rs) -{ - if (!rs) - return; - - rs->recordsize += nfs_rpcsvc_call_verflen (rs); - return; -} - - -void -nfs_rpcsvc_handle_vectored_prep_rpc_call (rpcsvc_conn_t *conn) -{ - rpcsvc_actor_t *actor = NULL; - rpcsvc_request_t *req = NULL; - rpcsvc_record_state_t *rs = NULL; - rpcsvc_t *svc = NULL; - int ret = -1; - ssize_t remfrag = RPCSVC_ACTOR_ERROR; - int newbuf = 0; - - if (!conn) - return; - - rs = &conn->rstate; - - /* In case one of the steps below fails, we need to make sure that the - * remaining frag in the kernel's buffers are read-out so that the - * requests that follow can be served. - */ - rs->remainingfrag = rs->fragsize - rs->recordsize; - rs->vecstate = RPCSVC_VECTOR_IGNORE; - req = nfs_rpcsvc_request_create (conn); - svc = nfs_rpcsvc_conn_rpcsvc (conn); - if (!req) - goto err; - - if (!nfs_rpcsvc_request_accepted (req)) - goto err_reply; - - actor = nfs_rpcsvc_program_actor (conn, req); - if (!actor) - goto err_reply; - - if (!actor->vector_sizer) { - ret = -1; - nfs_rpcsvc_request_seterr (req, PROC_UNAVAIL); - goto err_reply; - } - - nfs_rpcsvc_conn_ref (conn); - THIS = nfs_rpcsvc_request_actorxl (req); - ret = actor->vector_sizer (req, &remfrag, &newbuf); - nfs_rpcsvc_conn_unref (conn); - - if (ret == RPCSVC_ACTOR_ERROR) { - ret = -1; - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); - goto err_reply; - } - - rs->remainingfrag = remfrag; - rs->vecstate = RPCSVC_VECTOR_READPROCHDR; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Vectored RPC proc header remaining:" - " %d", rs->remainingfrag); - conn->vectoredreq = req; - - /* Store the reference to the current frag pointer. This is where the - * proc header will be read into. - */ - req->msg.iov_base = rs->fragcurrent; - req->msg.iov_len = rs->remainingfrag; - ret = 0; - -err_reply: - if (ret == -1) - ret = nfs_rpcsvc_error_reply (req); - - /* No need to propagate error beyond this function since the reply - * has now been queued. */ - ret = 0; -err: - return; -} - - -void -nfs_rpcsvc_update_vectored_verfsz (rpcsvc_conn_t *conn) -{ - rpcsvc_record_state_t *rs = NULL; - uint32_t verflen = 0; - - if (!conn) - return; - - rs = &conn->rstate; - - verflen = nfs_rpcsvc_call_verflen (rs); - rs->recordsize += 8; - if (verflen > 0) { - rs->remainingfrag = verflen; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Vectored RPC verf remaining: " - " %d", rs->remainingfrag); - rs->vecstate = RPCSVC_VECTOR_READVERF; - } else { - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Vectored RPC preparing call"); - nfs_rpcsvc_handle_vectored_prep_rpc_call (conn); - } - - return; -} - - -void -nfs_rpcsvc_update_vectored_cred (rpcsvc_record_state_t *rs) -{ - uint32_t credlen = 0; - - if (!rs) - return; - - credlen = nfs_rpcsvc_call_credlen (rs); - /* Update remainingfrag to read the 8 bytes needed for - * reading verf flavour and verf len. - */ - rs->remainingfrag = (2 * sizeof (uint32_t)); - rs->vecstate = RPCSVC_VECTOR_READVERFSZ; - rs->recordsize += credlen; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Vectored RPC verfsz remaining: %d", - rs->remainingfrag); - - return; -} - -void -nfs_rpcsvc_update_vectored_barerpc (rpcsvc_record_state_t *rs) -{ - uint32_t credlen = 0; - - if (!rs) - return; - - credlen = nfs_rpcsvc_call_credlen (rs); - rs->recordsize = RPCSVC_BARERPC_MSGSZ; - if (credlen == 0) { - rs->remainingfrag = 8; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Vectored RPC verfsz remaining" - ": %d", rs->remainingfrag); - rs->vecstate = RPCSVC_VECTOR_READVERFSZ; - } else { - rs->remainingfrag = credlen; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Vectored RPC cred remaining: " - "%d", rs->remainingfrag); - rs->vecstate = RPCSVC_VECTOR_READCRED; - } - - return; -} - - -void -nfs_rpcsvc_handle_vectored_rpc_call (rpcsvc_conn_t *conn) -{ - rpcsvc_actor_t *actor = NULL; - rpcsvc_request_t *req = NULL; - rpcsvc_record_state_t *rs = NULL; - rpcsvc_t *svc = NULL; - int ret = -1; - ssize_t remfrag = -1; - int newbuf = 0; - - if (!conn) - return; - - rs = &conn->rstate; - - req = conn->vectoredreq; - svc = nfs_rpcsvc_conn_rpcsvc (conn); - - if (!req) - goto err; - - actor = nfs_rpcsvc_program_actor (conn, req); - if (!actor) - goto err_reply; - - if (!actor->vector_sizer) { - ret = -1; - nfs_rpcsvc_request_seterr (req, PROC_UNAVAIL); - goto err_reply; - } - - req->msg.iov_len = (unsigned long)((long)rs->fragcurrent - (long)req->msg.iov_base); - nfs_rpcsvc_conn_ref (conn); - THIS = nfs_rpcsvc_request_actorxl (req); - ret = actor->vector_sizer (req, &remfrag, &newbuf); - nfs_rpcsvc_conn_unref (conn); - if (ret == RPCSVC_ACTOR_ERROR) { - ret = -1; - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); - goto err_reply; - } - - if (newbuf) { - rs->vectoriob = iobuf_get (svc->ctx->iobuf_pool); - rs->fragcurrent = iobuf_ptr (rs->vectoriob); - rs->vecstate = RPCSVC_VECTOR_READVEC; - rs->remainingfrag = remfrag; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Vectored RPC buf remaining:" - " %d", rs->remainingfrag); - } else { - rs->remainingfrag = remfrag; - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Vectored RPC proc remaining:" - " %d", rs->remainingfrag); - } - - ret = 0; -err_reply: - if (ret == -1) - ret = nfs_rpcsvc_error_reply (req); - - /* No need to propagate error beyond this function since the reply - * has now been queued. */ - ret = 0; -err: - return; -} - - - -void -nfs_rpcsvc_record_vectored_call_actor (rpcsvc_conn_t *conn) -{ - rpcsvc_actor_t *actor = NULL; - rpcsvc_request_t *req = NULL; - rpcsvc_record_state_t *rs = NULL; - rpcsvc_t *svc = NULL; - int ret = -1; - - if (!conn) - return; - - rs = &conn->rstate; - req = conn->vectoredreq; - svc = nfs_rpcsvc_conn_rpcsvc (conn); - - if (!req) - goto err; - - actor = nfs_rpcsvc_program_actor (conn, req); - if (!actor) - goto err_reply; - - if (actor->vector_actor) { - nfs_rpcsvc_conn_ref (conn); - THIS = nfs_rpcsvc_request_actorxl (req); - ret = actor->vector_actor (req, rs->vectoriob); - } else { - nfs_rpcsvc_request_seterr (req, PROC_UNAVAIL); - gf_log (GF_RPCSVC, GF_LOG_ERROR, "No vectored handler present"); - ret = RPCSVC_ACTOR_ERROR; - } - -err_reply: - if (ret == RPCSVC_ACTOR_ERROR) - ret = nfs_rpcsvc_error_reply (req); - - /* No need to propagate error beyond this function since the reply - * has now been queued. */ - ret = 0; -err: - return; -} - - - -ssize_t -nfs_rpcsvc_update_vectored_state (rpcsvc_conn_t *conn) -{ - rpcsvc_record_state_t *rs = NULL; - rpcsvc_t *svc = NULL; - - if (!conn) - return 0; - - /* At this point, we can be confident that the activeiob contains - * exactly the first RPCSVC_BARERPC_MSGSZ bytes needed in order to - * determine the program and actor. So the next state will be - * to read the credentials. - * - * But first, try to determine how many more bytes do we need from the - * network to complete the RPC message including the credentials. - */ - - rs = &conn->rstate; - if (nfs_rpcsvc_record_vectored_baremsg (rs)) - nfs_rpcsvc_update_vectored_barerpc (rs); - else if (nfs_rpcsvc_record_vectored_cred (rs)) - nfs_rpcsvc_update_vectored_cred (rs); - else if (nfs_rpcsvc_record_vectored_verfsz (rs)) - nfs_rpcsvc_update_vectored_verfsz (conn); - else if (nfs_rpcsvc_record_vectored_verfread (rs)) { - nfs_rpcsvc_update_vectored_verf (rs); - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Vectored RPC preparing call"); - nfs_rpcsvc_handle_vectored_prep_rpc_call (conn); - } else if (nfs_rpcsvc_record_vectored_readprochdr (rs)) - nfs_rpcsvc_handle_vectored_rpc_call (conn); - else if (nfs_rpcsvc_record_vectored_ignore (rs)) { - svc = nfs_rpcsvc_conn_rpcsvc (conn); - nfs_rpcsvc_record_init (rs, svc->ctx->iobuf_pool); - } else if (nfs_rpcsvc_record_vectored_readvec (rs)) { - svc = nfs_rpcsvc_conn_rpcsvc (conn); - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Vectored RPC vector read"); - nfs_rpcsvc_record_vectored_call_actor (conn); - nfs_rpcsvc_record_init (rs, svc->ctx->iobuf_pool); - } - - return 0; -} - - -ssize_t -nfs_rpcsvc_record_read_partial_frag (rpcsvc_record_state_t *rs, - ssize_t dataread); - -ssize_t -nfs_rpcsvc_update_vectored_msg (rpcsvc_conn_t *conn, ssize_t dataread) -{ - - if (!conn) - return dataread; - - /* find out how much of the bare msg is pending and set that up to be - * read into the updated fragcurrent along with the updated size into - * remainingfrag. - */ - - - /* Incidently, the logic needed here is similar to a regular partial - * fragment read since we've already set the remainingfrag member in - * rstate to be RPCSVC_BARERPC_MSGSZ for the purpose of a vectored - * fragment. - */ - return nfs_rpcsvc_record_read_partial_frag (&conn->rstate, dataread); -} - -/* FIX: As a first version of vectored reading, I am assuming dataread will - * always be equal to RPCSVC_BARERPC_MSGSZ for the sake of simplicity on the - * belief that we're never actually reading more bytes than needed in each - * poll_in. - */ -ssize_t -nfs_rpcsvc_handle_vectored_frag (rpcsvc_conn_t *conn, ssize_t dataread) -{ - if (!conn) - return dataread; - - /* At this point we can be confident that only the frag size has been - * read from the network. Now it is up to us to have the remaining RPC - * fields given to us here. - */ - - /* Since the poll_in handler uses the remainingfrag field to determine - * how much to read from the network, we'll hack this scheme to tell - * the poll_in to read at most RPCSVC_BARERPC_MSGSZ bytes. This is done - * to, as a first step, identify which (program, actor) we need to call. - */ - - dataread = nfs_rpcsvc_update_vectored_msg (conn, dataread); - - if (conn->rstate.remainingfrag == 0) { - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Vectored frag complete"); - dataread = nfs_rpcsvc_update_vectored_state (conn); - } - - return dataread; -} - - -int -nfs_rpcsvc_record_update_state (rpcsvc_conn_t *conn, ssize_t dataread) -{ - rpcsvc_record_state_t *rs = NULL; - rpcsvc_t *svc = NULL; - - if (!conn) - return -1; - - rs = &conn->rstate; - /* At entry into this function, fragcurrent will be pointing to the\ - * start of the area into which dataread number of bytes were read. - */ - - if (nfs_rpcsvc_record_readfraghdr(rs)) - dataread = nfs_rpcsvc_record_update_fraghdr (rs, dataread); - - if (nfs_rpcsvc_record_readfrag(rs)) { - /* The minimum needed for triggering the vectored handler is - * the frag size field. The fragsize member remains set to this - * size till this request is completely extracted from the - * network. Once all the data has been read from the network, - * the request structure would've been created. The point being - * that even if it takes multiple calls to network IO for - * getting the vectored fragment, we can continue to use this - * condition as the flag to tell us that this is a vectored - * fragment. - */ - if ((dataread > 0) && (nfs_rpcsvc_record_vectored (rs))) { - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Vectored frag"); - dataread = nfs_rpcsvc_handle_vectored_frag (conn, - dataread); - } else if (dataread > 0) { - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Regular frag"); - dataread = nfs_rpcsvc_record_update_frag (rs, dataread); - } - } - - /* This should not happen. We are never reading more than the current - * fragment needs. Something is seriously wrong. - */ - if (dataread > 0) { - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Data Left: %zd", dataread); - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Unwanted data read from " - " connection."); - } - - /* If we're now supposed to wait for a new fragment header and if the - * fragment that we just completed in the previous call to - * rpcsvc_record_update_frag was the last fragment for the current - * RPC record, then, it is time to perform the translation from - * XDR formatted buffer in activeiob followed by the upcall to the - * protocol actor. - */ - if ((nfs_rpcsvc_record_readfraghdr(rs)) && (rs->islastfrag)) { - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Full Record Received."); - nfs_rpcsvc_handle_rpc_call (conn); - svc = nfs_rpcsvc_conn_rpcsvc (conn); - nfs_rpcsvc_record_init (rs, svc->ctx->iobuf_pool); - } - - return 0; -} - - -char * -nfs_rpcsvc_record_read_addr (rpcsvc_record_state_t *rs) -{ - - if (nfs_rpcsvc_record_readfraghdr (rs)) - return nfs_rpcsvc_record_currenthdr_addr (rs); - else if (nfs_rpcsvc_record_readfrag (rs)) - return nfs_rpcsvc_record_currentfrag_addr (rs); - - return NULL; -} - - -int -nfs_rpcsvc_conn_data_poll_in (rpcsvc_conn_t *conn) -{ - ssize_t dataread = -1; - size_t readsize = 0; - char *readaddr = NULL; - int ret = -1; - - readaddr = nfs_rpcsvc_record_read_addr (&conn->rstate); - if (!readaddr) - goto err; - - readsize = nfs_rpcsvc_record_read_size (&conn->rstate); - if (readsize == -1) - goto err; - - dataread = nfs_rpcsvc_socket_read (conn->sockfd, readaddr, readsize); - gf_log (GF_RPCSVC, GF_LOG_TRACE, "conn: 0x%lx, readsize: %zu, dataread:" - "%zd", (long)conn, readsize, dataread); - - if (dataread > 0) - ret = nfs_rpcsvc_record_update_state (conn, dataread); - -err: - return ret; -} - - -int -nfs_rpcsvc_conn_data_poll_err (rpcsvc_conn_t *conn) -{ - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Received error event"); - nfs_rpcsvc_conn_deinit (conn); - return 0; -} - - -int -__nfs_rpcsvc_conn_data_poll_out (rpcsvc_conn_t *conn) -{ - rpcsvc_txbuf_t *txbuf = NULL; - rpcsvc_txbuf_t *tmp = NULL; - ssize_t written = -1; - char *writeaddr = NULL; - size_t writesize = -1; - - if (!conn) - return -1; - - /* Attempt transmission of each of the pending buffers */ - list_for_each_entry_safe (txbuf, tmp, &conn->txbufs, txlist) { -tx_remaining: - writeaddr = (char *)(txbuf->buf.iov_base + txbuf->offset); - writesize = (txbuf->buf.iov_len - txbuf->offset); - - if (txbuf->txbehave & RPCSVC_TXB_FIRST) { - gf_log (GF_RPCSVC, GF_LOG_TRACE, "First Tx Buf"); - nfs_rpcsvc_socket_block_tx (conn->sockfd); - } - - written = nfs_rpcsvc_socket_write (conn->sockfd, writeaddr, - writesize); - if (txbuf->txbehave & RPCSVC_TXB_LAST) { - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Last Tx Buf"); - nfs_rpcsvc_socket_unblock_tx (conn->sockfd); - } - gf_log (GF_RPCSVC, GF_LOG_TRACE, "conn: 0x%lx, Tx request: %zu," - " Tx sent: %zd", (long)conn, writesize, written); - - /* There was an error transmitting this buffer */ - if (written == -1) - break; - - if (written >= 0) - txbuf->offset += written; - - /* If the current buffer has been completely transmitted, - * delete it from the list and move on to the next buffer. - */ - if (txbuf->offset == txbuf->buf.iov_len) { - /* It doesnt matter who ref'ed this iobuf, rpcsvc for - * its own header or a RPC program. - */ - if (txbuf->iob) - iobuf_unref (txbuf->iob); - if (txbuf->iobref) - iobref_unref (txbuf->iobref); - - list_del (&txbuf->txlist); - mem_put (conn->txpool, txbuf); - } else - /* If the current buffer is incompletely tx'd, do not - * go to the head of the loop, since that moves us to - * the next buffer. - */ - goto tx_remaining; - } - - /* If we've broken out of the loop above then we must unblock - * the transmission now. - */ - nfs_rpcsvc_socket_unblock_tx (conn->sockfd); - if (list_empty (&conn->txbufs)) - conn->eventidx = event_select_on (conn->stage->eventpool, - conn->sockfd, conn->eventidx, - -1, 0); - - return 0; -} - - -int -nfs_rpcsvc_conn_data_poll_out (rpcsvc_conn_t *conn) -{ - if (!conn) - return -1; - - - pthread_mutex_lock (&conn->connlock); - { - __nfs_rpcsvc_conn_data_poll_out (conn); - } - pthread_mutex_unlock (&conn->connlock); - - return 0; -} - - -int -nfs_rpcsvc_conn_data_handler (int fd, int idx, void *data, int poll_in, - int poll_out, int poll_err) -{ - rpcsvc_conn_t *conn = NULL; - int ret = 0; - - if (!data) - return 0; - - conn = (rpcsvc_conn_t *)data; - - if (poll_out) - ret = nfs_rpcsvc_conn_data_poll_out (conn); - - if (poll_err) { - ret = nfs_rpcsvc_conn_data_poll_err (conn); - return 0; - } - - if (poll_in) { - ret = 0; - ret = nfs_rpcsvc_conn_data_poll_in (conn); - } - - if (ret == -1) - nfs_rpcsvc_conn_data_poll_err (conn); - - return 0; -} - - -int -nfs_rpcsvc_conn_listening_handler (int fd, int idx, void *data, int poll_in, - int poll_out, int poll_err) -{ - rpcsvc_conn_t *newconn = NULL; - rpcsvc_stage_t *selectedstage = NULL; - int ret = -1; - rpcsvc_conn_t *conn = NULL; - rpcsvc_program_t *prog = NULL; - rpcsvc_t *svc = NULL; - - if (!poll_in) - return 0; - - conn = (rpcsvc_conn_t *)data; - prog = (rpcsvc_program_t *)conn->program; - svc = nfs_rpcsvc_conn_rpcsvc (conn); - newconn = nfs_rpcsvc_conn_accept_init (svc, fd, prog); - if (!newconn) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "failed to accept connection"); - goto err; - } - - selectedstage = nfs_rpcsvc_select_stage (svc); - if (!selectedstage) - goto close_err; - - /* Now that we've accepted the connection, we need to associate - * its events to a stage. - */ - ret = nfs_rpcsvc_stage_conn_associate (selectedstage, newconn, - nfs_rpcsvc_conn_data_handler, - newconn); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "could not associated stage " - " with new connection"); - goto close_err; - } - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "New Connection: Program %s, Num: %d," - " Ver: %d, Port: %d", prog->progname, prog->prognum, - prog->progver, prog->progport); - ret = 0; -close_err: - if (ret == -1) - nfs_rpcsvc_conn_unref (newconn); - -err: - return ret; -} - - -/* Register the program with the local portmapper service. */ -int -nfs_rpcsvc_program_register_portmap (rpcsvc_t *svc, rpcsvc_program_t *newprog) -{ - if (!newprog) - return -1; - - if (!svc->register_portmap) - return 0; - - if (!(pmap_set(newprog->prognum, newprog->progver, IPPROTO_TCP, - newprog->progport))) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Could not register with" - " portmap"); - return -1; - } - - return 0; -} - - -int -nfs_rpcsvc_program_unregister_portmap (rpcsvc_t *svc, rpcsvc_program_t *prog) -{ - if (!prog) - return -1; - - if (!svc->register_portmap) - return 0; - - if (!(pmap_unset(prog->prognum, prog->progver))) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Could not unregister with" - " portmap"); - return -1; - } - - return 0; -} - - -int -nfs_rpcsvc_stage_program_register (rpcsvc_stage_t *stg, - rpcsvc_program_t *newprog) -{ - rpcsvc_conn_t *newconn = NULL; - rpcsvc_t *svc = NULL; - - if ((!stg) || (!newprog)) - return -1; - - svc = nfs_rpcsvc_stage_service (stg); - /* Create a listening socket */ - newconn = nfs_rpcsvc_conn_listen_init (svc, newprog); - if (!newconn) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "could not create listening" - " connection"); - return -1; - } - - if ((nfs_rpcsvc_stage_conn_associate (stg, newconn, - nfs_rpcsvc_conn_listening_handler, - newconn)) == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR,"could not associate stage with" - " listening connection"); - return -1; - } - - return 0; -} - - -int -nfs_rpcsvc_program_register (rpcsvc_t *svc, rpcsvc_program_t program) -{ - rpcsvc_program_t *newprog = NULL; - rpcsvc_stage_t *selectedstage = NULL; - int ret = -1; - - if (!svc) - return -1; - - newprog = GF_CALLOC (1, sizeof(*newprog),gf_common_mt_rpcsvc_program_t); - if (!newprog) - return -1; - - if (!program.actors) - goto free_prog; - - memcpy (newprog, &program, sizeof (program)); - selectedstage = nfs_rpcsvc_select_stage (svc); - - ret = nfs_rpcsvc_stage_program_register (selectedstage, newprog); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "stage registration of program" - " failed"); - goto free_prog; - } - - ret = nfs_rpcsvc_program_register_portmap (svc, newprog); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "portmap registration of" - " program failed"); - goto free_prog; - } - - ret = 0; - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "New program registered: %s, Num: %d," - " Ver: %d, Port: %d", newprog->progname, newprog->prognum, - newprog->progver, newprog->progport); - -free_prog: - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Program registration failed:" - " %s, Num: %d, Ver: %d, Port: %d", newprog->progname, - newprog->prognum, newprog->progver, newprog->progport); - GF_FREE (newprog); - } - - return ret; -} - -/* The only difference between the generic submit and this one is that the - * generic submit is also used for submitting RPC error replies in where there - * are no payloads so the msgvec and msgbuf can be NULL. - * Since RPC programs should be using this function along with their payloads - * we must perform NULL checks before calling the generic submit. - */ -int -nfs_rpcsvc_submit_message (rpcsvc_request_t *req, struct iovec msgvec, - struct iobuf *msg) -{ - if ((!req) || (!req->conn) || (!msg) || (!msgvec.iov_base)) - return -1; - - return nfs_rpcsvc_submit_generic (req, msgvec, msg); -} - - -int -nfs_rpcsvc_program_unregister (rpcsvc_t *svc, rpcsvc_program_t prog) -{ - int ret = -1; - - if (!svc) - return -1; - - /* TODO: De-init the listening connection for this program. */ - ret = nfs_rpcsvc_program_unregister_portmap (svc, &prog); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "portmap unregistration of" - " program failed"); - goto err; - } - - ret = 0; - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Program unregistered: %s, Num: %d," - " Ver: %d, Port: %d", prog.progname, prog.prognum, - prog.progver, prog.progport); - -err: - if (ret == -1) - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Program unregistration failed" - ": %s, Num: %d, Ver: %d, Port: %d", prog.progname, - prog.prognum, prog.progver, prog.progport); - - return ret; -} - - -int -nfs_rpcsvc_conn_peername (rpcsvc_conn_t *conn, char *hostname, int hostlen) -{ - if (!conn) - return -1; - - return nfs_rpcsvc_socket_peername (conn->sockfd, hostname, hostlen); -} - - -int -nfs_rpcsvc_conn_peeraddr (rpcsvc_conn_t *conn, char *addrstr, int addrlen, - struct sockaddr *sa, socklen_t sasize) -{ - if (!conn) - return -1; - - return nfs_rpcsvc_socket_peeraddr (conn->sockfd, addrstr, addrlen, sa, - sasize); -} - diff --git a/xlators/nfs/lib/src/rpcsvc.h b/xlators/nfs/lib/src/rpcsvc.h deleted file mode 100644 index 5a669cf83..000000000 --- a/xlators/nfs/lib/src/rpcsvc.h +++ /dev/null @@ -1,720 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _NFS_RPCSVC_H -#define _NFS_RPCSVC_H - - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "event.h" -#include "logging.h" -#include "dict.h" -#include "mem-pool.h" -#include "list.h" -#include "iobuf.h" -#include "xdr-rpc.h" -#include "glusterfs.h" -#include "xlator.h" - -#include <pthread.h> -#include <sys/uio.h> - -#ifdef GF_DARWIN_HOST_OS -#include <nfs/rpcv2.h> -#define NGRPS RPCAUTH_UNIXGIDS -#endif - -#define GF_RPCSVC "nfsrpc" -#define RPCSVC_THREAD_STACK_SIZE ((size_t)(1024 * GF_UNIT_KB)) - -#define RPCSVC_DEFAULT_MEMFACTOR 15 -#define RPCSVC_EVENTPOOL_SIZE_MULT 1024 -#define RPCSVC_POOLCOUNT_MULT 35 -#define RPCSVC_CONN_READ (128 * GF_UNIT_KB) -#define RPCSVC_PAGE_SIZE (128 * GF_UNIT_KB) - -/* Defines for RPC record and fragment assembly */ - -#define RPCSVC_FRAGHDR_SIZE 4 /* 4-byte RPC fragment header size */ - -/* Given the 4-byte fragment header, returns non-zero if this fragment - * is the last fragment for the RPC record being assemebled. - * RPC Record marking standard defines a 32 bit value as the fragment - * header with the MSB signifying whether the fragment is the last - * fragment for the record being asembled. - */ -#define RPCSVC_LASTFRAG(fraghdr) ((uint32_t)(fraghdr & 0x80000000U)) - -/* Given the 4-byte fragment header, extracts the bits that contain - * the fragment size. - */ -#define RPCSVC_FRAGSIZE(fraghdr) ((uint32_t)(fraghdr & 0x7fffffffU)) - -/* RPC Record States */ -#define RPCSVC_READ_FRAGHDR 1 -#define RPCSVC_READ_FRAG 2 -/* The size in bytes, if crossed by a fragment will be handed over to the - * vectored actor so that it can allocate its buffers the way it wants. - * In our RPC layer, we assume that vectored RPC requests/records are never - * spread over multiple RPC fragments since that prevents us from determining - * whether the record should be handled in RPC layer completely or handed to - * the vectored handler. - */ -#define RPCSVC_VECTORED_FRAGSZ 4096 -#define RPCSVC_VECTOR_READCRED 1003 -#define RPCSVC_VECTOR_READVERFSZ 1004 -#define RPCSVC_VECTOR_READVERF 1005 -#define RPCSVC_VECTOR_IGNORE 1006 -#define RPCSVC_VECTOR_READVEC 1007 -#define RPCSVC_VECTOR_READPROCHDR 1008 - -#define nfs_rpcsvc_record_vectored_baremsg(rs) (((rs)->state == RPCSVC_READ_FRAG) && (rs)->vecstate == 0) -#define nfs_rpcsvc_record_vectored_cred(rs) ((rs)->vecstate == RPCSVC_VECTOR_READCRED) -#define nfs_rpcsvc_record_vectored_verfsz(rs) ((rs)->vecstate == RPCSVC_VECTOR_READVERFSZ) -#define nfs_rpcsvc_record_vectored_verfread(rs) ((rs)->vecstate == RPCSVC_VECTOR_READVERF) -#define nfs_rpcsvc_record_vectored_ignore(rs) ((rs)->vecstate == RPCSVC_VECTOR_IGNORE) -#define nfs_rpcsvc_record_vectored_readvec(rs) ((rs)->vecstate == RPCSVC_VECTOR_READVEC) -#define nfs_rpcsvc_record_vectored_readprochdr(rs) ((rs)->vecstate == RPCSVC_VECTOR_READPROCHDR) -#define nfs_rpcsvc_record_vectored(rs) ((rs)->fragsize > RPCSVC_VECTORED_FRAGSZ) -/* Includes bytes up to and including the credential length field. The credlen - * will be followed by @credlen bytes of credential data which will have to be - * read separately by the vectored reader. After the credentials comes the - * verifier which will also have to be read separately including the 8 bytes of - * verf flavour and verflen. - */ -#define RPCSVC_BARERPC_MSGSZ 32 -#define nfs_rpcsvc_record_readfraghdr(rs) ((rs)->state == RPCSVC_READ_FRAGHDR) -#define nfs_rpcsvc_record_readfrag(rs) ((rs)->state == RPCSVC_READ_FRAG) - -#define nfs_rpcsvc_conn_rpcsvc(conn) ((conn)->stage->svc) -#define RPCSVC_LOWVERS 2 -#define RPCSVC_HIGHVERS 2 - -typedef struct rpc_svc_program rpcsvc_program_t; -/* A Stage is the event handler thread together with - * the connections being served by this thread. - * It is called a stage because all the actors, i.e, protocol actors, - * defined by higher level users of the RPC layer, are executed here. - */ -typedef struct rpc_svc_stage_context { - pthread_t tid; - struct event_pool *eventpool; /* Per-stage event-pool */ - void *svc; /* Ref to the rpcsvc_t */ -} rpcsvc_stage_t; - - -/* RPC Records and Fragments assembly state. - * This is per-connection state that is used to determine - * how much data has come in, how much more needs to be read - * and where it needs to be read. - * - * All this state is then used to re-assemble network buffers into - * RPC fragments, which are then re-assembled into RPC records. - * - * See RFC 1831: "RPC: Remote Procedure Call Protocol Specification Version 2", - * particularly the section on Record Marking Standard. - */ -typedef struct rpcsvc_record_state { - - /* Pending messages storage - * This memory area is currently being used to assemble - * the latest RPC record. - * - * Note that this buffer contains the data other than the - * fragment headers received from the network. This is so that we can - * directly pass this buffer to higher layers without requiring to - * perform memory copies and marshalling of data. - */ - struct iobuf *activeiob; - - struct iobuf *vectoriob; - /* The pointer into activeiob memory, into which will go the - * contents from the next read from the network. - */ - char *fragcurrent; - - /* Size of the currently incomplete RPC fragment. - * This is filled in when the fragment header comes in. - * Even though only the 31 least significant bits are used from the - * fragment header, we use a 32 bit variable to store the size. - */ - uint32_t fragsize; - - /* The fragment header is always read in here so that - * the RPC messages contained in a RPC records can be processed - * separately without copying them out of the activeiob above. - */ - char fragheader[RPCSVC_FRAGHDR_SIZE]; - char *hdrcurrent; - - /* Bytes remaining to come in for the current fragment. */ - uint32_t remainingfrag; - - /* It is possible for the frag header to be split over separate - * read calls, so we need to keep track of how much is left. - */ - uint32_t remainingfraghdr; - - /* Record size, the total size of the RPC record, i.e. the total - * of all fragment sizes received till now. Does not include the size - * of a partial fragment which is continuing to be assembled right now. - */ - int recordsize; - - /* Current state of the record */ - int state; - - /* Current state of the vectored reading process. */ - int vecstate; - - /* Set to non-zero when the currently partial or complete fragment is - * the last fragment being received for the current RPC record. - */ - uint32_t islastfrag; - -} rpcsvc_record_state_t; - - -#define RPCSVC_CONNSTATE_CONNECTED 1 -#define RPCSVC_CONNSTATE_DISCONNECTED 2 - -#define nfs_rpcsvc_conn_check_active(conn) ((conn)->connstate==RPCSVC_CONNSTATE_CONNECTED) - -typedef struct rpcsvc_request rpcsvc_request_t; -/* Contains the state for each connection that is used for transmitting and - * receiving RPC messages. - * - * There is also an eventidx because each connection's fd is added to the event - * pool of the stage to which a connection belongs. - * Anything that can be accessed by a RPC program must be synced through - * connlock. - */ -typedef struct rpc_conn_state { - - /* Transport or connection state */ - - /* Once we start working on RDMA support, this TCP specific state will - * have to be abstracted away. - */ - int sockfd; - int eventidx; - int windowsize; - - /* Reference to the stage which is handling this - * connection. - */ - rpcsvc_stage_t *stage; - - /* RPC Records and Fragments assembly state. - * All incoming data is staged here before being - * called a full RPC message. - */ - rpcsvc_record_state_t rstate; - - /* It is possible that a client disconnects while - * the higher layer RPC service is busy in a call. - * In this case, we cannot just free the conn - * structure, since the higher layer service could - * still have a reference to it. - * The refcount avoids freeing until all references - * have been given up, although the connection is clos()ed at the first - * call to unref. - */ - int connref; - pthread_mutex_t connlock; - int connstate; - - /* The program that is listening for requests on this connection. */ - rpcsvc_program_t *program; - - /* List of buffers awaiting transmission */ - /* Accesses to txbufs between multiple threads calling - * rpcsvc_submit is synced through connlock. Prefer spinlock over - * mutex because this is a low overhead op that needs simple - * appending to the tx list. - */ - struct list_head txbufs; - - /* Mem pool for the txbufs above. */ - struct mem_pool *txpool; - - /* Memory pool for rpcsvc_request_t */ - struct mem_pool *rxpool; - - /* The request which hasnt yet been handed to the RPC program because - * this request is being treated as a vector request and so needs some - * more data to be got from the network. - */ - rpcsvc_request_t *vectoredreq; -} rpcsvc_conn_t; - - -#define RPCSVC_MAX_AUTH_BYTES 400 -typedef struct rpcsvc_auth_data { - int flavour; - int datalen; - char authdata[RPCSVC_MAX_AUTH_BYTES]; -} rpcsvc_auth_data_t; - -#define nfs_rpcsvc_auth_flavour(au) ((au).flavour) - -/* The container for the RPC call handed up to an actor. - * Dynamically allocated. Lives till the call reply is completely - * transmitted. - * */ -struct rpcsvc_request { - /* Connection over which this request came. */ - rpcsvc_conn_t *conn; - - /* The identifier for the call from client. - * Needed to pair the reply with the call. - */ - uint32_t xid; - - int prognum; - - int progver; - - int procnum; - /* Uid and gid filled by the rpc-auth module during the authentication - * phase. - */ - uid_t uid; - gid_t gid; - - /* Might want to move this to AUTH_UNIX specifix state since this array - * is not available for every authenticatino scheme. - */ - gid_t auxgids[NGRPS]; - int auxgidcount; - - - /* The RPC message payload, contains the data required - * by the program actors. This is the buffer that will need to - * be de-xdred by the actor. - */ - struct iovec msg; - - /* The full message buffer allocated to store the RPC headers. - * This buffer is ref'd when allocated why RPC svc and unref'd after - * the buffer is handed to the actor. That means if the actor or any - * higher layer wants to keep this buffer around, they too must ref it - * right after entering the program actor. - */ - struct iobuf *recordiob; - - /* Status of the RPC call, whether it was accepted or denied. */ - int rpc_stat; - - /* In case, the call was denied, the RPC error is stored here - * till the reply is sent. - */ - int rpc_err; - - /* In case the failure happened because of an authentication problem - * , this value needs to be assigned the correct auth error number. - */ - int auth_err; - - /* There can be cases of RPC requests where the reply needs to - * be built from multiple sources. For eg. where even the NFS reply can - * contain a payload, as in the NFSv3 read reply. Here the RPC header - * ,NFS header and the read data are brought together separately from - * different buffers, so we need to stage the buffers temporarily here - * before all of them get added to the connection's transmission list. - */ - struct list_head txlist; - - /* While the reply record is being built, this variable keeps track - * of how many bytes have been added to the record. - */ - size_t payloadsize; - - /* The credentials extracted from the rpc request */ - rpcsvc_auth_data_t cred; - - /* The verified extracted from the rpc request. In request side - * processing this contains the verifier sent by the client, on reply - * side processing, it is filled with the verified that will be - * sent to the client. - */ - rpcsvc_auth_data_t verf; - - /* Container for a RPC program wanting to store a temp - * request-specific item. - */ - void *private; - -}; - -#define nfs_rpcsvc_request_program(req) ((rpcsvc_program_t *)((req)->conn->program)) -#define nfs_rpcsvc_request_program_private(req) (((rpcsvc_program_t *)((req)->conn->program))->private) -#define nfs_rpcsvc_request_conn(req) (req)->conn -#define nfs_rpcsvc_program_xlator(prg) ((prg)->actorxl) -#define nfs_rpcsvc_request_actorxl(rq) (nfs_rpcsvc_request_program(rq))->actorxl -#define nfs_rpcsvc_request_accepted(req) ((req)->rpc_stat == MSG_ACCEPTED) -#define nfs_rpcsvc_request_accepted_success(req) ((req)->rpc_err == SUCCESS) -#define nfs_rpcsvc_request_uid(req) ((req)->uid) -#define nfs_rpcsvc_request_gid(req) ((req)->gid) -#define nfs_rpcsvc_stage_service(stg) ((rpcsvc_t *)((stg)->svc)) -#define nfs_rpcsvc_conn_stage(conn) ((conn)->stage) -#define nfs_rpcsvc_request_service(req) (nfs_rpcsvc_stage_service(nfs_rpcsvc_conn_stage(nfs_rpcsvc_request_conn(req)))) -#define nfs_rpcsvc_request_prog_minauth(req) (nfs_rpcsvc_request_program(req)->min_auth) -#define nfs_rpcsvc_request_cred_flavour(req) (nfs_rpcsvc_auth_flavour(req->cred)) -#define nfs_rpcsvc_request_verf_flavour(req) (nfs_rpcsvc_auth_flavour(req->verf)) - -#define nfs_rpcsvc_request_uid(req) ((req)->uid) -#define nfs_rpcsvc_request_gid(req) ((req)->gid) -#define nfs_rpcsvc_request_private(req) ((req)->private) -#define nfs_rpcsvc_request_xid(req) ((req)->xid) -#define nfs_rpcsvc_request_set_private(req,prv) (req)->private = (void *)(prv) -#define nfs_rpcsvc_request_record_iob(rq) ((rq)->recordiob) -#define nfs_rpcsvc_request_record_ref(req) (iobuf_ref ((req)->recordiob)) -#define nfs_rpcsvc_request_record_unref(req) (iobuf_unref ((req)->recordiob)) - - -#define RPCSVC_ACTOR_SUCCESS 0 -#define RPCSVC_ACTOR_ERROR (-1) - -/* Functor for every type of protocol actor - * must be defined like this. - * - * See the request structure for info on how to handle the request - * in the program actor. - * - * On successful santify checks inside the actor, it should return - * RPCSVC_ACTOR_SUCCESS. - * On an error, on which the RPC layer is expected to return a reply, the actor - * should return RPCSVC_ACTOR_ERROR. - * - */ -typedef int (*rpcsvc_actor) (rpcsvc_request_t *req); -typedef int (*rpcsvc_vector_actor) (rpcsvc_request_t *req, struct iobuf *iob); -typedef int (*rpcsvc_vector_sizer) (rpcsvc_request_t *req, ssize_t *readsize, - int *newiob); - -/* Every protocol actor will also need to specify the function the RPC layer - * will use to serialize or encode the message into XDR format just before - * transmitting on the connection. - */ -typedef void *(*rpcsvc_encode_reply) (void *msg); - -/* Once the reply has been transmitted, the message will have to be de-allocated - * , so every actor will need to provide a function that deallocates the message - * it had allocated as a response. - */ -typedef void (*rpcsvc_deallocate_reply) (void *msg); - - -#define RPCSVC_NAME_MAX 32 -/* The descriptor for each procedure/actor that runs - * over the RPC service. - */ -typedef struct rpc_svc_actor_desc { - char procname[RPCSVC_NAME_MAX]; - int procnum; - rpcsvc_actor actor; - - /* Handler for cases where the RPC requests fragments are large enough - * to benefit from being decoded into aligned memory addresses. While - * decoding the request in a non-vectored manner, due to the nature of - * the XDR scheme, RPC cannot guarantee memory aligned addresses for - * the resulting message-specific structures. Allowing a specialized - * handler for letting the RPC program read the data from the network - * directly into its alligned buffers. - */ - rpcsvc_vector_actor vector_actor; - rpcsvc_vector_sizer vector_sizer; - -} rpcsvc_actor_t; - -/* Describes a program and its version along with the function pointers - * required to handle the procedures/actors of each program/version. - * Never changed ever by any thread so no need for a lock. - */ -struct rpc_svc_program { - char progname[RPCSVC_NAME_MAX]; - int prognum; - int progver; - uint16_t progport; /* Registered with portmap */ - int progaddrfamily; /* AF_INET or AF_INET6 */ - char *proghost; /* Bind host, can be NULL */ - rpcsvc_actor_t *actors; /* All procedure handlers */ - int numactors; /* Num actors in actor array */ - int proghighvers; /* Highest ver for program - supported by the system. */ - int proglowvers; /* Lowest ver */ - - /* Program specific state handed to actors */ - void *private; - - /* An integer that identifies the min auth strength that is required - * by this protocol, for eg. MOUNT3 needs AUTH_UNIX at least. - * See RFC 1813, Section 5.2.1. - */ - int min_auth; - - /* The translator in whose context the actor must execute. This is - * needed to setup THIS for memory accounting to work correctly. - */ - xlator_t *actorxl; -}; - - -/* Contains global state required for all the RPC services. - */ -typedef struct rpc_svc_state { - - /* Contains the list of rpcsvc_stage_t - * list of (program, version) handlers. - * other options. - */ - - /* At this point, lock is not used to protect anything. Later, it'll - * be used for protecting stages. - */ - pthread_mutex_t rpclock; - - /* This is the first stage that is inited, so that any RPC based - * services that do not need multi-threaded support can just use the - * service right away. This is not added to the stages list - * declared later. - * This is also the stage over which all service listeners are run. - */ - rpcsvc_stage_t *defaultstage; - - /* When we have multi-threaded RPC support, we'll use this to link - * to the multiple Stages. - */ - struct list_head stages; /* All stages */ - - unsigned int memfactor; - - /* List of the authentication schemes available. */ - struct list_head authschemes; - - /* Reference to the options */ - dict_t *options; - - /* Allow insecure ports. */ - int allow_insecure; - - glusterfs_ctx_t *ctx; - - gf_boolean_t register_portmap; -} rpcsvc_t; - - -/* All users of RPC services should use this API to register their - * procedure handlers. - */ -extern int -nfs_rpcsvc_program_register (rpcsvc_t *svc, rpcsvc_program_t program); - -extern int -nfs_rpcsvc_program_unregister (rpcsvc_t *svc, rpcsvc_program_t program); - -/* Inits the global RPC service data structures. - * Called in main. - */ -extern rpcsvc_t * -nfs_rpcsvc_init (glusterfs_ctx_t *ctx, dict_t *options); - - -extern int -nfs_rpcsvc_submit_message (rpcsvc_request_t * req, struct iovec msg, - struct iobuf *iob); - -int -nfs_rpcsvc_submit_generic (rpcsvc_request_t *req, struct iovec msgvec, - struct iobuf *msg); -#define nfs_rpcsvc_record_currentfrag_addr(rs) ((rs)->fragcurrent) -#define nfs_rpcsvc_record_currenthdr_addr(rs) ((rs)->hdrcurrent) - -#define nfs_rpcsvc_record_update_currentfrag(rs, size) \ - do { \ - (rs)->fragcurrent += size; \ - } while (0) \ - -#define nfs_rpcsvc_record_update_currenthdr(rs, size) \ - do { \ - (rs)->hdrcurrent += size; \ - } while (0) \ - - -/* These are used to differentiate between multiple txbufs which form - * a single RPC record. For eg, one purpose we use these for is to - * prevent dividing a RPC record over multiple TCP segments. Multiple - * TCP segments are possible for a single RPC record because we generally do not - * have control over how the kernel's TCP segments the buffers when putting - * them on the wire. So, on Linux, we use these to set TCP_CORK to create - * a single TCP segment from multiple txbufs that are part of the same RPC - * record. This improves network performance by reducing tiny message - * transmissions. - */ -#define RPCSVC_TXB_FIRST 0x1 -#define RPCSVC_TXB_LAST 0x2 - -/* The list of buffers appended to a connection's pending - * transmission list. - */ -typedef struct rpcsvc_txbuf { - struct list_head txlist; - /* The iobuf which contains the full message to be transmitted */ - struct iobuf *iob; - - /* For vectored messages from an RPC program, we need to be able - * maintain a ref to an iobuf which we do not have access to directly - * except through the iobref which in turn could've been passed to - * the RPC program by a higher layer. - * - * So either the iob is defined or iobref is defined for a reply, - * never both. - */ - struct iobref *iobref; - /* In order to handle non-blocking writes, we'll need to keep track of - * how much data from an iobuf has been written and where the next - * transmission needs to start from. This iov.base points to the base of - * the iobuf, iov.len is the size of iobuf being used for the message - * from the total size in the iobuf. - */ - struct iovec buf; - /* offset is the point from where the next transmission for this buffer - * should start. - */ - size_t offset; - - /* This is a special field that tells us what kind of transmission - * behaviour to provide to a particular buffer. - * See the RPCSVC_TXB_* defines for more info. - */ - int txbehave; -} rpcsvc_txbuf_t; - -extern int -nfs_rpcsvc_error_reply (rpcsvc_request_t *req); - -#define RPCSVC_PEER_STRLEN 1024 -#define RPCSVC_AUTH_ACCEPT 1 -#define RPCSVC_AUTH_REJECT 2 -#define RPCSVC_AUTH_DONTCARE 3 - -extern int -nfs_rpcsvc_conn_peername (rpcsvc_conn_t *conn, char *hostname, int hostlen); - -extern int -nfs_rpcsvc_conn_peeraddr (rpcsvc_conn_t *conn, char *addrstr, int addrlen, - struct sockaddr *returnsa, socklen_t sasize); - -extern int -nfs_rpcsvc_conn_peer_check (dict_t *options, char *volname,rpcsvc_conn_t *conn); - -extern int -nfs_rpcsvc_conn_privport_check (rpcsvc_t *svc, char *volname, - rpcsvc_conn_t *conn); -#define nfs_rpcsvc_request_seterr(req, err) (req)->rpc_err = err -#define nfs_rpcsvc_request_set_autherr(req, err) (req)->auth_err = err - -extern void -nfs_rpcsvc_conn_deinit (rpcsvc_conn_t *conn); -extern void nfs_rpcsvc_conn_ref (rpcsvc_conn_t *conn); -extern void nfs_rpcsvc_conn_unref (rpcsvc_conn_t *conn); - -extern int nfs_rpcsvc_submit_vectors (rpcsvc_request_t *req); - -extern int nfs_rpcsvc_request_attach_vector (rpcsvc_request_t *req, - struct iovec msgvec, - struct iobuf *iob, - struct iobref *ioref, - int finalvector); -extern int -nfs_rpcsvc_request_attach_vectors (rpcsvc_request_t *req, struct iovec *payload, - int vcount, struct iobref *piobref); - -typedef int (*auth_init_conn) (rpcsvc_conn_t *conn, void *priv); -typedef int (*auth_init_request) (rpcsvc_request_t *req, void *priv); -typedef int (*auth_request_authenticate) (rpcsvc_request_t *req, void *priv); - -/* This structure needs to be registered by every authentication scheme. - * Our authentication schemes are stored per connection because - * each connection will end up using a different authentication scheme. - */ -typedef struct rpcsvc_auth_ops { - auth_init_conn conn_init; - auth_init_request request_init; - auth_request_authenticate authenticate; -} rpcsvc_auth_ops_t; - -typedef struct rpcsvc_auth_flavour_desc { - char authname[RPCSVC_NAME_MAX]; - int authnum; - rpcsvc_auth_ops_t *authops; - void *authprivate; -} rpcsvc_auth_t; - -typedef void * (*rpcsvc_auth_initer_t) (rpcsvc_t *svc, dict_t *options); - -struct rpcsvc_auth_list { - struct list_head authlist; - rpcsvc_auth_initer_t init; - /* Should be the name with which we identify the auth scheme given - * in the volfile options. - * This should be different from the authname in rpc_auth_t - * in way that makes it easier to specify this scheme in the volfile. - * This is because the technical names of the schemes can be a bit - * arcane. - */ - char name[RPCSVC_NAME_MAX]; - rpcsvc_auth_t *auth; - int enable; -}; - -extern int -nfs_rpcsvc_auth_request_init (rpcsvc_request_t *req); - -extern int -nfs_rpcsvc_auth_init (rpcsvc_t *svc, dict_t *options); - -extern int -nfs_rpcsvc_auth_conn_init (rpcsvc_conn_t *conn); - -extern int -nfs_rpcsvc_authenticate (rpcsvc_request_t *req); - -extern int -nfs_rpcsvc_auth_array (rpcsvc_t *svc, char *volname, int *autharr, int arrlen); - -/* If the request has been sent using AUTH_UNIX, this function returns the - * auxiliary gids as an array, otherwise, it returns NULL. - * Move to auth-unix specific source file when we need to modularize the - * authentication code even further to support mode auth schemes. - */ -extern gid_t * -nfs_rpcsvc_auth_unix_auxgids (rpcsvc_request_t *req, int *arrlen); - -extern int -nfs_rpcsvc_combine_gen_spec_volume_checks (int gen, int spec); - -extern char * -nfs_rpcsvc_volume_allowed (dict_t *options, char *volname); -#endif diff --git a/xlators/nfs/lib/src/xdr-common.h b/xlators/nfs/lib/src/xdr-common.h deleted file mode 100644 index b3992ab05..000000000 --- a/xlators/nfs/lib/src/xdr-common.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _NFS_XDR_COMMON_H_ -#define _NFS_XDR_COMMON_H_ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <rpc/rpc.h> -#define NFS_XDR_BYTES_PER_UNIT 4 - -/* Returns the address of the byte that follows the - * last byte used for decoding the previous xdr component. - * For eg, once the RPC call for NFS has been decoded, thie macro will return - * the address from which the NFS header starts. - */ -#define nfs_xdr_decoded_remaining_addr(xdr) ((&xdr)->x_private) - -/* Returns the length of the remaining record after the previous decode - * operation completed. - */ -#define nfs_xdr_decoded_remaining_len(xdr) ((&xdr)->x_handy) - -/* Returns the number of bytes used by the last encode operation. */ -#define nfs_xdr_encoded_length(xdr) (((size_t)(&xdr)->x_private) - ((size_t)(&xdr)->x_base)) - -#define nfs_xdr_decoded_length(xdr) (((size_t)(&xdr)->x_private) - ((size_t)(&xdr)->x_base)) - -#endif diff --git a/xlators/nfs/lib/src/xdr-nfs3.c b/xlators/nfs/lib/src/xdr-nfs3.c deleted file mode 100644 index febc6a695..000000000 --- a/xlators/nfs/lib/src/xdr-nfs3.c +++ /dev/null @@ -1,1897 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#include "xdr-nfs3.h" -#include "mem-pool.h" - -#if GF_DARWIN_HOST_OS -#define xdr_u_quad_t xdr_u_int64_t -#define xdr_quad_t xdr_int64_t -#define xdr_uint32_t xdr_u_int32_t -#endif - -bool_t -xdr_uint64 (XDR *xdrs, uint64 *objp) -{ - if (!xdr_uint64_t (xdrs, objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_int64 (XDR *xdrs, int64 *objp) -{ - if (!xdr_int64_t (xdrs, objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_uint32 (XDR *xdrs, uint32 *objp) -{ - if (!xdr_uint32_t (xdrs, objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_int32 (XDR *xdrs, int32 *objp) -{ - if (!xdr_int32_t (xdrs, objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_filename3 (XDR *xdrs, filename3 *objp) -{ - if (!xdr_string (xdrs, objp, ~0)) - return FALSE; - return TRUE; -} - -bool_t -xdr_nfspath3 (XDR *xdrs, nfspath3 *objp) -{ - if (!xdr_string (xdrs, objp, ~0)) - return FALSE; - return TRUE; -} - -bool_t -xdr_fileid3 (XDR *xdrs, fileid3 *objp) -{ - if (!xdr_uint64 (xdrs, objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_cookie3 (XDR *xdrs, cookie3 *objp) -{ - if (!xdr_uint64 (xdrs, objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_cookieverf3 (XDR *xdrs, cookieverf3 objp) -{ - if (!xdr_opaque (xdrs, objp, NFS3_COOKIEVERFSIZE)) - return FALSE; - return TRUE; -} - -bool_t -xdr_createverf3 (XDR *xdrs, createverf3 objp) -{ - if (!xdr_opaque (xdrs, objp, NFS3_CREATEVERFSIZE)) - return FALSE; - return TRUE; -} - -bool_t -xdr_writeverf3 (XDR *xdrs, writeverf3 objp) -{ - if (!xdr_opaque (xdrs, objp, NFS3_WRITEVERFSIZE)) - return FALSE; - return TRUE; -} - -bool_t -xdr_uid3 (XDR *xdrs, uid3 *objp) -{ - if (!xdr_uint32 (xdrs, objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_gid3 (XDR *xdrs, gid3 *objp) -{ - if (!xdr_uint32 (xdrs, objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_size3 (XDR *xdrs, size3 *objp) -{ - if (!xdr_uint64 (xdrs, objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_offset3 (XDR *xdrs, offset3 *objp) -{ - if (!xdr_uint64 (xdrs, objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mode3 (XDR *xdrs, mode3 *objp) -{ - if (!xdr_uint32 (xdrs, objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_count3 (XDR *xdrs, count3 *objp) -{ - if (!xdr_uint32 (xdrs, objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_nfsstat3 (XDR *xdrs, nfsstat3 *objp) -{ - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_ftype3 (XDR *xdrs, ftype3 *objp) -{ - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_specdata3 (XDR *xdrs, specdata3 *objp) -{ - if (!xdr_uint32 (xdrs, &objp->specdata1)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->specdata2)) - return FALSE; - return TRUE; -} - -bool_t -xdr_nfs_fh3 (XDR *xdrs, nfs_fh3 *objp) -{ - if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, NFS3_FHSIZE)) - return FALSE; - return TRUE; -} - -bool_t -xdr_nfstime3 (XDR *xdrs, nfstime3 *objp) -{ - if (!xdr_uint32 (xdrs, &objp->seconds)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->nseconds)) - return FALSE; - return TRUE; -} - -bool_t -xdr_fattr3 (XDR *xdrs, fattr3 *objp) -{ - if (!xdr_ftype3 (xdrs, &objp->type)) - return FALSE; - if (!xdr_mode3 (xdrs, &objp->mode)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->nlink)) - return FALSE; - if (!xdr_uid3 (xdrs, &objp->uid)) - return FALSE; - if (!xdr_gid3 (xdrs, &objp->gid)) - return FALSE; - if (!xdr_size3 (xdrs, &objp->size)) - return FALSE; - if (!xdr_size3 (xdrs, &objp->used)) - return FALSE; - if (!xdr_specdata3 (xdrs, &objp->rdev)) - return FALSE; - if (!xdr_uint64 (xdrs, &objp->fsid)) - return FALSE; - if (!xdr_fileid3 (xdrs, &objp->fileid)) - return FALSE; - if (!xdr_nfstime3 (xdrs, &objp->atime)) - return FALSE; - if (!xdr_nfstime3 (xdrs, &objp->mtime)) - return FALSE; - if (!xdr_nfstime3 (xdrs, &objp->ctime)) - return FALSE; - return TRUE; -} - -bool_t -xdr_post_op_attr (XDR *xdrs, post_op_attr *objp) -{ - if (!xdr_bool (xdrs, &objp->attributes_follow)) - return FALSE; - switch (objp->attributes_follow) { - case TRUE: - if (!xdr_fattr3 (xdrs, &objp->post_op_attr_u.attributes)) - return FALSE; - break; - case FALSE: - break; - default: - return FALSE; - } - return TRUE; -} - -bool_t -xdr_wcc_attr (XDR *xdrs, wcc_attr *objp) -{ - if (!xdr_size3 (xdrs, &objp->size)) - return FALSE; - if (!xdr_nfstime3 (xdrs, &objp->mtime)) - return FALSE; - if (!xdr_nfstime3 (xdrs, &objp->ctime)) - return FALSE; - return TRUE; -} - -bool_t -xdr_pre_op_attr (XDR *xdrs, pre_op_attr *objp) -{ - if (!xdr_bool (xdrs, &objp->attributes_follow)) - return FALSE; - switch (objp->attributes_follow) { - case TRUE: - if (!xdr_wcc_attr (xdrs, &objp->pre_op_attr_u.attributes)) - return FALSE; - break; - case FALSE: - break; - default: - return FALSE; - } - return TRUE; -} - -bool_t -xdr_wcc_data (XDR *xdrs, wcc_data *objp) -{ - if (!xdr_pre_op_attr (xdrs, &objp->before)) - return FALSE; - if (!xdr_post_op_attr (xdrs, &objp->after)) - return FALSE; - return TRUE; -} - -bool_t -xdr_post_op_fh3 (XDR *xdrs, post_op_fh3 *objp) -{ - if (!xdr_bool (xdrs, &objp->handle_follows)) - return FALSE; - switch (objp->handle_follows) { - case TRUE: - if (!xdr_nfs_fh3 (xdrs, &objp->post_op_fh3_u.handle)) - return FALSE; - break; - case FALSE: - break; - default: - return FALSE; - } - return TRUE; -} - -bool_t -xdr_time_how (XDR *xdrs, time_how *objp) -{ - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_set_mode3 (XDR *xdrs, set_mode3 *objp) -{ - if (!xdr_bool (xdrs, &objp->set_it)) - return FALSE; - switch (objp->set_it) { - case TRUE: - if (!xdr_mode3 (xdrs, &objp->set_mode3_u.mode)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - -bool_t -xdr_set_uid3 (XDR *xdrs, set_uid3 *objp) -{ - if (!xdr_bool (xdrs, &objp->set_it)) - return FALSE; - switch (objp->set_it) { - case TRUE: - if (!xdr_uid3 (xdrs, &objp->set_uid3_u.uid)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - -bool_t -xdr_set_gid3 (XDR *xdrs, set_gid3 *objp) -{ - if (!xdr_bool (xdrs, &objp->set_it)) - return FALSE; - switch (objp->set_it) { - case TRUE: - if (!xdr_gid3 (xdrs, &objp->set_gid3_u.gid)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - -bool_t -xdr_set_size3 (XDR *xdrs, set_size3 *objp) -{ - if (!xdr_bool (xdrs, &objp->set_it)) - return FALSE; - switch (objp->set_it) { - case TRUE: - if (!xdr_size3 (xdrs, &objp->set_size3_u.size)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - -bool_t -xdr_set_atime (XDR *xdrs, set_atime *objp) -{ - if (!xdr_time_how (xdrs, &objp->set_it)) - return FALSE; - switch (objp->set_it) { - case SET_TO_CLIENT_TIME: - if (!xdr_nfstime3 (xdrs, &objp->set_atime_u.atime)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - -bool_t -xdr_set_mtime (XDR *xdrs, set_mtime *objp) -{ - if (!xdr_time_how (xdrs, &objp->set_it)) - return FALSE; - switch (objp->set_it) { - case SET_TO_CLIENT_TIME: - if (!xdr_nfstime3 (xdrs, &objp->set_mtime_u.mtime)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - -bool_t -xdr_sattr3 (XDR *xdrs, sattr3 *objp) -{ - if (!xdr_set_mode3 (xdrs, &objp->mode)) - return FALSE; - if (!xdr_set_uid3 (xdrs, &objp->uid)) - return FALSE; - if (!xdr_set_gid3 (xdrs, &objp->gid)) - return FALSE; - if (!xdr_set_size3 (xdrs, &objp->size)) - return FALSE; - if (!xdr_set_atime (xdrs, &objp->atime)) - return FALSE; - if (!xdr_set_mtime (xdrs, &objp->mtime)) - return FALSE; - return TRUE; -} - -bool_t -xdr_diropargs3 (XDR *xdrs, diropargs3 *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->dir)) - return FALSE; - if (!xdr_filename3 (xdrs, &objp->name)) - return FALSE; - return TRUE; -} - -bool_t -xdr_getattr3args (XDR *xdrs, getattr3args *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->object)) - return FALSE; - return TRUE; -} - -bool_t -xdr_getattr3resok (XDR *xdrs, getattr3resok *objp) -{ - if (!xdr_fattr3 (xdrs, &objp->obj_attributes)) - return FALSE; - return TRUE; -} - -bool_t -xdr_getattr3res (XDR *xdrs, getattr3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_getattr3resok (xdrs, &objp->getattr3res_u.resok)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - -bool_t -xdr_sattrguard3 (XDR *xdrs, sattrguard3 *objp) -{ - if (!xdr_bool (xdrs, &objp->check)) - return FALSE; - switch (objp->check) { - case TRUE: - if (!xdr_nfstime3 (xdrs, &objp->sattrguard3_u.obj_ctime)) - return FALSE; - break; - case FALSE: - break; - default: - return FALSE; - } - return TRUE; -} - -bool_t -xdr_setattr3args (XDR *xdrs, setattr3args *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->object)) - return FALSE; - if (!xdr_sattr3 (xdrs, &objp->new_attributes)) - return FALSE; - if (!xdr_sattrguard3 (xdrs, &objp->guard)) - return FALSE; - return TRUE; -} - -bool_t -xdr_setattr3resok (XDR *xdrs, setattr3resok *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->obj_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_setattr3resfail (XDR *xdrs, setattr3resfail *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->obj_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_setattr3res (XDR *xdrs, setattr3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_setattr3resok (xdrs, &objp->setattr3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_setattr3resfail (xdrs, &objp->setattr3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_lookup3args (XDR *xdrs, lookup3args *objp) -{ - if (!xdr_diropargs3 (xdrs, &objp->what)) - return FALSE; - return TRUE; -} - -bool_t -xdr_lookup3resok (XDR *xdrs, lookup3resok *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->object)) - return FALSE; - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - if (!xdr_post_op_attr (xdrs, &objp->dir_attributes)) - return FALSE; - return TRUE; -} - -bool_t -xdr_lookup3resfail (XDR *xdrs, lookup3resfail *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->dir_attributes)) - return FALSE; - return TRUE; -} - -bool_t -xdr_lookup3res (XDR *xdrs, lookup3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_lookup3resok (xdrs, &objp->lookup3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_lookup3resfail (xdrs, &objp->lookup3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_access3args (XDR *xdrs, access3args *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->object)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->access)) - return FALSE; - return TRUE; -} - -bool_t -xdr_access3resok (XDR *xdrs, access3resok *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->access)) - return FALSE; - return TRUE; -} - -bool_t -xdr_access3resfail (XDR *xdrs, access3resfail *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - return TRUE; -} - -bool_t -xdr_access3res (XDR *xdrs, access3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_access3resok (xdrs, &objp->access3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_access3resfail (xdrs, &objp->access3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_readlink3args (XDR *xdrs, readlink3args *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->symlink)) - return FALSE; - return TRUE; -} - -bool_t -xdr_readlink3resok (XDR *xdrs, readlink3resok *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->symlink_attributes)) - return FALSE; - if (!xdr_nfspath3 (xdrs, &objp->data)) - return FALSE; - return TRUE; -} - -bool_t -xdr_readlink3resfail (XDR *xdrs, readlink3resfail *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->symlink_attributes)) - return FALSE; - return TRUE; -} - -bool_t -xdr_readlink3res (XDR *xdrs, readlink3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_readlink3resok (xdrs, &objp->readlink3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_readlink3resfail (xdrs, &objp->readlink3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_read3args (XDR *xdrs, read3args *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->file)) - return FALSE; - if (!xdr_offset3 (xdrs, &objp->offset)) - return FALSE; - if (!xdr_count3 (xdrs, &objp->count)) - return FALSE; - return TRUE; -} - -bool_t -xdr_read3resok_nocopy (XDR *xdrs, read3resok *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->file_attributes)) - return FALSE; - if (!xdr_count3 (xdrs, &objp->count)) - return FALSE; - if (!xdr_bool (xdrs, &objp->eof)) - return FALSE; - if (!xdr_u_int (xdrs, (u_int *) &objp->data.data_len)) - return FALSE; - return TRUE; -} - - -bool_t -xdr_read3resok (XDR *xdrs, read3resok *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->file_attributes)) - return FALSE; - if (!xdr_count3 (xdrs, &objp->count)) - return FALSE; - if (!xdr_bool (xdrs, &objp->eof)) - return FALSE; - if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0)) - return FALSE; - return TRUE; -} - -bool_t -xdr_read3resfail (XDR *xdrs, read3resfail *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->file_attributes)) - return FALSE; - return TRUE; -} - - -bool_t -xdr_read3res_nocopy (XDR *xdrs, read3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_read3resok_nocopy (xdrs, &objp->read3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_read3resfail (xdrs, &objp->read3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - - -bool_t -xdr_read3res (XDR *xdrs, read3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_read3resok (xdrs, &objp->read3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_read3resfail (xdrs, &objp->read3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_stable_how (XDR *xdrs, stable_how *objp) -{ - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_write3args (XDR *xdrs, write3args *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->file)) - return FALSE; - if (!xdr_offset3 (xdrs, &objp->offset)) - return FALSE; - if (!xdr_count3 (xdrs, &objp->count)) - return FALSE; - if (!xdr_stable_how (xdrs, &objp->stable)) - return FALSE; - - /* Added specifically to avoid copies from the xdr buffer into - * the write3args structure, which will also require an already - * allocated buffer. That is not optimal. - */ - if (!xdr_u_int (xdrs, (u_int *) &objp->data.data_len)) - return FALSE; - - /* The remaining bytes in the xdr buffer are the bytes that need to be - * written. See how these bytes are extracted in the xdr_to_write3args - * code path. Be careful, while using the write3args structure, since - * only the data.data_len has been filled. The actual data is - * extracted in xdr_to_write3args path. - */ - - /* if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0)) - return FALSE; - */ - return TRUE; -} - -bool_t -xdr_write3resok (XDR *xdrs, write3resok *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->file_wcc)) - return FALSE; - if (!xdr_count3 (xdrs, &objp->count)) - return FALSE; - if (!xdr_stable_how (xdrs, &objp->committed)) - return FALSE; - if (!xdr_writeverf3 (xdrs, objp->verf)) - return FALSE; - return TRUE; -} - -bool_t -xdr_write3resfail (XDR *xdrs, write3resfail *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->file_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_write3res (XDR *xdrs, write3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_write3resok (xdrs, &objp->write3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_write3resfail (xdrs, &objp->write3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_createmode3 (XDR *xdrs, createmode3 *objp) -{ - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_createhow3 (XDR *xdrs, createhow3 *objp) -{ - if (!xdr_createmode3 (xdrs, &objp->mode)) - return FALSE; - switch (objp->mode) { - case UNCHECKED: - case GUARDED: - if (!xdr_sattr3 (xdrs, &objp->createhow3_u.obj_attributes)) - return FALSE; - break; - case EXCLUSIVE: - if (!xdr_createverf3 (xdrs, objp->createhow3_u.verf)) - return FALSE; - break; - default: - return FALSE; - } - return TRUE; -} - -bool_t -xdr_create3args (XDR *xdrs, create3args *objp) -{ - if (!xdr_diropargs3 (xdrs, &objp->where)) - return FALSE; - if (!xdr_createhow3 (xdrs, &objp->how)) - return FALSE; - return TRUE; -} - -bool_t -xdr_create3resok (XDR *xdrs, create3resok *objp) -{ - if (!xdr_post_op_fh3 (xdrs, &objp->obj)) - return FALSE; - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_create3resfail (XDR *xdrs, create3resfail *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_create3res (XDR *xdrs, create3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_create3resok (xdrs, &objp->create3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_create3resfail (xdrs, &objp->create3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_mkdir3args (XDR *xdrs, mkdir3args *objp) -{ - if (!xdr_diropargs3 (xdrs, &objp->where)) - return FALSE; - if (!xdr_sattr3 (xdrs, &objp->attributes)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mkdir3resok (XDR *xdrs, mkdir3resok *objp) -{ - if (!xdr_post_op_fh3 (xdrs, &objp->obj)) - return FALSE; - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mkdir3resfail (XDR *xdrs, mkdir3resfail *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mkdir3res (XDR *xdrs, mkdir3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_mkdir3resok (xdrs, &objp->mkdir3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_mkdir3resfail (xdrs, &objp->mkdir3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_symlinkdata3 (XDR *xdrs, symlinkdata3 *objp) -{ - if (!xdr_sattr3 (xdrs, &objp->symlink_attributes)) - return FALSE; - if (!xdr_nfspath3 (xdrs, &objp->symlink_data)) - return FALSE; - return TRUE; -} - -bool_t -xdr_symlink3args (XDR *xdrs, symlink3args *objp) -{ - if (!xdr_diropargs3 (xdrs, &objp->where)) - return FALSE; - if (!xdr_symlinkdata3 (xdrs, &objp->symlink)) - return FALSE; - return TRUE; -} - -bool_t -xdr_symlink3resok (XDR *xdrs, symlink3resok *objp) -{ - if (!xdr_post_op_fh3 (xdrs, &objp->obj)) - return FALSE; - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_symlink3resfail (XDR *xdrs, symlink3resfail *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_symlink3res (XDR *xdrs, symlink3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_symlink3resok (xdrs, &objp->symlink3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_symlink3resfail (xdrs, &objp->symlink3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_devicedata3 (XDR *xdrs, devicedata3 *objp) -{ - if (!xdr_sattr3 (xdrs, &objp->dev_attributes)) - return FALSE; - if (!xdr_specdata3 (xdrs, &objp->spec)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mknoddata3 (XDR *xdrs, mknoddata3 *objp) -{ - if (!xdr_ftype3 (xdrs, &objp->type)) - return FALSE; - switch (objp->type) { - case NF3CHR: - case NF3BLK: - if (!xdr_devicedata3 (xdrs, &objp->mknoddata3_u.device)) - return FALSE; - break; - case NF3SOCK: - case NF3FIFO: - if (!xdr_sattr3 (xdrs, &objp->mknoddata3_u.pipe_attributes)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - -bool_t -xdr_mknod3args (XDR *xdrs, mknod3args *objp) -{ - if (!xdr_diropargs3 (xdrs, &objp->where)) - return FALSE; - if (!xdr_mknoddata3 (xdrs, &objp->what)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mknod3resok (XDR *xdrs, mknod3resok *objp) -{ - if (!xdr_post_op_fh3 (xdrs, &objp->obj)) - return FALSE; - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mknod3resfail (XDR *xdrs, mknod3resfail *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mknod3res (XDR *xdrs, mknod3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_mknod3resok (xdrs, &objp->mknod3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_mknod3resfail (xdrs, &objp->mknod3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_remove3args (XDR *xdrs, remove3args *objp) -{ - if (!xdr_diropargs3 (xdrs, &objp->object)) - return FALSE; - return TRUE; -} - -bool_t -xdr_remove3resok (XDR *xdrs, remove3resok *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_remove3resfail (XDR *xdrs, remove3resfail *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_remove3res (XDR *xdrs, remove3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_remove3resok (xdrs, &objp->remove3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_remove3resfail (xdrs, &objp->remove3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_rmdir3args (XDR *xdrs, rmdir3args *objp) -{ - if (!xdr_diropargs3 (xdrs, &objp->object)) - return FALSE; - return TRUE; -} - -bool_t -xdr_rmdir3resok (XDR *xdrs, rmdir3resok *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_rmdir3resfail (XDR *xdrs, rmdir3resfail *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->dir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_rmdir3res (XDR *xdrs, rmdir3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_rmdir3resok (xdrs, &objp->rmdir3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_rmdir3resfail (xdrs, &objp->rmdir3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_rename3args (XDR *xdrs, rename3args *objp) -{ - if (!xdr_diropargs3 (xdrs, &objp->from)) - return FALSE; - if (!xdr_diropargs3 (xdrs, &objp->to)) - return FALSE; - return TRUE; -} - -bool_t -xdr_rename3resok (XDR *xdrs, rename3resok *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->fromdir_wcc)) - return FALSE; - if (!xdr_wcc_data (xdrs, &objp->todir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_rename3resfail (XDR *xdrs, rename3resfail *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->fromdir_wcc)) - return FALSE; - if (!xdr_wcc_data (xdrs, &objp->todir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_rename3res (XDR *xdrs, rename3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_rename3resok (xdrs, &objp->rename3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_rename3resfail (xdrs, &objp->rename3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_link3args (XDR *xdrs, link3args *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->file)) - return FALSE; - if (!xdr_diropargs3 (xdrs, &objp->link)) - return FALSE; - return TRUE; -} - -bool_t -xdr_link3resok (XDR *xdrs, link3resok *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->file_attributes)) - return FALSE; - if (!xdr_wcc_data (xdrs, &objp->linkdir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_link3resfail (XDR *xdrs, link3resfail *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->file_attributes)) - return FALSE; - if (!xdr_wcc_data (xdrs, &objp->linkdir_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_link3res (XDR *xdrs, link3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_link3resok (xdrs, &objp->link3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_link3resfail (xdrs, &objp->link3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_readdir3args (XDR *xdrs, readdir3args *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->dir)) - return FALSE; - if (!xdr_cookie3 (xdrs, &objp->cookie)) - return FALSE; - if (!xdr_cookieverf3 (xdrs, objp->cookieverf)) - return FALSE; - if (!xdr_count3 (xdrs, &objp->count)) - return FALSE; - return TRUE; -} - -bool_t -xdr_entry3 (XDR *xdrs, entry3 *objp) -{ - if (!xdr_fileid3 (xdrs, &objp->fileid)) - return FALSE; - if (!xdr_filename3 (xdrs, &objp->name)) - return FALSE; - if (!xdr_cookie3 (xdrs, &objp->cookie)) - return FALSE; - if (!xdr_pointer (xdrs, (char **)&objp->nextentry, sizeof (entry3), (xdrproc_t) xdr_entry3)) - return FALSE; - return TRUE; -} - -bool_t -xdr_dirlist3 (XDR *xdrs, dirlist3 *objp) -{ - if (!xdr_pointer (xdrs, (char **)&objp->entries, sizeof (entry3), (xdrproc_t) xdr_entry3)) - return FALSE; - if (!xdr_bool (xdrs, &objp->eof)) - return FALSE; - return TRUE; -} - -bool_t -xdr_readdir3resok (XDR *xdrs, readdir3resok *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->dir_attributes)) - return FALSE; - if (!xdr_cookieverf3 (xdrs, objp->cookieverf)) - return FALSE; - if (!xdr_dirlist3 (xdrs, &objp->reply)) - return FALSE; - return TRUE; -} - -bool_t -xdr_readdir3resfail (XDR *xdrs, readdir3resfail *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->dir_attributes)) - return FALSE; - return TRUE; -} - -bool_t -xdr_readdir3res (XDR *xdrs, readdir3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_readdir3resok (xdrs, &objp->readdir3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_readdir3resfail (xdrs, &objp->readdir3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_readdirp3args (XDR *xdrs, readdirp3args *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->dir)) - return FALSE; - if (!xdr_cookie3 (xdrs, &objp->cookie)) - return FALSE; - if (!xdr_cookieverf3 (xdrs, objp->cookieverf)) - return FALSE; - if (!xdr_count3 (xdrs, &objp->dircount)) - return FALSE; - if (!xdr_count3 (xdrs, &objp->maxcount)) - return FALSE; - return TRUE; -} - -bool_t -xdr_entryp3 (XDR *xdrs, entryp3 *objp) -{ - if (!xdr_fileid3 (xdrs, &objp->fileid)) - return FALSE; - if (!xdr_filename3 (xdrs, &objp->name)) - return FALSE; - if (!xdr_cookie3 (xdrs, &objp->cookie)) - return FALSE; - if (!xdr_post_op_attr (xdrs, &objp->name_attributes)) - return FALSE; - if (!xdr_post_op_fh3 (xdrs, &objp->name_handle)) - return FALSE; - if (!xdr_pointer (xdrs, (char **)&objp->nextentry, sizeof (entryp3), (xdrproc_t) xdr_entryp3)) - return FALSE; - return TRUE; -} - -bool_t -xdr_dirlistp3 (XDR *xdrs, dirlistp3 *objp) -{ - if (!xdr_pointer (xdrs, (char **)&objp->entries, sizeof (entryp3), (xdrproc_t) xdr_entryp3)) - return FALSE; - if (!xdr_bool (xdrs, &objp->eof)) - return FALSE; - return TRUE; -} - -bool_t -xdr_readdirp3resok (XDR *xdrs, readdirp3resok *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->dir_attributes)) - return FALSE; - if (!xdr_cookieverf3 (xdrs, objp->cookieverf)) - return FALSE; - if (!xdr_dirlistp3 (xdrs, &objp->reply)) - return FALSE; - return TRUE; -} - -bool_t -xdr_readdirp3resfail (XDR *xdrs, readdirp3resfail *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->dir_attributes)) - return FALSE; - return TRUE; -} - -bool_t -xdr_readdirp3res (XDR *xdrs, readdirp3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_readdirp3resok (xdrs, &objp->readdirp3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_readdirp3resfail (xdrs, &objp->readdirp3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_fsstat3args (XDR *xdrs, fsstat3args *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->fsroot)) - return FALSE; - return TRUE; -} - -bool_t -xdr_fsstat3resok (XDR *xdrs, fsstat3resok *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - if (!xdr_size3 (xdrs, &objp->tbytes)) - return FALSE; - if (!xdr_size3 (xdrs, &objp->fbytes)) - return FALSE; - if (!xdr_size3 (xdrs, &objp->abytes)) - return FALSE; - if (!xdr_size3 (xdrs, &objp->tfiles)) - return FALSE; - if (!xdr_size3 (xdrs, &objp->ffiles)) - return FALSE; - if (!xdr_size3 (xdrs, &objp->afiles)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->invarsec)) - return FALSE; - return TRUE; -} - -bool_t -xdr_fsstat3resfail (XDR *xdrs, fsstat3resfail *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - return TRUE; -} - -bool_t -xdr_fsstat3res (XDR *xdrs, fsstat3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_fsstat3resok (xdrs, &objp->fsstat3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_fsstat3resfail (xdrs, &objp->fsstat3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_fsinfo3args (XDR *xdrs, fsinfo3args *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->fsroot)) - return FALSE; - return TRUE; -} - -bool_t -xdr_fsinfo3resok (XDR *xdrs, fsinfo3resok *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->rtmax)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->rtpref)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->rtmult)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->wtmax)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->wtpref)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->wtmult)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->dtpref)) - return FALSE; - if (!xdr_size3 (xdrs, &objp->maxfilesize)) - return FALSE; - if (!xdr_nfstime3 (xdrs, &objp->time_delta)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->properties)) - return FALSE; - return TRUE; -} - -bool_t -xdr_fsinfo3resfail (XDR *xdrs, fsinfo3resfail *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - return TRUE; -} - -bool_t -xdr_fsinfo3res (XDR *xdrs, fsinfo3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_fsinfo3resok (xdrs, &objp->fsinfo3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_fsinfo3resfail (xdrs, &objp->fsinfo3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_pathconf3args (XDR *xdrs, pathconf3args *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->object)) - return FALSE; - return TRUE; -} - -bool_t -xdr_pathconf3resok (XDR *xdrs, pathconf3resok *objp) -{ - register int32_t *buf; - - - if (xdrs->x_op == XDR_ENCODE) { - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->linkmax)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->name_max)) - return FALSE; - buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_bool (xdrs, &objp->no_trunc)) - return FALSE; - if (!xdr_bool (xdrs, &objp->chown_restricted)) - return FALSE; - if (!xdr_bool (xdrs, &objp->case_insensitive)) - return FALSE; - if (!xdr_bool (xdrs, &objp->case_preserving)) - return FALSE; - } else { - IXDR_PUT_BOOL(buf, objp->no_trunc); - IXDR_PUT_BOOL(buf, objp->chown_restricted); - IXDR_PUT_BOOL(buf, objp->case_insensitive); - IXDR_PUT_BOOL(buf, objp->case_preserving); - } - return TRUE; - } else if (xdrs->x_op == XDR_DECODE) { - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->linkmax)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->name_max)) - return FALSE; - buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_bool (xdrs, &objp->no_trunc)) - return FALSE; - if (!xdr_bool (xdrs, &objp->chown_restricted)) - return FALSE; - if (!xdr_bool (xdrs, &objp->case_insensitive)) - return FALSE; - if (!xdr_bool (xdrs, &objp->case_preserving)) - return FALSE; - } else { - objp->no_trunc = IXDR_GET_BOOL(buf); - objp->chown_restricted = IXDR_GET_BOOL(buf); - objp->case_insensitive = IXDR_GET_BOOL(buf); - objp->case_preserving = IXDR_GET_BOOL(buf); - } - return TRUE; - } - - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->linkmax)) - return FALSE; - if (!xdr_uint32 (xdrs, &objp->name_max)) - return FALSE; - if (!xdr_bool (xdrs, &objp->no_trunc)) - return FALSE; - if (!xdr_bool (xdrs, &objp->chown_restricted)) - return FALSE; - if (!xdr_bool (xdrs, &objp->case_insensitive)) - return FALSE; - if (!xdr_bool (xdrs, &objp->case_preserving)) - return FALSE; - return TRUE; -} - -bool_t -xdr_pathconf3resfail (XDR *xdrs, pathconf3resfail *objp) -{ - if (!xdr_post_op_attr (xdrs, &objp->obj_attributes)) - return FALSE; - return TRUE; -} - -bool_t -xdr_pathconf3res (XDR *xdrs, pathconf3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_pathconf3resok (xdrs, &objp->pathconf3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_pathconf3resfail (xdrs, &objp->pathconf3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_commit3args (XDR *xdrs, commit3args *objp) -{ - if (!xdr_nfs_fh3 (xdrs, &objp->file)) - return FALSE; - if (!xdr_offset3 (xdrs, &objp->offset)) - return FALSE; - if (!xdr_count3 (xdrs, &objp->count)) - return FALSE; - return TRUE; -} - -bool_t -xdr_commit3resok (XDR *xdrs, commit3resok *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->file_wcc)) - return FALSE; - if (!xdr_writeverf3 (xdrs, objp->verf)) - return FALSE; - return TRUE; -} - -bool_t -xdr_commit3resfail (XDR *xdrs, commit3resfail *objp) -{ - if (!xdr_wcc_data (xdrs, &objp->file_wcc)) - return FALSE; - return TRUE; -} - -bool_t -xdr_commit3res (XDR *xdrs, commit3res *objp) -{ - if (!xdr_nfsstat3 (xdrs, &objp->status)) - return FALSE; - switch (objp->status) { - case NFS3_OK: - if (!xdr_commit3resok (xdrs, &objp->commit3res_u.resok)) - return FALSE; - break; - default: - if (!xdr_commit3resfail (xdrs, &objp->commit3res_u.resfail)) - return FALSE; - break; - } - return TRUE; -} - -bool_t -xdr_fhandle3 (XDR *xdrs, fhandle3 *objp) -{ - if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3)) - return FALSE; - return TRUE; -} - -bool_t -xdr_dirpath (XDR *xdrs, dirpath *objp) -{ - if (!xdr_string (xdrs, objp, MNTPATHLEN)) - return FALSE; - return TRUE; -} - -bool_t -xdr_name (XDR *xdrs, name *objp) -{ - if (!xdr_string (xdrs, objp, MNTNAMLEN)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mountstat3 (XDR *xdrs, mountstat3 *objp) -{ - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp) -{ - if (!xdr_fhandle3 (xdrs, &objp->fhandle)) - return FALSE; - if (!xdr_array (xdrs, (char **)&objp->auth_flavors.auth_flavors_val, (u_int *) &objp->auth_flavors.auth_flavors_len, ~0, - sizeof (int), (xdrproc_t) xdr_int)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mountres3 (XDR *xdrs, mountres3 *objp) -{ - if (!xdr_mountstat3 (xdrs, &objp->fhs_status)) - return FALSE; - switch (objp->fhs_status) { - case MNT3_OK: - if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - -bool_t -xdr_mountlist (XDR *xdrs, mountlist *objp) -{ - if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct mountbody), (xdrproc_t) xdr_mountbody)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mountbody (XDR *xdrs, mountbody *objp) -{ - if (!xdr_name (xdrs, &objp->ml_hostname)) - return FALSE; - if (!xdr_dirpath (xdrs, &objp->ml_directory)) - return FALSE; - if (!xdr_mountlist (xdrs, &objp->ml_next)) - return FALSE; - return TRUE; -} - -bool_t -xdr_groups (XDR *xdrs, groups *objp) -{ - if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct groupnode), (xdrproc_t) xdr_groupnode)) - return FALSE; - return TRUE; -} - -bool_t -xdr_groupnode (XDR *xdrs, groupnode *objp) -{ - if (!xdr_name (xdrs, &objp->gr_name)) - return FALSE; - if (!xdr_groups (xdrs, &objp->gr_next)) - return FALSE; - return TRUE; -} - -bool_t -xdr_exports (XDR *xdrs, exports *objp) -{ - if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct exportnode), (xdrproc_t) xdr_exportnode)) - return FALSE; - return TRUE; -} - -bool_t -xdr_exportnode (XDR *xdrs, exportnode *objp) -{ - if (!xdr_dirpath (xdrs, &objp->ex_dir)) - return FALSE; - if (!xdr_groups (xdrs, &objp->ex_groups)) - return FALSE; - if (!xdr_exports (xdrs, &objp->ex_next)) - return FALSE; - return TRUE; -} - -void -xdr_free_exports_list (struct exportnode *first) -{ - struct exportnode *elist = NULL; - - if (!first) - return; - - while (first) { - elist = first->ex_next; - if (first->ex_dir) - GF_FREE (first->ex_dir); - - if (first->ex_groups) { - if (first->ex_groups->gr_name) - GF_FREE (first->ex_groups->gr_name); - GF_FREE (first->ex_groups); - } - - GF_FREE (first); - first = elist; - } - -} - - -void -xdr_free_mountlist (mountlist ml) -{ - struct mountbody *next = NULL; - - if (!ml) - return; - - while (ml) { - GF_FREE (ml->ml_hostname); - GF_FREE (ml->ml_directory); - next = ml->ml_next; - GF_FREE (ml); - ml = next; - } - - return; -} - - -/* Free statements are based on the way sunrpc xdr decoding - * code performs memory allocations. - */ -void -xdr_free_write3args_nocopy (write3args *wa) -{ - if (!wa) - return; - - FREE (wa->file.data.data_val); -} - - diff --git a/xlators/nfs/lib/src/xdr-nfs3.h b/xlators/nfs/lib/src/xdr-nfs3.h deleted file mode 100644 index 0530876a8..000000000 --- a/xlators/nfs/lib/src/xdr-nfs3.h +++ /dev/null @@ -1,1206 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _XDR_NFS3_H -#define _XDR_NFS3_H - -#include <rpc/rpc.h> -#include <sys/types.h> - -#define NFS3_FHSIZE 64 -#define NFS3_COOKIEVERFSIZE 8 -#define NFS3_CREATEVERFSIZE 8 -#define NFS3_WRITEVERFSIZE 8 - -#define NFS3_ENTRY3_FIXED_SIZE 24 -#define NFS3_POSTOPATTR_SIZE 88 -#define NFS3_READDIR_RESOK_SIZE (NFS3_POSTOPATTR_SIZE + sizeof (bool_t) + NFS3_COOKIEVERFSIZE) - -/* In size of post_op_fh3, the length of the file handle will have to be - * included separately since we have variable length fh. Here we only account - * for the field for handle_follows and for the file handle length field. - */ -#define NFS3_POSTOPFH3_FIXED_SIZE (sizeof (bool_t) + sizeof (uint32_t)) - -/* Similarly, the size of the entry will have to include the variable length - * file handle and the length of the entry name. - */ -#define NFS3_ENTRYP3_FIXED_SIZE (NFS3_ENTRY3_FIXED_SIZE + NFS3_POSTOPATTR_SIZE + NFS3_POSTOPFH3_FIXED_SIZE) - -typedef uint64_t uint64; -typedef int64_t int64; -typedef uint32_t uint32; -typedef int32_t int32; -typedef char *filename3; -typedef char *nfspath3; -typedef uint64 fileid3; -typedef uint64 cookie3; -typedef char cookieverf3[NFS3_COOKIEVERFSIZE]; -typedef char createverf3[NFS3_CREATEVERFSIZE]; -typedef char writeverf3[NFS3_WRITEVERFSIZE]; -typedef uint32 uid3; -typedef uint32 gid3; -typedef uint64 size3; -typedef uint64 offset3; -typedef uint32 mode3; -typedef uint32 count3; - -#define NFS3MODE_SETXUID 0x00800 -#define NFS3MODE_SETXGID 0x00400 -#define NFS3MODE_SAVESWAPTXT 0x00200 -#define NFS3MODE_ROWNER 0x00100 -#define NFS3MODE_WOWNER 0x00080 -#define NFS3MODE_XOWNER 0x00040 -#define NFS3MODE_RGROUP 0x00020 -#define NFS3MODE_WGROUP 0x00010 -#define NFS3MODE_XGROUP 0x00008 -#define NFS3MODE_ROTHER 0x00004 -#define NFS3MODE_WOTHER 0x00002 -#define NFS3MODE_XOTHER 0x00001 - -enum nfsstat3 { - NFS3_OK = 0, - NFS3ERR_PERM = 1, - NFS3ERR_NOENT = 2, - NFS3ERR_IO = 5, - NFS3ERR_NXIO = 6, - NFS3ERR_ACCES = 13, - NFS3ERR_EXIST = 17, - NFS3ERR_XDEV = 18, - NFS3ERR_NODEV = 19, - NFS3ERR_NOTDIR = 20, - NFS3ERR_ISDIR = 21, - NFS3ERR_INVAL = 22, - NFS3ERR_FBIG = 27, - NFS3ERR_NOSPC = 28, - NFS3ERR_ROFS = 30, - NFS3ERR_MLINK = 31, - NFS3ERR_NAMETOOLONG = 63, - NFS3ERR_NOTEMPTY = 66, - NFS3ERR_DQUOT = 69, - NFS3ERR_STALE = 70, - NFS3ERR_REMOTE = 71, - NFS3ERR_BADHANDLE = 10001, - NFS3ERR_NOT_SYNC = 10002, - NFS3ERR_BAD_COOKIE = 10003, - NFS3ERR_NOTSUPP = 10004, - NFS3ERR_TOOSMALL = 10005, - NFS3ERR_SERVERFAULT = 10006, - NFS3ERR_BADTYPE = 10007, - NFS3ERR_JUKEBOX = 10008, -}; -typedef enum nfsstat3 nfsstat3; - -enum ftype3 { - NF3REG = 1, - NF3DIR = 2, - NF3BLK = 3, - NF3CHR = 4, - NF3LNK = 5, - NF3SOCK = 6, - NF3FIFO = 7, -}; -typedef enum ftype3 ftype3; - -struct specdata3 { - uint32 specdata1; - uint32 specdata2; -}; -typedef struct specdata3 specdata3; - -struct nfs_fh3 { - struct { - u_int data_len; - char *data_val; - } data; -}; -typedef struct nfs_fh3 nfs_fh3; - -struct nfstime3 { - uint32 seconds; - uint32 nseconds; -}; -typedef struct nfstime3 nfstime3; - -struct fattr3 { - ftype3 type; - mode3 mode; - uint32 nlink; - uid3 uid; - gid3 gid; - size3 size; - size3 used; - specdata3 rdev; - uint64 fsid; - fileid3 fileid; - nfstime3 atime; - nfstime3 mtime; - nfstime3 ctime; -}; -typedef struct fattr3 fattr3; - -struct post_op_attr { - bool_t attributes_follow; - union { - fattr3 attributes; - } post_op_attr_u; -}; -typedef struct post_op_attr post_op_attr; - -struct wcc_attr { - size3 size; - nfstime3 mtime; - nfstime3 ctime; -}; -typedef struct wcc_attr wcc_attr; - -struct pre_op_attr { - bool_t attributes_follow; - union { - wcc_attr attributes; - } pre_op_attr_u; -}; -typedef struct pre_op_attr pre_op_attr; - -struct wcc_data { - pre_op_attr before; - post_op_attr after; -}; -typedef struct wcc_data wcc_data; - -struct post_op_fh3 { - bool_t handle_follows; - union { - nfs_fh3 handle; - } post_op_fh3_u; -}; -typedef struct post_op_fh3 post_op_fh3; - -enum time_how { - DONT_CHANGE = 0, - SET_TO_SERVER_TIME = 1, - SET_TO_CLIENT_TIME = 2, -}; -typedef enum time_how time_how; - -struct set_mode3 { - bool_t set_it; - union { - mode3 mode; - } set_mode3_u; -}; -typedef struct set_mode3 set_mode3; - -struct set_uid3 { - bool_t set_it; - union { - uid3 uid; - } set_uid3_u; -}; -typedef struct set_uid3 set_uid3; - -struct set_gid3 { - bool_t set_it; - union { - gid3 gid; - } set_gid3_u; -}; -typedef struct set_gid3 set_gid3; - -struct set_size3 { - bool_t set_it; - union { - size3 size; - } set_size3_u; -}; -typedef struct set_size3 set_size3; - -struct set_atime { - time_how set_it; - union { - nfstime3 atime; - } set_atime_u; -}; -typedef struct set_atime set_atime; - -struct set_mtime { - time_how set_it; - union { - nfstime3 mtime; - } set_mtime_u; -}; -typedef struct set_mtime set_mtime; - -struct sattr3 { - set_mode3 mode; - set_uid3 uid; - set_gid3 gid; - set_size3 size; - set_atime atime; - set_mtime mtime; -}; -typedef struct sattr3 sattr3; - -struct diropargs3 { - nfs_fh3 dir; - filename3 name; -}; -typedef struct diropargs3 diropargs3; - -struct getattr3args { - nfs_fh3 object; -}; -typedef struct getattr3args getattr3args; - -struct getattr3resok { - fattr3 obj_attributes; -}; -typedef struct getattr3resok getattr3resok; - -struct getattr3res { - nfsstat3 status; - union { - getattr3resok resok; - } getattr3res_u; -}; -typedef struct getattr3res getattr3res; - -struct sattrguard3 { - bool_t check; - union { - nfstime3 obj_ctime; - } sattrguard3_u; -}; -typedef struct sattrguard3 sattrguard3; - -struct setattr3args { - nfs_fh3 object; - sattr3 new_attributes; - sattrguard3 guard; -}; -typedef struct setattr3args setattr3args; - -struct setattr3resok { - wcc_data obj_wcc; -}; -typedef struct setattr3resok setattr3resok; - -struct setattr3resfail { - wcc_data obj_wcc; -}; -typedef struct setattr3resfail setattr3resfail; - -struct setattr3res { - nfsstat3 status; - union { - setattr3resok resok; - setattr3resfail resfail; - } setattr3res_u; -}; -typedef struct setattr3res setattr3res; - -struct lookup3args { - diropargs3 what; -}; -typedef struct lookup3args lookup3args; - -struct lookup3resok { - nfs_fh3 object; - post_op_attr obj_attributes; - post_op_attr dir_attributes; -}; -typedef struct lookup3resok lookup3resok; - -struct lookup3resfail { - post_op_attr dir_attributes; -}; -typedef struct lookup3resfail lookup3resfail; - -struct lookup3res { - nfsstat3 status; - union { - lookup3resok resok; - lookup3resfail resfail; - } lookup3res_u; -}; -typedef struct lookup3res lookup3res; -#define ACCESS3_READ 0x0001 -#define ACCESS3_LOOKUP 0x0002 -#define ACCESS3_MODIFY 0x0004 -#define ACCESS3_EXTEND 0x0008 -#define ACCESS3_DELETE 0x0010 -#define ACCESS3_EXECUTE 0x0020 - -struct access3args { - nfs_fh3 object; - uint32 access; -}; -typedef struct access3args access3args; - -struct access3resok { - post_op_attr obj_attributes; - uint32 access; -}; -typedef struct access3resok access3resok; - -struct access3resfail { - post_op_attr obj_attributes; -}; -typedef struct access3resfail access3resfail; - -struct access3res { - nfsstat3 status; - union { - access3resok resok; - access3resfail resfail; - } access3res_u; -}; -typedef struct access3res access3res; - -struct readlink3args { - nfs_fh3 symlink; -}; -typedef struct readlink3args readlink3args; - -struct readlink3resok { - post_op_attr symlink_attributes; - nfspath3 data; -}; -typedef struct readlink3resok readlink3resok; - -struct readlink3resfail { - post_op_attr symlink_attributes; -}; -typedef struct readlink3resfail readlink3resfail; - -struct readlink3res { - nfsstat3 status; - union { - readlink3resok resok; - readlink3resfail resfail; - } readlink3res_u; -}; -typedef struct readlink3res readlink3res; - -struct read3args { - nfs_fh3 file; - offset3 offset; - count3 count; -}; -typedef struct read3args read3args; - -struct read3resok { - post_op_attr file_attributes; - count3 count; - bool_t eof; - struct { - u_int data_len; - char *data_val; - } data; -}; -typedef struct read3resok read3resok; - -struct read3resfail { - post_op_attr file_attributes; -}; -typedef struct read3resfail read3resfail; - -struct read3res { - nfsstat3 status; - union { - read3resok resok; - read3resfail resfail; - } read3res_u; -}; -typedef struct read3res read3res; - -enum stable_how { - UNSTABLE = 0, - DATA_SYNC = 1, - FILE_SYNC = 2, -}; -typedef enum stable_how stable_how; - -struct write3args { - nfs_fh3 file; - offset3 offset; - count3 count; - stable_how stable; - struct { - u_int data_len; - char *data_val; - } data; -}; -typedef struct write3args write3args; - -/* Generally, the protocol allows the file handle to be less than 64 bytes but - * our server does not return file handles less than 64b so we can safely say - * sizeof (nfs_fh3) rather than first trying to extract the fh size of the - * network followed by a sized-read of the file handle. - */ -#define NFS3_WRITE3ARGS_SIZE (sizeof (uint32_t) + NFS3_FHSIZE + sizeof (offset3) + sizeof (count3) + sizeof (uint32_t)) -struct write3resok { - wcc_data file_wcc; - count3 count; - stable_how committed; - writeverf3 verf; -}; -typedef struct write3resok write3resok; - -struct write3resfail { - wcc_data file_wcc; -}; -typedef struct write3resfail write3resfail; - -struct write3res { - nfsstat3 status; - union { - write3resok resok; - write3resfail resfail; - } write3res_u; -}; -typedef struct write3res write3res; - -enum createmode3 { - UNCHECKED = 0, - GUARDED = 1, - EXCLUSIVE = 2, -}; -typedef enum createmode3 createmode3; - -struct createhow3 { - createmode3 mode; - union { - sattr3 obj_attributes; - createverf3 verf; - } createhow3_u; -}; -typedef struct createhow3 createhow3; - -struct create3args { - diropargs3 where; - createhow3 how; -}; -typedef struct create3args create3args; - -struct create3resok { - post_op_fh3 obj; - post_op_attr obj_attributes; - wcc_data dir_wcc; -}; -typedef struct create3resok create3resok; - -struct create3resfail { - wcc_data dir_wcc; -}; -typedef struct create3resfail create3resfail; - -struct create3res { - nfsstat3 status; - union { - create3resok resok; - create3resfail resfail; - } create3res_u; -}; -typedef struct create3res create3res; - -struct mkdir3args { - diropargs3 where; - sattr3 attributes; -}; -typedef struct mkdir3args mkdir3args; - -struct mkdir3resok { - post_op_fh3 obj; - post_op_attr obj_attributes; - wcc_data dir_wcc; -}; -typedef struct mkdir3resok mkdir3resok; - -struct mkdir3resfail { - wcc_data dir_wcc; -}; -typedef struct mkdir3resfail mkdir3resfail; - -struct mkdir3res { - nfsstat3 status; - union { - mkdir3resok resok; - mkdir3resfail resfail; - } mkdir3res_u; -}; -typedef struct mkdir3res mkdir3res; - -struct symlinkdata3 { - sattr3 symlink_attributes; - nfspath3 symlink_data; -}; -typedef struct symlinkdata3 symlinkdata3; - -struct symlink3args { - diropargs3 where; - symlinkdata3 symlink; -}; -typedef struct symlink3args symlink3args; - -struct symlink3resok { - post_op_fh3 obj; - post_op_attr obj_attributes; - wcc_data dir_wcc; -}; -typedef struct symlink3resok symlink3resok; - -struct symlink3resfail { - wcc_data dir_wcc; -}; -typedef struct symlink3resfail symlink3resfail; - -struct symlink3res { - nfsstat3 status; - union { - symlink3resok resok; - symlink3resfail resfail; - } symlink3res_u; -}; -typedef struct symlink3res symlink3res; - -struct devicedata3 { - sattr3 dev_attributes; - specdata3 spec; -}; -typedef struct devicedata3 devicedata3; - -struct mknoddata3 { - ftype3 type; - union { - devicedata3 device; - sattr3 pipe_attributes; - } mknoddata3_u; -}; -typedef struct mknoddata3 mknoddata3; - -struct mknod3args { - diropargs3 where; - mknoddata3 what; -}; -typedef struct mknod3args mknod3args; - -struct mknod3resok { - post_op_fh3 obj; - post_op_attr obj_attributes; - wcc_data dir_wcc; -}; -typedef struct mknod3resok mknod3resok; - -struct mknod3resfail { - wcc_data dir_wcc; -}; -typedef struct mknod3resfail mknod3resfail; - -struct mknod3res { - nfsstat3 status; - union { - mknod3resok resok; - mknod3resfail resfail; - } mknod3res_u; -}; -typedef struct mknod3res mknod3res; - -struct remove3args { - diropargs3 object; -}; -typedef struct remove3args remove3args; - -struct remove3resok { - wcc_data dir_wcc; -}; -typedef struct remove3resok remove3resok; - -struct remove3resfail { - wcc_data dir_wcc; -}; -typedef struct remove3resfail remove3resfail; - -struct remove3res { - nfsstat3 status; - union { - remove3resok resok; - remove3resfail resfail; - } remove3res_u; -}; -typedef struct remove3res remove3res; - -struct rmdir3args { - diropargs3 object; -}; -typedef struct rmdir3args rmdir3args; - -struct rmdir3resok { - wcc_data dir_wcc; -}; -typedef struct rmdir3resok rmdir3resok; - -struct rmdir3resfail { - wcc_data dir_wcc; -}; -typedef struct rmdir3resfail rmdir3resfail; - -struct rmdir3res { - nfsstat3 status; - union { - rmdir3resok resok; - rmdir3resfail resfail; - } rmdir3res_u; -}; -typedef struct rmdir3res rmdir3res; - -struct rename3args { - diropargs3 from; - diropargs3 to; -}; -typedef struct rename3args rename3args; - -struct rename3resok { - wcc_data fromdir_wcc; - wcc_data todir_wcc; -}; -typedef struct rename3resok rename3resok; - -struct rename3resfail { - wcc_data fromdir_wcc; - wcc_data todir_wcc; -}; -typedef struct rename3resfail rename3resfail; - -struct rename3res { - nfsstat3 status; - union { - rename3resok resok; - rename3resfail resfail; - } rename3res_u; -}; -typedef struct rename3res rename3res; - -struct link3args { - nfs_fh3 file; - diropargs3 link; -}; -typedef struct link3args link3args; - -struct link3resok { - post_op_attr file_attributes; - wcc_data linkdir_wcc; -}; -typedef struct link3resok link3resok; - -struct link3resfail { - post_op_attr file_attributes; - wcc_data linkdir_wcc; -}; -typedef struct link3resfail link3resfail; - -struct link3res { - nfsstat3 status; - union { - link3resok resok; - link3resfail resfail; - } link3res_u; -}; -typedef struct link3res link3res; - -struct readdir3args { - nfs_fh3 dir; - cookie3 cookie; - cookieverf3 cookieverf; - count3 count; -}; -typedef struct readdir3args readdir3args; - -struct entry3 { - fileid3 fileid; - filename3 name; - cookie3 cookie; - struct entry3 *nextentry; -}; -typedef struct entry3 entry3; - -struct dirlist3 { - entry3 *entries; - bool_t eof; -}; -typedef struct dirlist3 dirlist3; - -struct readdir3resok { - post_op_attr dir_attributes; - cookieverf3 cookieverf; - dirlist3 reply; -}; -typedef struct readdir3resok readdir3resok; - -struct readdir3resfail { - post_op_attr dir_attributes; -}; -typedef struct readdir3resfail readdir3resfail; - -struct readdir3res { - nfsstat3 status; - union { - readdir3resok resok; - readdir3resfail resfail; - } readdir3res_u; -}; -typedef struct readdir3res readdir3res; - -struct readdirp3args { - nfs_fh3 dir; - cookie3 cookie; - cookieverf3 cookieverf; - count3 dircount; - count3 maxcount; -}; -typedef struct readdirp3args readdirp3args; - -struct entryp3 { - fileid3 fileid; - filename3 name; - cookie3 cookie; - post_op_attr name_attributes; - post_op_fh3 name_handle; - struct entryp3 *nextentry; -}; -typedef struct entryp3 entryp3; - -struct dirlistp3 { - entryp3 *entries; - bool_t eof; -}; -typedef struct dirlistp3 dirlistp3; - -struct readdirp3resok { - post_op_attr dir_attributes; - cookieverf3 cookieverf; - dirlistp3 reply; -}; -typedef struct readdirp3resok readdirp3resok; - -struct readdirp3resfail { - post_op_attr dir_attributes; -}; -typedef struct readdirp3resfail readdirp3resfail; - -struct readdirp3res { - nfsstat3 status; - union { - readdirp3resok resok; - readdirp3resfail resfail; - } readdirp3res_u; -}; -typedef struct readdirp3res readdirp3res; - -struct fsstat3args { - nfs_fh3 fsroot; -}; -typedef struct fsstat3args fsstat3args; - -struct fsstat3resok { - post_op_attr obj_attributes; - size3 tbytes; - size3 fbytes; - size3 abytes; - size3 tfiles; - size3 ffiles; - size3 afiles; - uint32 invarsec; -}; -typedef struct fsstat3resok fsstat3resok; - -struct fsstat3resfail { - post_op_attr obj_attributes; -}; -typedef struct fsstat3resfail fsstat3resfail; - -struct fsstat3res { - nfsstat3 status; - union { - fsstat3resok resok; - fsstat3resfail resfail; - } fsstat3res_u; -}; -typedef struct fsstat3res fsstat3res; -#define FSF3_LINK 0x0001 -#define FSF3_SYMLINK 0x0002 -#define FSF3_HOMOGENEOUS 0x0008 -#define FSF3_CANSETTIME 0x0010 - -struct fsinfo3args { - nfs_fh3 fsroot; -}; -typedef struct fsinfo3args fsinfo3args; - -struct fsinfo3resok { - post_op_attr obj_attributes; - uint32 rtmax; - uint32 rtpref; - uint32 rtmult; - uint32 wtmax; - uint32 wtpref; - uint32 wtmult; - uint32 dtpref; - size3 maxfilesize; - nfstime3 time_delta; - uint32 properties; -}; -typedef struct fsinfo3resok fsinfo3resok; - -struct fsinfo3resfail { - post_op_attr obj_attributes; -}; -typedef struct fsinfo3resfail fsinfo3resfail; - -struct fsinfo3res { - nfsstat3 status; - union { - fsinfo3resok resok; - fsinfo3resfail resfail; - } fsinfo3res_u; -}; -typedef struct fsinfo3res fsinfo3res; - -struct pathconf3args { - nfs_fh3 object; -}; -typedef struct pathconf3args pathconf3args; - -struct pathconf3resok { - post_op_attr obj_attributes; - uint32 linkmax; - uint32 name_max; - bool_t no_trunc; - bool_t chown_restricted; - bool_t case_insensitive; - bool_t case_preserving; -}; -typedef struct pathconf3resok pathconf3resok; - -struct pathconf3resfail { - post_op_attr obj_attributes; -}; -typedef struct pathconf3resfail pathconf3resfail; - -struct pathconf3res { - nfsstat3 status; - union { - pathconf3resok resok; - pathconf3resfail resfail; - } pathconf3res_u; -}; -typedef struct pathconf3res pathconf3res; - -struct commit3args { - nfs_fh3 file; - offset3 offset; - count3 count; -}; -typedef struct commit3args commit3args; - -struct commit3resok { - wcc_data file_wcc; - writeverf3 verf; -}; -typedef struct commit3resok commit3resok; - -struct commit3resfail { - wcc_data file_wcc; -}; -typedef struct commit3resfail commit3resfail; - -struct commit3res { - nfsstat3 status; - union { - commit3resok resok; - commit3resfail resfail; - } commit3res_u; -}; -typedef struct commit3res commit3res; -#define MNTPATHLEN 1024 -#define MNTNAMLEN 255 -#define FHSIZE3 NFS3_FHSIZE - -typedef struct { - u_int fhandle3_len; - char *fhandle3_val; -} fhandle3; - -typedef char *dirpath; - -typedef char *name; - -enum mountstat3 { - MNT3_OK = 0, - MNT3ERR_PERM = 1, - MNT3ERR_NOENT = 2, - MNT3ERR_IO = 5, - MNT3ERR_ACCES = 13, - MNT3ERR_NOTDIR = 20, - MNT3ERR_INVAL = 22, - MNT3ERR_NAMETOOLONG = 63, - MNT3ERR_NOTSUPP = 10004, - MNT3ERR_SERVERFAULT = 10006, -}; -typedef enum mountstat3 mountstat3; - -struct mountres3_ok { - fhandle3 fhandle; - struct { - u_int auth_flavors_len; - int *auth_flavors_val; - } auth_flavors; -}; -typedef struct mountres3_ok mountres3_ok; - -struct mountres3 { - mountstat3 fhs_status; - union { - mountres3_ok mountinfo; - } mountres3_u; -}; -typedef struct mountres3 mountres3; - -typedef struct mountbody *mountlist; - -struct mountbody { - name ml_hostname; - dirpath ml_directory; - mountlist ml_next; -}; -typedef struct mountbody mountbody; - -typedef struct groupnode *groups; - -struct groupnode { - name gr_name; - groups gr_next; -}; -typedef struct groupnode groupnode; - -typedef struct exportnode *exports; - -struct exportnode { - dirpath ex_dir; - groups ex_groups; - exports ex_next; -}; -typedef struct exportnode exportnode; - -#define NFS_PROGRAM 100003 -#define NFS_V3 3 - -#define NFS3_NULL 0 -#define NFS3_GETATTR 1 -#define NFS3_SETATTR 2 -#define NFS3_LOOKUP 3 -#define NFS3_ACCESS 4 -#define NFS3_READLINK 5 -#define NFS3_READ 6 -#define NFS3_WRITE 7 -#define NFS3_CREATE 8 -#define NFS3_MKDIR 9 -#define NFS3_SYMLINK 10 -#define NFS3_MKNOD 11 -#define NFS3_REMOVE 12 -#define NFS3_RMDIR 13 -#define NFS3_RENAME 14 -#define NFS3_LINK 15 -#define NFS3_READDIR 16 -#define NFS3_READDIRP 17 -#define NFS3_FSSTAT 18 -#define NFS3_FSINFO 19 -#define NFS3_PATHCONF 20 -#define NFS3_COMMIT 21 -#define NFS3_PROC_COUNT 22 - -#define MOUNT_PROGRAM 100005 -#define MOUNT_V3 3 -#define MOUNT_V1 1 - -#define MOUNT3_NULL 0 -#define MOUNT3_MNT 1 -#define MOUNT3_DUMP 2 -#define MOUNT3_UMNT 3 -#define MOUNT3_UMNTALL 4 -#define MOUNT3_EXPORT 5 -#define MOUNT3_PROC_COUNT 6 - -#define MOUNT1_NULL 0 -#define MOUNT1_DUMP 2 -#define MOUNT1_UMNT 3 -#define MOUNT1_EXPORT 5 -#define MOUNT1_PROC_COUNT 6 -/* the xdr functions */ - -extern bool_t xdr_uint64 (XDR *, uint64*); -extern bool_t xdr_int64 (XDR *, int64*); -extern bool_t xdr_uint32 (XDR *, uint32*); -extern bool_t xdr_int32 (XDR *, int32*); -extern bool_t xdr_filename3 (XDR *, filename3*); -extern bool_t xdr_nfspath3 (XDR *, nfspath3*); -extern bool_t xdr_fileid3 (XDR *, fileid3*); -extern bool_t xdr_cookie3 (XDR *, cookie3*); -extern bool_t xdr_cookieverf3 (XDR *, cookieverf3); -extern bool_t xdr_createverf3 (XDR *, createverf3); -extern bool_t xdr_writeverf3 (XDR *, writeverf3); -extern bool_t xdr_uid3 (XDR *, uid3*); -extern bool_t xdr_gid3 (XDR *, gid3*); -extern bool_t xdr_size3 (XDR *, size3*); -extern bool_t xdr_offset3 (XDR *, offset3*); -extern bool_t xdr_mode3 (XDR *, mode3*); -extern bool_t xdr_count3 (XDR *, count3*); -extern bool_t xdr_nfsstat3 (XDR *, nfsstat3*); -extern bool_t xdr_ftype3 (XDR *, ftype3*); -extern bool_t xdr_specdata3 (XDR *, specdata3*); -extern bool_t xdr_nfs_fh3 (XDR *, nfs_fh3*); -extern bool_t xdr_nfstime3 (XDR *, nfstime3*); -extern bool_t xdr_fattr3 (XDR *, fattr3*); -extern bool_t xdr_post_op_attr (XDR *, post_op_attr*); -extern bool_t xdr_wcc_attr (XDR *, wcc_attr*); -extern bool_t xdr_pre_op_attr (XDR *, pre_op_attr*); -extern bool_t xdr_wcc_data (XDR *, wcc_data*); -extern bool_t xdr_post_op_fh3 (XDR *, post_op_fh3*); -extern bool_t xdr_time_how (XDR *, time_how*); -extern bool_t xdr_set_mode3 (XDR *, set_mode3*); -extern bool_t xdr_set_uid3 (XDR *, set_uid3*); -extern bool_t xdr_set_gid3 (XDR *, set_gid3*); -extern bool_t xdr_set_size3 (XDR *, set_size3*); -extern bool_t xdr_set_atime (XDR *, set_atime*); -extern bool_t xdr_set_mtime (XDR *, set_mtime*); -extern bool_t xdr_sattr3 (XDR *, sattr3*); -extern bool_t xdr_diropargs3 (XDR *, diropargs3*); -extern bool_t xdr_getattr3args (XDR *, getattr3args*); -extern bool_t xdr_getattr3resok (XDR *, getattr3resok*); -extern bool_t xdr_getattr3res (XDR *, getattr3res*); -extern bool_t xdr_sattrguard3 (XDR *, sattrguard3*); -extern bool_t xdr_setattr3args (XDR *, setattr3args*); -extern bool_t xdr_setattr3resok (XDR *, setattr3resok*); -extern bool_t xdr_setattr3resfail (XDR *, setattr3resfail*); -extern bool_t xdr_setattr3res (XDR *, setattr3res*); -extern bool_t xdr_lookup3args (XDR *, lookup3args*); -extern bool_t xdr_lookup3resok (XDR *, lookup3resok*); -extern bool_t xdr_lookup3resfail (XDR *, lookup3resfail*); -extern bool_t xdr_lookup3res (XDR *, lookup3res*); -extern bool_t xdr_access3args (XDR *, access3args*); -extern bool_t xdr_access3resok (XDR *, access3resok*); -extern bool_t xdr_access3resfail (XDR *, access3resfail*); -extern bool_t xdr_access3res (XDR *, access3res*); -extern bool_t xdr_readlink3args (XDR *, readlink3args*); -extern bool_t xdr_readlink3resok (XDR *, readlink3resok*); -extern bool_t xdr_readlink3resfail (XDR *, readlink3resfail*); -extern bool_t xdr_readlink3res (XDR *, readlink3res*); -extern bool_t xdr_read3args (XDR *, read3args*); -extern bool_t xdr_read3resok (XDR *, read3resok*); -extern bool_t xdr_read3resfail (XDR *, read3resfail*); -extern bool_t xdr_read3res (XDR *, read3res*); -extern bool_t xdr_read3res_nocopy (XDR *xdrs, read3res *objp); -extern bool_t xdr_stable_how (XDR *, stable_how*); -extern bool_t xdr_write3args (XDR *, write3args*); -extern bool_t xdr_write3resok (XDR *, write3resok*); -extern bool_t xdr_write3resfail (XDR *, write3resfail*); -extern bool_t xdr_write3res (XDR *, write3res*); -extern bool_t xdr_createmode3 (XDR *, createmode3*); -extern bool_t xdr_createhow3 (XDR *, createhow3*); -extern bool_t xdr_create3args (XDR *, create3args*); -extern bool_t xdr_create3resok (XDR *, create3resok*); -extern bool_t xdr_create3resfail (XDR *, create3resfail*); -extern bool_t xdr_create3res (XDR *, create3res*); -extern bool_t xdr_mkdir3args (XDR *, mkdir3args*); -extern bool_t xdr_mkdir3resok (XDR *, mkdir3resok*); -extern bool_t xdr_mkdir3resfail (XDR *, mkdir3resfail*); -extern bool_t xdr_mkdir3res (XDR *, mkdir3res*); -extern bool_t xdr_symlinkdata3 (XDR *, symlinkdata3*); -extern bool_t xdr_symlink3args (XDR *, symlink3args*); -extern bool_t xdr_symlink3resok (XDR *, symlink3resok*); -extern bool_t xdr_symlink3resfail (XDR *, symlink3resfail*); -extern bool_t xdr_symlink3res (XDR *, symlink3res*); -extern bool_t xdr_devicedata3 (XDR *, devicedata3*); -extern bool_t xdr_mknoddata3 (XDR *, mknoddata3*); -extern bool_t xdr_mknod3args (XDR *, mknod3args*); -extern bool_t xdr_mknod3resok (XDR *, mknod3resok*); -extern bool_t xdr_mknod3resfail (XDR *, mknod3resfail*); -extern bool_t xdr_mknod3res (XDR *, mknod3res*); -extern bool_t xdr_remove3args (XDR *, remove3args*); -extern bool_t xdr_remove3resok (XDR *, remove3resok*); -extern bool_t xdr_remove3resfail (XDR *, remove3resfail*); -extern bool_t xdr_remove3res (XDR *, remove3res*); -extern bool_t xdr_rmdir3args (XDR *, rmdir3args*); -extern bool_t xdr_rmdir3resok (XDR *, rmdir3resok*); -extern bool_t xdr_rmdir3resfail (XDR *, rmdir3resfail*); -extern bool_t xdr_rmdir3res (XDR *, rmdir3res*); -extern bool_t xdr_rename3args (XDR *, rename3args*); -extern bool_t xdr_rename3resok (XDR *, rename3resok*); -extern bool_t xdr_rename3resfail (XDR *, rename3resfail*); -extern bool_t xdr_rename3res (XDR *, rename3res*); -extern bool_t xdr_link3args (XDR *, link3args*); -extern bool_t xdr_link3resok (XDR *, link3resok*); -extern bool_t xdr_link3resfail (XDR *, link3resfail*); -extern bool_t xdr_link3res (XDR *, link3res*); -extern bool_t xdr_readdir3args (XDR *, readdir3args*); -extern bool_t xdr_entry3 (XDR *, entry3*); -extern bool_t xdr_dirlist3 (XDR *, dirlist3*); -extern bool_t xdr_readdir3resok (XDR *, readdir3resok*); -extern bool_t xdr_readdir3resfail (XDR *, readdir3resfail*); -extern bool_t xdr_readdir3res (XDR *, readdir3res*); -extern bool_t xdr_readdirp3args (XDR *, readdirp3args*); -extern bool_t xdr_entryp3 (XDR *, entryp3*); -extern bool_t xdr_dirlistp3 (XDR *, dirlistp3*); -extern bool_t xdr_readdirp3resok (XDR *, readdirp3resok*); -extern bool_t xdr_readdirp3resfail (XDR *, readdirp3resfail*); -extern bool_t xdr_readdirp3res (XDR *, readdirp3res*); -extern bool_t xdr_fsstat3args (XDR *, fsstat3args*); -extern bool_t xdr_fsstat3resok (XDR *, fsstat3resok*); -extern bool_t xdr_fsstat3resfail (XDR *, fsstat3resfail*); -extern bool_t xdr_fsstat3res (XDR *, fsstat3res*); -extern bool_t xdr_fsinfo3args (XDR *, fsinfo3args*); -extern bool_t xdr_fsinfo3resok (XDR *, fsinfo3resok*); -extern bool_t xdr_fsinfo3resfail (XDR *, fsinfo3resfail*); -extern bool_t xdr_fsinfo3res (XDR *, fsinfo3res*); -extern bool_t xdr_pathconf3args (XDR *, pathconf3args*); -extern bool_t xdr_pathconf3resok (XDR *, pathconf3resok*); -extern bool_t xdr_pathconf3resfail (XDR *, pathconf3resfail*); -extern bool_t xdr_pathconf3res (XDR *, pathconf3res*); -extern bool_t xdr_commit3args (XDR *, commit3args*); -extern bool_t xdr_commit3resok (XDR *, commit3resok*); -extern bool_t xdr_commit3resfail (XDR *, commit3resfail*); -extern bool_t xdr_commit3res (XDR *, commit3res*); -extern bool_t xdr_fhandle3 (XDR *, fhandle3*); -extern bool_t xdr_dirpath (XDR *, dirpath*); -extern bool_t xdr_name (XDR *, name*); -extern bool_t xdr_mountstat3 (XDR *, mountstat3*); -extern bool_t xdr_mountres3_ok (XDR *, mountres3_ok*); -extern bool_t xdr_mountres3 (XDR *, mountres3*); -extern bool_t xdr_mountlist (XDR *, mountlist*); -extern bool_t xdr_mountbody (XDR *, mountbody*); -extern bool_t xdr_groups (XDR *, groups*); -extern bool_t xdr_groupnode (XDR *, groupnode*); -extern bool_t xdr_exports (XDR *, exports*); -extern bool_t xdr_exportnode (XDR *, exportnode*); - -extern void xdr_free_exports_list (struct exportnode *first); -extern void xdr_free_mountlist (mountlist ml); - -extern void xdr_free_write3args_nocopy (write3args *wa); -#endif diff --git a/xlators/nfs/lib/src/xdr-rpc.c b/xlators/nfs/lib/src/xdr-rpc.c deleted file mode 100644 index 274e118a3..000000000 --- a/xlators/nfs/lib/src/xdr-rpc.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <string.h> -#include <rpc/rpc.h> -#include <rpc/pmap_clnt.h> -#include <arpa/inet.h> -#include <rpc/xdr.h> -#include <sys/uio.h> -#include <rpc/auth_unix.h> - -#include "mem-pool.h" -#include "xdr-rpc.h" -#include "xdr-common.h" -#include "logging.h" - -/* Decodes the XDR format in msgbuf into rpc_msg. - * The remaining payload is returned into payload. - */ -int -nfs_xdr_to_rpc_call (char *msgbuf, size_t len, struct rpc_msg *call, - struct iovec *payload, char *credbytes, char *verfbytes) -{ - XDR xdr; - char opaquebytes[MAX_AUTH_BYTES]; - struct opaque_auth *oa = NULL; - - if ((!msgbuf) || (!call)) - return -1; - - memset (call, 0, sizeof (*call)); - - oa = &call->rm_call.cb_cred; - if (!credbytes) - oa->oa_base = opaquebytes; - else - oa->oa_base = credbytes; - - oa = &call->rm_call.cb_verf; - if (!verfbytes) - oa->oa_base = opaquebytes; - else - oa->oa_base = verfbytes; - - xdrmem_create (&xdr, msgbuf, len, XDR_DECODE); - if (!xdr_callmsg (&xdr, call)) - return -1; - - if (payload) { - payload->iov_base = nfs_xdr_decoded_remaining_addr (xdr); - payload->iov_len = nfs_xdr_decoded_remaining_len (xdr); - } - - return 0; -} - - -bool_t -nfs_true_func (XDR *s, caddr_t *a) -{ - return TRUE; -} - - -int -nfs_rpc_fill_empty_reply (struct rpc_msg *reply, uint32_t xid) -{ - if (!reply) - return -1; - - /* Setting to 0 also results in reply verifier flavor to be - * set to AUTH_NULL which is what we want right now. - */ - memset (reply, 0, sizeof (*reply)); - reply->rm_xid = xid; - reply->rm_direction = REPLY; - - return 0; -} - -int -nfs_rpc_fill_denied_reply (struct rpc_msg *reply, int rjstat, int auth_err) -{ - if (!reply) - return -1; - - reply->rm_reply.rp_stat = MSG_DENIED; - reply->rjcted_rply.rj_stat = rjstat; - if (rjstat == RPC_MISMATCH) { - /* No problem with hardocoding - * RPC version numbers. We only support - * v2 anyway. - */ - reply->rjcted_rply.rj_vers.low = 2; - reply->rjcted_rply.rj_vers.high = 2; - } else if (rjstat == AUTH_ERROR) - reply->rjcted_rply.rj_why = auth_err; - - return 0; -} - - -int -nfs_rpc_fill_accepted_reply (struct rpc_msg *reply, int arstat, int proglow, - int proghigh, int verf, int len, char *vdata) -{ - if (!reply) - return -1; - - reply->rm_reply.rp_stat = MSG_ACCEPTED; - reply->acpted_rply.ar_stat = arstat; - - reply->acpted_rply.ar_verf.oa_flavor = verf; - reply->acpted_rply.ar_verf.oa_length = len; - reply->acpted_rply.ar_verf.oa_base = vdata; - if (arstat == PROG_MISMATCH) { - reply->acpted_rply.ar_vers.low = proglow; - reply->acpted_rply.ar_vers.high = proghigh; - } else if (arstat == SUCCESS) { - - /* This is a hack. I'd really like to build a custom - * XDR library because Sun RPC interface is not very flexible. - */ - reply->acpted_rply.ar_results.proc = (xdrproc_t)nfs_true_func; - reply->acpted_rply.ar_results.where = NULL; - } - - return 0; -} - -int -nfs_rpc_reply_to_xdr (struct rpc_msg *reply, char *dest, size_t len, - struct iovec *dst) -{ - XDR xdr; - - if ((!dest) || (!reply) || (!dst)) - return -1; - - xdrmem_create (&xdr, dest, len, XDR_ENCODE); - if (!xdr_replymsg(&xdr, reply)) - return -1; - - dst->iov_base = dest; - dst->iov_len = nfs_xdr_encoded_length (xdr); - - return 0; -} - - -int -nfs_xdr_to_auth_unix_cred (char *msgbuf, int msglen, struct authunix_parms *au, - char *machname, gid_t *gids) -{ - XDR xdr; - - if ((!msgbuf) || (!machname) || (!gids) || (!au)) - return -1; - - au->aup_machname = machname; -#ifdef GF_DARWIN_HOST_OS - au->aup_gids = (int *)gids; -#else - au->aup_gids = gids; -#endif - - xdrmem_create (&xdr, msgbuf, msglen, XDR_DECODE); - - if (!xdr_authunix_parms (&xdr, au)) - return -1; - - return 0; -} - -ssize_t -nfs_xdr_length_round_up (size_t len, size_t bufsize) -{ - int roundup = 0; - - roundup = len % NFS_XDR_BYTES_PER_UNIT; - if (roundup > 0) - roundup = NFS_XDR_BYTES_PER_UNIT - roundup; - - if ((roundup > 0) && ((roundup + len) <= bufsize)) - len += roundup; - - return len; -} - -int -nfs_xdr_bytes_round_up (struct iovec *vec, size_t bufsize) -{ - vec->iov_len = nfs_xdr_length_round_up (vec->iov_len, bufsize); - return 0; -} - -void -nfs_xdr_vector_round_up (struct iovec *vec, int vcount, uint32_t count) -{ - uint32_t round_count = 0; - - round_count = nfs_xdr_length_round_up (count, 1048576); - round_count -= count; - if (round_count == 0) - return; - - vec[vcount-1].iov_len += round_count; -} diff --git a/xlators/nfs/lib/src/xdr-rpc.h b/xlators/nfs/lib/src/xdr-rpc.h deleted file mode 100644 index ddcbe6655..000000000 --- a/xlators/nfs/lib/src/xdr-rpc.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _NFS_XDR_RPC_H -#define _NFS_XDR_RPC_H_ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <rpc/rpc.h> -#include <rpc/pmap_clnt.h> -#include <arpa/inet.h> -#include <rpc/xdr.h> -#include <sys/uio.h> - -/* Converts a given network buffer from its XDR format to a structure - * that contains everything an RPC call needs to work. - */ -extern int -nfs_xdr_to_rpc_call (char *msgbuf, size_t len, struct rpc_msg *call, - struct iovec *payload, char *credbytes, char *verfbytes); - -extern int -nfs_rpc_fill_empty_reply (struct rpc_msg *reply, uint32_t xid); - -extern int -nfs_rpc_fill_denied_reply (struct rpc_msg *reply, int rjstat, int auth_err); - -extern int -nfs_rpc_fill_accepted_reply (struct rpc_msg *reply, int arstat, int proglow, - int proghigh, int verf, int len, char *vdata); -extern int -nfs_rpc_reply_to_xdr (struct rpc_msg *reply, char *dest, size_t len, - struct iovec *dst); - -extern int -nfs_xdr_to_auth_unix_cred (char *msgbuf, int msglen, struct authunix_parms *au, - char *machname, gid_t *gids); -/* Macros that simplify accesing the members of an RPC call structure. */ -#define nfs_rpc_call_xid(call) ((call)->rm_xid) -#define nfs_rpc_call_direction(call) ((call)->rm_direction) -#define nfs_rpc_call_rpcvers(call) ((call)->ru.RM_cmb.cb_rpcvers) -#define nfs_rpc_call_program(call) ((call)->ru.RM_cmb.cb_prog) -#define nfs_rpc_call_progver(call) ((call)->ru.RM_cmb.cb_vers) -#define nfs_rpc_call_progproc(call) ((call)->ru.RM_cmb.cb_proc) -#define nfs_rpc_opaque_auth_flavour(oa) ((oa)->oa_flavor) -#define nfs_rpc_opaque_auth_len(oa) ((oa)->oa_length) - -#define nfs_rpc_call_cred_flavour(call) (nfs_rpc_opaque_auth_flavour ((&(call)->ru.RM_cmb.cb_cred))) -#define nfs_rpc_call_cred_len(call) (nfs_rpc_opaque_auth_len ((&(call)->ru.RM_cmb.cb_cred))) - - -#define nfs_rpc_call_verf_flavour(call) (nfs_rpc_opaque_auth_flavour ((&(call)->ru.RM_cmb.cb_verf))) -#define nfs_rpc_call_verf_len(call) (nfs_rpc_opaque_auth_len ((&(call)->ru.RM_cmb.cb_verf))) - -extern int -nfs_xdr_bytes_round_up (struct iovec *vec, size_t bufsize); - -extern ssize_t -nfs_xdr_length_round_up (size_t len, size_t bufsize); - -void -nfs_xdr_vector_round_up (struct iovec *vec, int vcount, uint32_t count); -#endif diff --git a/xlators/nfs/server/src/Makefile.am b/xlators/nfs/server/src/Makefile.am index f8968916c..62fbf6535 100644 --- a/xlators/nfs/server/src/Makefile.am +++ b/xlators/nfs/server/src/Makefile.am @@ -1,13 +1,24 @@ xlator_LTLIBRARIES = server.la xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/nfs -nfsrpclibdir = $(top_srcdir)/xlators/nfs/lib/src -server_la_LDFLAGS = -module -avoidversion -server_la_SOURCES = nfs.c nfs-common.c nfs-fops.c nfs-inodes.c nfs-generics.c mount3.c nfs3-fh.c nfs3.c nfs3-helpers.c $(nfsrpclibdir)/auth-null.c $(nfsrpclibdir)/auth-unix.c $(nfsrpclibdir)/msg-nfs3.c $(nfsrpclibdir)/rpc-socket.c $(nfsrpclibdir)/rpcsvc-auth.c $(nfsrpclibdir)/rpcsvc.c $(nfsrpclibdir)/xdr-nfs3.c $(nfsrpclibdir)/xdr-rpc.c +nfsrpclibdir = $(top_srcdir)/rpc/rpc-lib/src +server_la_LDFLAGS = -module -avoid-version +server_la_SOURCES = nfs.c nfs-common.c nfs-fops.c nfs-inodes.c \ + nfs-generics.c mount3.c nfs3-fh.c nfs3.c nfs3-helpers.c nlm4.c \ + nlmcbk_svc.c mount3udp_svc.c acl3.c server_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la -noinst_HEADERS = nfs.h nfs-common.h nfs-fops.h nfs-inodes.h nfs-generics.h mount3.h nfs3-fh.h nfs3.h nfs3-helpers.h nfs-mem-types.h $(nfsrpclibdir)/xdr-rpc.h $(nfsrpclibdir)/msg-nfs3.h $(nfsrpclibdir)/xdr-common.h $(nfsrpclibdir)/xdr-nfs3.h $(nfsrpclibdir)/rpc-socket.h $(nfsrpclibdir)/rpcsvc.h -AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS)\ - -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles $(GF_CFLAGS)\ - -I$(nfsrpclibdir) -L$(xlatordir)/ -I$(CONTRIBDIR)/rbtree +noinst_HEADERS = nfs.h nfs-common.h nfs-fops.h nfs-inodes.h nfs-generics.h \ + mount3.h nfs3-fh.h nfs3.h nfs3-helpers.h nfs-mem-types.h nlm4.h \ + acl3.h + +AM_CPPFLAGS = $(GF_CPPFLAGS) \ + -DLIBDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/auth\" \ + -I$(top_srcdir)/libglusterfs/src \ + -I$(nfsrpclibdir) -I$(CONTRIBDIR)/rbtree \ + -I$(top_srcdir)/rpc/xdr/src/ + +AM_CFLAGS = -Wall $(GF_CFLAGS) + +AM_LDFLAGS = -L$(xlatordir) CLEANFILES = diff --git a/xlators/nfs/server/src/acl3.c b/xlators/nfs/server/src/acl3.c new file mode 100644 index 000000000..08b099b4e --- /dev/null +++ b/xlators/nfs/server/src/acl3.c @@ -0,0 +1,708 @@ +/* + * Copyright (c) 2012 Red Hat, Inc. <http://www.redhat.com> + * This file is part of GlusterFS. + * + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "defaults.h" +#include "rpcsvc.h" +#include "dict.h" +#include "xlator.h" +#include "nfs.h" +#include "mem-pool.h" +#include "logging.h" +#include "nfs-fops.h" +#include "inode.h" +#include "nfs3.h" +#include "nfs-mem-types.h" +#include "nfs3-helpers.h" +#include "nfs3-fh.h" +#include "nfs-generics.h" +#include "acl3.h" + + +typedef ssize_t (*acl3_serializer) (struct iovec outmsg, void *args); + +extern void nfs3_call_state_wipe (nfs3_call_state_t *cs); + +extern nfs3_call_state_t * +nfs3_call_state_init (struct nfs3_state *s, rpcsvc_request_t *req, xlator_t *v); + +extern int +nfs3_fh_validate (struct nfs3_fh *fh); + +extern fattr3 +nfs3_stat_to_fattr3 (struct iatt *buf); + +#define acl3_validate_nfs3_state(request, state, status, label, retval) \ + do { \ + state = rpcsvc_request_program_private (request); \ + if (!state) { \ + gf_log (GF_ACL, GF_LOG_ERROR, "NFSv3 state " \ + "missing from RPC request"); \ + rpcsvc_request_seterr (req, SYSTEM_ERR); \ + status = NFS3ERR_SERVERFAULT; \ + goto label; \ + } \ + } while (0); \ + +#define acl3_validate_gluster_fh(handle, status, errlabel) \ + do { \ + if (!nfs3_fh_validate (handle)) { \ + status = NFS3ERR_SERVERFAULT; \ + goto errlabel; \ + } \ + } while (0) \ + + +extern xlator_t * +nfs3_fh_to_xlator (struct nfs3_state *nfs3, struct nfs3_fh *fh); + +#define acl3_map_fh_to_volume(nfs3state, handle, req, volume, status, label) \ + do { \ + char exportid[256], gfid[256]; \ + rpc_transport_t *trans = NULL; \ + volume = nfs3_fh_to_xlator ((nfs3state), handle); \ + if (!volume) { \ + uuid_unparse (handle->exportid, exportid); \ + uuid_unparse (handle->gfid, gfid); \ + trans = rpcsvc_request_transport (req); \ + gf_log (GF_ACL, GF_LOG_ERROR, "Failed to map " \ + "FH to vol: client=%s, exportid=%s, gfid=%s",\ + trans->peerinfo.identifier, exportid, \ + gfid); \ + gf_log (GF_ACL, GF_LOG_ERROR, \ + "Stale nfs client %s must be trying to "\ + "connect to a deleted volume, please " \ + "unmount it.", trans->peerinfo.identifier);\ + status = NFS3ERR_STALE; \ + goto label; \ + } else { \ + gf_log (GF_ACL, GF_LOG_TRACE, "FH to Volume: %s"\ + ,volume->name); \ + rpcsvc_request_set_private (req, volume); \ + } \ + } while (0); \ + +#define acl3_volume_started_check(nfs3state, vlm, rtval, erlbl) \ + do { \ + if ((!nfs_subvolume_started (nfs_state (nfs3state->nfsx), vlm))){\ + gf_log (GF_ACL, GF_LOG_ERROR, "Volume is disabled: %s",\ + vlm->name); \ + rtval = RPCSVC_ACTOR_IGNORE; \ + goto erlbl; \ + } \ + } while (0) \ + +#define acl3_check_fh_resolve_status(cst, nfstat, erlabl) \ + do { \ + xlator_t *xlatorp = NULL; \ + char buf[256], gfid[256]; \ + rpc_transport_t *trans = NULL; \ + if ((cst)->resolve_ret < 0) { \ + trans = rpcsvc_request_transport (cst->req); \ + xlatorp = nfs3_fh_to_xlator (cst->nfs3state, \ + &cst->resolvefh); \ + uuid_unparse (cst->resolvefh.gfid, gfid); \ + snprintf (buf, sizeof (buf), "(%s) %s : %s", \ + trans->peerinfo.identifier, \ + xlatorp ? xlatorp->name : "ERR", \ + gfid); \ + gf_log (GF_ACL, GF_LOG_ERROR, "Unable to resolve FH"\ + ": %s", buf); \ + nfstat = nfs3_errno_to_nfsstat3 (cst->resolve_errno);\ + goto erlabl; \ + } \ + } while (0) \ + +#define acl3_handle_call_state_init(nfs3state, calls, rq, v, opstat, errlabel)\ + do { \ + calls = nfs3_call_state_init ((nfs3state), (rq), v); \ + if (!calls) { \ + gf_log (GF_ACL, GF_LOG_ERROR, "Failed to " \ + "init call state"); \ + opstat = NFS3ERR_SERVERFAULT; \ + rpcsvc_request_seterr (req, SYSTEM_ERR); \ + goto errlabel; \ + } \ + } while (0) \ + + +int +acl3svc_submit_reply (rpcsvc_request_t *req, void *arg, acl3_serializer sfunc) +{ + struct iovec outmsg = {0, }; + struct iobuf *iob = NULL; + struct nfs3_state *nfs3 = NULL; + int ret = -1; + ssize_t msglen = 0; + struct iobref *iobref = NULL; + + if (!req) + return -1; + + nfs3 = (struct nfs3_state *)rpcsvc_request_program_private (req); + if (!nfs3) { + gf_log (GF_ACL, GF_LOG_ERROR, "mount state not found"); + goto ret; + } + + /* First, get the io buffer into which the reply in arg will + * be serialized. + */ + iob = iobuf_get (nfs3->iobpool); + if (!iob) { + gf_log (GF_ACL, GF_LOG_ERROR, "Failed to get iobuf"); + goto ret; + } + + iobuf_to_iovec (iob, &outmsg); + /* Use the given serializer to translate the give C structure in arg + * to XDR format which will be written into the buffer in outmsg. + */ + msglen = sfunc (outmsg, arg); + if (msglen < 0) { + gf_log (GF_ACL, GF_LOG_ERROR, "Failed to encode message"); + goto ret; + } + outmsg.iov_len = msglen; + + iobref = iobref_new (); + if (iobref == NULL) { + gf_log (GF_ACL, GF_LOG_ERROR, "Failed to get iobref"); + goto ret; + } + + ret = iobref_add (iobref, iob); + if (ret) { + gf_log (GF_ACL, GF_LOG_ERROR, "Failed to add iob to iobref"); + goto ret; + } + + /* Then, submit the message for transmission. */ + ret = rpcsvc_submit_message (req, &outmsg, 1, NULL, 0, iobref); + if (ret == -1) { + gf_log (GF_ACL, GF_LOG_ERROR, "Reply submission failed"); + goto ret; + } + + ret = 0; +ret: + if (iob) + iobuf_unref (iob); + if (iobref) + iobref_unref (iobref); + + return ret; +} + + +int +acl3svc_null (rpcsvc_request_t *req) +{ + struct iovec dummyvec = {0, }; + + if (!req) { + gf_log (GF_ACL, GF_LOG_ERROR, "Got NULL request!"); + return 0; + } + rpcsvc_submit_generic (req, &dummyvec, 1, NULL, 0, NULL); + return 0; +} + +int +acl3_getacl_reply (nfs3_call_state_t *cs, getaclreply *reply) +{ + acl3svc_submit_reply (cs->req, (void *)reply, + (acl3_serializer)xdr_serialize_getaclreply); + return 0; +} + + +int +acl3_getacl_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata) +{ + nfsstat3 stat = NFS3ERR_SERVERFAULT; + nfs3_call_state_t *cs = NULL; + data_t *data = NULL; + int *p = NULL; + int i = 0; + getaclreply *getaclreply = NULL; + + if (!frame->local) { + gf_log (GF_ACL, GF_LOG_ERROR, "Invalid argument," + " frame->local NULL"); + return EINVAL; + } + cs = frame->local; + getaclreply = &cs->args.getaclreply; + if (op_ret == -1) { + stat = nfs3_cbk_errno_status (op_ret, op_errno); + goto err; + } + + getaclreply->aclentry.aclentry_val = cs->aclentry; + getaclreply->daclentry.daclentry_val = cs->daclentry; + + /* FIXME: use posix_acl_from_xattr() */ + data = dict_get (dict, POSIX_ACL_ACCESS_XATTR); + if (data && (p = data_to_bin (data))) { + /* POSIX_ACL_VERSION */ + p++; + while ((char *)p < (data->data + data->len)) { + getaclreply->aclentry.aclentry_val[i].type = *(*(short **)&p)++; + getaclreply->aclentry.aclentry_val[i].perm = *(*(short **)&p)++; + getaclreply->aclentry.aclentry_val[i].uid = *(*(int **)&p)++; + i++; + } + getaclreply->aclcount = getaclreply->aclentry.aclentry_len = i; + } + i = 0; + + data = dict_get (dict, POSIX_ACL_DEFAULT_XATTR); + if (data && (p = data_to_bin (data))) { + /* POSIX_ACL_VERSION */ + p++; + while ((char *)p < (data->data + data->len)) { + getaclreply->daclentry.daclentry_val[i].type = *(*(short **)&p)++; + getaclreply->daclentry.daclentry_val[i].perm = *(*(short **)&p)++; + getaclreply->daclentry.daclentry_val[i].uid = *(*(int **)&p)++; + i++; + } + getaclreply->daclcount = getaclreply->daclentry.daclentry_len = i; + } + + acl3_getacl_reply (cs, getaclreply); + nfs3_call_state_wipe (cs); + return 0; + +err: + if (getaclreply) + getaclreply->status = stat; + acl3_getacl_reply (cs, getaclreply); + nfs3_call_state_wipe (cs); + return 0; +} + +int +acl3_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata) +{ + nfsstat3 stat = NFS3ERR_SERVERFAULT; + nfs3_call_state_t *cs = NULL; + getaclreply *getaclreply = NULL; + int ret = -1; + nfs_user_t nfu = {0, }; + + if (!frame->local) { + gf_log (GF_ACL, GF_LOG_ERROR, "Invalid argument," + " frame->local NULL"); + return EINVAL; + } + + cs = frame->local; + getaclreply = &cs->args.getaclreply; + + if (op_ret == -1) { + stat = nfs3_cbk_errno_status (op_ret, op_errno); + goto err; + } + + getaclreply->attr_follows = 1; + getaclreply->attr = nfs3_stat_to_fattr3 (buf); + getaclreply->mask = 0xf; + nfs_request_user_init (&nfu, cs->req); + ret = nfs_getxattr (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, NULL, NULL, + acl3_getacl_cbk, cs); + if (ret == -1) { + stat = nfs3_cbk_errno_status (op_ret, op_errno); + goto err; + } + return 0; +err: + getaclreply->status = stat; + acl3_getacl_reply (cs, getaclreply); + nfs3_call_state_wipe (cs); + return 0; +} + + +int +acl3_getacl_resume (void *carg) +{ + int ret = -1; + nfs3_call_state_t *cs = NULL; + nfsstat3 stat = NFS3ERR_SERVERFAULT; + nfs_user_t nfu = {0, }; + + if (!carg) + return ret; + + cs = (nfs3_call_state_t *)carg; + acl3_check_fh_resolve_status (cs, stat, acl3err); + nfs_request_user_init (&nfu, cs->req); + + ret = nfs_stat (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + acl3_stat_cbk, cs); + stat = -ret; +acl3err: + if (ret < 0) { + gf_log (GF_ACL, GF_LOG_ERROR, "unable to open_and_resume"); + cs->args.getaclreply.status = nfs3_errno_to_nfsstat3 (stat); + acl3_getacl_reply (cs, &cs->args.getaclreply); + nfs3_call_state_wipe (cs); + } + + return ret; +} + + +int +acl3svc_getacl (rpcsvc_request_t *req) +{ + xlator_t *vol = NULL; + struct nfs_state *nfs = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + int ret = RPCSVC_ACTOR_ERROR; + nfsstat3 stat = NFS3ERR_SERVERFAULT; + struct nfs3_fh fh, *fhp = NULL; + getaclargs getaclargs; + + if (!req) + return ret; + + acl3_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + memset (&getaclargs, 0, sizeof (getaclargs)); + getaclargs.fh.n_bytes = (char *)&fh; + if (xdr_to_getaclargs(req->msg[0], &getaclargs) <= 0) { + gf_log (GF_ACL, GF_LOG_ERROR, "Error decoding args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; + } + fhp = &fh; + acl3_validate_gluster_fh (&fh, stat, acl3err); + acl3_map_fh_to_volume (nfs->nfs3state, fhp, req, + vol, stat, acl3err); + acl3_handle_call_state_init (nfs->nfs3state, cs, req, + vol, stat, rpcerr); + + cs->vol = vol; + acl3_volume_started_check (nfs3, vol, ret, acl3err); + + ret = nfs3_fh_resolve_and_resume (cs, fhp, + NULL, acl3_getacl_resume); + +acl3err: + if (ret < 0) { + gf_log (GF_ACL, GF_LOG_ERROR, "unable to resolve and resume"); + if (cs) { + cs->args.getaclreply.status = stat; + acl3_getacl_reply (cs, &cs->args.getaclreply); + nfs3_call_state_wipe (cs); + } + return 0; + } + +rpcerr: + return ret; +} + +int +acl3_setacl_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno, + dict_t *xdata) +{ + nfs3_call_state_t *cs = NULL; + cs = frame->local; + if (op_ret < 0) { + nfsstat3 status = nfs3_cbk_errno_status (op_ret, op_errno); + cs->args.setaclreply.status = status; + } + + acl3svc_submit_reply (cs->req, (void *)&cs->args.setaclreply, + (acl3_serializer)xdr_serialize_setaclreply); + return 0; +} + +int +acl3_setacl_resume (void *carg) +{ + int ret = -1; + nfs3_call_state_t *cs = NULL; + nfsstat3 stat = NFS3ERR_SERVERFAULT; + nfs_user_t nfu = {0, }; + dict_t *xattr = NULL; + + if (!carg) + return ret; + cs = (nfs3_call_state_t *)carg; + acl3_check_fh_resolve_status (cs, stat, acl3err); + nfs_request_user_init (&nfu, cs->req); + xattr = dict_new(); + if (cs->aclcount) + ret = dict_set_static_bin (xattr, POSIX_ACL_ACCESS_XATTR, cs->aclxattr, + cs->aclcount * 8 + 4); + if (cs->daclcount) + ret = dict_set_static_bin (xattr, POSIX_ACL_DEFAULT_XATTR, + cs->daclxattr, cs->daclcount * 8 + 4); + + ret = nfs_setxattr (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, xattr, + 0, NULL, acl3_setacl_cbk, cs); + dict_unref (xattr); + +acl3err: + if (ret < 0) { + stat = -ret; + gf_log (GF_ACL, GF_LOG_ERROR, "unable to open_and_resume"); + cs->args.setaclreply.status = nfs3_errno_to_nfsstat3 (stat); + acl3svc_submit_reply (cs->req, (void *)&cs->args.setaclreply, + (acl3_serializer)xdr_serialize_setaclreply); + nfs3_call_state_wipe (cs); + } + + return ret; +} + + +int +acl3svc_setacl (rpcsvc_request_t *req) +{ + xlator_t *vol = NULL; + struct nfs_state *nfs = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + int ret = RPCSVC_ACTOR_ERROR; + nfsstat3 stat = NFS3ERR_SERVERFAULT; + struct nfs3_fh fh; + struct nfs3_fh *fhp = NULL; + setaclargs setaclargs; + aclentry *aclentry = NULL; + struct aclentry *daclentry = NULL; + int i = 0; + struct posix_acl_xattr_header *bufheader = NULL; + struct posix_acl_xattr_entry *bufentry = NULL; + + if (!req) + return ret; + aclentry = GF_CALLOC (NFS_ACL_MAX_ENTRIES, sizeof(*aclentry), + gf_nfs_mt_arr); + if (!aclentry) { + goto rpcerr; + } + daclentry = GF_CALLOC (NFS_ACL_MAX_ENTRIES, sizeof(*daclentry), + gf_nfs_mt_arr); + if (!daclentry) { + goto rpcerr; + } + + acl3_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + memset (&setaclargs, 0, sizeof (setaclargs)); + memset (&fh, 0, sizeof (fh)); + setaclargs.fh.n_bytes = (char *)&fh; + setaclargs.aclentry.aclentry_val = aclentry; + setaclargs.daclentry.daclentry_val = daclentry; + if (xdr_to_setaclargs(req->msg[0], &setaclargs) <= 0) { + gf_log (GF_ACL, GF_LOG_ERROR, "Error decoding args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; + } + fhp = &fh; + acl3_validate_gluster_fh (fhp, stat, acl3err); + acl3_map_fh_to_volume (nfs->nfs3state, fhp, req, + vol, stat, acl3err); + acl3_handle_call_state_init (nfs->nfs3state, cs, req, + vol, stat, rpcerr); + + cs->vol = vol; + acl3_volume_started_check (nfs3, vol, ret, rpcerr); + + cs->aclcount = setaclargs.aclcount; + cs->daclcount = setaclargs.daclcount; + + if ((cs->aclcount > NFS_ACL_MAX_ENTRIES) || + (cs->daclcount > NFS_ACL_MAX_ENTRIES)) + goto acl3err; + /* FIXME: use posix_acl_to_xattr() */ + /* Populate xattr buffer for user ACL */ + bufheader = (struct posix_acl_xattr_header *)(cs->aclxattr); + bufheader->version = htole32(POSIX_ACL_VERSION); + bufentry = bufheader->entries; + for (i = 0; i < cs->aclcount; i++) { + int uaceuid; + const struct aclentry *uace = &aclentry[i]; + switch (uace->type) { + case POSIX_ACL_USER: + case POSIX_ACL_GROUP: + uaceuid = uace->uid; + break; + default: + uaceuid = POSIX_ACL_UNDEFINED_ID; + break; + } + bufentry->tag = htole16(uace->type); + bufentry->perm = htole16(uace->perm); + bufentry->id = htole32(uaceuid); + + bufentry++; + } + + /* Populate xattr buffer for Default ACL */ + bufheader = (struct posix_acl_xattr_header *)(cs->aclxattr); + bufheader->version = htole32(POSIX_ACL_VERSION); + bufentry = bufheader->entries; + for (i = 0; i < cs->daclcount; i++) { + int daceuid; + int dacetype; + const struct aclentry *dace = &daclentry[i]; + /* + * For "default ACL", NFSv3 handles the 'type' differently + * i.e. by logical OR'ing 'type' with NFS_ACL_DEFAULT. + * Which the backend File system does not understand and + * that needs to be masked OFF. + */ + dacetype = (dace->type & ~(NFS_ACL_DEFAULT)); + switch (dacetype) { + case POSIX_ACL_USER: + case POSIX_ACL_GROUP: + daceuid = dace->uid; + break; + default: + daceuid = POSIX_ACL_UNDEFINED_ID; + break; + } + bufentry->tag = htole16(dacetype); + bufentry->perm = htole16(dace->perm); + bufentry->id = htole32(daceuid); + + bufentry++; + } + + + ret = nfs3_fh_resolve_and_resume (cs, fhp, + NULL, acl3_setacl_resume); + +acl3err: + if (ret < 0) { + gf_log (GF_ACL, GF_LOG_ERROR, "unable to resolve and resume"); + cs->args.setaclreply.status = stat; + acl3svc_submit_reply (cs->req, (void *)&cs->args.setaclreply, + (acl3_serializer)xdr_serialize_setaclreply); + nfs3_call_state_wipe (cs); + GF_FREE(aclentry); + GF_FREE(daclentry); + return 0; + } + +rpcerr: + if (ret < 0) + nfs3_call_state_wipe (cs); + if (aclentry) + GF_FREE (aclentry); + if (daclentry) + GF_FREE (daclentry); + return ret; +} + + + +rpcsvc_actor_t acl3svc_actors[ACL3_PROC_COUNT] = { + {"NULL", ACL3_NULL, acl3svc_null, NULL, 0}, + {"GETACL", ACL3_GETACL, acl3svc_getacl, NULL, 0}, + {"SETACL", ACL3_SETACL, acl3svc_setacl, NULL, 0}, +}; + +rpcsvc_program_t acl3prog = { + .progname = "ACL3", + .prognum = ACL_PROGRAM, + .progver = ACLV3_VERSION, + .progport = GF_NFS3_PORT, + .actors = acl3svc_actors, + .numactors = ACL3_PROC_COUNT, + .min_auth = AUTH_NULL, +}; + +rpcsvc_program_t * +acl3svc_init(xlator_t *nfsx) +{ + struct nfs3_state *ns = NULL; + struct nfs_state *nfs = NULL; + dict_t *options = NULL; + int ret = -1; + char *portstr = NULL; + static gf_boolean_t acl3_inited = _gf_false; + + /* Already inited */ + if (acl3_inited) + return &acl3prog; + + nfs = (struct nfs_state*)nfsx->private; + + ns = nfs->nfs3state; + if (!ns) { + gf_log (GF_ACL, GF_LOG_ERROR, "ACL3 init failed"); + goto err; + } + acl3prog.private = ns; + + options = dict_new (); + + ret = gf_asprintf (&portstr, "%d", GF_ACL3_PORT); + if (ret == -1) + goto err; + + ret = dict_set_dynstr (options, "transport.socket.listen-port", + portstr); + if (ret == -1) + goto err; + ret = dict_set_str (options, "transport-type", "socket"); + if (ret == -1) { + gf_log (GF_ACL, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + + if (nfs->allow_insecure) { + ret = dict_set_str (options, "rpc-auth-allow-insecure", "on"); + if (ret == -1) { + gf_log (GF_ACL, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + ret = dict_set_str (options, "rpc-auth.ports.insecure", "on"); + if (ret == -1) { + gf_log (GF_ACL, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + } + + ret = dict_set_str (options, "transport.address-family", "inet"); + if (ret == -1) { + gf_log (GF_ACL, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + + ret = rpcsvc_create_listeners (nfs->rpcsvc, options, "ACL"); + if (ret == -1) { + gf_log (GF_ACL, GF_LOG_ERROR, "Unable to create listeners"); + dict_unref (options); + goto err; + } + + acl3_inited = _gf_true; + return &acl3prog; +err: + return NULL; +} diff --git a/xlators/nfs/server/src/acl3.h b/xlators/nfs/server/src/acl3.h new file mode 100644 index 000000000..e0e61281a --- /dev/null +++ b/xlators/nfs/server/src/acl3.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2012 Red Hat, Inc. <http://www.redhat.com> + * This file is part of GlusterFS. + * + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +#ifndef _ACL3_H +#define _ACL3_H + +#include "glusterfs-acl.h" + +#define GF_ACL3_PORT 38469 +#define GF_ACL GF_NFS"-ACL" + +/* + * NFSv3, identifies the default ACL by NFS_ACL_DEFAULT. Gluster + * NFS needs to mask it OFF before sending it upto POSIX layer + * or File system layer. + */ +#define NFS_ACL_DEFAULT 0x1000 + +#define NFS_ACL_MAX_ENTRIES 1024 + +rpcsvc_program_t * +acl3svc_init(xlator_t *nfsx); + +#endif diff --git a/xlators/nfs/server/src/mount3.c b/xlators/nfs/server/src/mount3.c index 47158dcca..b0824bf10 100644 --- a/xlators/nfs/server/src/mount3.c +++ b/xlators/nfs/server/src/mount3.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _CONFIG_H @@ -37,28 +28,79 @@ #include "locking.h" #include "iatt.h" #include "nfs-mem-types.h" - +#include "nfs.h" +#include "common-utils.h" +#include "store.h" #include <errno.h> #include <sys/socket.h> #include <sys/uio.h> + +#define IPv4_ADDR_SIZE 32 + +/* Macro to typecast the parameter to struct sockaddr_in + */ +#define SA(addr) ((struct sockaddr_in*)(addr)) + +/* Macro will mask the ip address with netmask. + */ +#define MASKED_IP(ipv4addr, netmask) \ + (ntohl(SA(ipv4addr)->sin_addr.s_addr) & (netmask)) + +/* Macro will compare two IP address after applying the mask + */ +#define COMPARE_IPv4_ADDRS(ip1, ip2, netmask) \ + ((MASKED_IP(ip1, netmask)) == (MASKED_IP(ip2, netmask))) + +/* This macro will assist in freeing up entire link list + * of host_auth_spec structure. + */ +#define FREE_HOSTSPEC(exp) do { \ + struct host_auth_spec *host= exp->hostspec; \ + while (NULL != host){ \ + struct host_auth_spec* temp = host; \ + host = host->next; \ + if (NULL != temp->host_addr) { \ + GF_FREE (temp->host_addr); \ + } \ + GF_FREE (temp); \ + } \ + exp->hostspec = NULL; \ + } while (0) + typedef ssize_t (*mnt3_serializer) (struct iovec outmsg, void *args); +extern void * +mount3udp_thread (void *argv); + +static inline void +mnt3_export_free (struct mnt3_export *exp) +{ + if (!exp) + return; + + if (exp->exptype == MNT3_EXPTYPE_DIR) + FREE_HOSTSPEC (exp); + GF_FREE (exp->expname); + GF_FREE (exp); +} /* Generic reply function for MOUNTv3 specific replies. */ int mnt3svc_submit_reply (rpcsvc_request_t *req, void *arg, mnt3_serializer sfunc) { - struct iovec outmsg = {0, }; - struct iobuf *iob = NULL; - struct mount3_state *ms = NULL; - int ret = -1; + struct iovec outmsg = {0, }; + struct iobuf *iob = NULL; + struct mount3_state *ms = NULL; + int ret = -1; + ssize_t msglen = 0; + struct iobref *iobref = NULL; if (!req) return -1; - ms = (struct mount3_state *)nfs_rpcsvc_request_program_private (req); + ms = (struct mount3_state *)rpcsvc_request_program_private (req); if (!ms) { gf_log (GF_MNT, GF_LOG_ERROR, "mount state not found"); goto ret; @@ -67,6 +109,7 @@ mnt3svc_submit_reply (rpcsvc_request_t *req, void *arg, mnt3_serializer sfunc) /* First, get the io buffer into which the reply in arg will * be serialized. */ + /* TODO: use 'xdrproc_t' instead of 'sfunc' to get the xdr-size */ iob = iobuf_get (ms->iobpool); if (!iob) { gf_log (GF_MNT, GF_LOG_ERROR, "Failed to get iobuf"); @@ -77,11 +120,27 @@ mnt3svc_submit_reply (rpcsvc_request_t *req, void *arg, mnt3_serializer sfunc) /* Use the given serializer to translate the give C structure in arg * to XDR format which will be written into the buffer in outmsg. */ - outmsg.iov_len = sfunc (outmsg, arg); + msglen = sfunc (outmsg, arg); + if (msglen < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to encode message"); + goto ret; + } + outmsg.iov_len = msglen; + + iobref = iobref_new (); + if (iobref == NULL) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to get iobref"); + goto ret; + } + + ret = iobref_add (iobref, iob); + if (ret) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to add iob to iobref"); + goto ret; + } /* Then, submit the message for transmission. */ - ret = nfs_rpcsvc_submit_message (req, outmsg, iob); - iobuf_unref (iob); + ret = rpcsvc_submit_message (req, &outmsg, 1, NULL, 0, iobref); if (ret == -1) { gf_log (GF_MNT, GF_LOG_ERROR, "Reply submission failed"); goto ret; @@ -89,6 +148,11 @@ mnt3svc_submit_reply (rpcsvc_request_t *req, void *arg, mnt3_serializer sfunc) ret = 0; ret: + if (NULL != iob) + iobuf_unref (iob); + if (NULL != iobref) + iobref_unref (iobref); + return ret; } @@ -172,13 +236,278 @@ mnt3svc_set_mountres3 (mountstat3 stat, struct nfs3_fh *fh, int *authflavor, return res; } +/* Read the rmtab from the store_handle and append (or not) the entries to the + * mountlist. + * + * Requires the store_handle to be locked. + */ +static int +__mount_read_rmtab (gf_store_handle_t *sh, struct list_head *mountlist, + gf_boolean_t append) +{ + int ret = 0; + unsigned int idx = 0; + struct mountentry *me = NULL, *tmp = NULL; + /* me->hostname is a char[MNTPATHLEN] */ + char key[MNTPATHLEN + 11]; + + GF_ASSERT (sh && mountlist); + + if (!gf_store_locked_local (sh)) { + gf_log (GF_MNT, GF_LOG_WARNING, "Not reading unlocked %s", + sh->path); + return -1; + } + + if (!append) { + list_for_each_entry_safe (me, tmp, mountlist, mlist) { + list_del (&me->mlist); + GF_FREE (me); + } + me = NULL; + } + + for (;;) { + char *value = NULL; + + if (me && append) { + /* do not add duplicates */ + list_for_each_entry (tmp, mountlist, mlist) { + if (!strcmp(tmp->hostname, me->hostname) && + !strcmp(tmp->exname, me->exname)) { + GF_FREE (me); + goto dont_add; + } + } + list_add_tail (&me->mlist, mountlist); + } else if (me) { + list_add_tail (&me->mlist, mountlist); + } + +dont_add: + me = GF_CALLOC (1, sizeof (*me), gf_nfs_mt_mountentry); + if (!me) { + gf_log (GF_MNT, GF_LOG_ERROR, "Out of memory"); + ret = -1; + goto out; + } + + INIT_LIST_HEAD (&me->mlist); + + snprintf (key, 9 + MNTPATHLEN, "hostname-%d", idx); + ret = gf_store_retrieve_value (sh, key, &value); + if (ret) + break; + strncpy (me->hostname, value, MNTPATHLEN); + GF_FREE (value); + + snprintf (key, 11 + MNTPATHLEN, "mountpoint-%d", idx); + ret = gf_store_retrieve_value (sh, key, &value); + if (ret) + break; + strncpy (me->exname, value, MNTPATHLEN); + GF_FREE (value); + + idx++; + gf_log (GF_MNT, GF_LOG_TRACE, "Read entries %s:%s", me->hostname, me->exname); + } + gf_log (GF_MNT, GF_LOG_DEBUG, "Read %d entries from '%s'", idx, sh->path); + GF_FREE (me); +out: + return ret; +} + +/* Overwrite the contents of the rwtab with te in-memory client list. + * Fail gracefully if the stora_handle is not locked. + */ +static void +__mount_rewrite_rmtab(struct mount3_state *ms, gf_store_handle_t *sh) +{ + struct mountentry *me = NULL; + char key[16]; + int fd, ret; + unsigned int idx = 0; + + if (!gf_store_locked_local (sh)) { + gf_log (GF_MNT, GF_LOG_WARNING, "Not modifying unlocked %s", + sh->path); + return; + } + + fd = gf_store_mkstemp (sh); + if (fd == -1) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to open %s", sh->path); + return; + } + + list_for_each_entry (me, &ms->mountlist, mlist) { + snprintf (key, 16, "hostname-%d", idx); + ret = gf_store_save_value (fd, key, me->hostname); + if (ret) + goto fail; + + snprintf (key, 16, "mountpoint-%d", idx); + ret = gf_store_save_value (fd, key, me->exname); + if (ret) + goto fail; + + idx++; + } + + gf_log (GF_MNT, GF_LOG_DEBUG, "Updated rmtab with %d entries", idx); + + close (fd); + if (gf_store_rename_tmppath (sh)) + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to overwrite rwtab %s", + sh->path); + + return; + +fail: + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to update %s", sh->path); + close (fd); + gf_store_unlink_tmppath (sh); +} + +/* Read the rmtab into a clean ms->mountlist. + */ +static void +mount_read_rmtab (struct mount3_state *ms) +{ + gf_store_handle_t *sh = NULL; + struct nfs_state *nfs = NULL; + int ret; + + nfs = (struct nfs_state *)ms->nfsx->private; + + ret = gf_store_handle_new (nfs->rmtab, &sh); + if (ret) { + gf_log (GF_MNT, GF_LOG_WARNING, "Failed to open '%s'", + nfs->rmtab); + return; + } + + if (gf_store_lock (sh)) { + gf_log (GF_MNT, GF_LOG_WARNING, "Failed to lock '%s'", + nfs->rmtab); + goto out; + } + + __mount_read_rmtab (sh, &ms->mountlist, _gf_false); + gf_store_unlock (sh); + +out: + gf_store_handle_destroy (sh); +} + +/* Write the ms->mountlist to the rmtab. + * + * The rmtab could be empty, or it can exists and have been updated by a + * different storage server without our knowing. + * + * 1. takes the store_handle lock on the current rmtab + * - blocks if an other storage server rewrites the rmtab at the same time + * 2. [if new_rmtab] takes the store_handle lock on the new rmtab + * 3. reads/merges the entries from the current rmtab + * 4. [if new_rmtab] reads/merges the entries from the new rmtab + * 5. [if new_rmtab] writes the new rmtab + * 6. [if not new_rmtab] writes the current rmtab + * 7 [if new_rmtab] replaces nfs->rmtab to point to the new location + * 8. [if new_rmtab] releases the store_handle lock of the new rmtab + * 9. releases the store_handle lock of the old rmtab + */ +void +mount_rewrite_rmtab (struct mount3_state *ms, char *new_rmtab) +{ + gf_store_handle_t *sh = NULL, *nsh = NULL; + struct nfs_state *nfs = NULL; + int ret; + char *rmtab = NULL; + + nfs = (struct nfs_state *)ms->nfsx->private; + + ret = gf_store_handle_new (nfs->rmtab, &sh); + if (ret) { + gf_log (GF_MNT, GF_LOG_WARNING, "Failed to open '%s'", + nfs->rmtab); + return; + } + + if (gf_store_lock (sh)) { + gf_log (GF_MNT, GF_LOG_WARNING, "Not rewriting '%s'", + nfs->rmtab); + goto free_sh; + } + + if (new_rmtab) { + ret = gf_store_handle_new (new_rmtab, &nsh); + if (ret) { + gf_log (GF_MNT, GF_LOG_WARNING, "Failed to open '%s'", + new_rmtab); + goto unlock_sh; + } + + if (gf_store_lock (nsh)) { + gf_log (GF_MNT, GF_LOG_WARNING, "Not rewriting '%s'", + new_rmtab); + goto free_nsh; + } + } + + /* always read the currently used rmtab */ + __mount_read_rmtab (sh, &ms->mountlist, _gf_true); + + if (new_rmtab) { + /* read the new rmtab and write changes to the new location */ + __mount_read_rmtab (nsh, &ms->mountlist, _gf_true); + __mount_rewrite_rmtab (ms, nsh); + + /* replace the nfs->rmtab reference to the new rmtab */ + rmtab = gf_strdup(new_rmtab); + if (rmtab == NULL) { + gf_log (GF_MNT, GF_LOG_ERROR, "Out of memory, keeping " + "%s as rmtab", nfs->rmtab); + } else { + GF_FREE (nfs->rmtab); + nfs->rmtab = new_rmtab; + } + + gf_store_unlock (nsh); + } else { + /* rewrite the current (unchanged location) rmtab */ + __mount_rewrite_rmtab (ms, sh); + } + +free_nsh: + if (new_rmtab) + gf_store_handle_destroy (nsh); +unlock_sh: + gf_store_unlock (sh); +free_sh: + gf_store_handle_destroy (sh); +} +/* Add a new NFS-client to the ms->mountlist and update the rmtab if we can. + * + * A NFS-client will only be removed from the ms->mountlist in case the + * NFS-client sends a unmount request. It is possible that a NFS-client + * crashed/rebooted had network loss or something else prevented the NFS-client + * to unmount cleanly. In this case, a duplicate entry would be added to the + * ms->mountlist, which is wrong and we should prevent. + * + * It is fully acceptible that the ms->mountlist is not 100% correct, this is a + * common issue for all(?) NFS-servers. + */ int mnt3svc_update_mountlist (struct mount3_state *ms, rpcsvc_request_t *req, char *expname) { struct mountentry *me = NULL; + struct mountentry *cur = NULL; int ret = -1; + char *colon = NULL; + struct nfs_state *nfs = NULL; + gf_store_handle_t *sh = NULL; if ((!ms) || (!req) || (!expname)) return -1; @@ -188,21 +517,62 @@ mnt3svc_update_mountlist (struct mount3_state *ms, rpcsvc_request_t *req, if (!me) return -1; - strcpy (me->exname, expname); + nfs = (struct nfs_state *)ms->nfsx->private; + + ret = gf_store_handle_new (nfs->rmtab, &sh); + if (ret) { + gf_log (GF_MNT, GF_LOG_WARNING, "Failed to open '%s'", + nfs->rmtab); + goto free_err; + } + + strncpy (me->exname, expname, MNTPATHLEN); + INIT_LIST_HEAD (&me->mlist); /* Must get the IP or hostname of the client so we * can map it into the mount entry. */ - ret = nfs_rpcsvc_conn_peername (req->conn, me->hostname, MNTPATHLEN); + ret = rpcsvc_transport_peername (req->trans, me->hostname, MNTPATHLEN); if (ret == -1) - goto free_err; + goto free_err2; + colon = strrchr (me->hostname, ':'); + if (colon) { + *colon = '\0'; + } LOCK (&ms->mountlock); { + /* in case locking fails, we just don't write the rmtab */ + if (gf_store_lock (sh)) { + gf_log (GF_MNT, GF_LOG_WARNING, "Failed to lock '%s'" + ", changes will not be written", nfs->rmtab); + } else { + __mount_read_rmtab (sh, &ms->mountlist, _gf_false); + } + + /* do not add duplicates */ + list_for_each_entry (cur, &ms->mountlist, mlist) { + if (!strcmp(cur->hostname, me->hostname) && + !strcmp(cur->exname, me->exname)) { + GF_FREE (me); + goto dont_add; + } + } list_add_tail (&me->mlist, &ms->mountlist); + + /* only write the rmtab in case it was locked */ + if (gf_store_locked_local (sh)) + __mount_rewrite_rmtab (ms, sh); } +dont_add: + if (gf_store_locked_local (sh)) + gf_store_unlock (sh); + UNLOCK (&ms->mountlock); +free_err2: + gf_store_handle_destroy (sh); + free_err: if (ret == -1) GF_FREE (me); @@ -221,6 +591,7 @@ __mnt3_get_volume_id (struct mount3_state *ms, xlator_t *mntxl, if ((!ms) || (!mntxl)) return ret; + LOCK (&ms->mountlock); list_for_each_entry (exp, &ms->exportlist, explist) { if (exp->vol == mntxl) { uuid_copy (volumeid, exp->volumeid); @@ -230,6 +601,7 @@ __mnt3_get_volume_id (struct mount3_state *ms, xlator_t *mntxl, } out: + UNLOCK (&ms->mountlock); return ret; } @@ -250,7 +622,7 @@ mnt3svc_lookup_mount_cbk (call_frame_t *frame, void *cookie, rpcsvc_t *svc = NULL; xlator_t *mntxl = NULL; uuid_t volumeid = {0, }; - char fhstr[1024]; + char fhstr[1024], *path = NULL; req = (rpcsvc_request_t *)frame->local; @@ -258,20 +630,29 @@ mnt3svc_lookup_mount_cbk (call_frame_t *frame, void *cookie, return -1; mntxl = (xlator_t *)cookie; - ms = (struct mount3_state *)nfs_rpcsvc_request_program_private (req); + ms = (struct mount3_state *)rpcsvc_request_program_private (req); if (!ms) { gf_log (GF_MNT, GF_LOG_ERROR, "mount state not found"); op_ret = -1; op_errno = EINVAL; } - if (op_ret == -1) + if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "error=%s", strerror (op_errno)); status = mnt3svc_errno_to_mnterr (op_errno); - + } if (status != MNT3_OK) goto xmit_res; - mnt3svc_update_mountlist (ms, req, mntxl->name); + path = GF_CALLOC (PATH_MAX, sizeof (char), gf_nfs_mt_char); + if (!path) { + gf_log (GF_MNT, GF_LOG_ERROR, "Out of memory"); + goto xmit_res; + } + + snprintf (path, PATH_MAX, "/%s", mntxl->name); + mnt3svc_update_mountlist (ms, req, path); + GF_FREE (path); if (gf_nfs_dvm_off (nfs_state (ms->nfsx))) { fh = nfs3_fh_build_indexed_root_fh (ms->nfsx->children, mntxl); goto xmit_res; @@ -281,13 +662,13 @@ mnt3svc_lookup_mount_cbk (call_frame_t *frame, void *cookie, fh = nfs3_fh_build_uuid_root_fh (volumeid); xmit_res: - nfs3_fh_to_str (&fh, fhstr); + nfs3_fh_to_str (&fh, fhstr, sizeof (fhstr)); gf_log (GF_MNT, GF_LOG_DEBUG, "MNT reply: fh %s, status: %d", fhstr, status); if (op_ret == 0) { - svc = nfs_rpcsvc_request_service (req); - autharrlen = nfs_rpcsvc_auth_array (svc, mntxl->name, autharr, - 10); + svc = rpcsvc_request_service (req); + autharrlen = rpcsvc_auth_array (svc, mntxl->name, autharr, + 10); } res = mnt3svc_set_mountres3 (status, &fh, autharr, autharrlen); @@ -302,7 +683,7 @@ int mnt3_match_dirpath_export (char *expname, char *dirpath) { int ret = 0; - int dlen = 0; + size_t dlen; if ((!expname) || (!dirpath)) return 0; @@ -313,7 +694,7 @@ mnt3_match_dirpath_export (char *expname, char *dirpath) * compare. */ dlen = strlen (dirpath); - if (dirpath [dlen - 1] == '/') + if (dlen && dirpath [dlen - 1] == '/') dirpath [dlen - 1] = '\0'; if (dirpath[0] != '/') @@ -337,11 +718,11 @@ mnt3svc_mount_inode (rpcsvc_request_t *req, struct mount3_state *ms, if ((!req) || (!xl) || (!ms) || (!exportinode)) return ret; - ret = nfs_inode_loc_fill (exportinode, &exportloc); + ret = nfs_inode_loc_fill (exportinode, &exportloc, NFS_RESOLVE_EXIST); if (ret < 0) { gf_log (GF_MNT, GF_LOG_ERROR, "Loc fill failed for export inode" - ": ino %"PRIu64", volume: %s", - exportinode->ino, xl->name); + ": gfid %s, volume: %s", + uuid_utoa (exportinode->gfid), xl->name); goto err; } @@ -378,7 +759,7 @@ mnt3svc_volume_mount (rpcsvc_request_t *req, struct mount3_state *ms, rootgfid[15] = 1; exportinode = inode_find (exp->vol->itable, rootgfid); if (!exportinode) { - gf_log (GF_MNT, GF_LOG_ERROR, "Faild to get root inode"); + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to get root inode"); ret = -ENOENT; goto err; } @@ -398,9 +779,10 @@ err: * we need to strip out the volume name first. */ char * -__volume_subdir (char *dirpath) +__volume_subdir (char *dirpath, char **volname) { char *subdir = NULL; + int volname_len = 0; if (!dirpath) return NULL; @@ -409,7 +791,22 @@ __volume_subdir (char *dirpath) dirpath++; subdir = index (dirpath, (int)'/'); + if (!subdir) + goto out; + if (!volname) + goto out; + + if (!*volname) + goto out; + + /* subdir points to the first / after the volume name while dirpath + * points to the first char of the volume name. + */ + volname_len = subdir - dirpath; + strncpy (*volname, dirpath, volname_len); + *(*volname + volname_len) = '\0'; +out: return subdir; } @@ -429,8 +826,8 @@ mnt3_resolve_state_wipe (mnt3_resolve_t *mres) /* Sets up the component argument to contain the next component in the path and * sets up path as an absolute path starting from the next component. */ -char * -__setup_next_component (char *path, char *component) +static char * +setup_next_component (char *path, size_t plen, char *component, size_t clen) { char *comp = NULL; char *nextcomp = NULL; @@ -438,7 +835,7 @@ __setup_next_component (char *path, char *component) if ((!path) || (!component)) return NULL; - strcpy (component, path); + strncpy (component, path, clen); comp = index (component, (int)'/'); if (!comp) goto err; @@ -446,7 +843,7 @@ __setup_next_component (char *path, char *component) comp++; nextcomp = index (comp, (int)'/'); if (nextcomp) { - strcpy (path, nextcomp); + strncpy (path, nextcomp, plen); *nextcomp = '\0'; } else path[0] = '\0'; @@ -471,24 +868,26 @@ __mnt3_resolve_export_subdir_comp (mnt3_resolve_t *mres) char *nextcomp = NULL; int ret = -EFAULT; nfs_user_t nfu = {0, }; - char gfidstr[512]; + uuid_t gfid = {0, }; if (!mres) return ret; - nextcomp = __setup_next_component (mres->remainingdir, dupsubdir); + nextcomp = setup_next_component (mres->remainingdir, + sizeof (mres->remainingdir), + dupsubdir, sizeof (dupsubdir)); if (!nextcomp) goto err; /* Wipe the contents of the previous component */ + uuid_copy (gfid, mres->resolveloc.inode->gfid); nfs_loc_wipe (&mres->resolveloc); - ret = nfs_entry_loc_fill (mres->exp->vol->itable, - mres->resolveloc.inode->gfid, nextcomp, + ret = nfs_entry_loc_fill (mres->exp->vol->itable, gfid, nextcomp, &mres->resolveloc, NFS_RESOLVE_CREATE); if ((ret < 0) && (ret != -2)) { - uuid_unparse (mres->resolveloc.inode->gfid, gfidstr); gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve and create " - "inode: parent gfid %s, entry %s", gfidstr, nextcomp); + "inode: parent gfid %s, entry %s", + uuid_utoa (gfid), nextcomp); ret = -EFAULT; goto err; } @@ -516,10 +915,13 @@ mnt3_resolve_subdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, rpcsvc_t *svc = NULL; mountres3 res = {0, }; xlator_t *mntxl = NULL; + char *path = NULL; mres = frame->local; mntxl = (xlator_t *)cookie; if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "path=%s (%s)", + mres->resolveloc.path, strerror (op_errno)); mntstat = mnt3svc_errno_to_mnterr (op_errno); goto err; } @@ -531,22 +933,30 @@ mnt3_resolve_subdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, if (strlen (mres->remainingdir) <= 0) { op_ret = -1; mntstat = MNT3_OK; + path = GF_CALLOC (PATH_MAX, sizeof (char), gf_nfs_mt_char); + if (!path) { + gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation " + "failed"); + goto err; + } + snprintf (path, PATH_MAX, "/%s%s", mres->exp->vol->name, + mres->resolveloc.path); mnt3svc_update_mountlist (mres->mstate, mres->req, - mres->exp->expname); - goto err; + path); + GF_FREE (path); + } else { + mres->parentfh = fh; + op_ret = __mnt3_resolve_export_subdir_comp (mres); + if (op_ret < 0) + mntstat = mnt3svc_errno_to_mnterr (-op_ret); } - - mres->parentfh = fh; - op_ret = __mnt3_resolve_export_subdir_comp (mres); - if (op_ret < 0) - mntstat = mnt3svc_errno_to_mnterr (-op_ret); err: if (op_ret == -1) { gf_log (GF_MNT, GF_LOG_DEBUG, "Mount reply status: %d", mntstat); - svc = nfs_rpcsvc_request_service (mres->req); - autharrlen = nfs_rpcsvc_auth_array (svc, mntxl->name, autharr, - 10); + svc = rpcsvc_request_service (mres->req); + autharrlen = rpcsvc_auth_array (svc, mntxl->name, autharr, + 10); res = mnt3svc_set_mountres3 (mntstat, &fh, autharr, autharrlen); mnt3svc_submit_reply (mres->req, (void *)&res, @@ -571,7 +981,7 @@ err: * of the exported directory can be built. */ int -__mnt3_resolve_export_subdir (mnt3_resolve_t *mres) +__mnt3_resolve_subdir (mnt3_resolve_t *mres) { char dupsubdir[MNTPATHLEN]; char *firstcomp = NULL; @@ -582,7 +992,9 @@ __mnt3_resolve_export_subdir (mnt3_resolve_t *mres) if (!mres) return ret; - firstcomp = __setup_next_component (mres->remainingdir, dupsubdir); + firstcomp = setup_next_component (mres->remainingdir, + sizeof (mres->remainingdir), + dupsubdir, sizeof (dupsubdir)); if (!firstcomp) goto err; @@ -605,21 +1017,152 @@ err: } +/** + * This function will verify if the client is allowed to mount + * the directory or not. Client's IP address will be compared with + * allowed IP list or range present in mnt3_export structure. + * + * @param req - RPC request. This structure contains client's IP address. + * @param export - mnt3_export structure. Contains allowed IP list/range. + * + * @return 0 - on Success and -EACCES on failure. + */ int -mnt3_resolve_export_subdir (rpcsvc_request_t *req, struct mount3_state *ms, - struct mnt3_export *exp) +mnt3_verify_auth (rpcsvc_request_t *req, struct mnt3_export *export) +{ + int retvalue = -EACCES; + int ret = 0; + int shiftbits = 0; + uint32_t ipv4netmask = 0; + uint32_t routingprefix = 0; + struct host_auth_spec *host = NULL; + struct sockaddr_in *client_addr = NULL; + struct sockaddr_in *allowed_addr = NULL; + struct addrinfo *allowed_addrinfo = NULL; + + /* Sanity check */ + if ((NULL == req) || + (NULL == req->trans) || + (NULL == export) || + (NULL == export->hostspec)) { + gf_log (GF_MNT, GF_LOG_ERROR, "Invalid argument"); + return retvalue; + } + + host = export->hostspec; + + + /* Client's IP address. */ + client_addr = (struct sockaddr_in *)(&(req->trans->peerinfo.sockaddr)); + + /* Try to see if the client IP matches the allowed IP list.*/ + while (NULL != host){ + GF_ASSERT (host->host_addr); + + if (NULL != allowed_addrinfo) { + freeaddrinfo (allowed_addrinfo); + allowed_addrinfo = NULL; + } + + /* Get the addrinfo for the allowed host (host_addr). */ + ret = getaddrinfo (host->host_addr, + NULL, + NULL, + &allowed_addrinfo); + if (0 != ret){ + gf_log (GF_MNT, GF_LOG_ERROR, "getaddrinfo: %s\n", + gai_strerror (ret)); + host = host->next; + + /* Failed to get IP addrinfo. Continue to check other + * allowed IPs in the list. + */ + continue; + } + + allowed_addr = (struct sockaddr_in *)(allowed_addrinfo->ai_addr); + + if (NULL == allowed_addr) { + gf_log (GF_MNT, GF_LOG_ERROR, "Invalid structure"); + break; + } + + if (AF_INET == allowed_addr->sin_family){ + if (IPv4_ADDR_SIZE < host->routeprefix) { + gf_log (GF_MNT, GF_LOG_ERROR, "invalid IP " + "configured for export-dir AUTH"); + host = host->next; + continue; + } + + /* -1 means no route prefix is provided. In this case + * the IP should be an exact match. Which is same as + * providing a route prefix of IPv4_ADDR_SIZE. + */ + if (-1 == host->routeprefix) { + routingprefix = IPv4_ADDR_SIZE; + } else { + routingprefix = host->routeprefix; + } + + /* Create a mask from the routing prefix. User provided + * CIDR address is split into IP address (host_addr) and + * routing prefix (routeprefix). This CIDR address may + * denote a single, distinct interface address or the + * beginning address of an entire network. + * + * e.g. the IPv4 block 192.168.100.0/24 represents the + * 256 IPv4 addresses from 192.168.100.0 to + * 192.168.100.255. + * Therefore to check if an IP matches 192.168.100.0/24 + * we should mask the IP with FFFFFF00 and compare it + * with host address part of CIDR. + */ + shiftbits = IPv4_ADDR_SIZE - routingprefix; + ipv4netmask = 0xFFFFFFFFUL << shiftbits; + + /* Mask both the IPs and then check if they match + * or not. */ + if (COMPARE_IPv4_ADDRS (allowed_addr, + client_addr, + ipv4netmask)){ + retvalue = 0; + break; + } + } + + /* Client IP didn't match the allowed IP. + * Check with the next allowed IP.*/ + host = host->next; + } + + if (NULL != allowed_addrinfo) { + freeaddrinfo (allowed_addrinfo); + } + + return retvalue; +} + +int +mnt3_resolve_subdir (rpcsvc_request_t *req, struct mount3_state *ms, + struct mnt3_export *exp, char *subdir) { mnt3_resolve_t *mres = NULL; - char *volume_subdir = NULL; int ret = -EFAULT; struct nfs3_fh pfh = GF_NFS3FH_STATIC_INITIALIZER; - if ((!req) || (!ms) || (!exp)) + if ((!req) || (!ms) || (!exp) || (!subdir)) return ret; - volume_subdir = __volume_subdir (exp->expname); - if (!volume_subdir) - goto err; + /* Need to check AUTH */ + if (NULL != exp->hostspec) { + ret = mnt3_verify_auth (req, exp); + if (0 != ret) { + gf_log (GF_MNT,GF_LOG_ERROR, + "AUTH verification failed"); + return ret; + } + } mres = GF_CALLOC (1, sizeof (mnt3_resolve_t), gf_nfs_mt_mnt3_resolve); if (!mres) { @@ -630,14 +1173,14 @@ mnt3_resolve_export_subdir (rpcsvc_request_t *req, struct mount3_state *ms, mres->exp = exp; mres->mstate = ms; mres->req = req; - strcpy (mres->remainingdir, volume_subdir); + strncpy (mres->remainingdir, subdir, MNTPATHLEN); if (gf_nfs_dvm_off (nfs_state (ms->nfsx))) pfh = nfs3_fh_build_indexed_root_fh (mres->mstate->nfsx->children, mres->exp->vol); else pfh = nfs3_fh_build_uuid_root_fh (exp->volumeid); mres->parentfh = pfh; - ret = __mnt3_resolve_export_subdir (mres); + ret = __mnt3_resolve_subdir (mres); if (ret < 0) { gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve export dir: %s" , mres->exp->expname); @@ -650,6 +1193,32 @@ err: int +mnt3_resolve_export_subdir (rpcsvc_request_t *req, struct mount3_state *ms, + struct mnt3_export *exp) +{ + char *volume_subdir = NULL; + int ret = -EFAULT; + + if ((!req) || (!ms) || (!exp)) + return ret; + + volume_subdir = __volume_subdir (exp->expname, NULL); + if (!volume_subdir) + goto err; + + ret = mnt3_resolve_subdir (req, ms, exp, volume_subdir); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve export dir: %s" + , exp->expname); + goto err; + } + +err: + return ret; +} + + +int mnt3svc_mount (rpcsvc_request_t *req, struct mount3_state *ms, struct mnt3_export *exp) { @@ -679,6 +1248,7 @@ mnt3_mntpath_to_export (struct mount3_state *ms, char *dirpath) if ((!ms) || (!dirpath)) return NULL; + LOCK (&ms->mountlock); list_for_each_entry (exp, &ms->exportlist, explist) { /* Search for the an exact match with the volume */ @@ -692,6 +1262,7 @@ mnt3_mntpath_to_export (struct mount3_state *ms, char *dirpath) gf_log (GF_MNT, GF_LOG_DEBUG, "Export not found"); foundexp: + UNLOCK (&ms->mountlock); return found; } @@ -700,24 +1271,37 @@ int mnt3_check_client_net (struct mount3_state *ms, rpcsvc_request_t *req, xlator_t *targetxl) { - rpcsvc_t *svc = NULL; - int ret = -1; + + rpcsvc_t *svc = NULL; + rpc_transport_t *trans = NULL; + struct sockaddr_storage sastorage = {0,}; + char peer[RPCSVC_PEER_STRLEN] = {0,}; + int ret = -1; if ((!ms) || (!req) || (!targetxl)) return -1; - svc = nfs_rpcsvc_request_service (req); - ret = nfs_rpcsvc_conn_peer_check (svc->options, targetxl->name, - nfs_rpcsvc_request_conn (req)); + svc = rpcsvc_request_service (req); + + trans = rpcsvc_request_transport (req); + ret = rpcsvc_transport_peeraddr (trans, peer, RPCSVC_PEER_STRLEN, + &sastorage, sizeof (sastorage)); + if (ret != 0) { + gf_log (GF_MNT, GF_LOG_WARNING, "Failed to get peer addr: %s", + gai_strerror (ret)); + } + + ret = rpcsvc_auth_check (svc, targetxl->name, trans); if (ret == RPCSVC_AUTH_REJECT) { - gf_log (GF_MNT, GF_LOG_TRACE, "Peer not allowed"); + gf_log (GF_MNT, GF_LOG_INFO, "Peer %s not allowed", peer); goto err; } - ret = nfs_rpcsvc_conn_privport_check (svc, targetxl->name, - nfs_rpcsvc_request_conn (req)); + ret = rpcsvc_transport_privport_check (svc, targetxl->name, + rpcsvc_request_transport (req)); if (ret == RPCSVC_AUTH_REJECT) { - gf_log (GF_MNT, GF_LOG_TRACE, "Unprivileged port not allowed"); + gf_log (GF_MNT, GF_LOG_INFO, "Peer %s rejected. Unprivileged " + "port not allowed", peer); goto err; } @@ -728,6 +1312,80 @@ err: int +mnt3_parse_dir_exports (rpcsvc_request_t *req, struct mount3_state *ms, + char *subdir) +{ + char volname[1024]; + struct mnt3_export *exp = NULL; + char *volname_ptr = NULL; + int ret = -1; + + if ((!ms) || (!subdir)) + return -1; + + volname_ptr = volname; + subdir = __volume_subdir (subdir, &volname_ptr); + if (!subdir) + goto err; + + exp = mnt3_mntpath_to_export (ms, volname); + if (!exp) + goto err; + + ret = mnt3_resolve_subdir (req, ms, exp, subdir); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve export dir: %s" + , subdir); + goto err; + } + +err: + return ret; +} + + +int +mnt3_find_export (rpcsvc_request_t *req, char *path, struct mnt3_export **e) +{ + int ret = -EFAULT; + struct mount3_state *ms = NULL; + struct mnt3_export *exp = NULL; + + if ((!req) || (!path) || (!e)) + return -1; + + ms = (struct mount3_state *) rpcsvc_request_program_private (req); + if (!ms) { + gf_log (GF_MNT, GF_LOG_ERROR, "Mount state not present"); + rpcsvc_request_seterr (req, SYSTEM_ERR); + goto err; + } + + gf_log (GF_MNT, GF_LOG_DEBUG, "dirpath: %s", path); + exp = mnt3_mntpath_to_export (ms, path); + if (exp) { + ret = 0; + *e = exp; + goto err; + } + + if (!gf_mnt3_export_dirs(ms)) { + ret = -1; + goto err; + } + + ret = mnt3_parse_dir_exports (req, ms, path); + if (ret == 0) { + ret = -2; + goto err; + } + +err: + return ret; +} + + +int mnt3svc_mnt (rpcsvc_request_t *req) { struct iovec pvec = {0, }; @@ -736,41 +1394,55 @@ mnt3svc_mnt (rpcsvc_request_t *req) struct mount3_state *ms = NULL; mountstat3 mntstat = MNT3ERR_SERVERFAULT; struct mnt3_export *exp = NULL; + struct nfs_state *nfs = NULL; if (!req) return -1; pvec.iov_base = path; pvec.iov_len = MNTPATHLEN; - ret = xdr_to_mountpath (pvec, req->msg); + ret = xdr_to_mountpath (pvec, req->msg[0]); if (ret == -1) { gf_log (GF_MNT, GF_LOG_ERROR, "Failed to decode args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } - ms = (struct mount3_state *)nfs_rpcsvc_request_program_private (req); + ms = (struct mount3_state *)rpcsvc_request_program_private (req); if (!ms) { gf_log (GF_MNT, GF_LOG_ERROR, "Mount state not present"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = -1; goto rpcerr; } ret = 0; + nfs = (struct nfs_state *)ms->nfsx->private; gf_log (GF_MNT, GF_LOG_DEBUG, "dirpath: %s", path); - exp = mnt3_mntpath_to_export (ms, path); - if (!exp) { + ret = mnt3_find_export (req, path, &exp); + if (ret == -2) { + ret = 0; + goto rpcerr; + } else if (ret < 0) { + ret = -1; + mntstat = MNT3ERR_NOENT; + goto mnterr; + } + + if (!nfs_subvolume_started (nfs, exp->vol)) { + gf_log (GF_MNT, GF_LOG_DEBUG, "Volume %s not started", + exp->vol->name); ret = -1; mntstat = MNT3ERR_NOENT; goto mnterr; } ret = mnt3_check_client_net (ms, req, exp->vol); - if (ret == -1) { + if (ret == RPCSVC_AUTH_REJECT) { mntstat = MNT3ERR_ACCES; gf_log (GF_MNT, GF_LOG_DEBUG, "Client mount not allowed"); - goto rpcerr; + ret = -1; + goto mnterr; } ret = mnt3svc_mount (req, ms, exp); @@ -796,8 +1468,7 @@ mnt3svc_null (rpcsvc_request_t *req) gf_log (GF_MNT, GF_LOG_ERROR, "Got NULL request!"); return 0; } - - nfs_rpcsvc_submit_generic (req, dummyvec, NULL); + rpcsvc_submit_generic (req, &dummyvec, 1, NULL, 0, NULL); return 0; } @@ -815,6 +1486,9 @@ __build_mountlist (struct mount3_state *ms, int *count) if ((!ms) || (!count)) return NULL; + /* read rmtab, other peers might have updated it */ + mount_read_rmtab(ms); + *count = 0; gf_log (GF_MNT, GF_LOG_DEBUG, "Building mount list:"); list_for_each_entry (me, &ms->mountlist, mlist) { @@ -825,6 +1499,8 @@ __build_mountlist (struct mount3_state *ms, int *count) " failed"); goto free_list; } + if (!first) + first = mlist; mlist->ml_directory = GF_CALLOC (namelen + 2, sizeof (char), gf_nfs_mt_char); @@ -834,8 +1510,7 @@ __build_mountlist (struct mount3_state *ms, int *count) goto free_list; } - strcpy (mlist->ml_directory, "/"); - strcat (mlist->ml_directory, me->exname); + strcpy (mlist->ml_directory, me->exname); namelen = strlen (me->hostname); mlist->ml_hostname = GF_CALLOC (namelen + 2, sizeof (char), @@ -856,9 +1531,6 @@ __build_mountlist (struct mount3_state *ms, int *count) } else prev = mlist; - if (!first) - first = mlist; - (*count)++; } @@ -903,19 +1575,19 @@ mnt3svc_dump (rpcsvc_request_t *req) if (!req) return -1; - ms = (struct mount3_state *)nfs_rpcsvc_request_program_private (req); + ms = (struct mount3_state *)rpcsvc_request_program_private (req); if (!ms) { - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); goto rpcerr; } sfunc = (mnt3_serializer)xdr_serialize_mountlist; mlist = mnt3svc_build_mountlist (ms, &ret); - arg = mlist; - + arg = &mlist; + if (!mlist) { if (ret != 0) { - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = -1; goto rpcerr; } else { @@ -935,67 +1607,71 @@ rpcerr: int -__mnt3svc_umount (struct mount3_state *ms, char *dirpath, char *hostname) +mnt3svc_umount (struct mount3_state *ms, char *dirpath, char *hostname) { struct mountentry *me = NULL; - char *exname = NULL; int ret = -1; + gf_store_handle_t *sh = NULL; + struct nfs_state *nfs = NULL; if ((!ms) || (!dirpath) || (!hostname)) return -1; - if (list_empty (&ms->mountlist)) - return 0; + nfs = (struct nfs_state *)ms->nfsx->private; - if (dirpath[0] == '/') - exname = dirpath+1; - else - exname = dirpath; - - list_for_each_entry (me, &ms->mountlist, mlist) { - if ((strcmp (me->exname, exname) == 0) && - (strcmp (me->hostname, hostname) == 0)) { - ret = 0; - break; - } + ret = gf_store_handle_new (nfs->rmtab, &sh); + if (ret) { + gf_log (GF_MNT, GF_LOG_WARNING, "Failed to open '%s'", + nfs->rmtab); + return 0; } - /* Need this check here because at the end of the search me might still - * be pointing to the last entry, which may not be the one we're - * looking for. - */ - if (ret == -1) {/* Not found in list. */ - gf_log (GF_MNT, GF_LOG_DEBUG, "Export not found"); - goto ret; + ret = gf_store_lock (sh); + if (ret) { + goto out_free; } - if (!me) - goto ret; + LOCK (&ms->mountlock); + { + __mount_read_rmtab (sh, &ms->mountlist, _gf_false); + if (list_empty (&ms->mountlist)) { + ret = 0; + goto out_unlock; + } - gf_log (GF_MNT, GF_LOG_DEBUG, "Unmounting: dir %s, host: %s", - me->exname, me->hostname); - list_del (&me->mlist); - GF_FREE (me); - ret = 0; -ret: - return ret; -} + ret = -1; + list_for_each_entry (me, &ms->mountlist, mlist) { + if ((strcmp (me->exname, dirpath) == 0) && + (strcmp (me->hostname, hostname) == 0)) { + ret = 0; + break; + } + } + /* Need this check here because at the end of the search me + * might still be pointing to the last entry, which may not be + * the one we're looking for. + */ + if (ret == -1) {/* Not found in list. */ + gf_log (GF_MNT, GF_LOG_TRACE, "Export not found"); + goto out_unlock; + } + if (!me) + goto out_unlock; -int -mnt3svc_umount (struct mount3_state *ms, char *dirpath, char *hostname) -{ - int ret = -1; - if ((!ms) || (!dirpath) || (!hostname)) - return -1; + gf_log (GF_MNT, GF_LOG_DEBUG, "Unmounting: dir %s, host: %s", + me->exname, me->hostname); - LOCK (&ms->mountlock); - { - ret = __mnt3svc_umount (ms, dirpath, hostname); + list_del (&me->mlist); + GF_FREE (me); + __mount_rewrite_rmtab (ms, sh); } +out_unlock: UNLOCK (&ms->mountlock); - + gf_store_unlock (sh); +out_free: + gf_store_handle_destroy (sh); return ret; } @@ -1009,6 +1685,7 @@ mnt3svc_umnt (rpcsvc_request_t *req) int ret = -1; struct mount3_state *ms = NULL; mountstat3 mstat = MNT3_OK; + char *colon = NULL; if (!req) return -1; @@ -1016,56 +1693,43 @@ mnt3svc_umnt (rpcsvc_request_t *req) /* Remove the mount point from the exports list. */ pvec.iov_base = dirpath; pvec.iov_len = MNTPATHLEN; - ret = xdr_to_mountpath (pvec, req->msg);; + ret = xdr_to_mountpath (pvec, req->msg[0]); if (ret == -1) { gf_log (GF_MNT, GF_LOG_ERROR, "Failed decode args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } - ms = (struct mount3_state *)nfs_rpcsvc_request_program_private (req); + ms = (struct mount3_state *)rpcsvc_request_program_private (req); if (!ms) { gf_log (GF_MNT, GF_LOG_ERROR, "Mount state not present"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = -1; goto rpcerr; } - ret = nfs_rpcsvc_conn_peername (req->conn, hostname, MNTPATHLEN); + ret = rpcsvc_transport_peername (req->trans, hostname, MNTPATHLEN); if (ret != 0) { gf_log (GF_MNT, GF_LOG_ERROR, "Failed to get remote name: %s", gai_strerror (ret)); - goto try_umount_with_addr; - } - - gf_log (GF_MNT, GF_LOG_DEBUG, "dirpath: %s, hostname: %s", dirpath, - hostname); - ret = mnt3svc_umount (ms, dirpath, hostname); - - /* Unmount succeeded with the given hostname. */ - if (ret == 0) - goto snd_reply; - -try_umount_with_addr: - if (ret != 0) - ret = nfs_rpcsvc_conn_peeraddr (req->conn, hostname, MNTPATHLEN, - NULL, 0); - - if (ret != 0) { - gf_log (GF_MNT, GF_LOG_ERROR, "Failed to get remote addr: %s", - gai_strerror (ret)); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); goto rpcerr; } + colon = strrchr (hostname, ':'); + if (colon) { + *colon= '\0'; + } gf_log (GF_MNT, GF_LOG_DEBUG, "dirpath: %s, hostname: %s", dirpath, hostname); ret = mnt3svc_umount (ms, dirpath, hostname); - if (ret == -1) - mstat = MNT3ERR_INVAL; - ret = 0; -snd_reply: + if (ret == -1) { + ret = 0; + mstat = MNT3ERR_NOENT; + } + /* FIXME: also take care of the corner case where the + * client was resolvable at mount but not at the umount - vice-versa. + */ mnt3svc_submit_reply (req, &mstat, (mnt3_serializer)xdr_serialize_mountstat3); @@ -1122,10 +1786,10 @@ mnt3svc_umntall (rpcsvc_request_t *req) if (!req) return ret; - ms = (struct mount3_state *)nfs_rpcsvc_request_program_private (req); + ms = (struct mount3_state *)rpcsvc_request_program_private (req); if (!ms) { gf_log (GF_MNT, GF_LOG_ERROR, "Mount state not present"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); goto rpcerr; } @@ -1149,11 +1813,24 @@ mnt3_xlchildren_to_exports (rpcsvc_t *svc, struct mount3_state *ms) int ret = -1; char *addrstr = NULL; struct mnt3_export *ent = NULL; + struct nfs_state *nfs = NULL; if ((!ms) || (!svc)) return NULL; + nfs = (struct nfs_state *)ms->nfsx->private; + if (!nfs) + return NULL; + + LOCK (&ms->mountlock); list_for_each_entry(ent, &ms->exportlist, explist) { + + /* If volume is not started yet, do not list it for tools like + * showmount. + */ + if (!nfs_subvolume_started (nfs, ent->vol)) + continue; + namelen = strlen (ent->expname) + 1; elist = GF_CALLOC (1, sizeof (*elist), gf_nfs_mt_exportnode); if (!elist) { @@ -1161,7 +1838,8 @@ mnt3_xlchildren_to_exports (rpcsvc_t *svc, struct mount3_state *ms) " failed"); goto free_list; } - + if (!first) + first = elist; elist->ex_dir = GF_CALLOC (namelen + 2, sizeof (char), gf_nfs_mt_char); if (!elist->ex_dir) { @@ -1169,16 +1847,10 @@ mnt3_xlchildren_to_exports (rpcsvc_t *svc, struct mount3_state *ms) " failed"); goto free_list; } - strcpy (elist->ex_dir, ent->expname); - addrstr = nfs_rpcsvc_volume_allowed (svc->options, - ent->vol->name); - if (addrstr) - addrstr = gf_strdup (addrstr); - else - addrstr = gf_strdup ("No Access"); - + addrstr = rpcsvc_volume_allowed (svc->options, + ent->vol->name); elist->ex_groups = GF_CALLOC (1, sizeof (struct groupnode), gf_nfs_mt_groupnode); if (!elist->ex_groups) { @@ -1186,21 +1858,29 @@ mnt3_xlchildren_to_exports (rpcsvc_t *svc, struct mount3_state *ms) " failed"); goto free_list; } + /*This check has to be done after checking + * elist->ex_groups allocation check to avoid resource leak; + */ + if (addrstr) + addrstr = gf_strdup (addrstr); + else + addrstr = gf_strdup ("No Access"); + if (!addrstr) { + goto free_list; + } elist->ex_groups->gr_name = addrstr; if (prev) { prev->ex_next = elist; prev = elist; } else prev = elist; - - if (!first) - first = elist; } ret = 0; free_list: + UNLOCK (&ms->mountlock); if (ret == -1) { xdr_free_exports_list (first); first = NULL; @@ -1220,21 +1900,25 @@ mnt3svc_export (rpcsvc_request_t *req) if (!req) return -1; - ms = (struct mount3_state *)nfs_rpcsvc_request_program_private (req); + ms = (struct mount3_state *)rpcsvc_request_program_private (req); if (!ms) { gf_log (GF_MNT, GF_LOG_ERROR, "mount state not found"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); goto err; } /* Using the children translator names, build the export list */ - elist = mnt3_xlchildren_to_exports (nfs_rpcsvc_request_service (req), + elist = mnt3_xlchildren_to_exports (rpcsvc_request_service (req), ms); + /* Do not return error when exports list is empty. An exports list can + * be empty when no subvolumes have come up. No point returning error + * and confusing the user. if (!elist) { gf_log (GF_MNT, GF_LOG_ERROR, "Failed to build exports list"); nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); goto err; } + */ /* Note how the serializer is passed to the generic reply function. */ mnt3svc_submit_reply (req, &elist, @@ -1246,7 +1930,233 @@ err: return ret; } +/* just declaring, definition is way down below */ +rpcsvc_program_t mnt3prog; + +/* nfs3_rootfh used by mount3udp thread needs to access mount3prog.private + * directly as we don't have nfs xlator pointer to dereference it. But thats OK + */ + +struct nfs3_fh * +nfs3_rootfh (char* path) +{ + struct mount3_state *ms = NULL; + struct nfs3_fh *fh = NULL; + struct mnt3_export *exp = NULL; + inode_t *inode = NULL; + char *tmp = NULL; + + ms = mnt3prog.private; + exp = mnt3_mntpath_to_export (ms, path); + if (exp == NULL) + goto err; + + tmp = (char *)path; + tmp = strchr (tmp, '/'); + if (tmp == NULL) + tmp = "/"; + + inode = inode_from_path (exp->vol->itable, tmp); + if (inode == NULL) + goto err; + + fh = GF_CALLOC (1, sizeof(*fh), gf_nfs_mt_nfs3_fh); + if (fh == NULL) + goto err; + nfs3_build_fh (inode, exp->volumeid, fh); + +err: + if (inode) + inode_unref (inode); + return fh; +} + +int +mount3udp_add_mountlist (char *host, dirpath *expname) +{ + struct mountentry *me = NULL; + struct mount3_state *ms = NULL; + char *export = NULL; + + ms = mnt3prog.private; + me = GF_CALLOC (1, sizeof (*me), gf_nfs_mt_mountentry); + if (!me) + return -1; + export = (char *)expname; + while (*export == '/') + export++; + + strncpy (me->exname, export, MNTPATHLEN); + strncpy (me->hostname, host, MNTPATHLEN); + INIT_LIST_HEAD (&me->mlist); + LOCK (&ms->mountlock); + { + list_add_tail (&me->mlist, &ms->mountlist); + mount_rewrite_rmtab(ms, NULL); + } + UNLOCK (&ms->mountlock); + return 0; +} + +int +mount3udp_delete_mountlist (char *hostname, dirpath *expname) +{ + struct mount3_state *ms = NULL; + char *export = NULL; + + ms = mnt3prog.private; + export = (char *)expname; + while (*export == '/') + export++; + mnt3svc_umount (ms, export, hostname); + return 0; +} + +/** + * This function will parse the hostip (IP addres, IP range, or hostname) + * and fill the host_auth_spec structure. + * + * @param hostspec - struct host_auth_spec + * @param hostip - IP address, IP range (CIDR format) or hostname + * + * @return 0 - on success and -1 on failure + */ +int +mnt3_export_fill_hostspec (struct host_auth_spec* hostspec, const char* hostip) +{ + char *ipdupstr = NULL; + char *savptr = NULL; + char *ip = NULL; + char *token = NULL; + int ret = -1; + + /* Create copy of the string so that the source won't change + */ + ipdupstr = gf_strdup (hostip); + if (NULL == ipdupstr) { + gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation failed"); + goto err; + } + + ip = strtok_r (ipdupstr, "/", &savptr); + hostspec->host_addr = gf_strdup (ip); + if (NULL == hostspec->host_addr) { + gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation failed"); + goto err; + } + + /* Check if the IP is in <IP address> / <Range> format. + * If yes, then strip the range and store it separately. + */ + token = strtok_r (NULL, "/", &savptr); + + if (NULL == token) { + hostspec->routeprefix = -1; + } else { + hostspec->routeprefix = atoi (token); + } + + // success + ret = 0; +err: + if (NULL != ipdupstr) { + GF_FREE (ipdupstr); + } + return ret; +} + + +/** + * This function will parse the AUTH parameter passed along with + * "export-dir" option. If AUTH parameter is present then it will be + * stripped from exportpath and stored in mnt3_export (exp) structure. + * + * @param exp - mnt3_export structure. Holds information needed for mount. + * @param exportpath - Value of "export-dir" key. Holds both export path + * and AUTH parameter for the path. + * exportpath format: <abspath>[(hostdesc[|hostspec|...])] + * + * @return This function will return 0 on success and -1 on failure. + */ +int +mnt3_export_parse_auth_param (struct mnt3_export* exp, char* exportpath) +{ + char *token = NULL; + char *savPtr = NULL; + char *hostip = NULL; + struct host_auth_spec *host = NULL; + int ret = 0; + + /* Using exportpath directly in strtok_r because we want + * to strip off AUTH parameter from exportpath. */ + token = strtok_r (exportpath, "(", &savPtr); + + /* Get the next token, which will be the AUTH parameter. */ + token = strtok_r (NULL, ")", &savPtr); + if (NULL == token) { + /* If AUTH is not present then we should return success. */ + return 0; + } + + /* Free any previously allocated hostspec structure. */ + if (NULL != exp->hostspec) { + GF_FREE (exp->hostspec); + exp->hostspec = NULL; + } + + exp->hostspec = GF_CALLOC (1, + sizeof (*(exp->hostspec)), + gf_nfs_mt_auth_spec); + if (NULL == exp->hostspec){ + gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation failed"); + return -1; + } + + /* AUTH parameter can have multiple entries. For each entry + * a host_auth_spec structure is created. */ + host = exp->hostspec; + + hostip = strtok_r (token, "|", &savPtr); + + /* Parse all AUTH parameters separated by '|' */ + while (NULL != hostip){ + ret = mnt3_export_fill_hostspec (host, hostip); + if (0 != ret) { + gf_log(GF_MNT, GF_LOG_WARNING, + "Failed to parse hostspec: %s", hostip); + goto err; + } + + hostip = strtok_r (NULL, "|", &savPtr); + if (NULL == hostip) { + break; + } + + host->next = GF_CALLOC (1, sizeof (*(host)), + gf_nfs_mt_auth_spec); + if (NULL == host->next){ + gf_log (GF_MNT,GF_LOG_ERROR, + "Memory allocation failed"); + goto err; + } + host = host->next; + } + + /* In case of success return from here */ + return 0; +err: + /* In case of failure free up hostspec structure. */ + FREE_HOSTSPEC (exp); + + return -1; +} + +/** + * exportpath will also have AUTH options (ip address, subnet address or + * hostname) mentioned. + * exportpath format: <abspath>[(hostdesc[|hostspec|...])] + */ struct mnt3_export * mnt3_init_export_ent (struct mount3_state *ms, xlator_t *xl, char *exportpath, uuid_t volumeid) @@ -1264,6 +2174,20 @@ mnt3_init_export_ent (struct mount3_state *ms, xlator_t *xl, char *exportpath, return NULL; } + if (NULL != exportpath) { + /* If exportpath is not NULL then we should check if AUTH + * parameter is present or not. If AUTH parameter is present + * then it will be stripped and stored in mnt3_export (exp) + * structure. + */ + if (0 != mnt3_export_parse_auth_param (exp, exportpath)){ + gf_log (GF_MNT, GF_LOG_ERROR, + "Failed to parse auth param"); + goto err; + } + } + + INIT_LIST_HEAD (&exp->explist); if (exportpath) alloclen = strlen (xl->name) + 2 + strlen (exportpath); @@ -1273,8 +2197,6 @@ mnt3_init_export_ent (struct mount3_state *ms, xlator_t *xl, char *exportpath, exp->expname = GF_CALLOC (alloclen, sizeof (char), gf_nfs_mt_char); if (!exp->expname) { gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation failed"); - GF_FREE (exp); - exp = NULL; goto err; } @@ -1290,14 +2212,27 @@ mnt3_init_export_ent (struct mount3_state *ms, xlator_t *xl, char *exportpath, exp->exptype = MNT3_EXPTYPE_VOLUME; ret = snprintf (exp->expname, alloclen, "/%s", xl->name); } - + if (ret < 0) { + gf_log (xl->name, GF_LOG_ERROR, + "Failed to set the export name"); + goto err; + } /* Just copy without discrimination, we'll determine whether to * actually use it when a mount request comes in and a file handle * needs to be built. */ uuid_copy (exp->volumeid, volumeid); exp->vol = xl; + + /* On success we should return from here*/ + return exp; err: + /* On failure free exp and it's members.*/ + if (NULL != exp) { + mnt3_export_free (exp); + exp = NULL; + } + return exp; } @@ -1337,8 +2272,7 @@ __mnt3_init_volume_direxports (struct mount3_state *ms, xlator_t *xlator, ret = 0; err: - if (dupopt) - GF_FREE (dupopt); + GF_FREE (dupopt); return ret; } @@ -1459,8 +2393,11 @@ __mnt3_init_volume_export (struct mount3_state *ms, dict_t *opts) goto err; } - gf_string2boolean (optstr, &boolt); - ret = 0; + ret = gf_string2boolean (optstr, &boolt); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to convert" + " string to boolean"); + } err: if (boolt == _gf_false) { @@ -1476,6 +2413,49 @@ err: int +__mnt3_init_dir_export (struct mount3_state *ms, dict_t *opts) +{ + int ret = -1; + char *optstr = NULL; + /* On by default. */ + gf_boolean_t boolt = _gf_true; + + if ((!ms) || (!opts)) + return -1; + + if (!dict_get (opts, "nfs3.export-dirs")) { + ret = 0; + goto err; + } + + ret = dict_get_str (opts, "nfs3.export-dirs", &optstr); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to read option: " + "nfs3.export-dirs"); + ret = -1; + goto err; + } + + ret = gf_string2boolean (optstr, &boolt); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to convert" + " string to boolean"); + } + +err: + if (boolt == _gf_false) { + gf_log (GF_MNT, GF_LOG_TRACE, "Dir exports disabled"); + ms->export_dirs = 0; + } else { + gf_log (GF_MNT, GF_LOG_TRACE, "Dir exports enabled"); + ms->export_dirs = 1; + } + + return ret; +} + + +int mnt3_init_options (struct mount3_state *ms, dict_t *options) { xlator_list_t *volentry = NULL; @@ -1485,6 +2465,7 @@ mnt3_init_options (struct mount3_state *ms, dict_t *options) return -1; __mnt3_init_volume_export (ms, options); + __mnt3_init_dir_export (ms, options); volentry = ms->nfsx->children; while (volentry) { gf_log (GF_MNT, GF_LOG_TRACE, "Initing options for: %s", @@ -1534,49 +2515,118 @@ mnt3_init_state (xlator_t *nfsx) return ms; } +int +mount_init_state (xlator_t *nfsx) +{ + int ret = -1; + struct nfs_state *nfs = NULL; + + if (!nfsx) + goto out; + + nfs = (struct nfs_state *)nfs_state (nfsx); + /*Maintaining global state for MOUNT1 and MOUNT3*/ + nfs->mstate = mnt3_init_state (nfsx); + if (!nfs->mstate) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to allocate" + "mount state"); + goto out; + } + ret = 0; +out: + return ret; +} + rpcsvc_actor_t mnt3svc_actors[MOUNT3_PROC_COUNT] = { - {"NULL", MOUNT3_NULL, mnt3svc_null, NULL, NULL}, - {"MNT", MOUNT3_MNT, mnt3svc_mnt, NULL, NULL}, - {"DUMP", MOUNT3_DUMP, mnt3svc_dump, NULL, NULL}, - {"UMNT", MOUNT3_UMNT, mnt3svc_umnt, NULL, NULL}, - {"UMNTALL", MOUNT3_UMNTALL, mnt3svc_umntall, NULL, NULL}, - {"EXPORT", MOUNT3_EXPORT, mnt3svc_export, NULL, NULL} + {"NULL", MOUNT3_NULL, mnt3svc_null, NULL, 0, DRC_NA}, + {"MNT", MOUNT3_MNT, mnt3svc_mnt, NULL, 0, DRC_NA}, + {"DUMP", MOUNT3_DUMP, mnt3svc_dump, NULL, 0, DRC_NA}, + {"UMNT", MOUNT3_UMNT, mnt3svc_umnt, NULL, 0, DRC_NA}, + {"UMNTALL", MOUNT3_UMNTALL, mnt3svc_umntall, NULL, 0, DRC_NA}, + {"EXPORT", MOUNT3_EXPORT, mnt3svc_export, NULL, 0, DRC_NA} }; /* Static init parts are assigned here, dynamic ones are done in * mnt3svc_init and mnt3_init_state. + * Making MOUNT3 a synctask so that the blocking DNS calls during rpc auth + * gets offloaded to syncenv, keeping the main/poll thread unblocked */ rpcsvc_program_t mnt3prog = { .progname = "MOUNT3", .prognum = MOUNT_PROGRAM, .progver = MOUNT_V3, .progport = GF_MOUNTV3_PORT, - .progaddrfamily = AF_INET, - .proghost = NULL, .actors = mnt3svc_actors, .numactors = MOUNT3_PROC_COUNT, + .min_auth = AUTH_NULL, + .synctask = _gf_true, }; + rpcsvc_program_t * mnt3svc_init (xlator_t *nfsx) { struct mount3_state *mstate = NULL; + struct nfs_state *nfs = NULL; + dict_t *options = NULL; + char *portstr = NULL; + int ret = -1; + pthread_t udp_thread; - if (!nfsx) + if (!nfsx || !nfsx->private) return NULL; + nfs = (struct nfs_state *)nfsx->private; + gf_log (GF_MNT, GF_LOG_DEBUG, "Initing Mount v3 state"); - mstate = mnt3_init_state (nfsx); + mstate = (struct mount3_state *)nfs->mstate; if (!mstate) { gf_log (GF_MNT, GF_LOG_ERROR, "Mount v3 state init failed"); goto err; } mnt3prog.private = mstate; + options = dict_new (); + + ret = gf_asprintf (&portstr, "%d", GF_MOUNTV3_PORT); + if (ret == -1) + goto err; + ret = dict_set_dynstr (options, "transport.socket.listen-port", portstr); + if (ret == -1) + goto err; + ret = dict_set_str (options, "transport-type", "socket"); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + + if (nfs->allow_insecure) { + ret = dict_set_str (options, "rpc-auth-allow-insecure", "on"); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + ret = dict_set_str (options, "rpc-auth.ports.insecure", "on"); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + } + + ret= rpcsvc_create_listeners (nfs->rpcsvc, options, nfsx->name); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "Unable to create listeners"); + dict_unref (options); + goto err; + } + + if (nfs->mount_udp) { + pthread_create (&udp_thread, NULL, mount3udp_thread, NULL); + } return &mnt3prog; err: return NULL; @@ -1584,12 +2634,12 @@ err: rpcsvc_actor_t mnt1svc_actors[MOUNT1_PROC_COUNT] = { - {"NULL", MOUNT1_NULL, mnt3svc_null, NULL, NULL}, - {{0}, }, - {"DUMP", MOUNT1_DUMP, mnt3svc_dump, NULL, NULL}, - {"UMNT", MOUNT1_UMNT, mnt3svc_umnt, NULL, NULL}, - {{0}, }, - {"EXPORT", MOUNT1_EXPORT, mnt3svc_export, NULL, NULL} + {"NULL", MOUNT1_NULL, mnt3svc_null, NULL, 0, DRC_NA}, + {"MNT", MOUNT1_MNT, NULL, NULL, 0, DRC_NA }, + {"DUMP", MOUNT1_DUMP, mnt3svc_dump, NULL, 0, DRC_NA}, + {"UMNT", MOUNT1_UMNT, mnt3svc_umnt, NULL, 0, DRC_NA}, + {"UMNTALL", MOUNT1_UMNTALL, NULL, NULL, 0, DRC_NA}, + {"EXPORT", MOUNT1_EXPORT, mnt3svc_export, NULL, 0, DRC_NA} }; rpcsvc_program_t mnt1prog = { @@ -1597,10 +2647,10 @@ rpcsvc_program_t mnt1prog = { .prognum = MOUNT_PROGRAM, .progver = MOUNT_V1, .progport = GF_MOUNTV1_PORT, - .progaddrfamily = AF_INET, - .proghost = NULL, .actors = mnt1svc_actors, .numactors = MOUNT1_PROC_COUNT, + .min_auth = AUTH_NULL, + .synctask = _gf_true, }; @@ -1608,12 +2658,18 @@ rpcsvc_program_t * mnt1svc_init (xlator_t *nfsx) { struct mount3_state *mstate = NULL; + struct nfs_state *nfs = NULL; + dict_t *options = NULL; + char *portstr = NULL; + int ret = -1; - if (!nfsx) + if (!nfsx || !nfsx->private) return NULL; + nfs = (struct nfs_state *)nfsx->private; + gf_log (GF_MNT, GF_LOG_DEBUG, "Initing Mount v1 state"); - mstate = mnt3_init_state (nfsx); + mstate = (struct mount3_state *)nfs->mstate; if (!mstate) { gf_log (GF_MNT, GF_LOG_ERROR, "Mount v3 state init failed"); goto err; @@ -1621,9 +2677,83 @@ mnt1svc_init (xlator_t *nfsx) mnt1prog.private = mstate; + options = dict_new (); + + ret = gf_asprintf (&portstr, "%d", GF_MOUNTV1_PORT); + if (ret == -1) + goto err; + + ret = dict_set_dynstr (options, "transport.socket.listen-port", portstr); + if (ret == -1) + goto err; + ret = dict_set_str (options, "transport-type", "socket"); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + + if (nfs->allow_insecure) { + ret = dict_set_str (options, "rpc-auth-allow-insecure", "on"); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + ret = dict_set_str (options, "rpc-auth.ports.insecure", "on"); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + } + + ret = rpcsvc_create_listeners (nfs->rpcsvc, options, nfsx->name); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "Unable to create listeners"); + dict_unref (options); + goto err; + } + return &mnt1prog; err: return NULL; } +int +mount_reconfigure_state (xlator_t *nfsx, dict_t *options) +{ + int ret = -1; + struct nfs_state *nfs = NULL; + struct mount3_state *ms = NULL; + struct mnt3_export *exp = NULL; + struct mnt3_export *texp = NULL; + + if ((!nfsx) || (!options)) + return (-1); + + nfs = (struct nfs_state *)nfs_state (nfsx); + if (!nfs) + return (-1); + + ms = nfs->mstate; + if (!ms) + return (-1); + + /* + * Free() up the old export list. mnt3_init_options() will + * rebuild the export list from scratch. Do it with locking + * to avoid unnecessary race conditions. + */ + LOCK (&ms->mountlock); + list_for_each_entry_safe (exp, texp, &ms->exportlist, explist) { + list_del (&exp->explist); + mnt3_export_free (exp); + } + ret = mnt3_init_options (ms, options); + UNLOCK (&ms->mountlock); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Options reconfigure failed"); + return (-1); + } + + return (0); +} diff --git a/xlators/nfs/server/src/mount3.h b/xlators/nfs/server/src/mount3.h index d4d6d446f..7fc16ed57 100644 --- a/xlators/nfs/server/src/mount3.h +++ b/xlators/nfs/server/src/mount3.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _MOUNT3_H_ @@ -50,7 +41,16 @@ mnt3svc_init (xlator_t *nfsx); extern rpcsvc_program_t * mnt1svc_init (xlator_t *nfsx); -/* Data structureused to store the list of mounts points currently +extern int +mount_init_state (xlator_t *nfsx); + +extern int +mount_reconfigure_state (xlator_t *nfsx, dict_t *options); + +void +mount_rewrite_rmtab (struct mount3_state *ms, char *new_rmtab); + +/* Data structure used to store the list of mounts points currently * in use by NFS clients. */ struct mountentry { @@ -65,6 +65,13 @@ struct mountentry { #define MNT3_EXPTYPE_VOLUME 1 #define MNT3_EXPTYPE_DIR 2 +/* Structure to hold export-dir AUTH parameter */ +struct host_auth_spec { + char *host_addr; /* Allowed IP or host name */ + int routeprefix; /* Routing prefix */ + struct host_auth_spec *next; /* Pointer to next AUTH struct */ +}; + struct mnt3_export { struct list_head explist; @@ -72,6 +79,11 @@ struct mnt3_export { * is exported or the subdirectory in the volume. */ char *expname; + /* + * IP address, hostname or subnets who are allowed to connect to expname + * subvolume or subdirectory + */ + struct host_auth_spec* hostspec; xlator_t *vol; int exptype; @@ -98,9 +110,11 @@ struct mount3_state { gf_lock_t mountlock; /* Set to 0 if exporting full volumes is disabled. On by default. */ - int export_volumes; + gf_boolean_t export_volumes; + gf_boolean_t export_dirs; }; +#define gf_mnt3_export_dirs(mst) ((mst)->export_dirs) struct mount3_resolve_state { struct mnt3_export *exp; diff --git a/xlators/nfs/server/src/mount3udp_svc.c b/xlators/nfs/server/src/mount3udp_svc.c new file mode 100644 index 000000000..fb59e282c --- /dev/null +++ b/xlators/nfs/server/src/mount3udp_svc.c @@ -0,0 +1,189 @@ +/* + Copyright (c) 2012 Gluster, Inc. <http://www.gluster.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 "xdr-nfs3.h" +#include "logging.h" +#include "mem-pool.h" +#include "nfs-mem-types.h" +#include "mount3.h" +#include <stdio.h> +#include <stdlib.h> +#include <rpc/pmap_clnt.h> +#include <string.h> +#include <memory.h> +#include <sys/socket.h> +#include <netinet/in.h> + + +extern struct nfs3_fh* nfs3_rootfh (char *dp); +extern mountres3 mnt3svc_set_mountres3 (mountstat3 stat, struct nfs3_fh *fh, + int *authflavor, u_int aflen); +extern int +mount3udp_add_mountlist (char *host, dirpath *expname); + +extern int +mount3udp_delete_mountlist (char *host, dirpath *expname); + + +/* only this thread will use this, no locking needed */ +char mnthost[INET_ADDRSTRLEN+1]; + +mountres3 * +mountudpproc3_mnt_3_svc(dirpath **dpp, struct svc_req *req) +{ + struct mountres3 *res = NULL; + int *autharr = NULL; + struct nfs3_fh *fh = NULL; + char *tmp = NULL; + + tmp = (char *)*dpp; + while (*tmp == '/') + tmp++; + fh = nfs3_rootfh (tmp); + if (fh == NULL) { + gf_log (GF_MNT, GF_LOG_DEBUG, "unable to get fh for %s", tmp); + goto err; + } + + res = GF_CALLOC (1, sizeof(*res), gf_nfs_mt_mountres3); + if (res == NULL) { + gf_log (GF_MNT, GF_LOG_ERROR, "unable to allocate memory"); + goto err; + } + autharr = GF_CALLOC (1, sizeof(*autharr), gf_nfs_mt_int); + if (autharr == NULL) { + gf_log (GF_MNT, GF_LOG_ERROR, "unable to allocate memory"); + goto err; + } + autharr[0] = AUTH_UNIX; + *res = mnt3svc_set_mountres3 (MNT3_OK, fh, autharr, 1); + mount3udp_add_mountlist (mnthost, *dpp); + return res; + + err: + GF_FREE (fh); + GF_FREE (res); + GF_FREE (autharr); + return NULL; +} + +mountstat3 * +mountudpproc3_umnt_3_svc(dirpath **dp, struct svc_req *req) +{ + mountstat3 *stat = NULL; + + stat = GF_CALLOC (1, sizeof(mountstat3), gf_nfs_mt_mountstat3); + if (stat == NULL) { + gf_log (GF_MNT, GF_LOG_ERROR, "unable to allocate memory"); + return NULL; + } + *stat = MNT3_OK; + mount3udp_delete_mountlist (mnthost, *dp); + return stat; +} + +static void +mountudp_program_3(struct svc_req *rqstp, register SVCXPRT *transp) +{ + union { + dirpath mountudpproc3_mnt_3_arg; + } argument; + char *result = NULL; + xdrproc_t _xdr_argument = NULL, _xdr_result = NULL; + char *(*local)(char *, struct svc_req *) = NULL; + mountres3 *res = NULL; + struct sockaddr_in *sin = NULL; + + sin = svc_getcaller (transp); + inet_ntop (AF_INET, &sin->sin_addr, mnthost, INET_ADDRSTRLEN+1); + + switch (rqstp->rq_proc) { + case NULLPROC: + (void) svc_sendreply (transp, (xdrproc_t) xdr_void, + (char *)NULL); + return; + + case MOUNT3_MNT: + _xdr_argument = (xdrproc_t) xdr_dirpath; + _xdr_result = (xdrproc_t) xdr_mountres3; + local = (char *(*)(char *, + struct svc_req *)) mountudpproc3_mnt_3_svc; + break; + + case MOUNT3_UMNT: + _xdr_argument = (xdrproc_t) xdr_dirpath; + _xdr_result = (xdrproc_t) xdr_mountstat3; + local = (char *(*)(char *, + struct svc_req *)) mountudpproc3_umnt_3_svc; + break; + + default: + svcerr_noproc (transp); + return; + } + memset ((char *)&argument, 0, sizeof (argument)); + if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, + (caddr_t) &argument)) { + svcerr_decode (transp); + return; + } + result = (*local)((char *)&argument, rqstp); + if (result == NULL) { + gf_log (GF_MNT, GF_LOG_DEBUG, "PROC returned error"); + svcerr_systemerr (transp); + } + if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, + result)) { + gf_log (GF_MNT, GF_LOG_ERROR, "svc_sendreply returned error"); + svcerr_systemerr (transp); + } + if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, + (caddr_t) &argument)) { + gf_log (GF_MNT, GF_LOG_ERROR, "unable to free arguments"); + } + if (result == NULL) + return; + /* free the result */ + switch (rqstp->rq_proc) { + case MOUNT3_MNT: + res = (mountres3 *) result; + GF_FREE (res->mountres3_u.mountinfo.fhandle.fhandle3_val); + GF_FREE (res->mountres3_u.mountinfo.auth_flavors.auth_flavors_val); + GF_FREE (res); + break; + + case MOUNT3_UMNT: + GF_FREE (result); + break; + } + return; +} + +void * +mount3udp_thread (void *argv) +{ + register SVCXPRT *transp = NULL; + + transp = svcudp_create(RPC_ANYSOCK); + if (transp == NULL) { + gf_log (GF_MNT, GF_LOG_ERROR, "svcudp_create error"); + return NULL; + } + if (!svc_register(transp, MOUNT_PROGRAM, MOUNT_V3, + mountudp_program_3, IPPROTO_UDP)) { + gf_log (GF_MNT, GF_LOG_ERROR, "svc_register error"); + return NULL; + } + + svc_run (); + gf_log (GF_MNT, GF_LOG_ERROR, "svc_run returned"); + return NULL; +} diff --git a/xlators/nfs/server/src/nfs-common.c b/xlators/nfs/server/src/nfs-common.c index ef2d1d3fd..f74396ee8 100644 --- a/xlators/nfs/server/src/nfs-common.c +++ b/xlators/nfs/server/src/nfs-common.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _CONFIG_H @@ -88,13 +79,13 @@ nfs_mntpath_to_xlator (xlator_list_t *cl, char *path) { char volname[MNTPATHLEN]; char *volptr = NULL; - int pathlen = 0; + size_t pathlen; xlator_t *targetxl = NULL; if ((!cl) || (!path)) return NULL; - strcpy (volname, path); + strncpy (volname, path, MNTPATHLEN); pathlen = strlen (volname); gf_log (GF_NFS, GF_LOG_TRACE, "Subvolume search: %s", path); if (volname[0] == '/') @@ -102,7 +93,7 @@ nfs_mntpath_to_xlator (xlator_list_t *cl, char *path) else volptr = &volname[0]; - if (volname[pathlen - 1] == '/') + if (pathlen && volname[pathlen - 1] == '/') volname[pathlen - 1] = '\0'; while (cl) { @@ -131,7 +122,7 @@ nfs_zero_filled_stat (struct iatt *buf) * we've already mapped the root ino to 1 so it is not guaranteed to be * 0. */ - if ((buf->ia_nlink == 0) && (buf->ia_type == 0)) + if ((buf->ia_nlink == 0) && (buf->ia_ctime == 0)) return 1; return 0; @@ -141,53 +132,18 @@ nfs_zero_filled_stat (struct iatt *buf) void nfs_loc_wipe (loc_t *loc) { - if (!loc) - return; - - if (loc->path) { - GF_FREE ((char *)loc->path); - loc->path = NULL; - } - - if (loc->parent) { - inode_unref (loc->parent); - loc->parent = NULL; - } - - if (loc->inode) { - inode_unref (loc->inode); - loc->inode = NULL; - } - - loc->ino = 0; + loc_wipe (loc); } int nfs_loc_copy (loc_t *dst, loc_t *src) { - int ret = -1; - - dst->ino = src->ino; - - if (src->inode) - dst->inode = inode_ref (src->inode); - - if (src->parent) - dst->parent = inode_ref (src->parent); - - dst->path = gf_strdup (src->path); - - if (!dst->path) - goto out; + int ret = -1; - dst->name = strrchr (dst->path, '/'); - if (dst->name) - dst->name++; + ret = loc_copy (dst, src); - ret = 0; -out: - return ret; + return ret; } @@ -201,24 +157,24 @@ nfs_loc_fill (loc_t *loc, inode_t *inode, inode_t *parent, char *path) if (inode) { loc->inode = inode_ref (inode); - loc->ino = inode->ino; + if (!uuid_is_null (inode->gfid)) + uuid_copy (loc->gfid, inode->gfid); } if (parent) loc->parent = inode_ref (parent); - loc->path = gf_strdup (path); - if (!loc->path) { - gf_log (GF_NFS, GF_LOG_ERROR, "strdup failed"); - goto loc_wipe; + if (path) { + loc->path = gf_strdup (path); + if (!loc->path) { + gf_log (GF_NFS, GF_LOG_ERROR, "strdup failed"); + goto loc_wipe; + } + loc->name = strrchr (loc->path, '/'); + if (loc->name) + loc->name++; } - loc->name = strrchr (loc->path, '/'); - if (loc->name) - loc->name++; - else - goto loc_wipe; - ret = 0; loc_wipe: if (ret < 0) @@ -229,7 +185,7 @@ loc_wipe: int -nfs_inode_loc_fill (inode_t *inode, loc_t *loc) +nfs_inode_loc_fill (inode_t *inode, loc_t *loc, int how) { char *resolvedpath = NULL; inode_t *parent = NULL; @@ -238,34 +194,47 @@ nfs_inode_loc_fill (inode_t *inode, loc_t *loc) if ((!inode) || (!loc)) return ret; - if ((inode) && (inode->ino == 1)) - goto ignore_parent; - - parent = inode_parent (inode, 0, NULL); - if (!parent) - goto err; + /* If gfid is not null, then the inode is already linked to + * the inode table, and not a newly created one. For newly + * created inode, inode_path returns null gfid as the path. + */ + if (!uuid_is_null (inode->gfid)) { + ret = inode_path (inode, NULL, &resolvedpath); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "path resolution failed " + "%s", resolvedpath); + goto err; + } + } -ignore_parent: - ret = inode_path (inode, NULL, &resolvedpath); - if (ret < 0) - goto err; + if (resolvedpath == NULL) { + char tmp_path[GFID_STR_PFX_LEN + 1] = {0,}; + snprintf (tmp_path, sizeof (tmp_path), "<gfid:%s>", + uuid_utoa (loc->gfid)); + resolvedpath = gf_strdup (tmp_path); + } else { + parent = inode_parent (inode, loc->pargfid, NULL); + } ret = nfs_loc_fill (loc, inode, parent, resolvedpath); - if (ret < 0) + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "loc fill resolution failed %s", + resolvedpath); goto err; + } + ret = 0; err: if (parent) inode_unref (parent); - if (resolvedpath) - GF_FREE (resolvedpath); + GF_FREE (resolvedpath); return ret; } int -nfs_gfid_loc_fill (inode_table_t *itable, uuid_t gfid, loc_t *loc) +nfs_gfid_loc_fill (inode_table_t *itable, uuid_t gfid, loc_t *loc, int how) { int ret = -EFAULT; inode_t *inode = NULL; @@ -275,11 +244,33 @@ nfs_gfid_loc_fill (inode_table_t *itable, uuid_t gfid, loc_t *loc) inode = inode_find (itable, gfid); if (!inode) { - ret = -ENOENT; - goto err; - } + gf_log (GF_NFS, GF_LOG_TRACE, "Inode not found in itable, will try to create one."); + if (how == NFS_RESOLVE_CREATE) { + gf_log (GF_NFS, GF_LOG_TRACE, "Inode needs to be created."); + inode = inode_new (itable); + if (!inode) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to " + "allocate memory"); + ret = -ENOMEM; + goto err; + } + + } else { + gf_log (GF_NFS, GF_LOG_ERROR, "Inode not found in itable and no creation was requested."); + ret = -ENOENT; + goto err; + } + } else { + gf_log (GF_NFS, GF_LOG_TRACE, "Inode was found in the itable."); + } - ret = nfs_inode_loc_fill (inode, loc); + uuid_copy (loc->gfid, gfid); + + ret = nfs_inode_loc_fill (inode, loc, how); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "Inode loc filling failed.: %s", strerror (-ret)); + goto err; + } err: if (inode) @@ -294,7 +285,7 @@ nfs_root_loc_fill (inode_table_t *itable, loc_t *loc) uuid_t rootgfid = {0, }; rootgfid[15] = 1; - return nfs_gfid_loc_fill (itable, rootgfid, loc); + return nfs_gfid_loc_fill (itable, rootgfid, loc, NFS_RESOLVE_EXIST); } @@ -310,11 +301,14 @@ nfs_parent_inode_loc_fill (inode_t *parent, inode_t *entryinode, char *entry, return ret; ret = inode_path (parent, entry, &path); - if (ret < 0) + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "path resolution failed %s", + path); goto err; + } ret = nfs_loc_fill (loc, entryinode, parent, path); - + GF_FREE (path); err: return ret; } @@ -346,6 +340,8 @@ nfs_entry_loc_fill (inode_table_t *itable, uuid_t pargfid, char *entry, if (!parent) goto err; + uuid_copy (loc->pargfid, pargfid); + ret = -2; entryinode = inode_grep (itable, parent, entry); if (!entryinode) { @@ -373,13 +369,18 @@ nfs_entry_loc_fill (inode_table_t *itable, uuid_t pargfid, char *entry, ret = inode_path (parent, entry, &resolvedpath); if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "path resolution failed %s", + resolvedpath); ret = -3; goto err; } ret = nfs_loc_fill (loc, entryinode, parent, resolvedpath); - if (ret < 0) + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "loc_fill failed %s", + resolvedpath); ret = -3; + } err: if (parent) @@ -388,8 +389,7 @@ err: if (entryinode) inode_unref (entryinode); - if (resolvedpath) - GF_FREE (resolvedpath); + GF_FREE (resolvedpath); return ret; } @@ -408,6 +408,9 @@ nfs_hash_gfid (uuid_t gfid) uint32_t b1 = 0; uint32_t b2 = 0; + if (__is_root_gfid (gfid)) + return 0x1; + memcpy (&msb64, &gfid[8], 8); memcpy (&lsb64, &gfid[0], 8); @@ -425,3 +428,38 @@ nfs_hash_gfid (uuid_t gfid) } +void +nfs_fix_generation (xlator_t *this, inode_t *inode) +{ + uint64_t raw_ctx = 0; + struct nfs_inode_ctx *ictx = NULL; + struct nfs_state *priv = NULL; + int ret = -1; + + if (!inode) { + return; + } + priv = this->private; + + if (inode_ctx_get(inode,this,&raw_ctx) == 0) { + ictx = (struct nfs_inode_ctx *)raw_ctx; + ictx->generation = priv->generation; + } + else { + ictx = GF_CALLOC (1, sizeof (struct nfs_inode_ctx), + gf_nfs_mt_inode_ctx); + if (!ictx) { + gf_log (this->name, GF_LOG_ERROR, + "could not allocate nfs inode ctx"); + return; + } + INIT_LIST_HEAD(&ictx->shares); + ictx->generation = priv->generation; + ret = inode_ctx_put (inode, this, (uint64_t)ictx); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "could not store nfs inode ctx"); + return; + } + } +} diff --git a/xlators/nfs/server/src/nfs-common.h b/xlators/nfs/server/src/nfs-common.h index ec46336a8..2e97f1563 100644 --- a/xlators/nfs/server/src/nfs-common.h +++ b/xlators/nfs/server/src/nfs-common.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _NFS_COMMON_H_ @@ -32,10 +23,12 @@ #include "iatt.h" #include "uuid.h" -#define NFS_PATH_MAX PATH_MAX +//NFS_PATH_MAX hard-coded to 4096 as a work around for bug 2476. +//nfs server crashes when path received is longer than PATH_MAX +#define NFS_PATH_MAX 4096 #define NFS_NAME_MAX NAME_MAX -#define NFS_DEFAULT_CREATE_MODE 0644 +#define NFS_DEFAULT_CREATE_MODE 0600 extern xlator_t * nfs_xlid_to_xlator (xlator_list_t *cl, uint8_t xlid); @@ -65,7 +58,7 @@ nfs_loc_fill (loc_t *loc, inode_t *inode, inode_t *parent, char *path); #define NFS_RESOLVE_CREATE 2 extern int -nfs_inode_loc_fill (inode_t *inode, loc_t *loc); +nfs_inode_loc_fill (inode_t *inode, loc_t *loc, int how); extern int nfs_ino_loc_fill (inode_table_t *itable, uuid_t gfid, loc_t *l); @@ -79,4 +72,10 @@ nfs_root_loc_fill (inode_table_t *itable, loc_t *loc); extern uint32_t nfs_hash_gfid (uuid_t gfid); + +extern int +nfs_gfid_loc_fill (inode_table_t *itable, uuid_t gfid, loc_t *loc, int how); + +void +nfs_fix_generation (xlator_t *this, inode_t *inode); #endif diff --git a/xlators/nfs/server/src/nfs-fops.c b/xlators/nfs/server/src/nfs-fops.c index 1c5b4f5cc..236b80c76 100644 --- a/xlators/nfs/server/src/nfs-fops.c +++ b/xlators/nfs/server/src/nfs-fops.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _CONFIG_H @@ -22,6 +13,9 @@ #include "config.h" #endif +#include <grp.h> +#include <pwd.h> + #include "dict.h" #include "xlator.h" #include "iobuf.h" @@ -31,10 +25,80 @@ #include "nfs-fops.h" #include "inode.h" #include "nfs-common.h" - +#include "nfs3-helpers.h" +#include "nfs-mem-types.h" #include <libgen.h> #include <semaphore.h> +void +nfs_fix_groups (xlator_t *this, call_stack_t *root) +{ + struct passwd mypw; + char mystrs[1024]; + struct passwd *result; + gid_t mygroups[GF_MAX_AUX_GROUPS]; + int ngroups; + int i; + struct nfs_state *priv = this->private; + const gid_list_t *agl; + gid_list_t gl; + + if (!priv->server_aux_gids) { + return; + } + + agl = gid_cache_lookup(&priv->gid_cache, root->uid); + if (agl) { + for (ngroups = 0; ngroups < agl->gl_count; ngroups++) + root->groups[ngroups] = agl->gl_list[ngroups]; + root->ngrps = ngroups; + gid_cache_release(&priv->gid_cache, agl); + return; + } + + /* No cached list found. */ + if (getpwuid_r(root->uid,&mypw,mystrs,sizeof(mystrs),&result) != 0) { + gf_log (this->name, GF_LOG_ERROR, + "getpwuid_r(%u) failed", root->uid); + return; + } + + if (!result) { + gf_log (this->name, GF_LOG_ERROR, + "getpwuid_r(%u) found nothing", root->uid); + return; + } + + gf_log (this->name, GF_LOG_TRACE, "mapped %u => %s", + root->uid, result->pw_name); + + ngroups = GF_MAX_AUX_GROUPS; + if (getgrouplist(result->pw_name,root->gid,mygroups,&ngroups) == -1) { + gf_log (this->name, GF_LOG_ERROR, + "could not map %s to group list", result->pw_name); + return; + } + + /* Add the group data to the cache. */ + gl.gl_list = GF_CALLOC(ngroups, sizeof(gid_t), gf_nfs_mt_aux_gids); + if (gl.gl_list) { + /* It's not fatal if the alloc failed. */ + gl.gl_id = root->uid; + gl.gl_count = ngroups; + memcpy(gl.gl_list, mygroups, sizeof(gid_t) * ngroups); + if (gid_cache_add(&priv->gid_cache, &gl) != 1) + GF_FREE(gl.gl_list); + } + + /* Copy data to the frame. */ + for (i = 0; i < ngroups; ++i) { + gf_log (this->name, GF_LOG_TRACE, + "%s is in group %u", result->pw_name, mygroups[i]); + root->groups[i] = mygroups[i]; + } + root->ngrps = ngroups; +} + struct nfs_fop_local * nfs_fop_local_init (xlator_t *nfsx) { @@ -52,13 +116,9 @@ nfs_fop_local_init (xlator_t *nfsx) void nfs_fop_local_wipe (xlator_t *nfsx, struct nfs_fop_local *l) { - struct nfs_state *nfs = NULL; - if ((!nfsx) || (!l)) return; - nfs = nfsx->private; - if (l->iobref) iobref_unref (l->iobref); @@ -74,9 +134,7 @@ nfs_fop_local_wipe (xlator_t *nfsx, struct nfs_fop_local *l) if (l->dictgfid) dict_unref (l->dictgfid); - loc_wipe (&l->revalidate_loc); - - mem_put (nfs->foppool, l); + mem_put (l); return; } @@ -96,7 +154,7 @@ unsigned int cval = 1; int nfs_frame_getctr () { - int val = 0; + uint64_t val = 0; pthread_mutex_lock (&ctr); { @@ -124,20 +182,33 @@ nfs_create_frame (xlator_t *xl, nfs_user_t *nfu) frame = create_frame (xl, (call_pool_t *)xl->ctx->pool); if (!frame) goto err; + if (call_stack_alloc_groups (frame->root, nfu->ngrps) != 0) { + STACK_DESTROY (frame->root); + frame = NULL; + goto err; + } + + frame->root->pid = NFS_PID; 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->lk_owner = nfu->lk_owner; - frame->root->ngrps = nfu->ngrps - 1; + if (nfu->ngrps != 1) { + 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]; + 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]; + } } - frame->root->lk_owner = nfs_frame_getctr (); + + /* + * It's tempting to do this *instead* of using nfu above, but we need + * to have those values in case nfs_fix_groups doesn't do anything. + */ + nfs_fix_groups(xl,frame->root); err: return frame; @@ -145,7 +216,7 @@ err: #define nfs_fop_handle_frame_create(fram, xla, nfuser, retval, errlabel) \ do { \ - fram = nfs_create_frame (xla, (nfuser)); \ + fram = nfs_create_frame (xla, (nfuser)); \ if (!fram) { \ retval = (-ENOMEM); \ gf_log (GF_NFS, GF_LOG_ERROR,"Frame creation failed");\ @@ -157,28 +228,31 @@ err: * 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) \ +#define nfs_fop_save_root_ino(locl, loc) \ + do { \ + if (((loc)->inode) && \ + __is_root_gfid ((loc)->inode->gfid)) \ + (locl)->rootinode = 1; \ + else if (((loc)->parent) && \ + __is_root_gfid ((loc)->parent->gfid)) \ + (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) \ - +#define nfs_fop_save_root_fd_ino(locl, fdesc) \ + do { \ + if (__is_root_gfid ((fdesc)->inode->gfid)) \ + (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) \ +#define nfs_fop_restore_root_ino(locl, fopret, preattr, postattr, prepar, postpar) \ do { \ + if (fopret == -1) \ + break; \ if ((locl)->rootinode) { \ if ((preattr)) { \ ((struct iatt *)(preattr))->ia_ino = 1; \ @@ -203,17 +277,21 @@ err: /* 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) \ +#define nfs_fop_newloc_save_root_ino(locl, newloc) \ + do { \ + if (((newloc)->inode) && \ + __is_root_gfid ((newloc)->inode->gfid)) \ + (locl)->newrootinode = 1; \ + else if (((newloc)->parent) && \ + __is_root_gfid ((newloc)->parent->gfid)) \ + (locl)->newrootparentinode = 1; \ + } while (0) + +#define nfs_fop_newloc_restore_root_ino(locl, fopret, preattr, postattr, prepar, postpar) \ do { \ + if (fopret == -1) \ + break; \ + \ if ((locl)->newrootinode) { \ if ((preattr)) \ ((struct iatt *)(preattr))->ia_ino = 1; \ @@ -272,9 +350,6 @@ out: } \ } 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: @@ -289,7 +364,7 @@ out: * * 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 + * that it silently performs all the relevant GlusterFS state maintenance * 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, @@ -307,29 +382,13 @@ nfs_fop_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, { struct nfs_fop_local *local = NULL; fop_lookup_cbk_t progcbk; - inode_table_t *itable = NULL; - xlator_t *xl = NULL; - - xl = cookie; - - local = frame->local; - nfs_fop_restore_root_ino (local, buf, NULL, NULL, postparent); - - if (op_ret == -1 && local->is_revalidate == 1) { - /* perform a fresh lookup if revalidate fails */ - itable = local->revalidate_loc.inode->table; - inode_unref (local->revalidate_loc.inode); - local->revalidate_loc.inode = inode_new (itable); - local->is_revalidate = 2; /* prevent entering revalidate loops */ - - STACK_WIND_COOKIE (frame, nfs_fop_lookup_cbk, xl, xl, - xl->fops->lookup, &local->revalidate_loc, - local->dictgfid); - return 0; + if (op_ret == 0) { + nfs_fix_generation(this,inode); } nfl_to_prog_data (local, progcbk, frame); + nfs_fop_restore_root_ino (local, op_ret, buf, NULL, NULL, postparent); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, xattr, postparent); @@ -356,11 +415,6 @@ nfs_fop_lookup (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, nfs_fop_save_root_ino (nfl, loc); nfs_fop_gfid_setup (nfl, loc->inode, ret, err); - if (!uuid_is_null (loc->inode->gfid)) { - nfl->is_revalidate = 1; - loc_copy (&nfl->revalidate_loc, loc); - } - STACK_WIND_COOKIE (frame, nfs_fop_lookup_cbk, xl, xl, xl->fops->lookup, loc, nfl->dictgfid); @@ -374,18 +428,63 @@ err: return ret; } +int32_t +nfs_fop_access_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + struct nfs_fop_local *nfl = NULL; + fop_access_cbk_t progcbk = NULL; + + nfl_to_prog_data (nfl, progcbk, frame); + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, xdata); + + nfs_stack_destroy (nfl, frame); + return 0; +} + +int +nfs_fop_access (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, + int32_t accesstest, fop_access_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + uint32_t accessbits = 0; + + if ((!xl) || (!loc) || (!nfu)) + return ret; + + gf_log (GF_NFS, GF_LOG_TRACE, "Access: %s", loc->path); + nfs_fop_handle_frame_create (frame, nfsx, nfu, ret, err); + nfs_fop_handle_local_init (frame, nfsx, nfl, cbk, local, ret, err); + nfs_fop_save_root_ino (nfl, loc); + + accessbits = nfs3_request_to_accessbits (accesstest); + STACK_WIND_COOKIE (frame, nfs_fop_access_cbk, xl, xl, xl->fops->access, + loc, accessbits, NULL); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (nfl, 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) + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_stat_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, buf, NULL, NULL, NULL); + nfs_fop_restore_root_ino (nfl, op_ret, buf, NULL, NULL, NULL); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, buf); + progcbk (frame, cookie, this, op_ret, op_errno, buf, xdata); nfs_stack_destroy (nfl, frame); return 0; @@ -409,7 +508,7 @@ nfs_fop_stat (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, nfs_fop_save_root_ino (nfl, loc); STACK_WIND_COOKIE (frame, nfs_fop_stat_cbk, xl, xl, xl->fops->stat, - loc); + loc, NULL); ret = 0; err: if (ret < 0) { @@ -423,15 +522,16 @@ err: 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) + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_fstat_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, buf, NULL, NULL, NULL); + nfs_fop_restore_root_ino (nfl, op_ret, buf, NULL, NULL, NULL); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, buf); + progcbk (frame, cookie, this, op_ret, op_errno, buf, xdata); nfs_stack_destroy (nfl, frame); return 0; @@ -455,7 +555,7 @@ nfs_fop_fstat (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, nfs_fop_save_root_fd_ino (nfl, fd); STACK_WIND_COOKIE (frame, nfs_fop_fstat_cbk, xl, xl, xl->fops->fstat, - fd); + fd, NULL); ret = 0; err: @@ -470,14 +570,14 @@ err: 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) + int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_opendir_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, fd); + progcbk (frame, cookie, this, op_ret, op_errno, fd, xdata); nfs_stack_destroy (nfl, frame); return 0; } @@ -499,7 +599,7 @@ nfs_fop_opendir (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, nfs_fop_handle_local_init (frame, nfsx, nfl, cbk, local, ret, err); STACK_WIND_COOKIE (frame, nfs_fop_opendir_cbk, xl, xl, - xl->fops->opendir, pathloc, dirfd); + xl->fops->opendir, pathloc, dirfd, NULL); ret = 0; err: @@ -513,14 +613,14 @@ err: int nfs_fop_flush_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno) + int32_t op_ret, int32_t op_errno, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_flush_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno); + progcbk (frame, cookie, this, op_ret, op_errno, xdata); nfs_stack_destroy (nfl, frame); return 0; @@ -542,7 +642,7 @@ nfs_fop_flush (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, nfs_fop_handle_local_init (frame, nfsx, nfl, cbk, local, ret, err); STACK_WIND_COOKIE (frame, nfs_fop_flush_cbk, xl, xl, xl->fops->flush, - fd); + fd, NULL); ret = 0; err: if (ret < 0) { @@ -556,14 +656,15 @@ err: 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) + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries, + dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_readdirp_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, entries); + progcbk (frame, cookie, this, op_ret, op_errno, entries, xdata); nfs_stack_destroy (nfl, frame); @@ -588,7 +689,7 @@ nfs_fop_readdirp (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *dirfd, nfs_fop_handle_local_init (frame, nfsx, nfl, cbk, local, ret, err); STACK_WIND_COOKIE (frame, nfs_fop_readdirp_cbk, xl, xl, - xl->fops->readdirp, dirfd, bufsize, offset); + xl->fops->readdirp, dirfd, bufsize, offset, 0); ret = 0; err: @@ -603,7 +704,8 @@ err: 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) + int32_t op_ret, int32_t op_errno, struct statvfs *buf, + dict_t *xdata) { struct nfs_fop_local *nfl = NULL; @@ -611,7 +713,7 @@ nfs_fop_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, buf); + progcbk (frame, cookie, this, op_ret, op_errno, buf, xdata); nfs_stack_destroy (nfl, frame); return 0; @@ -634,7 +736,7 @@ nfs_fop_statfs (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, nfs_fop_handle_local_init (frame, nfsx, nfl, cbk, local, ret, err); STACK_WIND_COOKIE (frame, nfs_fop_statfs_cbk, xl, xl, - xl->fops->statfs, pathloc); + xl->fops->statfs, pathloc, NULL); ret = 0; err: if (ret < 0) { @@ -650,16 +752,21 @@ 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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_create_cbk_t progcbk = NULL; + if (op_ret == 0) { + nfs_fix_generation(this,inode); + } + nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent); + nfs_fop_restore_root_ino (nfl, op_ret, buf, NULL, preparent, + postparent); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, fd, inode, buf, - preparent, postparent); + preparent, postparent, NULL); nfs_stack_destroy (nfl, frame); return 0; @@ -685,7 +792,7 @@ nfs_fop_create (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, nfs_fop_gfid_setup (nfl, pathloc->inode, ret, err); STACK_WIND_COOKIE (frame, nfs_fop_create_cbk, xl, xl, xl->fops->create, - pathloc, flags, mode, fd, nfl->dictgfid); + pathloc, flags, mode, 0, fd, nfl->dictgfid); ret = 0; err: @@ -701,15 +808,16 @@ err: 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 iatt *post, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_setattr_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, pre, post, NULL, NULL); + nfs_fop_restore_root_ino (nfl, op_ret, pre, post, NULL, NULL); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, pre, post); + progcbk (frame, cookie, this, op_ret, op_errno, pre, post, + xdata); nfs_stack_destroy (nfl, frame); return 0; } @@ -734,7 +842,7 @@ nfs_fop_setattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, nfs_fop_save_root_ino (nfl, pathloc); STACK_WIND_COOKIE (frame, nfs_fop_setattr_cbk, xl, xl, - xl->fops->setattr, pathloc, buf, valid); + xl->fops->setattr, pathloc, buf, valid, NULL); ret = 0; err: if (ret < 0) { @@ -750,16 +858,20 @@ 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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_mkdir_cbk_t progcbk = NULL; + if (op_ret == 0) { + nfs_fix_generation(this,inode); + } + nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent); + nfs_fop_restore_root_ino (nfl, op_ret, buf, NULL,preparent, postparent); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, - preparent, postparent); + preparent, postparent, xdata); nfs_stack_destroy (nfl, frame); return 0; } @@ -783,7 +895,7 @@ nfs_fop_mkdir (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, nfs_fop_gfid_setup (nfl, pathloc->inode, ret, err); STACK_WIND_COOKIE (frame, nfs_fop_mkdir_cbk, xl, xl, xl->fops->mkdir, - pathloc, mode, nfl->dictgfid); + pathloc, mode, 0, nfl->dictgfid); ret = 0; err: if (ret < 0) { @@ -799,16 +911,20 @@ 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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_symlink_cbk_t progcbk = NULL; + if (op_ret == 0) { + nfs_fix_generation(this,inode); + } + nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent); + nfs_fop_restore_root_ino (nfl, op_ret,buf, NULL, preparent, postparent); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, - preparent, postparent); + preparent, postparent, xdata); nfs_stack_destroy (nfl, frame); return 0; } @@ -831,7 +947,8 @@ nfs_fop_symlink (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, char *target, nfs_fop_gfid_setup (nfl, pathloc->inode, ret, err); STACK_WIND_COOKIE (frame, nfs_fop_symlink_cbk, xl, xl, - xl->fops->symlink, target, pathloc, nfl->dictgfid); + xl->fops->symlink, target, pathloc, + 0, nfl->dictgfid); ret = 0; err: if (ret < 0) { @@ -846,15 +963,16 @@ err: 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 iatt *buf, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_readlink_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, buf, NULL, NULL, NULL); + nfs_fop_restore_root_ino (nfl, op_ret, buf, NULL, NULL, NULL); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, path, buf); + progcbk (frame, cookie, this, op_ret, op_errno, path, buf, + xdata); nfs_stack_destroy (nfl, frame); return 0; } @@ -877,7 +995,7 @@ nfs_fop_readlink (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, nfs_fop_save_root_ino (nfl, pathloc); STACK_WIND_COOKIE (frame, nfs_fop_readlink_cbk, xl, xl, - xl->fops->readlink, pathloc, size); + xl->fops->readlink, pathloc, size, NULL); ret = 0; err: if (ret < 0) { @@ -893,16 +1011,20 @@ 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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_mknod_cbk_t progcbk = NULL; + if (op_ret == 0) { + nfs_fix_generation(this,inode); + } + nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent); + nfs_fop_restore_root_ino (nfl, op_ret,buf, NULL, preparent, postparent); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, - preparent, postparent); + preparent, postparent, xdata); nfs_stack_destroy (nfl, frame); return 0; } @@ -926,7 +1048,7 @@ nfs_fop_mknod (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, nfs_fop_gfid_setup (nfl, pathloc->inode, ret, err); STACK_WIND_COOKIE (frame, nfs_fop_mknod_cbk, xl, xl, xl->fops->mknod, - pathloc, mode, dev, nfl->dictgfid); + pathloc, mode, dev, 0, nfl->dictgfid); ret = 0; err: if (ret < 0) { @@ -940,16 +1062,17 @@ err: 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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = frame->local; fop_rmdir_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, NULL, NULL, preparent, postparent); + nfs_fop_restore_root_ino (nfl, op_ret, NULL, NULL, preparent, + postparent); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, preparent, - postparent); + postparent, NULL); nfs_stack_destroy (nfl, frame); return 0; } @@ -973,7 +1096,7 @@ nfs_fop_rmdir (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, nfs_fop_save_root_ino (nfl, pathloc); STACK_WIND_COOKIE (frame, nfs_fop_rmdir_cbk, xl, xl, xl->fops->rmdir, - pathloc, 0); + pathloc, 0, NULL); ret = 0; err: if (ret < 0) { @@ -989,16 +1112,17 @@ err: 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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = frame->local; fop_unlink_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, NULL, NULL, preparent, postparent); + nfs_fop_restore_root_ino (nfl, op_ret, NULL, NULL, preparent, + postparent); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, preparent, - postparent); + postparent, xdata); nfs_stack_destroy (nfl, frame); return 0; } @@ -1021,7 +1145,7 @@ nfs_fop_unlink (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, nfs_fop_save_root_ino (nfl, pathloc); STACK_WIND_COOKIE (frame, nfs_fop_unlink_cbk, xl, xl, - xl->fops->unlink, pathloc); + xl->fops->unlink, pathloc, 0, NULL); ret = 0; err: if (ret < 0) { @@ -1038,16 +1162,21 @@ 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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_link_cbk_t progcbk = NULL; + if (op_ret == 0) { + nfs_fix_generation(this,inode); + } + nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent); + nfs_fop_restore_root_ino (nfl, op_ret, buf, NULL, preparent, + postparent); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, - preparent, postparent); + preparent, postparent, xdata); nfs_stack_destroy (nfl, frame); return 0; @@ -1072,7 +1201,7 @@ nfs_fop_link (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc, nfs_fop_save_root_ino (nfl, newloc); STACK_WIND_COOKIE (frame, nfs_fop_link_cbk, xl, xl, xl->fops->link, - oldloc, newloc); + oldloc, newloc, NULL); ret = 0; err: if (ret < 0) { @@ -1088,7 +1217,8 @@ 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 iatt *prenewparent, struct iatt *postnewparent, + dict_t *xdata) { struct nfs_fop_local *nfl = NULL; @@ -1097,15 +1227,16 @@ nfs_fop_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, nfl_to_prog_data (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. + * could have 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, + nfs_fop_restore_root_ino (nfl, op_ret, NULL, NULL, preoldparent, + postoldparent); + nfs_fop_newloc_restore_root_ino (nfl, op_ret, buf, NULL, prenewparent, postnewparent); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, buf, preoldparent, postoldparent, prenewparent, - postnewparent); + postnewparent, xdata); nfs_stack_destroy (nfl, frame); return 0; } @@ -1130,7 +1261,7 @@ nfs_fop_rename (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc, nfs_fop_newloc_save_root_ino (nfl, newloc); STACK_WIND_COOKIE (frame, nfs_fop_rename_cbk, xl, xl, - xl->fops->rename, oldloc, newloc); + xl->fops->rename, oldloc, newloc, NULL); ret = 0; err: if (ret < 0) { @@ -1144,14 +1275,14 @@ err: 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) + int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_open_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, fd); + progcbk (frame, cookie, this, op_ret, op_errno, fd, xdata); nfs_stack_destroy (nfl, frame); return 0; @@ -1159,7 +1290,7 @@ nfs_fop_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int nfs_fop_open (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, - int32_t flags, fd_t *fd, int32_t wbflags, fop_open_cbk_t cbk, + int32_t flags, fd_t *fd, fop_open_cbk_t cbk, void *local) { call_frame_t *frame = NULL; @@ -1174,7 +1305,7 @@ nfs_fop_open (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, nfs_fop_handle_local_init (frame, nfsx, nfl, cbk, local, ret, err); STACK_WIND_COOKIE (frame, nfs_fop_open_cbk, xl, xl, xl->fops->open, - loc, flags, fd, wbflags); + loc, flags, fd, NULL); ret = 0; err: if (ret < 0) { @@ -1189,15 +1320,16 @@ err: 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 iatt *postbuf, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_writev_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, prebuf, postbuf, NULL, NULL); + nfs_fop_restore_root_ino (nfl, op_ret, prebuf, postbuf, NULL, NULL); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, prebuf,postbuf); + progcbk (frame, cookie, this, op_ret, op_errno, prebuf, + postbuf, xdata); nfs_stack_destroy (nfl, frame); @@ -1207,20 +1339,20 @@ nfs_fop_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int nfs_fop_write (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, - struct iobuf *srciob, struct iovec *vector, int32_t count, + struct iobref *srciobref, 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 ((!nfsx) || (!xl) || (!fd) || (!vector) || (!nfu) || (!srciob)) + if ((!nfsx) || (!xl) || (!fd) || (!vector) || (!nfu) || (!srciobref)) return ret; nfs_fop_handle_frame_create (frame, nfsx, nfu, ret, err); nfs_fop_handle_local_init (frame, nfsx, 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"); @@ -1229,8 +1361,9 @@ nfs_fop_write (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, } iobref_add (nfl->iobref, srciob); - STACK_WIND_COOKIE (frame, nfs_fop_writev_cbk, xl, xl,xl->fops->writev - , fd, vector, count, offset, nfl->iobref); +*/ + STACK_WIND_COOKIE (frame, nfs_fop_writev_cbk, xl, xl,xl->fops->writev, + fd, vector, count, offset, fd->flags, srciobref, NULL); ret = 0; err: if (ret < 0) { @@ -1245,15 +1378,17 @@ err: 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 iatt *postbuf, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_fsync_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, prebuf, postbuf, NULL, NULL); + nfs_fop_restore_root_ino (nfl, op_ret, prebuf, postbuf, NULL, NULL); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, prebuf,postbuf); + progcbk (frame, cookie, this, op_ret, op_errno, prebuf, + postbuf, xdata); + nfs_stack_destroy (nfl, frame); return 0; } @@ -1276,7 +1411,7 @@ nfs_fop_fsync (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, nfs_fop_save_root_fd_ino (nfl, fd); STACK_WIND_COOKIE (frame, nfs_fop_fsync_cbk, xl, xl, - xl->fops->fsync, fd, datasync); + xl->fops->fsync, fd, datasync, NULL); ret = 0; err: if (ret < 0) { @@ -1291,16 +1426,17 @@ err: 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) + int32_t count, struct iatt *stbuf, struct iobref *iobref, + dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_readv_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, stbuf, NULL, NULL, NULL); + nfs_fop_restore_root_ino (nfl, op_ret, stbuf, NULL, NULL, NULL); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, vector, count, - stbuf, iobref); + stbuf, iobref, xdata); nfs_stack_destroy (nfl, frame); return 0; @@ -1323,7 +1459,149 @@ nfs_fop_read (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, nfs_fop_save_root_fd_ino (nfl, fd); STACK_WIND_COOKIE (frame, nfs_fop_readv_cbk, xl, xl, xl->fops->readv, - fd, size, offset); + fd, size, offset, 0, NULL); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (nfl, frame); + } + + return ret; +} + +int32_t +nfs_fop_lk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct gf_flock *flock, + dict_t *xdata) +{ + struct nfs_fop_local *nfl = NULL; + fop_lk_cbk_t progcbk = NULL; + + nfl_to_prog_data (nfl, progcbk, frame); + + if (!op_ret) + fd_lk_insert_and_merge (nfl->fd, nfl->cmd, &nfl->flock); + + fd_unref (nfl->fd); + + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, flock, xdata); + + nfs_stack_destroy (nfl, frame); + return 0; +} + + +int +nfs_fop_lk (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, + int cmd, struct gf_flock *flock, fop_lk_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, nfsx, nfu, ret, err); + nfs_fop_handle_local_init (frame, nfsx, nfl, cbk, local, ret, err); + + nfl->cmd = cmd; + nfl->fd = fd_ref (fd); + nfl->flock = *flock; + + STACK_WIND_COOKIE (frame, nfs_fop_lk_cbk, xl, xl, xl->fops->lk, + fd, cmd, flock, NULL); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (nfl, frame); + } + + return ret; +} + +int32_t +nfs_fop_getxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata) +{ + struct nfs_fop_local *nfl = NULL; + fop_getxattr_cbk_t progcbk = NULL; + + nfl_to_prog_data (nfl, progcbk, frame); + + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, dict, xdata); + + nfs_stack_destroy (nfl, frame); + return 0; +} + + +int +nfs_fop_getxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, + char *name, dict_t *xdata, fop_getxattr_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, nfsx, nfu, ret, err); + nfs_fop_handle_local_init (frame, nfsx, nfl, cbk, local, ret, err); + + STACK_WIND_COOKIE (frame, nfs_fop_getxattr_cbk, xl, xl, xl->fops->getxattr, + loc, name, NULL); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (nfl, frame); + } + + return ret; +} + + +int32_t +nfs_fop_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + struct nfs_fop_local *nfl = NULL; + fop_setxattr_cbk_t progcbk = NULL; + + nfl_to_prog_data (nfl, progcbk, frame); + + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, xdata); + + nfs_stack_destroy (nfl, frame); + return 0; +} + + +int +nfs_fop_setxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, + loc_t *loc, dict_t *dict, int32_t flags, dict_t *xdata, + fop_setxattr_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, nfsx, nfu, ret, err); + nfs_fop_handle_local_init (frame, nfsx, nfl, cbk, local, ret, err); + + STACK_WIND_COOKIE (frame, nfs_fop_setxattr_cbk, xl, xl, xl->fops->setxattr, + loc, dict, flags, xdata); ret = 0; err: if (ret < 0) { @@ -1338,15 +1616,16 @@ err: 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 iatt *postbuf, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_truncate_cbk_t progcbk = NULL; nfl_to_prog_data (nfl, progcbk, frame); - nfs_fop_restore_root_ino (nfl, prebuf, postbuf, NULL, NULL); + nfs_fop_restore_root_ino (nfl, op_ret, prebuf, postbuf, NULL, NULL); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, prebuf,postbuf); + progcbk (frame, cookie, this, op_ret, op_errno, prebuf, + postbuf, xdata); nfs_stack_destroy (nfl, frame); return 0; @@ -1369,7 +1648,7 @@ nfs_fop_truncate (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, nfs_fop_save_root_ino (nfl, loc); STACK_WIND_COOKIE (frame, nfs_fop_truncate_cbk, xl, xl, - xl->fops->truncate, loc, offset); + xl->fops->truncate, loc, offset, NULL); ret = 0; err: diff --git a/xlators/nfs/server/src/nfs-fops.h b/xlators/nfs/server/src/nfs-fops.h index 4feb916e2..44e99c66b 100644 --- a/xlators/nfs/server/src/nfs-fops.h +++ b/xlators/nfs/server/src/nfs-fops.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _NFS_FOPS_H_ @@ -96,16 +87,14 @@ struct nfs_fop_local { */ int rootparentinode; - char path[NFS_NAME_MAX]; - char newpath[NFS_NAME_MAX]; + char path[NFS_NAME_MAX + 1]; + char newpath[NFS_NAME_MAX + 1]; xlator_t *nfsx; dict_t *dictgfid; - /* Determine whether the call was a lookup revalidate in cases where - * lookup fails. Mangle the copied loc_t to perform a fresh lookup - */ - int is_revalidate; - loc_t revalidate_loc; + fd_t *fd; + int cmd; + struct gf_flock flock; }; extern struct nfs_fop_local * @@ -122,7 +111,7 @@ nfs_fop_local_wipe (xlator_t *xl, struct nfs_fop_local *l); nflocal = nfs_fop_local_init (nf); \ if (nflocal) { \ nflocal->proglocal = plocal; \ - nflocal->progcbk = pcbk; \ + nflocal->progcbk = *VOID(&pcbk); \ nflocal->nfsx = nf; \ if (fram) \ ((call_frame_t *)fram)->local = nflocal;\ @@ -140,7 +129,7 @@ nfs_fop_local_wipe (xlator_t *xl, struct nfs_fop_local *l); #define nfs_fop_handle_local_init(fram,nfx, nfloc, cbck,prgloc,retval,lab) \ do { \ - prog_data_to_nfl (nfx, nfloc, fram, cbck, prgloc); \ + prog_data_to_nfl (nfx, nfloc, fram, cbck, prgloc); \ if (!nfloc) { \ gf_log (GF_NFS,GF_LOG_ERROR,"Failed to init local");\ retval = -ENOMEM; \ @@ -186,12 +175,12 @@ nfs_fop_fsync (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, extern int nfs_fop_write (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, - struct iobuf *srciob, struct iovec *vector, int32_t count, + struct iobref *srciobref, struct iovec *vector, int32_t count, off_t offset, fop_writev_cbk_t cbk, void *local); extern int nfs_fop_open (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, - int32_t flags, fd_t *fd, int32_t wbflags, fop_open_cbk_t cbk, + int32_t flags, fd_t *fd, fop_open_cbk_t cbk, void *local); extern int @@ -239,4 +228,21 @@ extern int nfs_fop_stat (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, fop_stat_cbk_t cbk, void *local); +extern int +nfs_fop_access (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, + int32_t accesstest, fop_access_cbk_t cbk, void *local); + +extern int +nfs_fop_lk (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, + int cmd, struct gf_flock *flock, fop_lk_cbk_t cbk, void *local); + +extern int +nfs_fop_getxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, + char *name, dict_t *xdata, fop_getxattr_cbk_t cbk, void *local); + +extern int +nfs_fop_setxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, + loc_t *loc, dict_t *dict, int32_t flags, dict_t *xdata, + fop_setxattr_cbk_t cbk, void *local); + #endif diff --git a/xlators/nfs/server/src/nfs-generics.c b/xlators/nfs/server/src/nfs-generics.c index eb6dc580b..cb32b7f1b 100644 --- a/xlators/nfs/server/src/nfs-generics.c +++ b/xlators/nfs/server/src/nfs-generics.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _CONFIG_H @@ -46,6 +37,19 @@ nfs_fstat (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, return ret; } +int +nfs_access (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, + int32_t accesstest, fop_access_cbk_t cbk, void *local) +{ + int ret = -EFAULT; + + if ((!nfsx) || (!xl) || (!pathloc) || (!nfu)) + return ret; + + ret = nfs_fop_access (nfsx, xl, nfu, pathloc, accesstest, cbk, local); + + return ret; +} int nfs_stat (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, @@ -83,8 +87,7 @@ nfs_lookup (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, if ((!nfsx) || (!xl) || (!pathloc) || (!nfu)) return ret; - ret = nfs_inode_lookup (nfsx, xl, nfu, pathloc, cbk, local); - + ret = nfs_fop_lookup (nfsx, xl, nfu, pathloc, cbk, local); return ret; } @@ -139,7 +142,6 @@ nfs_truncate (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, return ret; } - int nfs_read (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, size_t size, off_t offset, fop_readv_cbk_t cbk, void *local) @@ -147,6 +149,28 @@ nfs_read (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, size_t size, return nfs_fop_read (nfsx, xl, nfu, fd, size, offset, cbk, local); } +int +nfs_lk (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, + int cmd, struct gf_flock *flock, fop_lk_cbk_t cbk, void *local) +{ + return nfs_fop_lk ( nfsx, xl, nfu, fd, cmd, flock, cbk, local); +} + +int +nfs_getxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, + char *name, dict_t *xdata, fop_getxattr_cbk_t cbk, void *local) +{ + return nfs_fop_getxattr (nfsx, xl, nfu, loc, name, xdata, cbk, local); +} + +int +nfs_setxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, + loc_t *loc, dict_t *dict, int32_t flags, dict_t *xdata, + fop_setxattr_cbk_t cbk, void *local) +{ + return nfs_fop_setxattr (nfsx, xl, nfu, loc, dict, flags, xdata, cbk, + local); +} int nfs_fsync (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, @@ -158,11 +182,11 @@ nfs_fsync (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, int nfs_write (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, - struct iobuf *srciob, struct iovec *vector, int32_t count, + struct iobref *srciobref, struct iovec *vector, int32_t count, off_t offset, fop_writev_cbk_t cbk, void *local) { - return nfs_fop_write (nfsx, xl, nfu, fd, srciob, vector, count, offset, - cbk, local); + return nfs_fop_write (nfsx, xl, nfu, fd, srciobref, vector, count, + offset, cbk, local); } @@ -175,7 +199,7 @@ nfs_open (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, if ((!nfsx) || (!xl) || (!pathloc) || (!nfu)) return ret; - ret = nfs_inode_open (nfsx, xl, nfu, pathloc, flags, GF_OPEN_NOWB, cbk, + ret = nfs_inode_open (nfsx, xl, nfu, pathloc, flags, cbk, local); return ret; } @@ -318,3 +342,4 @@ nfs_opendir (xlator_t *nfsx, xlator_t *fopxl, nfs_user_t *nfu, loc_t *pathloc, return nfs_inode_opendir (nfsx, fopxl, nfu, pathloc, cbk, local); } + diff --git a/xlators/nfs/server/src/nfs-generics.h b/xlators/nfs/server/src/nfs-generics.h index 91915f120..01876d68e 100644 --- a/xlators/nfs/server/src/nfs-generics.h +++ b/xlators/nfs/server/src/nfs-generics.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _NFS_GENERICS_H_ @@ -43,7 +34,7 @@ struct nfs_direntcache { * different NFS versions can simply call a standard interface and have fop * interface dependent functions be handled internally. * This structure is part of such an abstraction. The fops layer stores any - * state is requires in the fd. For eg, the dirent cache for a directory fd_t. + * state is requires in the fd. E.g. the dirent cache for a directory fd_t. */ typedef struct nfs_fop_fdcontext { pthread_mutex_t lock; @@ -92,7 +83,7 @@ nfs_fsync (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, extern int nfs_write (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, - struct iobuf *srciob, struct iovec *vector, int32_t count, + struct iobref *srciobref, struct iovec *vector, int32_t count, off_t offset, fop_writev_cbk_t cbk, void *local); extern int @@ -157,4 +148,21 @@ nfs_read_sync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, size_t size, extern int nfs_opendir (xlator_t *nfsx, xlator_t *fopxl, nfs_user_t *nfu, loc_t *pathloc, fop_opendir_cbk_t cbk, void *local); + +extern int +nfs_access (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, + int32_t accesstest, fop_access_cbk_t cbk, void *local); +extern int +nfs_lk (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, + int cmd, struct gf_flock *flock, fop_lk_cbk_t cbk, void *local); + +extern int +nfs_getxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, + char *name, dict_t *xdata, fop_getxattr_cbk_t cbk, void *local); + +extern int +nfs_setxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, + loc_t *loc, dict_t *dict, int32_t flags, dict_t *xdata, + fop_setxattr_cbk_t cbk, void *local); + #endif diff --git a/xlators/nfs/server/src/nfs-inodes.c b/xlators/nfs/server/src/nfs-inodes.c index a69e1d791..63d5e8a19 100644 --- a/xlators/nfs/server/src/nfs-inodes.c +++ b/xlators/nfs/server/src/nfs-inodes.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _CONFIG_H @@ -36,7 +27,7 @@ do { \ nflocal = fram->local; \ fram->local = nflocal->proglocal; \ - pcbk = nflocal->progcbk; \ + *VOID(&pcbk) = nflocal->progcbk; \ nfs_fop_local_wipe (nflocal->nfsx, nflocal); \ } while (0) \ @@ -57,10 +48,10 @@ nfl_inodes_init (struct nfs_fop_local *nfl, inode_t *inode, inode_t *parent, nfl->newparent = inode_ref (newparent); if (name) - strcpy (nfl->path, name); + strncpy (nfl->path, name, NFS_NAME_MAX); if (newname) - strcpy (nfl->newpath, newname); + strncpy (nfl->newpath, newname, NFS_NAME_MAX); return; } @@ -70,15 +61,16 @@ int32_t nfs_inode_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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = frame->local; fop_create_cbk_t progcbk = NULL; + inode_t *linked_inode = NULL; if (op_ret == -1) goto do_not_link; - inode_link (inode, nfl->parent, nfl->path, buf); + linked_inode = inode_link (inode, nfl->parent, nfl->path, buf); do_not_link: /* NFS does not need it, upper layers should not expect the pointer to @@ -89,7 +81,13 @@ do_not_link: inodes_nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, fd, inode, buf, - preparent, postparent); + preparent, postparent, xdata); + + if (linked_inode) { + inode_lookup (linked_inode); + inode_unref (linked_inode); + } + return 0; } @@ -135,21 +133,27 @@ int32_t nfs_inode_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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = frame->local; fop_mkdir_cbk_t progcbk = NULL; + inode_t *linked_inode = NULL; if (op_ret == -1) goto do_not_link; - inode_link (inode, nfl->parent, nfl->path, buf); + linked_inode = inode_link (inode, nfl->parent, nfl->path, buf); do_not_link: inodes_nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, - preparent, postparent); + preparent, postparent, xdata); + + if (linked_inode) { + inode_lookup (linked_inode); + inode_unref (linked_inode); + } return 0; } @@ -180,7 +184,7 @@ err: int32_t nfs_inode_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, fd_t *fd) + int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; @@ -196,14 +200,14 @@ nfs_inode_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, */ inodes_nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, fd); + progcbk (frame, cookie, this, op_ret, op_errno, fd, xdata); return 0; } int nfs_inode_open (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, - int32_t flags, int32_t wbflags, fop_open_cbk_t cbk, void *local) + int32_t flags, fop_open_cbk_t cbk, void *local) { struct nfs_fop_local *nfl = NULL; fd_t *newfd = NULL; @@ -220,7 +224,7 @@ nfs_inode_open (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, } nfs_fop_handle_local_init (NULL, nfsx, nfl, cbk, local, ret, fd_err); - ret = nfs_fop_open (nfsx, xl, nfu, loc, flags, newfd, wbflags, + ret = nfs_fop_open (nfsx, xl, nfu, loc, flags, newfd, nfs_inode_open_cbk, nfl); if (ret < 0) @@ -242,7 +246,8 @@ int32_t nfs_inode_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 iatt *prenewparent, struct iatt *postnewparent, + dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_rename_cbk_t progcbk = NULL; @@ -259,7 +264,7 @@ do_not_link: if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, buf, preoldparent, postoldparent, prenewparent, - postnewparent); + postnewparent, xdata); return 0; } @@ -292,22 +297,29 @@ int32_t nfs_inode_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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_link_cbk_t progcbk = NULL; + inode_t *linked_inode = NULL; if (op_ret == -1) goto do_not_link; nfl = frame->local; - inode_link (inode, nfl->newparent, nfl->path, buf); + linked_inode = inode_link (inode, nfl->newparent, nfl->path, buf); do_not_link: inodes_nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, - preparent, postparent); + preparent, postparent, xdata); + + if (linked_inode) { + inode_lookup (linked_inode); + inode_unref (linked_inode); + } + return 0; } @@ -336,65 +348,9 @@ err: int32_t -nfs_inode_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 *nfl = NULL; - fop_lookup_cbk_t progcbk = NULL; - inode_t *linked_inode = NULL; - uuid_t rootgfid = {0, }; - - if (op_ret == -1) - goto do_not_link; - - rootgfid[15] = 1; - if (uuid_compare (rootgfid, inode->gfid) == 0) - goto do_not_link; - - nfl = frame->local; - - linked_inode = inode_link (inode, nfl->newparent, nfl->path, buf); - - if (linked_inode) - inode_unref (linked_inode); - -do_not_link: - inodes_nfl_to_prog_data (nfl, progcbk, frame); - if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, - xattr, postparent); - return 0; -} - - -int -nfs_inode_lookup (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, - fop_lookup_cbk_t cbk, void *local) -{ - struct nfs_fop_local *nfl = NULL; - int ret = -EFAULT; - - if ((!nfsx) || (!xl) || (!loc) || (!nfu)) - return -EFAULT; - - nfs_fop_handle_local_init (NULL, nfsx, nfl, cbk, local, ret, err); - nfl_inodes_init (nfl, NULL, NULL, loc->parent, loc->name, NULL); - ret = nfs_fop_lookup (nfsx, xl, nfu, loc, nfs_inode_lookup_cbk, nfl); - -err: - if (ret < 0) - nfs_fop_local_wipe (xl, nfl); - - return ret; -} - - -int32_t nfs_inode_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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_unlink_cbk_t progcbk = NULL; @@ -405,12 +361,13 @@ nfs_inode_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, goto do_not_unlink; inode_unlink (nfl->inode, nfl->parent, nfl->path); + inode_forget (nfl->inode, 0); do_not_unlink: inodes_nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, preparent, - postparent); + postparent, xdata); return 0; } @@ -441,7 +398,7 @@ err: int32_t nfs_inode_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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_rmdir_cbk_t progcbk = NULL; @@ -452,12 +409,13 @@ nfs_inode_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, goto do_not_unlink; inode_unlink (nfl->inode, nfl->parent, nfl->path); + inode_forget (nfl->inode, 0); do_not_unlink: inodes_nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, preparent, - postparent); + postparent, xdata); return 0; } @@ -490,23 +448,30 @@ int32_t nfs_inode_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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_mknod_cbk_t progcbk = NULL; + inode_t *linked_inode = NULL; nfl = frame->local; if (op_ret == -1) goto do_not_link; - inode_link (inode, nfl->parent, nfl->path, buf); + linked_inode = inode_link (inode, nfl->parent, nfl->path, buf); do_not_link: inodes_nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, - preparent, postparent); + preparent, postparent, xdata); + + if (linked_inode) { + inode_lookup (linked_inode); + inode_unref (linked_inode); + } + return 0; } @@ -540,22 +505,28 @@ int32_t nfs_inode_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 iatt *postparent, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_symlink_cbk_t progcbk = NULL; + inode_t *linked_inode = NULL; nfl = frame->local; if (op_ret == -1) goto do_not_link; - inode_link (inode, nfl->parent, nfl->path, buf); + linked_inode = inode_link (inode, nfl->parent, nfl->path, buf); do_not_link: inodes_nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) progcbk (frame, cookie, this, op_ret, op_errno, inode, buf, - preparent, postparent); + preparent, postparent, xdata); + + if (linked_inode) { + inode_lookup (linked_inode); + inode_unref (linked_inode); + } return 0; } @@ -586,21 +557,20 @@ err: int32_t nfs_inode_opendir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, fd_t *fd) + int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata) { struct nfs_fop_local *nfl = NULL; fop_open_cbk_t progcbk = NULL; - if ((op_ret == -1) && (fd)) - fd_unref (fd); - else + if (op_ret != -1) fd_bind (fd); inodes_nfl_to_prog_data (nfl, progcbk, frame); if (progcbk) - progcbk (frame, cookie, this, op_ret, op_errno, fd); + progcbk (frame, cookie, this, op_ret, op_errno, fd, xdata); + return 0; } diff --git a/xlators/nfs/server/src/nfs-inodes.h b/xlators/nfs/server/src/nfs-inodes.h index a34a26738..ba7a57124 100644 --- a/xlators/nfs/server/src/nfs-inodes.h +++ b/xlators/nfs/server/src/nfs-inodes.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _NFS_INODES_H_ @@ -48,7 +39,7 @@ nfs_inode_mkdir (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, extern int nfs_inode_open (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, - int32_t flags, int32_t wbflags, fop_open_cbk_t cbk, + int32_t flags, fop_open_cbk_t cbk, void *local); extern int diff --git a/xlators/nfs/server/src/nfs-mem-types.h b/xlators/nfs/server/src/nfs-mem-types.h index 0909a7fb8..450b6f2fe 100644 --- a/xlators/nfs/server/src/nfs-mem-types.h +++ b/xlators/nfs/server/src/nfs-mem-types.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2008-2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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. */ @@ -37,12 +28,25 @@ enum gf_nfs_mem_types_ { gf_nfs_mt_entry3, gf_nfs_mt_entryp3, gf_nfs_mt_nfs3_fd_entry, + gf_nfs_mt_nfs3_fh, gf_nfs_mt_nfs_initer_list, gf_nfs_mt_xlator_t, gf_nfs_mt_list_head, gf_nfs_mt_mnt3_resolve, gf_nfs_mt_mnt3_export, + gf_nfs_mt_int, + gf_nfs_mt_mountres3, + gf_nfs_mt_mountstat3, gf_nfs_mt_inode_q, + gf_nfs_mt_nlm4_state, + gf_nfs_mt_nlm4_cm, + gf_nfs_mt_nlm4_fde, + gf_nfs_mt_nlm4_nlmclnt, + gf_nfs_mt_nlm4_share, + gf_nfs_mt_aux_gids, + gf_nfs_mt_inode_ctx, + gf_nfs_mt_auth_spec, + gf_nfs_mt_arr, gf_nfs_mt_end }; #endif diff --git a/xlators/nfs/server/src/nfs.c b/xlators/nfs/server/src/nfs.c index 3dbb0bc45..75c8fe44e 100644 --- a/xlators/nfs/server/src/nfs.c +++ b/xlators/nfs/server/src/nfs.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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. */ /* This is the primary translator source for NFS. @@ -39,6 +30,209 @@ #include "mount3.h" #include "nfs3.h" #include "nfs-mem-types.h" +#include "nfs3-helpers.h" +#include "nlm4.h" +#include "options.h" +#include "acl3.h" +#include "rpc-drc.h" + +#define STRINGIFY(val) #val +#define TOSTRING(val) STRINGIFY(val) + +#define OPT_SERVER_AUX_GIDS "nfs.server-aux-gids" +#define OPT_SERVER_GID_CACHE_TIMEOUT "nfs.server.aux-gid-timeout" + +/* TODO: DATADIR should be based on configure's $(localstatedir) */ +#define DATADIR "/var/lib/glusterd" +#define NFS_DATADIR DATADIR "/nfs" + +/* Forward declaration */ +int nfs_add_initer (struct list_head *list, nfs_version_initer_t init); + +static int +nfs_init_version (xlator_t *this, nfs_version_initer_t init) +{ + int ret = -1; + struct nfs_initer_list *version = NULL; + struct nfs_initer_list *tmp = NULL; + rpcsvc_program_t *prog = NULL; + struct list_head *versions = NULL; + struct nfs_state *nfs = NULL; + gf_boolean_t found = _gf_false; + + if ((!this) || (!this->private) || (!init)) + return (-1); + + nfs = (struct nfs_state *)this->private; + + ret = nfs_add_initer (&nfs->versions, init); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, + "Failed to add protocol initializer"); + goto err; + } + + versions = &nfs->versions; + list_for_each_entry_safe (version, tmp, versions, list) { + prog = version->program; + if (version->init == init) { + prog = init(this); + if (!prog) { + ret = -1; + goto err; + } + version->program = prog; + found = _gf_true; + break; + } + } + + /* program not added */ + if (!found) { + gf_log (GF_NFS, GF_LOG_ERROR, + "Program: %s NOT found", prog->progname); + goto err; + } + + /* Check if nfs.port is configured */ + if (nfs->override_portnum) + prog->progport = nfs->override_portnum; + + gf_log (GF_NFS, GF_LOG_DEBUG, "Starting program: %s", prog->progname); + + ret = rpcsvc_program_register (nfs->rpcsvc, prog); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "Program: %s init failed", + prog->progname); + goto err; + } + + /* Registration with portmapper is disabled, Nothing to do */ + if (!nfs->register_portmap) + goto err; + + ret = rpcsvc_program_register_portmap (prog, prog->progport); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, + "Program %s registration failed", + prog->progname); + goto err; + } + ret = 0; /* All well */ +err: + return ret; +} + +static int +nfs_deinit_version (struct nfs_state *nfs, nfs_version_initer_t init) +{ + int ret = -1; + struct nfs_initer_list *version = NULL; + struct nfs_initer_list *tmp = NULL; + rpcsvc_program_t *prog = NULL; + struct list_head *versions = NULL; + + if ((!nfs) || (!init)) + return (-1); + + versions = &nfs->versions; + list_for_each_entry_safe (version, tmp, versions, list) { + prog = version->program; + if (version->init == init) { + prog = version->program; + ret = rpcsvc_program_unregister (nfs->rpcsvc, prog); + if (ret != 0) + return (-1); + list_del (&version->list); + GF_FREE (version); + return (0); + } + } + + return (-1); +} + +static int +nfs_reconfigure_acl3 (xlator_t *this) +{ + struct nfs_state *nfs = NULL; + + if ((!this) || (!this->private)) + return (-1); + + nfs = (struct nfs_state *)this->private; + + /* ACL is enabled */ + if (nfs->enable_acl) + return nfs_init_version (this, acl3svc_init); + + /* ACL is disabled */ + return nfs_deinit_version (nfs, acl3svc_init); +} + +static int +nfs_reconfigure_nlm4 (xlator_t *this) +{ + struct nfs_state *nfs = NULL; + + if ((!this) || (!this->private)) + return (-1); + + nfs = (struct nfs_state *)this->private; + + /* NLM is enabled */ + if (nfs->enable_nlm) + return nfs_init_version (this, nlm4svc_init); + + /* NLM is disabled */ + return nfs_deinit_version (nfs, nlm4svc_init); +} + +static int +nfs_program_register_portmap_all (struct nfs_state *nfs) +{ + struct list_head *versions = NULL; + struct nfs_initer_list *version = NULL; + struct nfs_initer_list *tmp = NULL; + rpcsvc_program_t *prog = NULL; + + if (nfs == NULL) + return (-1); + + versions = &nfs->versions; + list_for_each_entry_safe (version, tmp, versions, list) { + prog = version->program; + if (prog == NULL) + continue; + if (nfs->override_portnum) + prog->progport = nfs->override_portnum; + (void) rpcsvc_program_register_portmap (prog, prog->progport); + } + + return (0); +} + +static int +nfs_program_unregister_portmap_all (struct nfs_state *nfs) +{ + struct list_head *versions = NULL; + struct nfs_initer_list *version = NULL; + struct nfs_initer_list *tmp = NULL; + rpcsvc_program_t *prog = NULL; + + if (nfs == NULL) + return (-1); + + versions = &nfs->versions; + list_for_each_entry_safe (version, tmp, versions, list) { + prog = version->program; + if (prog == NULL) + continue; + (void) rpcsvc_program_unregister_portmap (prog); + } + + return (0); +} /* Every NFS version must call this function with the init function * for its particular version. @@ -81,8 +275,8 @@ nfs_deinit_versions (struct list_head *versions, xlator_t *this) version->deinit (this); */ if (version->program) - nfs_rpcsvc_program_unregister (nfs->rpcsvc, - *(version->program)); + rpcsvc_program_unregister (nfs->rpcsvc, + (version->program)); list_del (&version->list); GF_FREE (version); @@ -91,7 +285,6 @@ nfs_deinit_versions (struct list_head *versions, xlator_t *this) return 0; } - int nfs_init_versions (struct nfs_state *nfs, xlator_t *this) { @@ -113,20 +306,34 @@ nfs_init_versions (struct nfs_state *nfs, xlator_t *this) } prog = version->init (this); - prog->actorxl = this; - version->program = prog; if (!prog) { ret = -1; goto err; } + version->program = prog; + if (nfs->override_portnum) + prog->progport = nfs->override_portnum; gf_log (GF_NFS, GF_LOG_DEBUG, "Starting program: %s", prog->progname); - ret = nfs_rpcsvc_program_register (nfs->rpcsvc, *prog); + + ret = rpcsvc_program_register (nfs->rpcsvc, prog); if (ret == -1) { - gf_log (GF_NFS, GF_LOG_ERROR, "Program init failed"); + gf_log (GF_NFS, GF_LOG_ERROR, "Program: %s init failed", + prog->progname); goto err; } + if (nfs->register_portmap) { + ret = rpcsvc_program_register_portmap (prog, + prog->progport); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, + "Program %s registration failed", + prog->progname); + goto err; + } + } + } ret = 0; @@ -143,25 +350,43 @@ nfs_add_all_initiators (struct nfs_state *nfs) /* Add the initializers for all versions. */ ret = nfs_add_initer (&nfs->versions, mnt3svc_init); if (ret == -1) { - gf_log (GF_NFS, GF_LOG_ERROR, "Failed to add protocol" - " initializer"); + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to add " + "MOUNT3 protocol initializer"); goto ret; } ret = nfs_add_initer (&nfs->versions, mnt1svc_init); if (ret == -1) { - gf_log (GF_NFS, GF_LOG_ERROR, "Failed to add protocol" - " initializer"); + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to add " + "MOUNT1 protocol initializer"); goto ret; } ret = nfs_add_initer (&nfs->versions, nfs3svc_init); if (ret == -1) { - gf_log (GF_NFS, GF_LOG_ERROR, "Failed to add protocol" - " initializer"); + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to add " + "NFS3 protocol initializer"); goto ret; } + if (nfs->enable_nlm == _gf_true) { + ret = nfs_add_initer (&nfs->versions, nlm4svc_init); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to add protocol" + " initializer"); + goto ret; + } + } + + if (nfs->enable_acl == _gf_true) { + ret = nfs_add_initer (&nfs->versions, acl3svc_init); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to add " + "ACL protocol initializer"); + goto ret; + } + } + ret = 0; ret: return ret; @@ -204,6 +429,13 @@ nfs_subvolume_set_started (struct nfs_state *nfs, xlator_t *xl) LOCK (&nfs->svinitlock); { for (;x < nfs->allsubvols; ++x) { + if (nfs->initedxl[x] == xl) { + gf_log (GF_NFS, GF_LOG_DEBUG, + "Volume already started %s", + xl->name); + break; + } + if (nfs->initedxl[x] == NULL) { nfs->initedxl[x] = xl; ++nfs->upsubvols; @@ -233,6 +465,7 @@ nfs_start_subvol_lookup_cbk (call_frame_t *frame, void *cookie, goto err; } + nfs_subvolume_set_started (this->private, ((xlator_t *)cookie)); gf_log (GF_NFS, GF_LOG_TRACE, "Started %s", ((xlator_t *)cookie)->name); err: return 0; @@ -256,8 +489,7 @@ nfs_startup_subvolume (xlator_t *nfsx, xlator_t *xl) goto err; } - nfs_subvolume_set_started (nfsx->private, xl); - ret = nfs_inode_loc_fill (xl->itable->root, &rootloc); + ret = nfs_root_loc_fill (xl->itable, &rootloc); if (ret == -1) { gf_log (GF_NFS, GF_LOG_CRITICAL, "Failed to init root loc"); goto err; @@ -358,7 +590,7 @@ nfs_init_subvolumes (struct nfs_state *nfs, xlator_list_t *cl) } LOCK_INIT (&nfs->svinitlock); - nfs->initedxl = GF_CALLOC (svcount, sizeof (xlator_t *), + nfs->initedxl = GF_CALLOC (svcount, sizeof (xlator_t *), gf_nfs_mt_xlator_t ); if (!nfs->initedxl) { gf_log (GF_NFS, GF_LOG_ERROR, "Failed to allocated inited xls"); @@ -431,13 +663,30 @@ nfs_request_user_init (nfs_user_t *nfu, rpcsvc_request_t *req) if ((!req) || (!nfu)) return; - gidarr = nfs_rpcsvc_auth_unix_auxgids (req, &gids); - nfs_user_create (nfu, nfs_rpcsvc_request_uid (req), - nfs_rpcsvc_request_gid (req), gidarr, gids); + gidarr = rpcsvc_auth_unix_auxgids (req, &gids); + nfs_user_create (nfu, rpcsvc_request_uid (req), + rpcsvc_request_gid (req), gidarr, gids); return; } +void +nfs_request_primary_user_init (nfs_user_t *nfu, rpcsvc_request_t *req, + uid_t uid, gid_t gid) +{ + gid_t *gidarr = NULL; + int gids = 0; + + if ((!req) || (!nfu)) + return; + + gidarr = rpcsvc_auth_unix_auxgids (req, &gids); + nfs_user_create (nfu, uid, gid, gidarr, gids); + + return; +} + + int32_t mem_acct_init (xlator_t *this) { @@ -447,7 +696,7 @@ mem_acct_init (xlator_t *this) return ret; ret = xlator_mem_acct_init (this, gf_nfs_mt_end + 1); - + if (ret != 0) { gf_log(this->name, GF_LOG_ERROR, "Memory accounting init" "failed"); @@ -466,14 +715,16 @@ nfs_init_state (xlator_t *this) unsigned int fopspoolsize = 0; char *optstr = NULL; gf_boolean_t boolt = _gf_false; + struct stat stbuf = {0,}; if (!this) return NULL; - if ((!this->children) || (!this->children->xlator)) { - gf_log (GF_NFS, GF_LOG_ERROR, "nfs must have at least one" - " child subvolume"); - return NULL; + if (!this->children) { + gf_log (GF_NFS, GF_LOG_INFO, + "NFS is manually disabled: Exiting"); + /* Nothing for nfs process to do, exit cleanly */ + kill (getpid (), SIGTERM); } nfs = GF_CALLOC (1, sizeof (*nfs), gf_nfs_mt_nfs_state); @@ -482,15 +733,23 @@ nfs_init_state (xlator_t *this) return NULL; } - /* RPC service needs to be started before NFS versions can be - * inited. */ - nfs->rpcsvc = nfs_rpcsvc_init (this->ctx, this->options); - if (!nfs->rpcsvc) { - gf_log (GF_NFS, GF_LOG_ERROR, "RPC service init failed"); - goto free_nfs; + nfs->memfactor = GF_NFS_DEFAULT_MEMFACTOR; + if (dict_get (this->options, "nfs.mem-factor")) { + ret = dict_get_str (this->options, "nfs.mem-factor", + &optstr); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to parse dict"); + goto free_rpcsvc; + } + + ret = gf_string2uint (optstr, &nfs->memfactor); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to parse uint " + "string"); + goto free_rpcsvc; + } } - nfs->memfactor = GF_NFS_DEFAULT_MEMFACTOR; fopspoolsize = nfs->memfactor * GF_NFS_CONCURRENT_OPS_MULT; /* FIXME: Really saddens me to see this as xlator wide. */ nfs->foppool = mem_pool_new (struct nfs_fop_local, fopspoolsize); @@ -520,6 +779,20 @@ nfs_init_state (xlator_t *this) nfs->dynamicvolumes = GF_NFS_DVM_ON; } + nfs->enable_nlm = _gf_true; + ret = dict_get_str_boolean (this->options, "nfs.nlm", _gf_true); + if (ret == _gf_false) { + gf_log (GF_NFS, GF_LOG_INFO, "NLM is manually disabled"); + nfs->enable_nlm = _gf_false; + } + + nfs->enable_acl = _gf_true; + ret = dict_get_str_boolean (this->options, "nfs.acl", _gf_true); + if (ret == _gf_false) { + gf_log (GF_NFS, GF_LOG_INFO, "ACL is manually disabled"); + nfs->enable_acl = _gf_false; + } + nfs->enable_ino32 = 0; if (dict_get (this->options, "nfs.enable-ino32")) { ret = dict_get_str (this->options, "nfs.enable-ino32", @@ -539,8 +812,165 @@ nfs_init_state (xlator_t *this) if (boolt == _gf_true) nfs->enable_ino32 = 1; } + + if (dict_get (this->options, "nfs.port")) { + ret = dict_get_str (this->options, "nfs.port", + &optstr); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to parse dict"); + goto free_foppool; + } + + ret = gf_string2uint (optstr, &nfs->override_portnum); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to parse uint " + "string"); + goto free_foppool; + } + } + + if (dict_get(this->options, "transport.socket.listen-port") == NULL) { + if (nfs->override_portnum) + ret = gf_asprintf (&optstr, "%d", + nfs->override_portnum); + else + ret = gf_asprintf (&optstr, "%d", GF_NFS3_PORT); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "failed mem-allocation"); + goto free_foppool; + } + ret = dict_set_dynstr (this->options, + "transport.socket.listen-port", optstr); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "dict_set_dynstr error"); + goto free_foppool; + } + } + + if (dict_get(this->options, "transport-type") == NULL) { + ret = dict_set_str (this->options, "transport-type", "socket"); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "dict_set_str error"); + goto free_foppool; + } + } + + nfs->mount_udp = 0; + if (dict_get(this->options, "nfs.mount-udp")) { + ret = dict_get_str (this->options, "nfs.mount-udp", &optstr); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to parse dict"); + goto free_foppool; + } + + ret = gf_string2boolean (optstr, &boolt); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to parse bool " + "string"); + goto free_foppool; + } + + if (boolt == _gf_true) + nfs->mount_udp = 1; + } + + nfs->rmtab = gf_strdup (NFS_DATADIR "/rmtab"); + if (dict_get(this->options, "nfs.mount-rmtab")) { + ret = dict_get_str (this->options, "nfs.mount-rmtab", &nfs->rmtab); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to parse dict"); + goto free_foppool; + } + } + + /* support both options rpc-auth.ports.insecure and + * rpc-auth-allow-insecure for backward compatibility + */ + nfs->allow_insecure = 1; + if (dict_get(this->options, "rpc-auth.ports.insecure")) { + ret = dict_get_str (this->options, "rpc-auth.ports.insecure", + &optstr); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to parse dict"); + goto free_foppool; + } + + ret = gf_string2boolean (optstr, &boolt); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to parse bool " + "string"); + goto free_foppool; + } + + if (boolt == _gf_false) + nfs->allow_insecure = 0; + } + + if (dict_get(this->options, "rpc-auth-allow-insecure")) { + ret = dict_get_str (this->options, "rpc-auth-allow-insecure", + &optstr); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to parse dict"); + goto free_foppool; + } + + ret = gf_string2boolean (optstr, &boolt); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to parse bool " + "string"); + goto free_foppool; + } + + if (boolt == _gf_false) + nfs->allow_insecure = 0; + } + + if (nfs->allow_insecure) { + /* blindly set both the options */ + dict_del (this->options, "rpc-auth-allow-insecure"); + ret = dict_set_str (this->options, + "rpc-auth-allow-insecure", "on"); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "dict_set_str error"); + goto free_foppool; + } + dict_del (this->options, "rpc-auth.ports.insecure"); + ret = dict_set_str (this->options, + "rpc-auth.ports.insecure", "on"); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "dict_set_str error"); + goto free_foppool; + } + } + + GF_OPTION_INIT (OPT_SERVER_AUX_GIDS, nfs->server_aux_gids, + bool, free_foppool); + GF_OPTION_INIT (OPT_SERVER_GID_CACHE_TIMEOUT, nfs->server_aux_gids_max_age, + uint32, free_foppool); + + if (gid_cache_init(&nfs->gid_cache, nfs->server_aux_gids_max_age) < 0) { + gf_log(GF_NFS, GF_LOG_ERROR, "Failed to initialize group cache."); + goto free_foppool; + } + + if (stat("/sbin/rpc.statd", &stbuf) == -1) { + gf_log (GF_NFS, GF_LOG_WARNING, "/sbin/rpc.statd not found. " + "Disabling NLM"); + nfs->enable_nlm = _gf_false; + } + + nfs->rpcsvc = rpcsvc_init (this, this->ctx, this->options, 0); + if (!nfs->rpcsvc) { + ret = -1; + gf_log (GF_NFS, GF_LOG_ERROR, "RPC service init failed"); + goto free_foppool; + } + + nfs->register_portmap = rpcsvc_register_portmap_enabled (nfs->rpcsvc); + this->private = (void *)nfs; INIT_LIST_HEAD (&nfs->versions); + nfs->generation = 1965; ret = 0; @@ -551,7 +981,6 @@ free_foppool: free_rpcsvc: /* * rpcsvc_deinit */ -free_nfs: if (ret < 0) { GF_FREE (nfs); nfs = NULL; @@ -561,36 +990,243 @@ free_nfs: } int -validate_options (xlator_t *this, dict_t *options, char **op_errstr) +nfs_drc_init (xlator_t *this) { - char *str=NULL; - gf_boolean_t nfs_ino32; + int ret = -1; + rpcsvc_t *svc = NULL; - int ret = 0; + svc = ((struct nfs_state *)(this->private))->rpcsvc; + if (!svc) + goto out; + ret = rpcsvc_drc_init (svc, this->options); + out: + return ret; +} - ret = dict_get_str (options, "nfs.enable-ino32", - &str); - if (ret == 0) { - ret = gf_string2boolean (str, - &nfs_ino32); - if (ret == -1) { - gf_log (this->name, GF_LOG_WARNING, - "'nfs.enable-ino32' takes only boolean" - " arguments"); - *op_errstr = gf_strdup ("Error, should be boolean"); - ret = -1; +int +nfs_reconfigure_state (xlator_t *this, dict_t *options) +{ + int ret = 0; + int keyindx = 0; + char *optstr = NULL; + gf_boolean_t optbool; + uint32_t optuint32; + struct nfs_state *nfs = NULL; + char *blacklist_keys[] = { + "nfs.port", + "nfs.transport-type", + "nfs.mem-factor", + NULL}; + + GF_VALIDATE_OR_GOTO (GF_NFS, this, out); + GF_VALIDATE_OR_GOTO (GF_NFS, this->private, out); + GF_VALIDATE_OR_GOTO (GF_NFS, options, out); + + nfs = (struct nfs_state *)this->private; + + /* Black listed options can't be reconfigured, they need + * NFS to be restarted. There are two cases 1. SET 2. UNSET. + * 1. SET */ + while (blacklist_keys[keyindx]) { + if (dict_get (options, blacklist_keys[keyindx])) { + gf_log (GF_NFS, GF_LOG_ERROR, + "Reconfiguring %s needs NFS restart", + blacklist_keys[keyindx]); goto out; } + keyindx ++; + } + + /* UNSET for nfs.mem-factor */ + if ((!dict_get (options, "nfs.mem-factor")) && + (nfs->memfactor != GF_NFS_DEFAULT_MEMFACTOR)) { + gf_log (GF_NFS, GF_LOG_INFO, + "Reconfiguring nfs.mem-factor needs NFS restart"); + goto out; + } + + /* UNSET for nfs.port */ + if ((!dict_get (options, "nfs.port")) && + (nfs->override_portnum)) { + gf_log (GF_NFS, GF_LOG_ERROR, + "Reconfiguring nfs.port needs NFS restart"); + goto out; + } + + /* reconfig nfs.mount-rmtab */ + optstr = NFS_DATADIR "/rmtab"; + if (dict_get (options, "nfs.mount-rmtab")) { + ret = dict_get_str (options, "nfs.mount-rmtab", &optstr); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to read " + "reconfigured option: nfs.mount-rmtab"); + goto out; + } + gf_path_strip_trailing_slashes (optstr); + } + if (strcmp (nfs->rmtab, optstr) != 0) { + mount_rewrite_rmtab (nfs->mstate, optstr); + gf_log (GF_NFS, GF_LOG_INFO, + "Reconfigured nfs.mount-rmtab path: %s", + nfs->rmtab); + } + + GF_OPTION_RECONF (OPT_SERVER_AUX_GIDS, optbool, + options, bool, out); + if (nfs->server_aux_gids != optbool) { + nfs->server_aux_gids = optbool; + gf_log(GF_NFS, GF_LOG_INFO, "Reconfigured %s with value %d", + OPT_SERVER_AUX_GIDS, optbool); + } + + GF_OPTION_RECONF (OPT_SERVER_GID_CACHE_TIMEOUT, optuint32, + options, uint32, out); + if (nfs->server_aux_gids_max_age != optuint32) { + nfs->server_aux_gids_max_age = optuint32; + gid_cache_reconf (&nfs->gid_cache, optuint32); + gf_log(GF_NFS, GF_LOG_INFO, "Reconfigured %s with value %d", + OPT_SERVER_GID_CACHE_TIMEOUT, optuint32); + } + + /* reconfig nfs.dynamic-volumes */ + ret = dict_get_str_boolean (options, "nfs.dynamic-volumes", + GF_NFS_DVM_OFF); + switch (ret) { + case GF_NFS_DVM_ON: + case GF_NFS_DVM_OFF: + optbool = ret; + break; + default: + optbool = GF_NFS_DVM_OFF; + break; + } + if (nfs->dynamicvolumes != optbool) { + nfs->dynamicvolumes = optbool; + gf_log(GF_NFS, GF_LOG_INFO, "Reconfigured nfs.dynamic-volumes" + " with value %d", optbool); + } + + optbool = _gf_false; + if (dict_get (options, "nfs.enable-ino32")) { + ret = dict_get_str_boolean (options, "nfs.enable-ino32", + _gf_false); + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, + "Failed to read reconfigured option: " + "nfs.enable-ino32"); + goto out; + } + optbool = ret; + } + if (nfs->enable_ino32 != optbool) { + nfs->enable_ino32 = optbool; + gf_log(GF_NFS, GF_LOG_INFO, "Reconfigured nfs.enable-ino32" + " with value %d", optbool); } - ret =0; -out: - return ret; + /* nfs.nlm is enabled by default */ + ret = dict_get_str_boolean (options, "nfs.nlm", _gf_true); + if (ret < 0) { + optbool = _gf_true; + } else { + optbool = ret; + } + if (nfs->enable_nlm != optbool) { + gf_log (GF_NFS, GF_LOG_INFO, "NLM is manually %s", + (optbool ? "enabled":"disabled")); + nfs->enable_nlm = optbool; + nfs_reconfigure_nlm4 (this); + } + + /* nfs.acl is enabled by default */ + ret = dict_get_str_boolean (options, "nfs.acl", _gf_true); + if (ret < 0) { + optbool = _gf_true; + } else { + optbool = ret; + } + if (nfs->enable_acl != optbool) { + gf_log (GF_NFS, GF_LOG_INFO, "ACL is manually %s", + (optbool ? "enabled":"disabled")); + nfs->enable_acl = optbool; + nfs_reconfigure_acl3 (this); + } + + ret = 0; +out: + return ret; } +/* + * reconfigure() for NFS server xlator. + */ +int +reconfigure (xlator_t *this, dict_t *options) +{ + int ret = 0; + struct nfs_state *nfs = NULL; + gf_boolean_t regpmap = _gf_true; + + if ((!this) || (!this->private) || (!options)) + return (-1); + + nfs = (struct nfs_state *)this->private; + + /* Reconfigure nfs options */ + ret = nfs_reconfigure_state(this, options); + if (ret) { + gf_log (GF_NFS, GF_LOG_ERROR, + "nfs reconfigure state failed"); + return (-1); + } + + /* Reconfigure nfs3 options */ + ret = nfs3_reconfigure_state(this, options); + if (ret) { + gf_log (GF_NFS, GF_LOG_ERROR, + "nfs3 reconfigure state failed"); + return (-1); + } + + /* Reconfigure mount options */ + ret = mount_reconfigure_state(this, options); + if (ret) { + gf_log (GF_NFS, GF_LOG_ERROR, + "mount reconfigure state failed"); + return (-1); + } + + /* Reconfigure rpc layer */ + ret = rpcsvc_reconfigure_options (nfs->rpcsvc, options); + if (ret) { + gf_log (GF_NFS, GF_LOG_ERROR, + "rpcsvc reconfigure options failed"); + return (-1); + } + regpmap = rpcsvc_register_portmap_enabled(nfs->rpcsvc); + if (nfs->register_portmap != regpmap) { + nfs->register_portmap = regpmap; + if (regpmap) { + (void) nfs_program_register_portmap_all (nfs); + } else { + (void) nfs_program_unregister_portmap_all (nfs); + } + } + + /* Reconfigure drc */ + ret = rpcsvc_drc_reconfigure (nfs->rpcsvc, options); + if (ret) { + gf_log (GF_NFS, GF_LOG_ERROR, + "rpcsvc DRC reconfigure failed"); + return (-1); + } + + return (0); +} + int init (xlator_t *this) { @@ -619,10 +1255,36 @@ init (xlator_t *this) { goto err; } - ret = 0; -err: + ret = mount_init_state (this); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_CRITICAL, "Failed to init Mount" + "state"); + goto err; + } + + ret = nlm4_init_state (this); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_CRITICAL, "Failed to init NLM" + "state"); + goto err; + } + + ret = nfs_init_versions (nfs, this); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to initialize " + "protocols"); + /* Do not return an error on this. If we dont return + * an error, the process keeps running and it helps + * to point out where the log is by doing ps ax|grep gluster. + */ + ret = 0; + goto err; + } + + ret = nfs_drc_init (this); if (ret == 0) gf_log (GF_NFS, GF_LOG_INFO, "NFS service started"); +err: return ret; } @@ -631,39 +1293,27 @@ err: int notify (xlator_t *this, int32_t event, void *data, ...) { - struct nfs_state *nfs = NULL; xlator_t *subvol = NULL; - int ret = -1; + struct nfs_state *priv = NULL; - nfs = (struct nfs_state *)this->private; subvol = (xlator_t *)data; gf_log (GF_NFS, GF_LOG_TRACE, "Notification received: %d", event); - switch (event) - { - case GF_EVENT_CHILD_UP: - { - nfs_startup_subvolume (this, subvol); - if ((nfs->upsubvols == nfs->allsubvols) && - (!nfs->subvols_started)) { - nfs->subvols_started = 1; - gf_log (GF_NFS, GF_LOG_TRACE, "All children up," - " starting RPC"); - ret = nfs_init_versions (nfs, this); - if (ret == -1) - gf_log (GF_NFS, GF_LOG_CRITICAL, - "Failed to initialize " - "protocols"); - } - break; - } - case GF_EVENT_PARENT_UP: - { - default_notify (this, GF_EVENT_PARENT_UP, data); - break; - } + switch (event) { + case GF_EVENT_CHILD_UP: + nfs_startup_subvolume (this, subvol); + break; + + case GF_EVENT_CHILD_MODIFIED: + priv = this->private; + ++(priv->generation); + break; + + case GF_EVENT_PARENT_UP: + default_notify (this, GF_EVENT_PARENT_UP, data); + break; } return 0; @@ -682,8 +1332,141 @@ fini (xlator_t *this) return 0; } -struct xlator_cbks cbks = { }; -struct xlator_fops fops = { }; +int32_t +nfs_forget (xlator_t *this, inode_t *inode) +{ + uint64_t ctx = 0; + struct nfs_inode_ctx *ictx = NULL; + + if (inode_ctx_del (inode, this, &ctx)) + return -1; + + ictx = (struct nfs_inode_ctx *)ctx; + GF_FREE (ictx); + + return 0; +} + +gf_boolean_t +_nfs_export_is_for_vol (char *exname, char *volname) +{ + gf_boolean_t ret = _gf_false; + char *tmp = NULL; + + tmp = exname; + if (tmp[0] == '/') + tmp++; + + if (!strcmp (tmp, volname)) + ret = _gf_true; + + return ret; +} + +int +nfs_priv_to_dict (xlator_t *this, dict_t *dict) +{ + int ret = -1; + struct nfs_state *priv = NULL; + struct mountentry *mentry = NULL; + char *volname = NULL; + char key[1024] = {0,}; + int count = 0; + + GF_VALIDATE_OR_GOTO (THIS->name, this, out); + GF_VALIDATE_OR_GOTO (THIS->name, dict, out); + + priv = this->private; + GF_ASSERT (priv); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Could not get volname"); + goto out; + } + + list_for_each_entry (mentry, &priv->mstate->mountlist, mlist) { + if (!_nfs_export_is_for_vol (mentry->exname, volname)) + continue; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "client%d.hostname", count); + ret = dict_set_str (dict, key, mentry->hostname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Error writing hostname to dict"); + goto out; + } + + /* No connection data available yet in nfs server. + * Hence, setting to 0 to prevent cli failing + */ + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "client%d.bytesread", count); + ret = dict_set_uint64 (dict, key, 0); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Error writing bytes read to dict"); + goto out; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "client%d.byteswrite", count); + ret = dict_set_uint64 (dict, key, 0); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Error writing bytes write to dict"); + goto out; + } + + count++; + } + + ret = dict_set_int32 (dict, "clientcount", count); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Error writing client count to dict"); + +out: + gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +extern int32_t +nlm_priv (xlator_t *this); + +int32_t +nfs_priv (xlator_t *this) +{ + int32_t ret = -1; + + /* DRC needs the global drc structure, xl is of no use to it. */ + ret = rpcsvc_drc_priv (((struct nfs_state *)(this->private))->rpcsvc->drc); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, "Statedump of DRC failed"); + goto out; + } + + ret = nlm_priv (this); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, "Statedump of NLM failed"); + goto out; + } + out: + return ret; +} + + +struct xlator_cbks cbks = { + .forget = nfs_forget, +}; + +struct xlator_fops fops; + +struct xlator_dumpops dumpops = { + .priv = nfs_priv, + .priv_to_dict = nfs_priv_to_dict, +}; /* TODO: If needed, per-volume options below can be extended to be export + * specific also because after export-dir is introduced, a volume is not @@ -693,28 +1476,53 @@ struct xlator_fops fops = { }; struct volume_options options[] = { { .key = {"nfs3.read-size"}, .type = GF_OPTION_TYPE_SIZET, - .description = "Size in which the client should issue read requests" - " to the Gluster NFSv3 server. Must be a multiple of" - " 4KiB." + .min = GF_NFS3_RTMIN, + .max = GF_NFS3_RTMAX, + .default_value = TOSTRING(GF_NFS3_RTPREF), + .description = "Size in which the client should issue read requests " + "to the Gluster NFSv3 server. Must be a multiple of " + "4KB (4096). Min and Max supported values are 4KB " + "(4096) and 1MB (1048576) respectively. If the " + "specified value is within the supported range but " + "not a multiple of 4096, it is rounded up to the " + "nearest multiple of 4096." }, { .key = {"nfs3.write-size"}, .type = GF_OPTION_TYPE_SIZET, - .description = "Size in which the client should issue write requests" - " to the Gluster NFSv3 server. Must be a multiple of" - " 4KiB." + .min = GF_NFS3_WTMIN, + .max = GF_NFS3_WTMAX, + .default_value = TOSTRING(GF_NFS3_WTPREF), + .description = "Size in which the client should issue write requests " + "to the Gluster NFSv3 server. Must be a multiple of " + "1KB (1024). Min and Max supported values are " + "4KB (4096) and 1MB(1048576) respectively. If the " + "specified value is within the supported range but " + "not a multiple of 4096, it is rounded up to the " + "nearest multiple of 4096." }, { .key = {"nfs3.readdir-size"}, .type = GF_OPTION_TYPE_SIZET, + .min = GF_NFS3_DTMIN, + .max = GF_NFS3_DTMAX, + .default_value = TOSTRING(GF_NFS3_DTPREF), .description = "Size in which the client should issue directory " - " reading requests." + "reading requests to the Gluster NFSv3 server. Must " + "be a multiple of 1KB (1024). Min and Max supported " + "values are 4KB (4096) and 1MB (1048576) respectively." + "If the specified value is within the supported range " + "but not a multiple of 4096, it is rounded up to the " + "nearest multiple of 4096." }, { .key = {"nfs3.*.volume-access"}, .type = GF_OPTION_TYPE_STR, + .value = {"read-only", "read-write"}, + .default_value = "read-write", .description = "Type of access desired for this subvolume: " " read-only, read-write(default)" }, { .key = {"nfs3.*.trusted-write"}, .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", .description = "On an UNSTABLE write from client, return STABLE flag" " to force client to not send a COMMIT request. In " "some environments, combined with a replicated " @@ -729,6 +1537,7 @@ struct volume_options options[] = { }, { .key = {"nfs3.*.trusted-sync"}, .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", .description = "All writes and COMMIT requests are treated as async." " This implies that no write requests are guaranteed" " to be on server disks when the write reply is " @@ -737,17 +1546,41 @@ struct volume_options options[] = { }, { .key = {"nfs3.*.export-dir"}, - .type = GF_OPTION_TYPE_STR, + .type = GF_OPTION_TYPE_PATH, + .default_value = "", .description = "By default, all subvolumes of nfs are exported as " "individual exports. There are cases where a " "subdirectory or subdirectories in the volume need to " "be exported separately. This option can also be used " "in conjunction with nfs3.export-volumes option to " "restrict exports only to the subdirectories specified" - " through this option. Must be an absolute path." + " through this option. Must be an absolute path. Along" + " with path allowed list of IPs/hostname can be " + "associated with each subdirectory. If provided " + "connection will allowed only from these IPs. By " + "default connections from all IPs are allowed. " + "Format: <dir>[(hostspec[|hostspec|...])][,...]. Where" + " hostspec can be an IP address, hostname or an IP " + "range in CIDR notation. " + "e.g. /foo(192.168.1.0/24|host1|10.1.1.8),/host2." + " NOTE: Care must be taken while configuring this " + "option as invalid entries and/or unreachable DNS " + "servers can introduce unwanted delay in all the mount" + " calls." + }, + { .key = {"nfs3.export-dirs"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "on", + .description = "By default, all subvolumes of nfs are exported as " + "individual exports. There are cases where a " + "subdirectory or subdirectories in the volume need to " + "be exported separately. Enabling this option allows " + "any directory on a volumes to be exported separately." + "Directory exports are enabled by default." }, { .key = {"nfs3.export-volumes"}, .type = GF_OPTION_TYPE_BOOL, + .default_value = "on", .description = "Enable or disable exporting whole volumes, instead " "if used in conjunction with nfs3.export-dir, can " "allow setting up only subdirectories as exports. On " @@ -755,6 +1588,7 @@ struct volume_options options[] = { }, { .key = {"rpc-auth.auth-unix"}, .type = GF_OPTION_TYPE_BOOL, + .default_value = "on", .description = "Disable or enable the AUTH_UNIX authentication type." "Must always be enabled for better interoperability." "However, can be disabled if needed. Enabled by" @@ -762,14 +1596,26 @@ struct volume_options options[] = { }, { .key = {"rpc-auth.auth-null"}, .type = GF_OPTION_TYPE_BOOL, + .default_value = "on", .description = "Disable or enable the AUTH_NULL authentication type." "Must always be enabled. This option is here only to" " avoid unrecognized option warnings" }, { .key = {"rpc-auth.auth-unix.*"}, .type = GF_OPTION_TYPE_BOOL, + .default_value = "on", + .description = "Disable or enable the AUTH_UNIX authentication type " + "for a particular exported volume overriding defaults" + " and general setting for AUTH_UNIX scheme. Must " + "always be enabled for better interoperability." + "However, can be disabled if needed. Enabled by" + "default." + }, + { .key = {"rpc-auth.auth-unix.*.allow"}, + .type = GF_OPTION_TYPE_STR, + .default_value = "on", .description = "Disable or enable the AUTH_UNIX authentication type " - "for a particular exported volume over-riding defaults" + "for a particular exported volume overriding defaults" " and general setting for AUTH_UNIX scheme. Must " "always be enabled for better interoperability." "However, can be disabled if needed. Enabled by" @@ -777,42 +1623,48 @@ struct volume_options options[] = { }, { .key = {"rpc-auth.auth-null.*"}, .type = GF_OPTION_TYPE_BOOL, + .default_value = "on", .description = "Disable or enable the AUTH_NULL authentication type " - "for a particular exported volume over-riding defaults" + "for a particular exported volume overriding defaults" " and general setting for AUTH_NULL. Must always be " "enabled. This option is here only to avoid " "unrecognized option warnings." }, { .key = {"rpc-auth.addr.allow"}, - .type = GF_OPTION_TYPE_STR, + .type = GF_OPTION_TYPE_INTERNET_ADDRESS_LIST, + .default_value = "all", .description = "Allow a comma separated list of addresses and/or" " hostnames to connect to the server. By default, all" - " connections are disallowed. This allows users to " + " connections are allowed. This allows users to " "define a general rule for all exported volumes." }, { .key = {"rpc-auth.addr.reject"}, - .type = GF_OPTION_TYPE_STR, + .type = GF_OPTION_TYPE_INTERNET_ADDRESS_LIST, + .default_value = "none", .description = "Reject a comma separated list of addresses and/or" " hostnames from connecting to the server. By default," - " all connections are disallowed. This allows users to" + " all connections are allowed. This allows users to" "define a general rule for all exported volumes." }, { .key = {"rpc-auth.addr.*.allow"}, - .type = GF_OPTION_TYPE_STR, + .type = GF_OPTION_TYPE_INTERNET_ADDRESS_LIST, + .default_value = "all", .description = "Allow a comma separated list of addresses and/or" " hostnames to connect to the server. By default, all" - " connections are disallowed. This allows users to " + " connections are allowed. This allows users to " "define a rule for a specific exported volume." }, { .key = {"rpc-auth.addr.*.reject"}, - .type = GF_OPTION_TYPE_STR, + .type = GF_OPTION_TYPE_INTERNET_ADDRESS_LIST, + .default_value = "none", .description = "Reject a comma separated list of addresses and/or" " hostnames from connecting to the server. By default," - " all connections are disallowed. This allows users to" + " all connections are allowed. This allows users to" "define a rule for a specific exported volume." }, { .key = {"rpc-auth.ports.insecure"}, .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", .description = "Allow client connections from unprivileged ports. By " "default only privileged ports are allowed. This is a" "global setting in case insecure ports are to be " @@ -820,31 +1672,35 @@ struct volume_options options[] = { }, { .key = {"rpc-auth.ports.*.insecure"}, .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", .description = "Allow client connections from unprivileged ports. By " "default only privileged ports are allowed. Use this" - " option to set enable or disable insecure ports for " - "a specific subvolume and to over-ride global setting " - " set by the previous option." + " option to enable or disable insecure ports for " + "a specific subvolume and to override the global " + "setting set by the previous option." }, { .key = {"rpc-auth.addr.namelookup"}, .type = GF_OPTION_TYPE_BOOL, - .description = "Users have the option of turning off name lookup for" - " incoming client connections using this option. In some " + .default_value = "off", + .description = "Users have the option of turning on name lookup for" + " incoming client connections using this option. Use this " + "option to turn on name lookups during address-based " + "authentication. Turning this on will enable you to" + " use hostnames in nfs.rpc-auth-* filters. In some " "setups, the name server can take too long to reply to DNS " - "queries resulting in timeouts of mount requests. Use this " - "option to turn off name lookups during address " - "authentication. Note, turning this off will prevent you from" - " using hostnames in rpc-auth.addr.* filters. By default, " - " name lookup is on." + "queries resulting in timeouts of mount requests. By " + "default, name lookup is off" }, { .key = {"nfs.dynamic-volumes"}, .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", .description = "Internal option set to tell gnfs to use a different" " scheme for encoding file handles when DVM is being" " used." }, { .key = {"nfs3.*.volume-id"}, .type = GF_OPTION_TYPE_STR, + .default_value = "", .description = "When nfs.dynamic-volumes is set, gnfs expects every " "subvolume to have this option set for it, so that " "gnfs can use this option to identify the volume. " @@ -853,18 +1709,117 @@ struct volume_options options[] = { }, { .key = {"nfs.enable-ino32"}, .type = GF_OPTION_TYPE_BOOL, + .default_value = "no", .description = "For nfs clients or apps that do not support 64-bit " "inode numbers, use this option to make NFS return " - "32-bit inode numbers instead. Disabled by default so " - "NFS returns 64-bit inode numbers by default." + "32-bit inode numbers instead. Disabled by default, so" + " NFS returns 64-bit inode numbers." }, { .key = {"rpc.register-with-portmap"}, .type = GF_OPTION_TYPE_BOOL, - .description = "For systems that need to run multiple nfs servers, we" - "need to prevent more than one from registering with " + .default_value = "on", + .description = "For systems that need to run multiple nfs servers, " + "only one registration is possible with " "portmap service. Use this option to turn off portmap " "registration for Gluster NFS. On by default" }, - { .key = {NULL} }, -}; + { .key = {"rpc.outstanding-rpc-limit"}, + .type = GF_OPTION_TYPE_INT, + .min = RPCSVC_MIN_OUTSTANDING_RPC_LIMIT, + .max = RPCSVC_MAX_OUTSTANDING_RPC_LIMIT, + .default_value = TOSTRING(RPCSVC_DEFAULT_OUTSTANDING_RPC_LIMIT), + .description = "Parameter to throttle the number of incoming RPC " + "requests from a client. 0 means no limit (can " + "potentially run out of memory)" + }, + { .key = {"nfs.port"}, + .type = GF_OPTION_TYPE_INT, + .min = 1, + .max = 0xffff, + .default_value = TOSTRING(GF_NFS3_PORT), + .description = "Use this option on systems that need Gluster NFS to " + "be associated with a non-default port number." + }, + { .key = {"nfs.mem-factor"}, + .type = GF_OPTION_TYPE_INT, + .min = 1, + .max = 1024, + .default_value = TOSTRING(GF_NFS_DEFAULT_MEMFACTOR), + .description = "Use this option to make NFS be faster on systems by " + "using more memory. This option specifies a multiple " + "that determines the total amount of memory used. " + "Default value is 15. Increase to use more memory in " + "order to improve performance for certain use cases." + "Please consult gluster-users list before using this " + "option." + }, + { .key = {"nfs.*.disable"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "false", + .description = "This option is used to start or stop NFS server" + "for individual volume." + }, + + { .key = {"nfs.nlm"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "on", + .description = "This option, if set to 'off', disables NLM server " + "by not registering the service with the portmapper." + " Set it to 'on' to re-enable it. Default value: 'on'" + }, + { .key = {"nfs.mount-udp"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", + .description = "set the option to 'on' to enable mountd on UDP. " + "Required for some Solaris and AIX NFS clients. " + "The need for enabling this option often depends " + "on the usage of NLM." + }, + { .key = {"nfs.mount-rmtab"}, + .type = GF_OPTION_TYPE_PATH, + .default_value = DATADIR "/rmtab", + .description = "Set the location of the cache file that is used to " + "list all the NFS-clients that have connected " + "through the MOUNT protocol. If this is on shared " + "storage, all GlusterFS servers will update and " + "output (with 'showmount') the same list." + }, + { .key = {OPT_SERVER_AUX_GIDS}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", + .description = "Let the server look up which groups a user belongs " + "to, overwriting the list passed from the client. " + "This enables support for group lists longer than " + "can be passed through the NFS protocol, but is not " + "secure unless users and groups are well synchronized " + "between clients and servers." + }, + { .key = {OPT_SERVER_GID_CACHE_TIMEOUT}, + .type = GF_OPTION_TYPE_INT, + .min = 0, + .max = 3600, + .default_value = "5", + .description = "Number of seconds to cache auxiliary-GID data, when " + OPT_SERVER_AUX_GIDS " is set." + }, + { .key = {"nfs.acl"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "on", + .description = "This option is used to control ACL support for NFS." + }, + { .key = {"nfs.drc"}, + .type = GF_OPTION_TYPE_STR, + .default_value = "on", + .description = "Enable Duplicate Request Cache in gNFS server to " + "improve correctness of non-idempotent operations like " + "write, delete, link, et al" + }, + { .key = {"nfs.drc-size"}, + .type = GF_OPTION_TYPE_INT, + .default_value = "0x20000", + .description = "Sets the number of non-idempotent " + "requests to cache in drc" + }, + { .key = {NULL} }, +}; diff --git a/xlators/nfs/server/src/nfs.h b/xlators/nfs/server/src/nfs.h index b6a1d4a46..00c7f8046 100644 --- a/xlators/nfs/server/src/nfs.h +++ b/xlators/nfs/server/src/nfs.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef __NFS_H__ @@ -28,6 +19,8 @@ #include "rpcsvc.h" #include "dict.h" #include "xlator.h" +#include "lkowner.h" +#include "gidcache.h" #define GF_NFS "nfs" @@ -43,7 +36,13 @@ #define GF_NFS_MAX_MEMFACTOR 30 #define GF_NFS_DVM_ON 1 -#define GF_NFS_DVM_OFF 2 +#define GF_NFS_DVM_OFF 0 + +/* This corresponds to the max 16 number of group IDs that are sent through an + * RPC request. Since NFS is the only one going to set this, we can be safe + * in keeping this size hardcoded. + */ +#define GF_REQUEST_MAXGROUPS 16 /* Callback into a version-specific NFS protocol. * The return type is used by the nfs.c code to register the protocol. @@ -58,10 +57,12 @@ struct nfs_initer_list { rpcsvc_program_t *program; }; - struct nfs_state { rpcsvc_t *rpcsvc; struct list_head versions; + struct mount3_state *mstate; + struct nfs3_state *nfs3state; + struct nlm4_state *nlm4state; struct mem_pool *foppool; unsigned int memfactor; xlator_list_t *subvols; @@ -73,6 +74,23 @@ struct nfs_state { int subvols_started; int dynamicvolumes; int enable_ino32; + unsigned int override_portnum; + int allow_insecure; + int enable_nlm; + int enable_acl; + int mount_udp; + char *rmtab; + struct rpc_clnt *rpc_clnt; + gf_boolean_t server_aux_gids; + uint32_t server_aux_gids_max_age; + gid_cache_t gid_cache; + uint32_t generation; + gf_boolean_t register_portmap; +}; + +struct nfs_inode_ctx { + struct list_head shares; + uint32_t generation; }; #define gf_nfs_dvm_on(nfsstt) (((struct nfs_state *)nfsstt)->dynamicvolumes == GF_NFS_DVM_ON) @@ -93,6 +111,7 @@ typedef struct nfs_user_info { uid_t uid; gid_t gids[NFS_NGROUPS]; int ngrps; + gf_lkowner_t lk_owner; } nfs_user_t; extern int @@ -105,4 +124,12 @@ nfs_user_create (nfs_user_t *newnfu, uid_t uid, gid_t gid, gid_t *auxgids, extern void nfs_request_user_init (nfs_user_t *nfu, rpcsvc_request_t *req); +extern void +nfs_request_primary_user_init (nfs_user_t *nfu, rpcsvc_request_t *req, + uid_t uid, gid_t gid); +extern int +nfs_subvolume_started (struct nfs_state *nfs, xlator_t *xl); + +extern void +nfs_fix_groups (xlator_t *this, call_stack_t *root); #endif diff --git a/xlators/nfs/server/src/nfs3-fh.c b/xlators/nfs/server/src/nfs3-fh.c index 49236d609..e199c56dc 100644 --- a/xlators/nfs/server/src/nfs3-fh.c +++ b/xlators/nfs/server/src/nfs3-fh.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _CONFIG_H @@ -31,6 +22,7 @@ #include "nfs3-fh.h" #include "nfs-common.h" #include "iatt.h" +#include "common-utils.h" int @@ -45,6 +37,12 @@ nfs3_fh_validate (struct nfs3_fh *fh) if (fh->ident[1] != GF_NFSFH_IDENT1) return 0; + if (fh->ident[2] != GF_NFSFH_IDENT2) + return 0; + + if (fh->ident[3] != GF_NFSFH_IDENT3) + return 0; + return 1; } @@ -57,8 +55,9 @@ nfs3_fh_init (struct nfs3_fh *fh, struct iatt *buf) fh->ident[0] = GF_NFSFH_IDENT0; fh->ident[1] = GF_NFSFH_IDENT1; + fh->ident[2] = GF_NFSFH_IDENT2; + fh->ident[3] = GF_NFSFH_IDENT3; - fh->hashcount = 0; uuid_copy (fh->gfid, buf->ia_gfid); } @@ -111,105 +110,35 @@ nfs3_fh_is_root_fh (struct nfs3_fh *fh) } -nfs3_hash_entry_t -nfs3_fh_hash_entry (uuid_t gfid) -{ - nfs3_hash_entry_t hash = 0; - int shiftsize = 48; - uint64_t ino = 0; - uint64_t gen = 0; - nfs3_hash_entry_t inomsb = 0; - nfs3_hash_entry_t inolsb = 0; - nfs3_hash_entry_t inols23b = 0; - - nfs3_hash_entry_t genmsb = 0; - nfs3_hash_entry_t genlsb = 0; - nfs3_hash_entry_t genls23b = 0; - - memcpy (&ino, &gfid[8], 8); - hash = ino; - while (shiftsize != 0) { - hash ^= (ino >> shiftsize); - shiftsize -= 16; - } -/* - gf_log ("FILEHANDLE", GF_LOG_TRACE, "INO %"PRIu64, ino); - gf_log ("FILEHANDLE",GF_LOG_TRACE, "PRI HASH %d", hash); -*/ - inomsb = (ino >> 56); -// gf_log ("FILEHANDLE", GF_LOG_TRACE, "inomsb %d", inomsb); - - inolsb = ((ino << 56) >> 56); -// gf_log ("FILEHANDLE", GF_LOG_TRACE, "inolsb %d", inolsb); - - inolsb = (inolsb << 8); -// gf_log ("FILEHANDLE", GF_LOG_TRACE, "inolsb to inomsb %d", inolsb); - inols23b = ((ino << 40) >> 48); -// gf_log ("FILEHANDLE", GF_LOG_TRACE, "inols23b %d", inols23b); - - inols23b = (inols23b << 8); -// gf_log ("FILEHDNALE", GF_LOG_TRACE, "inols23b %d", inols23b); - - memcpy (&gen, &gfid[0], 8); - genmsb = (gen >> 56); -// gf_log ("FILEHANDLE", GF_LOG_TRACE, "inomsb %d", inomsb); - - genlsb = ((gen << 56) >> 56); -// gf_log ("FILEHANDLE", GF_LOG_TRACE, "inolsb %d", inolsb); - - genlsb = (genlsb << 8); -// gf_log ("FILEHANDLE", GF_LOG_TRACE, "inolsb to inomsb %d", inolsb); - - genls23b = ((gen << 40) >> 48); -// gf_log ("FILEHANDLE", GF_LOG_TRACE, "inols23b %d", inols23b); - - genls23b = (genls23b << 8); -// gf_log ("FILEHDNALE", GF_LOG_TRACE, "inols23b %d", inols23b); - - hash ^= inolsb ^ inomsb ^ inols23b ^ genmsb ^ genlsb ^ genls23b; - return hash; - -} - - void -nfs3_fh_to_str (struct nfs3_fh *fh, char *str) +nfs3_fh_to_str (struct nfs3_fh *fh, char *str, size_t len) { - char gfid[512]; - char exportid[512]; + char gfid[GF_UUID_BUF_SIZE]; + char exportid[GF_UUID_BUF_SIZE]; if ((!fh) || (!str)) return; - uuid_unparse (fh->gfid, gfid); - uuid_unparse (fh->exportid, exportid); - sprintf (str, "FH: hashcount %d, exportid %s, gfid %s", - fh->hashcount, exportid, gfid); + snprintf (str, len, "FH: exportid %s, gfid %s", + uuid_utoa_r (fh->exportid, exportid), + uuid_utoa_r (fh->gfid, gfid)); } - void nfs3_log_fh (struct nfs3_fh *fh) { -// int x = 0; char gfidstr[512]; char exportidstr[512]; if (!fh) return; - uuid_unparse (fh->gfid, gfidstr); - uuid_unparse (fh->exportid, exportidstr); - gf_log ("nfs3-fh", GF_LOG_TRACE, "filehandle: hashcount %d, exportid %d" - ", gfid 0x%s", fh->hashcount, exportidstr, gfidstr); -/* - for (; x < fh->hashcount; ++x) - gf_log ("FILEHANDLE", GF_LOG_TRACE, "Hash %d: %d", x, - fh->entryhash[x]); -*/ + gf_log ("nfs3-fh", GF_LOG_TRACE, "filehandle: exportid " + "0x%s, gfid 0x%s", + uuid_utoa_r (fh->exportid, exportidstr), + uuid_utoa_r (fh->gfid, gfidstr)); } - int nfs3_fh_build_parent_fh (struct nfs3_fh *child, struct iatt *newstat, struct nfs3_fh *newfh) @@ -219,53 +148,35 @@ nfs3_fh_build_parent_fh (struct nfs3_fh *child, struct iatt *newstat, nfs3_fh_init (newfh, newstat); uuid_copy (newfh->exportid, child->exportid); - if (newstat->ia_ino == 1) - goto done; - newfh->hashcount = child->hashcount - 1; - memcpy (newfh->entryhash, child->entryhash, - newfh->hashcount * GF_NFSFH_ENTRYHASH_SIZE); + return 0; +} -done: -// nfs3_log_fh (newfh); +int +nfs3_build_fh (inode_t *inode, uuid_t exportid, struct nfs3_fh *newfh) +{ + if (!newfh || !inode) + return -1; + newfh->ident[0] = GF_NFSFH_IDENT0; + newfh->ident[1] = GF_NFSFH_IDENT1; + newfh->ident[2] = GF_NFSFH_IDENT2; + newfh->ident[3] = GF_NFSFH_IDENT3; + uuid_copy (newfh->gfid, inode->gfid); + uuid_copy (newfh->exportid, exportid); return 0; } - int nfs3_fh_build_child_fh (struct nfs3_fh *parent, struct iatt *newstat, struct nfs3_fh *newfh) { - int hashcount = 0; - int entry = 0; - if ((!parent) || (!newstat) || (!newfh)) return -1; nfs3_fh_init (newfh, newstat); uuid_copy (newfh->exportid, parent->exportid); - newfh->hashcount = parent->hashcount + 1; - /* Only copy the hashes that are available in the parent file - * handle. */ - if (parent->hashcount > GF_NFSFH_MAXHASHES) - hashcount = GF_NFSFH_MAXHASHES; - else - hashcount = parent->hashcount; - - memcpy (newfh->entryhash, parent->entryhash, - hashcount * GF_NFSFH_ENTRYHASH_SIZE); - - /* Do not insert parent dir hash if there is no space left in the hash - * array of the child entry. */ - if (newfh->hashcount <= GF_NFSFH_MAXHASHES) { - entry = newfh->hashcount - 1; - newfh->entryhash[entry] = nfs3_fh_hash_entry (parent->gfid); - } - -// nfs3_log_fh (newfh); - return 0; } @@ -273,34 +184,5 @@ nfs3_fh_build_child_fh (struct nfs3_fh *parent, struct iatt *newstat, uint32_t nfs3_fh_compute_size (struct nfs3_fh *fh) { - uint32_t fhlen = 0; - - if (!fh) - return 0; - - if (fh->hashcount <= GF_NFSFH_MAXHASHES) - fhlen = nfs3_fh_hashcounted_size (fh->hashcount); - else - fhlen = nfs3_fh_hashcounted_size (GF_NFSFH_MAXHASHES); - - return fhlen; -} - - -/* There is no point searching at a directory level which is beyond that of - * the hashcount given in the file handle. - */ -int -nfs3_fh_hash_index_is_beyond (struct nfs3_fh *fh, int hashidx) -{ - if (!fh) - return 1; - - if (fh->hashcount >= hashidx) - return 0; - else - return 1; - - return 1; + return GF_NFSFH_STATIC_SIZE; } - diff --git a/xlators/nfs/server/src/nfs3-fh.h b/xlators/nfs/server/src/nfs3-fh.h index f52c36ecf..1049cdc96 100644 --- a/xlators/nfs/server/src/nfs3-fh.h +++ b/xlators/nfs/server/src/nfs3-fh.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _NFS_FH_H_ @@ -35,17 +26,10 @@ * handles for now. This will change if and when we need v4. */ #define GF_NFSFH_IDENT0 ':' #define GF_NFSFH_IDENT1 'O' -#define GF_NFSFH_IDENT_SIZE (sizeof(char) * 2) -#define GF_NFSFH_STATIC_SIZE (GF_NFSFH_IDENT_SIZE + (2*sizeof (uuid_t)) + sizeof (uint16_t)) -#define GF_NFSFH_MAX_HASH_BYTES (NFS3_FHSIZE - GF_NFSFH_STATIC_SIZE) - -/* Each hash element in the file handle is of 2 bytes thus giving - * us theoretically 65536 unique entries in a directory. - */ -typedef uint16_t nfs3_hash_entry_t; -#define GF_NFSFH_ENTRYHASH_SIZE (sizeof (nfs3_hash_entry_t)) -#define GF_NFSFH_MAXHASHES ((int)(GF_NFSFH_MAX_HASH_BYTES / GF_NFSFH_ENTRYHASH_SIZE)) -#define nfs3_fh_hashcounted_size(hcount) (GF_NFSFH_STATIC_SIZE + (hcount * GF_NFSFH_ENTRYHASH_SIZE)) +#define GF_NFSFH_IDENT2 'G' +#define GF_NFSFH_IDENT3 'L' +#define GF_NFSFH_IDENT_SIZE (sizeof(char) * 4) +#define GF_NFSFH_STATIC_SIZE (GF_NFSFH_IDENT_SIZE + (2*sizeof (uuid_t))) #define nfs3_fh_exportid_to_index(exprtid) ((uint16_t)exprtid[15]) /* ATTENTION: Change in size of the structure below should be reflected in the @@ -54,9 +38,9 @@ typedef uint16_t nfs3_hash_entry_t; struct nfs3_fh { /* Used to ensure that a bunch of bytes are actually a GlusterFS NFS - * file handle. Should contain ":O" + * file handle. Should contain ":OGL" */ - char ident[2]; + char ident[4]; /* UUID that identifies an export. The value stored in exportid * depends on the usage of gluster nfs. If the DVM is enabled using @@ -72,11 +56,11 @@ struct nfs3_fh { /* File/dir gfid. */ uuid_t gfid; - - /* Number of file/ino hash elements that follow the ino. */ - uint16_t hashcount; - - nfs3_hash_entry_t entryhash[GF_NFSFH_MAXHASHES]; + /* This structure must be exactly NFS3_FHSIZE (64) bytes long. + Having the structure shorter results in buffer overflows + during XDR decoding. + */ + unsigned char padding[NFS3_FHSIZE - GF_NFSFH_STATIC_SIZE]; } __attribute__((__packed__)); #define GF_NFS3FH_STATIC_INITIALIZER {{0},} @@ -84,9 +68,6 @@ struct nfs3_fh { extern uint32_t nfs3_fh_compute_size (struct nfs3_fh *fh); -extern int -nfs3_fh_hash_index_is_beyond (struct nfs3_fh *fh, int hashidx); - extern uint16_t nfs3_fh_hash_entry (uuid_t gfid); @@ -107,7 +88,7 @@ extern void nfs3_log_fh (struct nfs3_fh *fh); extern void -nfs3_fh_to_str (struct nfs3_fh *fh, char *str); +nfs3_fh_to_str (struct nfs3_fh *fh, char *str, size_t len); extern int nfs3_fh_build_parent_fh (struct nfs3_fh *child, struct iatt *newstat, @@ -115,4 +96,8 @@ nfs3_fh_build_parent_fh (struct nfs3_fh *child, struct iatt *newstat, extern struct nfs3_fh nfs3_fh_build_uuid_root_fh (uuid_t volumeid); + +extern int +nfs3_build_fh (inode_t *inode, uuid_t exportid, struct nfs3_fh *newfh); + #endif diff --git a/xlators/nfs/server/src/nfs3-helpers.c b/xlators/nfs/server/src/nfs3-helpers.c index cff029d6e..9059fc341 100644 --- a/xlators/nfs/server/src/nfs3-helpers.c +++ b/xlators/nfs/server/src/nfs3-helpers.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _CONFIG_H @@ -35,8 +26,16 @@ #include "nfs3-helpers.h" #include "nfs-mem-types.h" #include "iatt.h" +#include "common-utils.h" #include <string.h> +extern int +nfs3_set_root_looked_up (struct nfs3_state *nfs3, struct nfs3_fh *rootfh); + +extern int +nfs3_is_root_looked_up (struct nfs3_state *nfs3, struct nfs3_fh *rootfh); + + #define nfs3_call_resume(cst) \ do { \ if (((cst)) && (cst)->resume_fn) \ @@ -94,21 +93,18 @@ struct nfs3stat_strerror nfs3stat_strerror_table[] = { uint64_t nfs3_iatt_gfid_to_ino (struct iatt *buf) { - uuid_t gfid = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; - uint64_t ino = 0; + uint64_t ino = 0; if (!buf) return 0; - if ((buf->ia_ino != 1) && (uuid_compare (buf->ia_gfid, gfid) != 0)) { - if (gf_nfs_enable_ino32()) { - ino = (uint32_t )nfs_hash_gfid (buf->ia_gfid); - goto hashout; - } + if (gf_nfs_enable_ino32()) { + ino = (uint32_t )nfs_hash_gfid (buf->ia_gfid); + goto hashout; + } - memcpy (&ino, &buf->ia_gfid[8], sizeof (uint64_t)); - } else - ino = 1; + /* from posix its guaranteed to send unique ino */ + ino = buf->ia_ino; hashout: return ino; @@ -248,6 +244,10 @@ nfs3_errno_to_nfsstat3 (int errnum) stat = NFS3ERR_IO; break; + case EDQUOT: + stat = NFS3ERR_DQUOT; + break; + default: stat = NFS3ERR_SERVERFAULT; break; @@ -256,6 +256,20 @@ nfs3_errno_to_nfsstat3 (int errnum) return stat; } +/* + * Special case: If op_ret is -1, it's very unusual op_errno being + * 0 which means something came wrong from upper layer(s). If it + * happens by any means, then set NFS3 status to NFS3ERR_SERVERFAULT. + */ +inline nfsstat3 +nfs3_cbk_errno_status (int32_t op_ret, int32_t op_errno) +{ + if ((op_ret == -1) && (op_errno == 0)) { + return NFS3ERR_SERVERFAULT; + } + + return nfs3_errno_to_nfsstat3 (op_errno); +} void nfs3_fill_lookup3res_error (lookup3res *res, nfsstat3 stat, @@ -275,6 +289,9 @@ nfs3_stat_to_fattr3 (struct iatt *buf) { fattr3 fa = {0, }; + if (buf == NULL) + goto out; + if (IA_ISDIR (buf->ia_type)) fa.type = NF3DIR; else if (IA_ISREG (buf->ia_type)) @@ -334,26 +351,17 @@ nfs3_stat_to_fattr3 (struct iatt *buf) fa.fsid = buf->ia_dev; fa.fileid = nfs3_iatt_gfid_to_ino (buf); - /* FIXME: Handle time resolutions for sub-second granularity */ - if (buf->ia_atime == 9669) { - fa.mtime.seconds = 0; - fa.mtime.nseconds = 0; - fa.atime.seconds = 0; - fa.atime.nseconds = 0; - } else { - fa.mtime.seconds = buf->ia_mtime; - fa.mtime.nseconds = 0; - fa.atime.seconds = buf->ia_atime; - fa.atime.seconds = 0; - fa.atime.nseconds = 0; - } fa.atime.seconds = buf->ia_atime; - fa.atime.nseconds = 0; + fa.atime.nseconds = buf->ia_atime_nsec; fa.ctime.seconds = buf->ia_ctime; - fa.ctime.nseconds = 0; + fa.ctime.nseconds = buf->ia_ctime_nsec; + fa.mtime.seconds = buf->ia_mtime; + fa.mtime.nseconds = buf->ia_mtime_nsec; + +out: return fa; } @@ -396,11 +404,10 @@ nfs3_stat_to_pre_op_attr (struct iatt *pre) poa.attributes_follow = TRUE; poa.pre_op_attr_u.attributes.size = pre->ia_size; - if (pre->ia_atime == 9669) - poa.pre_op_attr_u.attributes.mtime.seconds = 0; - else - poa.pre_op_attr_u.attributes.mtime.seconds = pre->ia_mtime; + poa.pre_op_attr_u.attributes.mtime.seconds = pre->ia_mtime; + poa.pre_op_attr_u.attributes.mtime.nseconds = pre->ia_mtime_nsec; poa.pre_op_attr_u.attributes.ctime.seconds = pre->ia_ctime; + poa.pre_op_attr_u.attributes.ctime.nseconds = pre->ia_ctime_nsec; out: return poa; @@ -498,7 +505,7 @@ nfs3_fill_fsinfo3res (struct nfs3_state *nfs3, fsinfo3res *res, resok.wtpref = nfs3->writesize; resok.wtmult = GF_NFS3_WTMULT; resok.dtpref = nfs3->readdirsize; - resok.maxfilesize = GF_NFS3_MAXFILE; + resok.maxfilesize = GF_NFS3_MAXFILESIZE; resok.time_delta = tdelta; resok.properties = GF_NFS3_FS_PROP; @@ -553,158 +560,49 @@ nfs3_prep_access3args (access3args *args, struct nfs3_fh *fh) args->object.data.data_val = (void *)fh; } +#define POSIX_READ 4 +#define POSIX_WRITE 2 +#define POSIX_EXEC 1 uint32_t -nfs3_owner_accessbits (ia_prot_t prot, ia_type_t type, uint32_t request) +nfs3_accessbits (int32_t accbits) { - uint32_t accresult = 0; - - if (IA_PROT_RUSR (prot) && (request & ACCESS3_READ)) - accresult |= ACCESS3_READ; - - if (request & ACCESS3_LOOKUP) - if ((IA_ISDIR (type)) && (IA_PROT_XUSR (prot))) - accresult |= ACCESS3_LOOKUP; - - if ((IA_PROT_WUSR (prot) && (request & ACCESS3_MODIFY))) - accresult |= ACCESS3_MODIFY; - - if ((IA_PROT_WUSR (prot) && (request & ACCESS3_EXTEND))) - accresult |= ACCESS3_EXTEND; - - /* ACCESS3_DELETE is ignored for now since that requires - * knowing the permissions on the parent directory. - */ - - if (request & ACCESS3_EXECUTE) - if (IA_PROT_XUSR (prot) && (!IA_ISDIR (type))) - accresult |= ACCESS3_EXECUTE; - - return accresult; -} - - -uint32_t -nfs3_group_accessbits (ia_prot_t prot, ia_type_t type, uint32_t request) -{ - uint32_t accresult = 0; - - if (IA_PROT_RGRP (prot) && (request & ACCESS3_READ)) - accresult |= ACCESS3_READ; - - if (request & ACCESS3_LOOKUP) - if ((IA_ISDIR (type)) && IA_PROT_RGRP (prot)) - accresult |= ACCESS3_LOOKUP; - - if (IA_PROT_WGRP (prot) && (request & ACCESS3_MODIFY)) - accresult |= ACCESS3_MODIFY; - - if (IA_PROT_WGRP (prot) && (request & ACCESS3_EXTEND)) - accresult |= ACCESS3_EXTEND; - - /* ACCESS3_DELETE is ignored for now since that requires - * knowing the permissions on the parent directory. - */ - - if (request & ACCESS3_EXECUTE) - if (IA_PROT_XGRP (prot) && (!IA_ISDIR (type))) - accresult |= ACCESS3_EXECUTE; - - return accresult; -} - - -uint32_t -nfs3_other_accessbits (ia_prot_t prot, ia_type_t type, uint32_t request) -{ - uint32_t accresult = 0; + uint32_t accresult = 0; - if (IA_PROT_ROTH (prot) && (request & ACCESS3_READ)) + if (accbits & POSIX_READ) accresult |= ACCESS3_READ; - if (request & ACCESS3_LOOKUP) - if (IA_ISDIR (type) && IA_PROT_ROTH (prot)) - accresult |= ACCESS3_LOOKUP; + if (accbits & POSIX_WRITE) + accresult |= (ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE); - if (IA_PROT_WOTH (prot) && (request & ACCESS3_MODIFY)) - accresult |= ACCESS3_MODIFY; - - if (IA_PROT_WOTH (prot) && (request & ACCESS3_EXTEND)) - accresult |= ACCESS3_EXTEND; - - /* ACCESS3_DELETE is ignored for now since that requires - * knowing the permissions on the parent directory. - */ - - if (request & ACCESS3_EXECUTE) - if (IA_PROT_XOTH (prot) && (!IA_ISDIR (type))) - accresult |= ACCESS3_EXECUTE; + /* lookup on directory allowed only in case of execute permission */ + if (accbits & POSIX_EXEC) + accresult |= (ACCESS3_EXECUTE | ACCESS3_LOOKUP); return accresult; } - uint32_t -nfs3_superuser_accessbits (ia_prot_t prot, ia_type_t type, uint32_t request) +nfs3_request_to_accessbits (int32_t accbits) { - uint32_t accresult = 0; - - if (request & ACCESS3_READ) - accresult |= ACCESS3_READ; - - if (request & ACCESS3_LOOKUP) - if (IA_ISDIR (type)) - accresult |= ACCESS3_LOOKUP; - - if (request & ACCESS3_MODIFY) - accresult |= ACCESS3_MODIFY; - - if (request & ACCESS3_EXTEND) - accresult |= ACCESS3_EXTEND; + uint32_t acc_request = 0; - /* ACCESS3_DELETE is ignored for now since that requires - * knowing the permissions on the parent directory. - */ - - if (request & ACCESS3_EXECUTE) - if ((IA_PROT_XOTH (prot) || IA_PROT_XUSR (prot) || - IA_PROT_XGRP (prot)) && (!IA_ISDIR (type))) - accresult |= ACCESS3_EXECUTE; + if (accbits & ACCESS3_READ) + acc_request |= POSIX_READ; - return accresult; -} + if (accbits & (ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE)) + acc_request |= POSIX_WRITE; + /* For lookup on directory check for execute permission */ + if (accbits & (ACCESS3_EXECUTE | ACCESS3_LOOKUP)) + acc_request |= POSIX_EXEC; -uint32_t -nfs3_stat_to_accessbits (struct iatt *buf, uint32_t request, uid_t uid, - gid_t gid) -{ - uint32_t accresult = 0; - ia_prot_t prot = {0, }; - ia_type_t type = 0; - - prot = buf->ia_prot; - type = buf->ia_type; - - if (uid == 0) - accresult = nfs3_superuser_accessbits (prot, type, request); - else if (buf->ia_uid == uid) - accresult = nfs3_owner_accessbits (prot, type, request); - else if (buf->ia_gid == gid) - accresult = nfs3_group_accessbits (prot, type, request); - else - accresult = nfs3_other_accessbits (prot, type, request); - - return accresult; + return acc_request; } - - void -nfs3_fill_access3res (access3res *res, nfsstat3 status, struct iatt *buf, - uint32_t accbits, uid_t uid, gid_t gid, - uint64_t deviceid) +nfs3_fill_access3res (access3res *res, nfsstat3 status, int32_t accbits, + int32_t reqaccbits) { - post_op_attr objattr; uint32_t accres = 0; memset (res, 0, sizeof (*res)); @@ -712,12 +610,10 @@ nfs3_fill_access3res (access3res *res, nfsstat3 status, struct iatt *buf, if (status != NFS3_OK) return; - nfs3_map_deviceid_to_statdev (buf, deviceid); - objattr = nfs3_stat_to_post_op_attr (buf); - accres = nfs3_stat_to_accessbits (buf, accbits, uid, gid); + accres = nfs3_accessbits (accbits); - res->access3res_u.resok.obj_attributes = objattr; - res->access3res_u.resok.access = accres; + /* do not answer what was not asked */ + res->access3res_u.resok.access = accres & reqaccbits; } void @@ -795,7 +691,7 @@ nfs3_fill_entry3 (gf_dirent_t *entry, struct nfs3_fh *dfh) /* If the entry is . or .., we need to replace the physical ino and gen * with 1 and 0 respectively if the directory is root. This funging is * needed because there is no parent directory of the root. In that - * sense the behavious we provide is similar to the output of the + * sense the behavior we provide is similar to the output of the * command: "stat /.." */ entry->d_ino = nfs3_iatt_gfid_to_ino (&entry->d_stat); @@ -864,7 +760,7 @@ nfs3_fill_entryp3 (gf_dirent_t *entry, struct nfs3_fh *dirfh, uint64_t devid) /* If the entry is . or .., we need to replace the physical ino and gen * with 1 and 0 respectively if the directory is root. This funging is * needed because there is no parent directory of the root. In that - * sense the behavious we provide is similar to the output of the + * sense the behavior we provide is similar to the output of the * command: "stat /.." */ entry->d_ino = nfs3_iatt_gfid_to_ino (&entry->d_stat); @@ -1090,8 +986,8 @@ nfs3_fill_fsstat3res (fsstat3res *res, nfsstat3 stat, struct statvfs *fsbuf, nfs3_map_deviceid_to_statdev (postbuf, deviceid); poa = nfs3_stat_to_post_op_attr (postbuf); resok.tbytes = (size3)(fsbuf->f_frsize * fsbuf->f_blocks); - resok.fbytes = (size3)(fsbuf->f_bsize * fsbuf->f_bfree); - resok.abytes = (size3)(fsbuf->f_bsize * fsbuf->f_bavail); + resok.fbytes = (size3)(fsbuf->f_frsize * fsbuf->f_bfree); + resok.abytes = (size3)(fsbuf->f_frsize * fsbuf->f_bavail); resok.tfiles = (size3)(fsbuf->f_files); resok.ffiles = (size3)(fsbuf->f_ffree); resok.afiles = (size3)(fsbuf->f_favail); @@ -1718,680 +1614,1805 @@ err: } -/* When remove a file, we need to unref the cached fd for an inode but this - * needs to happen only when the file was in fact opened. However, it is - * possible that fd_lookup on a file returns an fd because the file was in - * process of being created(which also returns an fd) but since this fd was not - * opened through this path, in the NFS3 remove path, we'll end up removing the - * reference that belongs to someone else. That means, nfs3 remove path should - * not unref unless it is sure that the file was cached open also. If it was, - * only then perform the fd_unref, else not. - * - * We determine that using a flag in the inode context. - */ -int -nfs3_set_inode_opened (xlator_t *nfsxl, inode_t *inode) +void +nfs3_stat_to_errstr (uint32_t xid, char *op, nfsstat3 stat, int pstat, + char *errstr, size_t len) { - if ((!nfsxl) || (!inode)) - return -1; + if ((!op) || (!errstr)) + return; - inode_ctx_put (inode, nfsxl, GF_NFS3_FD_CACHED); + snprintf (errstr, len, "XID: %x, %s: NFS: %d(%s), POSIX: %d(%s)", + xid, op,stat, nfsstat3_strerror (stat), pstat, + strerror (pstat)); +} - return 0; +void +nfs3_log_common_call (uint32_t xid, char *op, struct nfs3_fh *fh) +{ + char fhstr[1024]; + + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s", xid, op, + fhstr); } -/* Returns 1 if inode was cached open, otherwise 0 */ -int -nfs3_cached_inode_opened (xlator_t *nfsxl, inode_t *inode) +void +nfs3_log_fh_entry_call (uint32_t xid, char *op, struct nfs3_fh *fh, + char *name) { - int ret = -1; - uint64_t cflag = 0; + char fhstr[1024]; - if ((!nfsxl) || (!inode)) - return -1; + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s, name: %s", xid, + op, fhstr, name); +} - ret = inode_ctx_get (inode, nfsxl, &cflag); - if (ret == -1) - ret = 0; - else if (cflag == GF_NFS3_FD_CACHED) - ret = 1; - return ret; +void +nfs3_log_rename_call (uint32_t xid, struct nfs3_fh *src, char *sname, + struct nfs3_fh *dst, char *dname) +{ + char sfhstr[1024]; + char dfhstr[1024]; + + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (src, sfhstr, sizeof (sfhstr)); + nfs3_fh_to_str (dst, dfhstr, sizeof (dfhstr)); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, RENAME: args: Src: %s, " + "name: %s, Dst: %s, name: %s", xid, sfhstr, sname, dfhstr, + dname); } -int32_t -nfs3_dir_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, fd_t *fd) + +void +nfs3_log_create_call (uint32_t xid, struct nfs3_fh *fh, char *name, + createmode3 mode) { - nfs3_call_state_t *cs = NULL; + char fhstr[1024]; + char *modestr = NULL; + char exclmode[] = "EXCLUSIVE"; + char unchkd[] = "UNCHECKED"; + char guarded[] = "GUARDED"; - cs = frame->local; - if (op_ret == -1) { - cs->resolve_ret = -1; - cs->resolve_errno = op_errno; - nfs3_call_resume (cs); - goto err; - } + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); + if (mode == EXCLUSIVE) + modestr = exclmode; + else if (mode == GUARDED) + modestr = guarded; + else + modestr = unchkd; - cs->fd = fd_ref (fd); - nfs3_set_inode_opened (cs->nfsx, cs->resolvedloc.inode); - gf_log (GF_NFS3, GF_LOG_TRACE, "FD_REF: %d", fd->refcount); - nfs3_call_resume (cs); -err: - return 0; + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, CREATE: args: %s, name: %s," + " mode: %s", xid, fhstr, name, modestr); } -int -__nfs3_dir_open_and_resume (nfs3_call_state_t *cs) +void +nfs3_log_mknod_call (uint32_t xid, struct nfs3_fh *fh, char *name, int type) { - nfs_user_t nfu = {0, }; - int ret = -EFAULT; + char fhstr[1024]; + char *modestr = NULL; + char chr[] = "CHAR"; + char blk[] = "BLK"; + char sock[] = "SOCK"; + char fifo[] = "FIFO"; - if (!cs) - return ret; + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); + if (type == NF3CHR) + modestr = chr; + else if (type == NF3BLK) + modestr = blk; + else if (type == NF3SOCK) + modestr = sock; + else + modestr = fifo; - nfs_user_root_create (&nfu); - ret = nfs_opendir (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - nfs3_dir_open_cbk, cs); - return ret; + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, MKNOD: args: %s, name: %s," + " type: %s", xid, fhstr, name, modestr); } -int -nfs3_dir_open_and_resume (nfs3_call_state_t *cs, nfs3_resume_fn_t resume) + +void +nfs3_log_symlink_call (uint32_t xid, struct nfs3_fh *fh, char *name, char *tgt) { - fd_t *fd = NULL; - int ret = -EFAULT; + char fhstr[1024]; - if ((!cs)) - return ret; + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, SYMLINK: args: %s, name: %s," + " target: %s", xid, fhstr, name, tgt); +} - cs->resume_fn = resume; - gf_log (GF_NFS3, GF_LOG_TRACE, "Opening: %s", cs->resolvedloc.path); - fd = fd_lookup (cs->resolvedloc.inode, 0); - if (fd) { - gf_log (GF_NFS3, GF_LOG_TRACE, "fd found in state: ref: %d", fd->refcount); - cs->fd = fd; /* Gets unrefd when the call state is wiped. */ - cs->resolve_ret = 0; - nfs3_call_resume (cs); - ret = 0; - goto err; - } - ret = __nfs3_dir_open_and_resume (cs); +void +nfs3_log_link_call (uint32_t xid, struct nfs3_fh *fh, char *name, + struct nfs3_fh *tgt) +{ + char dfhstr[1024]; + char tfhstr[1024]; -err: - return ret; + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (fh, dfhstr, sizeof (dfhstr)); + nfs3_fh_to_str (tgt, tfhstr, sizeof (tfhstr)); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, LINK: args: %s, name: %s," + " target: %s", xid, dfhstr, name, tfhstr); } -int -nfs3_flush_call_state (nfs3_call_state_t *cs, fd_t *openedfd) +void +nfs3_log_rw_call (uint32_t xid, char *op, struct nfs3_fh *fh, offset3 offt, + count3 count, int stablewrite) { - if ((!cs) || (!openedfd)) - return -1; + char fhstr[1024]; - gf_log (GF_NFS3, GF_LOG_TRACE, "Calling resume"); - cs->resolve_ret = 0; - gf_log (GF_NFS3, GF_LOG_TRACE, "Opening uncached fd done: %d", - openedfd->refcount); - cs->fd = fd_ref (openedfd); - list_del (&cs->openwait_q); - nfs3_call_resume (cs); + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); + if (stablewrite == -1) + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s, offset:" + " %"PRIu64", count: %"PRIu32, xid, op, fhstr, offt, + count); + else + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s, offset:" + " %"PRIu64", count: %"PRIu32", %s", xid, op, fhstr, + offt, count, + (stablewrite == UNSTABLE)?"UNSTABLE":"STABLE"); - return 0; } int -nfs3_flush_inode_queue (struct inode_op_queue *inode_q, fd_t *openedfd) -{ - nfs3_call_state_t *cstmp = NULL; - nfs3_call_state_t *cs = NULL; +nfs3_getattr_loglevel (nfsstat3 stat) { - if ((!openedfd) || (!inode_q)) - return -1; + int ll = GF_LOG_DEBUG; - list_for_each_entry_safe (cs, cstmp, &inode_q->opq, openwait_q) - nfs3_flush_call_state (cs, openedfd); + switch (stat) { - return 0; + case NFS3ERR_PERM: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ACCES: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; } int -nfs3_flush_open_wait_call_states (nfs3_call_state_t *cs, fd_t *openedfd) -{ - struct inode_op_queue *inode_q = NULL; - uint64_t ctxaddr = 0; - int ret = 0; +nfs3_setattr_loglevel (nfsstat3 stat) { - if (!cs) - return -1; + int ll = GF_LOG_DEBUG; - gf_log (GF_NFS3, GF_LOG_TRACE, "Flushing call state"); - ret = inode_ctx_get (cs->resolvedloc.inode, cs->nfsx, &ctxaddr); - if (ret == -1) { - gf_log (GF_NFS3, GF_LOG_TRACE, "No inode queue present"); - goto out; - } + switch (stat) { - inode_q = (struct inode_op_queue *)(long)ctxaddr; - if (!inode_q) - goto out; + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; - pthread_mutex_lock (&inode_q->qlock); - { - nfs3_flush_inode_queue (inode_q, openedfd); + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; } - pthread_mutex_unlock (&inode_q->qlock); -out: - return 0; + return ll; } int -__nfs3_fdcache_update_entry (struct nfs3_state *nfs3, fd_t *fd) -{ - uint64_t ctxaddr = 0; - struct nfs3_fd_entry *fde = NULL; +nfs3_lookup_loglevel (nfsstat3 stat) { - if ((!nfs3) || (!fd)) - return -1; + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_PERM: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ACCES: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; - gf_log (GF_NFS3, GF_LOG_TRACE, "Updating fd: 0x%lx", (long int)fd); - fd_ctx_get (fd, nfs3->nfsx, &ctxaddr); - fde = (struct nfs3_fd_entry *)(long)ctxaddr; - if (fde) { - list_del (&fde->list); - list_add_tail (&fde->list, &nfs3->fdlru); + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; } - return 0; + return ll; } int -nfs3_fdcache_update (struct nfs3_state *nfs3, fd_t *fd) -{ - if ((!nfs3) || (!fd)) - return -1; +nfs3_access_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; - LOCK (&nfs3->fdlrulock); - { - __nfs3_fdcache_update_entry (nfs3, fd); + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; } - UNLOCK (&nfs3->fdlrulock); - return 0; + return ll; } int -__nfs3_fdcache_remove_entry (struct nfs3_state *nfs3, struct nfs3_fd_entry *fde) -{ - if ((!fde) || (!nfs3)) - return 0; +nfs3_readlink_loglevel (nfsstat3 stat) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Removing fd: 0x%lx: %d", - (long int)fde->cachedfd, fde->cachedfd->refcount); - list_del (&fde->list); - fd_ctx_del (fde->cachedfd, nfs3->nfsx, NULL); - fd_unref (fde->cachedfd); - GF_FREE (fde); - --nfs3->fdcount; + int ll = GF_LOG_DEBUG; - return 0; -} + switch (stat) { + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} int -nfs3_fdcache_remove (struct nfs3_state *nfs3, fd_t *fd) -{ - struct nfs3_fd_entry *fde = NULL; - uint64_t ctxaddr = 0; +nfs3_read_loglevel (nfsstat3 stat) { - if ((!nfs3) || (!fd)) - return -1; + int ll = GF_LOG_DEBUG; + + switch (stat) { - LOCK (&nfs3->fdlrulock); - { - fd_ctx_get (fd, nfs3->nfsx, &ctxaddr); - fde = (struct nfs3_fd_entry *)(long)ctxaddr; - __nfs3_fdcache_remove_entry (nfs3, fde); + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; } - UNLOCK (&nfs3->fdlrulock); - return 0; + return ll; } int -__nfs3_fdcache_replace (struct nfs3_state *nfs3) -{ - struct nfs3_fd_entry *fde = NULL; - struct nfs3_fd_entry *tmp = NULL; +nfs3_write_loglevel (nfsstat3 stat) { - if (!nfs3) - return -1; + int ll = GF_LOG_DEBUG; - if (nfs3->fdcount <= GF_NFS3_FDCACHE_SIZE) - return 0; + switch (stat) { - list_for_each_entry_safe (fde, tmp, &nfs3->fdlru, list) + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; break; - __nfs3_fdcache_remove_entry (nfs3, fde); + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; - return 0; -} + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; -int -nfs3_fdcache_add (struct nfs3_state *nfs3, fd_t *fd) -{ - struct nfs3_fd_entry *fde = NULL; - int ret = -1; + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; - if ((!nfs3) || (!fd)) - return -1; + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; - fde = GF_CALLOC (1, sizeof (*fd), gf_nfs_mt_nfs3_fd_entry); - if (!fde) { - gf_log (GF_NFS3, GF_LOG_ERROR, "fd entry allocation failed"); - goto out; - } + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; - /* Already refd by caller. */ - fde->cachedfd = fd; - INIT_LIST_HEAD (&fde->list); - - LOCK (&nfs3->fdlrulock); - { - gf_log (GF_NFS3, GF_LOG_TRACE, "Adding fd: 0x%lx", - (long int) fd); - fd_ctx_set (fd, nfs3->nfsx, (uintptr_t)fde); - fd_bind (fd); - list_add_tail (&fde->list, &nfs3->fdlru); - ++nfs3->fdcount; - __nfs3_fdcache_replace (nfs3); + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; } - UNLOCK (&nfs3->fdlrulock); -out: - return ret; + return ll; } -int32_t -nfs3_file_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, fd_t *fd) -{ - nfs3_call_state_t *cs = NULL; - struct nfs3_state *nfs3 = NULL; +int +nfs3_create_loglevel (nfsstat3 stat) { - cs = frame->local; - if (op_ret == -1) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Opening uncached fd failed"); - cs->resolve_ret = -1; - cs->resolve_errno = op_errno; - fd = NULL; - } else { - gf_log (GF_NFS3, GF_LOG_TRACE, "Opening uncached fd done: %d", - fd->refcount); + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; } - nfs3 = nfs_rpcsvc_request_program_private (cs->req); - nfs3_flush_open_wait_call_states (cs, fd); - nfs3_fdcache_add (nfs3, fd); - return 0; + return ll; } -struct inode_op_queue * -__nfs3_get_inode_queue (nfs3_call_state_t *cs) -{ - struct inode_op_queue *inode_q = NULL; - int ret = -1; - uint64_t ctxaddr = 0; +int +nfs3_mkdir_loglevel (nfsstat3 stat) { - ret = __inode_ctx_get (cs->resolvedloc.inode, cs->nfsx, &ctxaddr); - if (ret == 0) { - inode_q = (struct inode_op_queue *)(long)ctxaddr; - gf_log (GF_NFS3, GF_LOG_TRACE, "Inode queue already inited"); - goto err; - } + int ll = GF_LOG_DEBUG; - inode_q = GF_CALLOC (1, sizeof (*inode_q), gf_nfs_mt_inode_q); - if (!inode_q) { - gf_log (GF_NFS3, GF_LOG_ERROR, "Memory allocation failed"); - goto err; - } + switch (stat) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Initing inode queue"); - INIT_LIST_HEAD (&inode_q->opq); - pthread_mutex_init (&inode_q->qlock, NULL); - __inode_ctx_put (cs->resolvedloc.inode, cs->nfsx, (uintptr_t)inode_q); + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; -err: - return inode_q; -} + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; -struct inode_op_queue * -nfs3_get_inode_queue (nfs3_call_state_t *cs) -{ - struct inode_op_queue *inode_q = NULL; + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; - LOCK (&cs->resolvedloc.inode->lock); - { - inode_q = __nfs3_get_inode_queue (cs); + default: + ll = GF_LOG_DEBUG; + break; } - UNLOCK (&cs->resolvedloc.inode->lock); - return inode_q; + return ll; } -#define GF_NFS3_FD_OPEN_INPROGRESS 1 -#define GF_NFS3_FD_NEEDS_OPEN 0 +int +nfs3_symlink_loglevel (nfsstat3 stat) { + int ll = GF_LOG_DEBUG; -int -__nfs3_queue_call_state (struct inode_op_queue *inode_q, nfs3_call_state_t *cs) -{ - int ret = -1; + switch (stat) { - if (!inode_q) - goto err; + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; - pthread_mutex_lock (&inode_q->qlock); - { - if (list_empty (&inode_q->opq)) { - gf_log (GF_NFS3, GF_LOG_TRACE, "First call in queue"); - ret = GF_NFS3_FD_NEEDS_OPEN; - } else - ret = GF_NFS3_FD_OPEN_INPROGRESS; + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; - gf_log (GF_NFS3, GF_LOG_TRACE, "Queueing call state"); - list_add_tail (&cs->openwait_q, &inode_q->opq); + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; } - pthread_mutex_unlock (&inode_q->qlock); -err: - return ret; + return ll; } -/* Returns GF_NFS3_FD_NEEDS_OPEN if the current call is the first one to be - * queued. If so, the caller will need to send the open fop. If this is a - * non-first call to be queued, it means the fd opening is in progress and - * GF_NFS3_FD_OPEN_INPROGRESS is returned. - * - * Returns -1 on error. - */ int -nfs3_queue_call_state (nfs3_call_state_t *cs) -{ - struct inode_op_queue *inode_q = NULL; - int ret = -1; +nfs3_mknod_loglevel (nfsstat3 stat) { - inode_q = nfs3_get_inode_queue (cs); - if (!inode_q) { - gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to get inode op queue"); - goto err; + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; } - ret = __nfs3_queue_call_state (inode_q, cs); + return ll; +} -err: - return ret; +int +nfs3_remove_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; } int -__nfs3_file_open_and_resume (nfs3_call_state_t *cs) -{ - nfs_user_t nfu = {0, }; - int ret = -EFAULT; +nfs3_rmdir_loglevel (nfsstat3 stat) { - if (!cs) - return ret; + int ll = GF_LOG_DEBUG; - ret = nfs3_queue_call_state (cs); - if (ret == -1) { - gf_log (GF_NFS3, GF_LOG_ERROR, "Error queueing call state"); - ret = -EFAULT; - goto out; - } else if (ret == GF_NFS3_FD_OPEN_INPROGRESS) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Open in progress. Will wait."); - ret = 0; - goto out; + switch (stat) { + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; } - nfs_user_root_create (&nfu); - gf_log (GF_NFS3, GF_LOG_TRACE, "Opening uncached fd"); - ret = nfs_open (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, O_RDWR, - nfs3_file_open_cbk, cs); -out: - return ret; + return ll; } -fd_t * -nfs3_fdcache_getfd (struct nfs3_state *nfs3, inode_t *inode) -{ - fd_t *fd = NULL; +int +nfs3_rename_loglevel (nfsstat3 stat) { - if ((!nfs3) || (!inode)) - return NULL; + int ll = GF_LOG_DEBUG; - fd = fd_lookup (inode, 0); - if (fd) { - /* Already refd by fd_lookup, so no need to ref again. */ - gf_log (GF_NFS3, GF_LOG_TRACE, "fd found in state: %d", - fd->refcount); - nfs3_fdcache_update (nfs3, fd); - } else - gf_log (GF_NFS3, GF_LOG_TRACE, "fd not found in state"); + switch (stat) { - return fd; -} + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; -int -nfs3_file_open_and_resume (nfs3_call_state_t *cs, nfs3_resume_fn_t resume) -{ - fd_t *fd = NULL; - int ret = -EFAULT; + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; - if (!cs) - return ret; + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; - cs->resume_fn = resume; - gf_log (GF_NFS3, GF_LOG_TRACE, "Opening: %s", cs->resolvedloc.path); - fd = nfs3_fdcache_getfd (cs->nfs3state, cs->resolvedloc.inode); - if (fd) { - cs->fd = fd; /* Gets unrefd when the call state is wiped. */ - cs->resolve_ret = 0; - nfs3_call_resume (cs); - ret = 0; - goto err; - } + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; - ret = __nfs3_file_open_and_resume (cs); + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; -err: - return ret; -} + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; -void -nfs3_stat_to_errstr (uint32_t xid, char *op, nfsstat3 stat, int pstat, - char *errstr) -{ - if ((!op) || (!errstr)) - return; + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; - sprintf (errstr, "XID: %x, %s: NFS: %d(%s), POSIX: %d(%s)", xid, op, - stat, nfsstat3_strerror (stat), pstat, strerror (pstat)); -} + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; -void -nfs3_log_common_call (uint32_t xid, char *op, struct nfs3_fh *fh) -{ - char fhstr[1024]; + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; - nfs3_fh_to_str (fh, fhstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s", xid, op, - fhstr); -} + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; -void -nfs3_log_fh_entry_call (uint32_t xid, char *op, struct nfs3_fh *fh, - char *name) -{ - char fhstr[1024]; + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; - nfs3_fh_to_str (fh, fhstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s, name: %s", xid, - op, fhstr, name); + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; } -void -nfs3_log_rename_call (uint32_t xid, struct nfs3_fh *src, char *sname, - struct nfs3_fh *dst, char *dname) -{ - char sfhstr[1024]; - char dfhstr[1024]; +int +nfs3_link_loglevel (nfsstat3 stat) { - nfs3_fh_to_str (src, sfhstr); - nfs3_fh_to_str (dst, dfhstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, RENAME: args: Src: %s, " - "name: %s, Dst: %s, name: %s", xid, sfhstr, sname, dfhstr, - dname); -} + int ll = GF_LOG_DEBUG; + switch (stat) { + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; -void -nfs3_log_create_call (uint32_t xid, struct nfs3_fh *fh, char *name, - createmode3 mode) -{ - char fhstr[1024]; - char *modestr = NULL; - char exclmode[] = "EXCLUSIVE"; - char unchkd[] = "UNCHECKED"; - char guarded[] = "GUARDED"; + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; - nfs3_fh_to_str (fh, fhstr); - if (mode == EXCLUSIVE) - modestr = exclmode; - else if (mode == GUARDED) - modestr = guarded; - else - modestr = unchkd; + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; - gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, CREATE: args: %s, name: %s," - " mode: %s", xid, fhstr, name, modestr); -} + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; -void -nfs3_log_mknod_call (uint32_t xid, struct nfs3_fh *fh, char *name, int type) -{ - char fhstr[1024]; - char *modestr = NULL; - char chr[] = "CHAR"; - char blk[] = "BLK"; - char sock[] = "SOCK"; - char fifo[] = "FIFO"; + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; - nfs3_fh_to_str (fh, fhstr); - if (type == NF3CHR) - modestr = chr; - else if (type == NF3BLK) - modestr = blk; - else if (type == NF3SOCK) - modestr = sock; - else - modestr = fifo; + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; - gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, MKNOD: args: %s, name: %s," - " type: %s", xid, fhstr, name, modestr); -} + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; -void -nfs3_log_symlink_call (uint32_t xid, struct nfs3_fh *fh, char *name, char *tgt) -{ - char fhstr[1024]; + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; - nfs3_fh_to_str (fh, fhstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, SYMLINK: args: %s, name: %s," - " target: %s", xid, fhstr, name, tgt); + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; } -void -nfs3_log_link_call (uint32_t xid, struct nfs3_fh *fh, char *name, - struct nfs3_fh *tgt) -{ - char dfhstr[1024]; - char tfhstr[1024]; +int +nfs3_readdir_loglevel (nfsstat3 stat) { - nfs3_fh_to_str (fh, dfhstr); - nfs3_fh_to_str (tgt, tfhstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, LINK: args: %s, name: %s," - " target: %s", xid, dfhstr, name, tfhstr); + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; } -void -nfs3_log_rw_call (uint32_t xid, char *op, struct nfs3_fh *fh, offset3 offt, - count3 count, int stablewrite) -{ - char fhstr[1024]; +int +nfs3_fsstat_loglevel (nfsstat3 stat) { - nfs3_fh_to_str (fh, fhstr); - if (stablewrite == -1) - gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s, offset:" - " %"PRIu64", count: %"PRIu32, xid, op, fhstr, offt, - count); - else - gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s, offset:" - " %"PRIu64", count: %"PRIu32", %s", xid, op, fhstr, - offt, count, - (stablewrite == UNSTABLE)?"UNSTABLE":"STABLE"); + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_PERM: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ACCES: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; } +struct nfs3op_str { + int op; + char str[100]; +}; + +struct nfs3op_str nfs3op_strings[] = { + { NFS3_NULL, "NULL"}, + { NFS3_GETATTR, "GETATTR"}, + { NFS3_SETATTR, "SETATTR"}, + { NFS3_LOOKUP, "LOOKUP"}, + { NFS3_ACCESS, "ACCESS"}, + { NFS3_READLINK, "READLINK"}, + { NFS3_READ, "READ"}, + { NFS3_WRITE, "WRITE"}, + { NFS3_CREATE, "CREATE"}, + { NFS3_MKDIR, "MKDIR"}, + { NFS3_SYMLINK, "SYMLINK"}, + { NFS3_MKNOD, "MKNOD"}, + { NFS3_REMOVE, "REMOVE"}, + { NFS3_RMDIR, "RMDIR"}, + { NFS3_RENAME, "RENAME"}, + { NFS3_LINK, "LINK"}, + { NFS3_READDIR, "READDIR"}, + { NFS3_READDIRP, "READDIRP"}, + { NFS3_FSSTAT, "FSSTAT"}, + { NFS3_FSINFO, "FSINFO"}, + { NFS3_PATHCONF, "PATHCONF"}, + { NFS3_COMMIT, "COMMIT"}, +}; + +int +nfs3_loglevel (int nfs_op, nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (nfs_op) { + case NFS3_GETATTR: + ll = nfs3_getattr_loglevel (stat); + break; + + case NFS3_SETATTR: + ll = nfs3_setattr_loglevel (stat); + break; + + case NFS3_LOOKUP: + ll = nfs3_lookup_loglevel (stat); + break; + + case NFS3_ACCESS: + ll = nfs3_access_loglevel (stat); + break; + + case NFS3_READLINK: + ll = nfs3_readlink_loglevel (stat); + break; + + case NFS3_READ: + ll = nfs3_read_loglevel (stat); + break; + + case NFS3_WRITE: + ll = nfs3_write_loglevel (stat); + break; + + case NFS3_CREATE: + ll = nfs3_create_loglevel (stat); + break; + + case NFS3_MKDIR: + ll = nfs3_mkdir_loglevel (stat); + break; + + case NFS3_SYMLINK: + ll = nfs3_symlink_loglevel (stat); + break; + + case NFS3_MKNOD: + ll = nfs3_mknod_loglevel (stat); + break; + + case NFS3_REMOVE: + ll = nfs3_remove_loglevel (stat); + break; + + case NFS3_RMDIR: + ll = nfs3_rmdir_loglevel (stat); + break; + + case NFS3_RENAME: + ll = nfs3_rename_loglevel (stat); + break; + + case NFS3_LINK: + ll = nfs3_link_loglevel (stat); + break; + + case NFS3_READDIR: + ll = nfs3_readdir_loglevel (stat); + break; + + case NFS3_READDIRP: + ll = nfs3_readdir_loglevel (stat); + break; + + case NFS3_FSSTAT: + ll = nfs3_fsstat_loglevel (stat); + break; + + case NFS3_FSINFO: + ll = nfs3_fsstat_loglevel (stat); + break; + + case NFS3_PATHCONF: + ll = nfs3_fsstat_loglevel (stat); + break; + + case NFS3_COMMIT: + ll = nfs3_write_loglevel (stat); + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} void -nfs3_log_common_res (uint32_t xid, char *op, nfsstat3 stat, int pstat) +nfs3_log_common_res (uint32_t xid, int op, nfsstat3 stat, int pstat) { char errstr[1024]; + int ll = nfs3_loglevel (op, stat); - nfs3_stat_to_errstr (xid, op, stat, pstat, errstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "%s", errstr); + if (THIS->ctx->log.loglevel < ll) + return; + nfs3_stat_to_errstr (xid, nfs3op_strings[op].str, stat, pstat, errstr, sizeof (errstr)); + gf_log (GF_NFS3, ll, "%s", errstr); } void nfs3_log_readlink_res (uint32_t xid, nfsstat3 stat, int pstat, char *linkpath) { char errstr[1024]; + int ll = nfs3_loglevel (NFS3_READLINK, stat); - nfs3_stat_to_errstr (xid, "READLINK", stat, pstat, errstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, target: %s", errstr, linkpath); + if (THIS->ctx->log.loglevel < ll) + return; + + nfs3_stat_to_errstr (xid, "READLINK", stat, pstat, errstr, sizeof (errstr)); + gf_log (GF_NFS3, ll, "%s, target: %s", + errstr, linkpath); } @@ -2400,14 +3421,18 @@ nfs3_log_read_res (uint32_t xid, nfsstat3 stat, int pstat, count3 count, int is_eof, struct iovec *vec, int32_t veccount) { char errstr[1024]; + int ll = GF_LOG_DEBUG; - nfs3_stat_to_errstr (xid, "READ", stat, pstat, errstr); + ll = nfs3_loglevel (NFS3_READ, stat); + if (THIS->ctx->log.loglevel < ll) + return; + nfs3_stat_to_errstr (xid, "READ", stat, pstat, errstr, sizeof (errstr)); if (vec) - gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, count: %"PRIu32", is_eof:" + gf_log (GF_NFS3, ll, "%s, count: %"PRIu32", is_eof:" " %d, vector: count: %d, len: %zd", errstr, count, is_eof, veccount, vec->iov_len); else - gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, count: %"PRIu32", is_eof:" + gf_log (GF_NFS3, ll, "%s, count: %"PRIu32", is_eof:" " %d", errstr, count, is_eof); } @@ -2417,25 +3442,32 @@ nfs3_log_write_res (uint32_t xid, nfsstat3 stat, int pstat, count3 count, int stable, uint64_t wverf) { char errstr[1024]; + int ll = nfs3_loglevel (NFS3_WRITE, stat); - nfs3_stat_to_errstr (xid, "WRITE", stat, pstat, errstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, count: %"PRIu32", %s,wverf: %"PRIu64 + if (THIS->ctx->log.loglevel < ll) + return; + + nfs3_stat_to_errstr (xid, "WRITE", stat, pstat, errstr, sizeof (errstr)); + gf_log (GF_NFS3, ll, "%s, count: %"PRIu32", %s,wverf: %"PRIu64 , errstr, count, (stable == UNSTABLE)?"UNSTABLE":"STABLE", wverf); } void -nfs3_log_newfh_res (uint32_t xid, char *op, nfsstat3 stat, int pstat, +nfs3_log_newfh_res (uint32_t xid, int op, nfsstat3 stat, int pstat, struct nfs3_fh *newfh) { char errstr[1024]; char fhstr[1024]; + int ll = nfs3_loglevel (op, stat); - nfs3_stat_to_errstr (xid, op, stat, pstat, errstr); - nfs3_fh_to_str (newfh, fhstr); + if (THIS->ctx->log.loglevel < ll) + return; + nfs3_stat_to_errstr (xid, nfs3op_strings[op].str, stat, pstat, errstr, sizeof (errstr)); + nfs3_fh_to_str (newfh, fhstr, sizeof (fhstr)); - gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, %s", errstr, fhstr); + gf_log (GF_NFS3, nfs3_loglevel (op, stat), "%s, %s", errstr, fhstr); } @@ -2444,9 +3476,12 @@ nfs3_log_readdir_res (uint32_t xid, nfsstat3 stat, int pstat, uint64_t cverf, count3 count, int is_eof) { char errstr[1024]; + int ll = nfs3_loglevel (NFS3_READDIR, stat); - nfs3_stat_to_errstr (xid, "READDIR", stat, pstat, errstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, count: %"PRIu32", cverf: %"PRIu64 + if (THIS->ctx->log.loglevel < ll) + return; + nfs3_stat_to_errstr (xid, "READDIR", stat, pstat, errstr, sizeof (errstr)); + gf_log (GF_NFS3, ll, "%s, count: %"PRIu32", cverf: %"PRIu64 ", is_eof: %d", errstr, count, cverf, is_eof); } @@ -2456,9 +3491,12 @@ nfs3_log_readdirp_res (uint32_t xid, nfsstat3 stat, int pstat, uint64_t cverf, count3 dircount, count3 maxcount, int is_eof) { char errstr[1024]; + int ll = nfs3_loglevel (NFS3_READDIRP, stat); - nfs3_stat_to_errstr (xid, "READDIRPLUS", stat, pstat, errstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, dircount: %"PRIu32", maxcount: %" + if (THIS->ctx->log.loglevel < ll) + return; + nfs3_stat_to_errstr (xid, "READDIRPLUS", stat, pstat, errstr, sizeof (errstr)); + gf_log (GF_NFS3, ll, "%s, dircount: %"PRIu32", maxcount: %" PRIu32", cverf: %"PRIu64", is_eof: %d", errstr, dircount, maxcount, cverf, is_eof); } @@ -2468,9 +3506,12 @@ void nfs3_log_commit_res (uint32_t xid, nfsstat3 stat, int pstat, uint64_t wverf) { char errstr[1024]; + int ll = nfs3_loglevel (NFS3_COMMIT, stat); - nfs3_stat_to_errstr (xid, "COMMIT", stat, pstat, errstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, wverf: %"PRIu64, errstr, wverf); + if (THIS->ctx->log.loglevel < ll) + return; + nfs3_stat_to_errstr (xid, "COMMIT", stat, pstat, errstr, sizeof (errstr)); + gf_log (GF_NFS3, ll, "%s, wverf: %"PRIu64, errstr, wverf); } @@ -2480,7 +3521,10 @@ nfs3_log_readdir_call (uint32_t xid, struct nfs3_fh *fh, count3 dircount, { char fhstr[1024]; - nfs3_fh_to_str (fh, fhstr); + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); if (maxcount == 0) gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, READDIR: args: %s," @@ -2501,9 +3545,11 @@ nfs3_fh_resolve_inode_done (nfs3_call_state_t *cs, inode_t *inode) return ret; gf_log (GF_NFS3, GF_LOG_TRACE, "FH inode resolved"); - ret = nfs_inode_loc_fill (inode, &cs->resolvedloc); - if (ret < 0) + ret = nfs_inode_loc_fill (inode, &cs->resolvedloc, NFS_RESOLVE_EXIST); + if (ret < 0) { + gf_log (GF_NFS3, GF_LOG_ERROR, "inode loc fill failed"); goto err; + } nfs3_call_resume (cs); @@ -2511,56 +3557,6 @@ err: return ret; } -#define GF_NFS3_FHRESOLVE_FOUND 1 -#define GF_NFS3_FHRESOLVE_NOTFOUND 2 -#define GF_NFS3_FHRESOLVE_DIRFOUND 3 - -int -nfs3_fh_resolve_check_entry (struct nfs3_fh *fh, gf_dirent_t *candidate, - int hashidx) -{ - struct iatt *ia = NULL; - int ret = GF_NFS3_FHRESOLVE_NOTFOUND; - nfs3_hash_entry_t entryhash = 0; - char gfidstr[512]; - - if ((!fh) || (!candidate)) - return ret; - - if ((strcmp (candidate->d_name, ".") == 0) || - (strcmp (candidate->d_name, "..") == 0)) - goto found_entry; - - ia = &candidate->d_stat; - if ((uuid_compare (candidate->d_stat.ia_gfid, fh->gfid)) == 0) { - uuid_unparse (candidate->d_stat.ia_gfid, gfidstr); - gf_log (GF_NFS3, GF_LOG_TRACE, "Found entry: gfid: %s, " - "name: %s, hashcount %d", gfidstr, candidate->d_name, - hashidx); - ret = GF_NFS3_FHRESOLVE_FOUND; - goto found_entry; - } - - /* This condition ensures that we never have to be afraid of having - * a directory hash conflict with a file hash. The consequence of - * this condition is that we can now have unlimited files in a directory - * and upto 65536 sub-directories in a directory. - */ - if (!IA_ISDIR (candidate->d_stat.ia_type)) - goto found_entry; - entryhash = fh->entryhash[hashidx]; - if (entryhash == nfs3_fh_hash_entry (ia->ia_gfid)) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Found hash match: %s: %d, " - "hashidx: %d", candidate->d_name, entryhash, hashidx); - ret = GF_NFS3_FHRESOLVE_DIRFOUND; - goto found_entry; - } - -found_entry: - - return ret; -} - int32_t nfs3_fh_resolve_entry_lookup_cbk (call_frame_t *frame, void *cookie, @@ -2570,392 +3566,82 @@ nfs3_fh_resolve_entry_lookup_cbk (call_frame_t *frame, void *cookie, struct iatt *postparent) { nfs3_call_state_t *cs = NULL; + inode_t *linked_inode = NULL; cs = frame->local; cs->resolve_ret = op_ret; cs->resolve_errno = op_errno; if (op_ret == -1) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Lookup failed: %s: %s", + gf_log (GF_NFS3, (op_errno == ENOENT ? GF_LOG_TRACE : GF_LOG_ERROR), + "Lookup failed: %s: %s", cs->resolvedloc.path, strerror (op_errno)); goto err; } else gf_log (GF_NFS3, GF_LOG_TRACE, "Entry looked up: %s", cs->resolvedloc.path); - inode_link (inode, cs->resolvedloc.parent, cs->resolvedloc.name, buf); + memcpy (&cs->stbuf, buf, sizeof (*buf)); + memcpy (&cs->postparent, postparent, sizeof (*postparent)); + linked_inode = inode_link (inode, cs->resolvedloc.parent, + cs->resolvedloc.name, buf); + if (linked_inode) { + inode_lookup (linked_inode); + inode_unref (cs->resolvedloc.inode); + cs->resolvedloc.inode = linked_inode; + } err: nfs3_call_resume (cs); return 0; } - int32_t -nfs3_fh_resolve_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, - gf_dirent_t *entries); - -int -nfs3_fh_resolve_found_entry (nfs3_call_state_t *cs, gf_dirent_t *candidate) -{ - int ret = 0; - nfs_user_t nfu = {0, }; - uuid_t gfid = {0, }; - - if ((!cs) || (!candidate)) - return -EFAULT; - - uuid_copy (gfid, cs->resolvedloc.inode->gfid); - nfs_loc_wipe (&cs->resolvedloc); - ret = nfs_entry_loc_fill (cs->vol->itable, gfid, candidate->d_name, - &cs->resolvedloc, NFS_RESOLVE_CREATE); - if (ret == -ENOENT) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Entry not in itable, needs" - " lookup"); - nfs_user_root_create (&nfu); - ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - nfs3_fh_resolve_entry_lookup_cbk, - cs); - } else { - gf_log (GF_NFS3, GF_LOG_TRACE, "Entry got from itable"); - nfs3_call_resume (cs); - } - - return ret; -} - - -int32_t -nfs3_fh_resolve_parent_lookup_cbk (call_frame_t *frame, void *cookie, +nfs3_fh_resolve_inode_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) { nfs3_call_state_t *cs = NULL; + inode_t *linked_inode = NULL; cs = frame->local; cs->resolve_ret = op_ret; cs->resolve_errno = op_errno; if (op_ret == -1) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Lookup failed: %s: %s", + gf_log (GF_NFS3, (op_errno == ENOENT ? GF_LOG_TRACE : GF_LOG_ERROR), + "Lookup failed: %s: %s", cs->resolvedloc.path, strerror (op_errno)); nfs3_call_resume (cs); goto err; - } else - gf_log (GF_NFS3, GF_LOG_TRACE, "Entry looked up: %s", - cs->resolvedloc.path); - - inode_link (inode, cs->resolvedloc.parent, cs->resolvedloc.name, buf); - nfs3_fh_resolve_entry_hard (cs); - -err: - return 0; -} - - -int -nfs3_fh_resolve_found_parent (nfs3_call_state_t *cs, gf_dirent_t *candidate) -{ - int ret = 0; - nfs_user_t nfu = {0, }; - uuid_t gfid = {0, }; - - if ((!cs) || (!candidate)) - return -EFAULT; - - uuid_copy (gfid, cs->resolvedloc.inode->gfid); - nfs_loc_wipe (&cs->resolvedloc); - ret = nfs_entry_loc_fill (cs->vol->itable, gfid, candidate->d_name, - &cs->resolvedloc, NFS_RESOLVE_CREATE); - if (ret == -ENOENT) { - nfs_user_root_create (&nfu); - ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - nfs3_fh_resolve_parent_lookup_cbk, - cs); - } else - nfs3_fh_resolve_entry_hard (cs); - - return ret; -} - - -int -nfs3_fh_resolve_found (nfs3_call_state_t *cs, gf_dirent_t *candidate) -{ - int ret = 0; - - if ((!cs) || (!candidate)) - return -EFAULT; - - if (!cs->resolventry) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Candidate entry was found"); - ret = nfs3_fh_resolve_found_entry (cs, candidate); - } else { - gf_log (GF_NFS3, GF_LOG_TRACE, "Entry's parent was found"); - ret = nfs3_fh_resolve_found_parent (cs, candidate); } - return ret; -} - - -int32_t -nfs3_fh_resolve_opendir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, fd_t *fd) -{ - nfs3_call_state_t *cs = NULL; - int ret = -EFAULT; - nfs_user_t nfu = {0, }; - - cs = frame->local; - cs->resolve_ret = op_ret; - cs->resolve_errno = op_errno; - - if (op_ret == -1) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Dir open failed: %s: %s", - cs->resolvedloc.path, strerror (op_errno)); - nfs3_call_resume (cs); - goto err; - } else - gf_log (GF_NFS3, GF_LOG_TRACE, "Reading directory: %s", - cs->resolvedloc.path); + memcpy (&cs->stbuf, buf, sizeof(*buf)); + memcpy (&cs->postparent, buf, sizeof(*postparent)); + linked_inode = inode_link (inode, cs->resolvedloc.parent, + cs->resolvedloc.name, buf); + if (linked_inode) { + inode_lookup (linked_inode); + inode_unref (cs->resolvedloc.inode); + cs->resolvedloc.inode = linked_inode; + } - nfs_user_root_create (&nfu); - /* Keep this directory fd_t around till we have either: - * a. found the entry, - * b. exhausted all the entries, - * c. decide to step into a child directory. - * - * This decision is made in nfs3_fh_resolve_check_response. + /* If it is an entry lookup and we landed in the callback for hard + * inode resolution, it means the parent inode was not available and + * had to be resolved first. Now that is done, lets head back into + * entry resolution. */ - cs->resolve_dir_fd = fd; - gf_log (GF_NFS3, GF_LOG_TRACE, "resolve new fd refed: 0x%lx, ref: %d", - (long)cs->resolve_dir_fd, cs->resolve_dir_fd->refcount); - ret = nfs_readdirp (cs->nfsx, cs->vol, &nfu, fd, GF_NFS3_DTPREF, 0, - nfs3_fh_resolve_readdir_cbk, cs); - -err: - return ret; -} - -int32_t -nfs3_fh_resolve_dir_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) -{ - nfs3_call_state_t *cs = NULL; - nfs_user_t nfu = {0, }; - - cs = frame->local; - cs->resolve_ret = op_ret; - cs->resolve_errno = op_errno; - - if (op_ret == -1) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Lookup failed: %s: %s", - cs->resolvedloc.path, strerror (op_errno)); - nfs3_call_resume (cs); - goto err; - } else - gf_log (GF_NFS3, GF_LOG_TRACE, "Dir will be opened: %s", - cs->resolvedloc.path); - - nfs_user_root_create (&nfu); - inode_link (inode, cs->resolvedloc.parent, cs->resolvedloc.name, buf); - nfs_opendir (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - nfs3_fh_resolve_opendir_cbk, cs); - + if (cs->resolventry) + nfs3_fh_resolve_entry_hard (cs); + else + nfs3_call_resume (cs); err: return 0; } -/* Validate the depth of the dir such that we do not end up opening and - * reading directories beyond those that are needed for resolving the file - * handle. - * Returns 1 if fh resolution can continue, 0 otherwise. - */ -int -nfs3_fh_resolve_validate_dirdepth (nfs3_call_state_t *cs) -{ - int ret = 1; - - if (!cs) - return 0; - - /* This condition will generally never be hit because the - * hash-matching scheme will prevent us from going into a - * directory that is not part of the hash-array. - */ - if (nfs3_fh_hash_index_is_beyond (&cs->resolvefh, cs->hashidx)) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Hash index is beyond: idx %d," - " fh idx: %d", cs->hashidx, cs->resolvefh.hashcount); - ret = 0; - goto out; - } - - if (cs->hashidx >= GF_NFSFH_MAXHASHES) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Hash index beyond max hashes:" - " hashidx %d, max: %d", cs->hashidx, - GF_NFSFH_MAXHASHES); - ret = 0; - goto out; - } - -out: - return ret; -} - - -int -nfs3_fh_resolve_dir_hard (nfs3_call_state_t *cs, uuid_t dirgfid, char *entry) -{ - int ret = -EFAULT; - nfs_user_t nfu = {0, }; - char gfidstr[512]; - - if (!cs) - return ret; - - cs->hashidx++; - nfs_loc_wipe (&cs->resolvedloc); - if (!nfs3_fh_resolve_validate_dirdepth (cs)) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Dir depth validation failed"); - nfs3_call_resume_estale (cs); - ret = 0; - goto out; - } - - nfs_user_root_create (&nfu); - uuid_unparse (dirgfid, gfidstr); - gf_log (GF_NFS3, GF_LOG_TRACE, "FH hard dir resolution: gfid: %s, " - "entry: %s, next hashcount: %d", gfidstr, entry, cs->hashidx); - ret = nfs_entry_loc_fill (cs->vol->itable, dirgfid, entry, - &cs->resolvedloc, NFS_RESOLVE_CREATE); - - if (ret == 0) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Dir will be opened: %s", - cs->resolvedloc.path); - ret = nfs_opendir (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - nfs3_fh_resolve_opendir_cbk, cs); - } else if (ret == -ENOENT) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Dir needs lookup: %s", - cs->resolvedloc.path); - ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - nfs3_fh_resolve_dir_lookup_cbk, cs); - } -out: - return ret; -} - - -/* - * Called in a recursive code path, so if another - * directory was opened in an earlier call during fh resolution, we must unref - * through this reference before opening another fd_t. - */ -#define nfs3_fh_resolve_close_cwd(cst) \ - do { \ - if ((cst)->resolve_dir_fd) { \ - gf_log (GF_NFS3, GF_LOG_TRACE, "resolve fd " \ - "unrefing: 0x%lx, ref: %d", \ - (long)(cst)->resolve_dir_fd, \ - (cst)->resolve_dir_fd->refcount); \ - fd_unref ((cst)->resolve_dir_fd); \ - } \ - } while (0) \ - - -int -nfs3_fh_resolve_check_response (nfs3_call_state_t *cs, gf_dirent_t *candidate, - int response, off_t last_offt) -{ - int ret = -EFAULT; - nfs_user_t nfu = {0, }; - - if (!cs) - return ret; - - switch (response) { - - case GF_NFS3_FHRESOLVE_DIRFOUND: - nfs3_fh_resolve_close_cwd (cs); - nfs3_fh_resolve_dir_hard (cs, cs->resolvedloc.inode->gfid, - candidate->d_name); - break; - - case GF_NFS3_FHRESOLVE_FOUND: - nfs3_fh_resolve_close_cwd (cs); - nfs3_fh_resolve_found (cs, candidate); - break; - - case GF_NFS3_FHRESOLVE_NOTFOUND: - nfs_user_root_create (&nfu); - nfs_readdirp (cs->nfsx, cs->vol, &nfu, cs->resolve_dir_fd, - GF_NFS3_DTPREF, last_offt, - nfs3_fh_resolve_readdir_cbk, cs); - break; - } - - return 0; -} - -int -nfs3_fh_resolve_search_dir (nfs3_call_state_t *cs, gf_dirent_t *entries) -{ - gf_dirent_t *candidate = NULL; - int ret = GF_NFS3_FHRESOLVE_NOTFOUND; - off_t lastoff = 0; - char gfidstr[512]; - - if ((!cs) || (!entries)) - return -EFAULT; - - if (list_empty (&entries->list)) - goto not_found; - - list_for_each_entry (candidate, &entries->list, list) { - lastoff = candidate->d_off; - uuid_unparse (candidate->d_stat.ia_gfid, gfidstr); - gf_log (GF_NFS3, GF_LOG_TRACE, "Candidate: %s, gfid: %s", - PRIu64, candidate->d_name, gfidstr); - ret = nfs3_fh_resolve_check_entry (&cs->resolvefh, candidate, - cs->hashidx); - if (ret != GF_NFS3_FHRESOLVE_NOTFOUND) - break; - } - -not_found: - nfs3_fh_resolve_check_response (cs, candidate, ret, lastoff); - return ret; -} - - -int32_t -nfs3_fh_resolve_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, - gf_dirent_t *entries) -{ - nfs3_call_state_t *cs = NULL; - - cs = frame->local; - if (op_ret <= 0) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Directory read done: %s: %s", - cs->resolvedloc.path, strerror (op_ret)); - cs->resolve_ret = -1; - cs->resolve_errno = ESTALE; - nfs3_call_resume (cs); - goto err; - } - - nfs3_fh_resolve_search_dir (cs, entries); - -err: - return 0; -} /* Needs no extra argument since it knows that the fh to be resolved is in * resolvefh and that it needs to start looking from the root. @@ -2965,38 +3651,25 @@ nfs3_fh_resolve_inode_hard (nfs3_call_state_t *cs) { int ret = -EFAULT; nfs_user_t nfu = {0, }; - char gfidstr[512]; if (!cs) return ret; - cs->hashidx++; + gf_log (GF_NFS3, GF_LOG_TRACE, "FH hard resolution for: gfid 0x%s", + uuid_utoa (cs->resolvefh.gfid)); + cs->hardresolved = 1; nfs_loc_wipe (&cs->resolvedloc); - if (!nfs3_fh_resolve_validate_dirdepth (cs)) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Dir depth validation failed"); - nfs3_call_resume_estale (cs); - ret = 0; + ret = nfs_gfid_loc_fill (cs->vol->itable, cs->resolvefh.gfid, + &cs->resolvedloc, NFS_RESOLVE_CREATE); + if (ret < 0) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to fill loc using gfid: " + "%s", strerror (-ret)); goto out; } nfs_user_root_create (&nfu); - uuid_unparse (cs->resolvefh.gfid, gfidstr); - gf_log (GF_NFS3, GF_LOG_TRACE, "FH hard resolution for: gfid 0x%s", - ", hashcount: %d, current hashidx %d", gfidstr, - cs->resolvefh.hashcount, cs->hashidx); - ret = nfs_root_loc_fill (cs->vol->itable, &cs->resolvedloc); - - if (ret == 0) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Dir will be opened: %s", - cs->resolvedloc.path); - ret = nfs_opendir (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - nfs3_fh_resolve_opendir_cbk, cs); - } else if (ret == -ENOENT) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Dir needs lookup: %s", - cs->resolvedloc.path); - ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - nfs3_fh_resolve_dir_lookup_cbk, cs); - } + ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_fh_resolve_inode_lookup_cbk, cs); out: return ret; @@ -3008,17 +3681,15 @@ nfs3_fh_resolve_entry_hard (nfs3_call_state_t *cs) { int ret = -EFAULT; nfs_user_t nfu = {0, }; - char gfidstr[512]; if (!cs) return ret; nfs_loc_wipe (&cs->resolvedloc); nfs_user_root_create (&nfu); - uuid_unparse (cs->resolvefh.gfid, gfidstr); gf_log (GF_NFS3, GF_LOG_TRACE, "FH hard resolution: gfid: %s " - ", entry: %s, hashidx: %d", gfidstr, cs->resolventry, - cs->hashidx); + ", entry: %s", uuid_utoa (cs->resolvefh.gfid), + cs->resolventry); ret = nfs_entry_loc_fill (cs->vol->itable, cs->resolvefh.gfid, cs->resolventry, &cs->resolvedloc, @@ -3027,8 +3698,22 @@ nfs3_fh_resolve_entry_hard (nfs3_call_state_t *cs) if (ret == -2) { gf_log (GF_NFS3, GF_LOG_TRACE, "Entry needs lookup: %s", cs->resolvedloc.path); - nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - nfs3_fh_resolve_entry_lookup_cbk, cs); + /* If the NFS op is lookup, let the resume callback + * handle the sending of the lookup fop. Similarly, + * if the NFS op is create, let the create call + * go ahead in the resume callback so that an EEXIST gets + * handled at posix without an extra fop at this point. + */ + if (nfs3_lookup_op (cs) || + (nfs3_create_op (cs) && !nfs3_create_exclusive_op (cs))) { + cs->lookuptype = GF_NFS3_FRESH; + cs->resolve_ret = 0; + nfs3_call_resume (cs); + } else { + cs->hardresolved = 1; + nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_fh_resolve_entry_lookup_cbk, cs); + } ret = 0; } else if (ret == -1) { gf_log (GF_NFS3, GF_LOG_TRACE, "Entry needs parent lookup: %s", @@ -3052,6 +3737,7 @@ nfs3_fh_resolve_inode (nfs3_call_state_t *cs) return ret; gf_log (GF_NFS3, GF_LOG_TRACE, "FH needs inode resolution"); + uuid_copy (cs->resolvedloc.gfid, cs->resolvefh.gfid); inode = inode_find (cs->vol->itable, cs->resolvefh.gfid); if (!inode) ret = nfs3_fh_resolve_inode_hard (cs); @@ -3072,13 +3758,97 @@ nfs3_fh_resolve_entry (nfs3_call_state_t *cs) if (!cs) return ret; - ret = nfs3_fh_resolve_entry_hard (cs); - if (ret < 0) - nfs3_call_resume_estale (cs); + return nfs3_fh_resolve_entry_hard (cs); +} + + +int +nfs3_fh_resolve_resume (nfs3_call_state_t *cs) +{ + int ret = -EFAULT; + + if (!cs) + return ret; + + if (cs->resolve_ret < 0) + goto err_resume_call; + + if (!cs->resolventry) + ret = nfs3_fh_resolve_inode (cs); + else + ret = nfs3_fh_resolve_entry (cs); + +err_resume_call: + if (ret < 0) { + cs->resolve_ret = -1; + cs->resolve_errno = EFAULT; + nfs3_call_resume (cs); + ret = 0; + } + + return ret; +} + + +int32_t +nfs3_fh_resolve_root_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) +{ + nfs3_call_state_t *cs = NULL; + cs = frame->local; + cs->resolve_ret = op_ret; + cs->resolve_errno = op_errno; + + if (op_ret == -1) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Root lookup failed: %s", + strerror (op_errno)); + goto err; + } else + gf_log (GF_NFS3, GF_LOG_TRACE, "Root looked up: %s", + cs->resolvedloc.path); + + nfs3_set_root_looked_up (cs->nfs3state, &cs->resolvefh); +err: + nfs3_fh_resolve_resume (cs); return 0; } + +int +nfs3_fh_resolve_root (nfs3_call_state_t *cs) +{ + int ret = -EFAULT; + nfs_user_t nfu = {0, }; + + if (!cs) + return ret; + + if (nfs3_is_root_looked_up (cs->nfs3state, &cs->resolvefh)) { + ret = nfs3_fh_resolve_resume (cs); + goto out; + } + + nfs_user_root_create (&nfu); + gf_log (GF_NFS3, GF_LOG_TRACE, "Root needs lookup"); + ret = nfs_root_loc_fill (cs->vol->itable, &cs->resolvedloc); + if (ret < 0) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to lookup root from itable: %s", + strerror (-ret)); + goto out; + } + + ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_fh_resolve_root_lookup_cbk, cs); + +out: + return ret; +} + + int nfs3_fh_resolve_and_resume (nfs3_call_state_t *cs, struct nfs3_fh *fh, char *entry, nfs3_resume_fn_t resum_fn) @@ -3099,18 +3869,13 @@ nfs3_fh_resolve_and_resume (nfs3_call_state_t *cs, struct nfs3_fh *fh, * * b. (fh, basename) resolution */ - if (!entry) /* a */ - ret = nfs3_fh_resolve_inode (cs); - else { /* b */ + if (entry) { /* b */ cs->resolventry = gf_strdup (entry); if (!cs->resolventry) goto err; - - ret = nfs3_fh_resolve_entry (cs); } + ret = nfs3_fh_resolve_root (cs); err: return ret; } - - diff --git a/xlators/nfs/server/src/nfs3-helpers.h b/xlators/nfs/server/src/nfs3-helpers.h index 7281dbb7d..4de1d5623 100644 --- a/xlators/nfs/server/src/nfs3-helpers.h +++ b/xlators/nfs/server/src/nfs3-helpers.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _NFS3_HELPER_H_ @@ -44,6 +35,9 @@ nfs3_extract_lookup_name (lookup3args *args); extern nfsstat3 nfs3_errno_to_nfsstat3 (int errnum); +extern nfsstat3 +nfs3_cbk_errno_status (int32_t, int32_t); + extern void nfs3_fill_lookup3res (lookup3res *res, nfsstat3 stat, struct nfs3_fh *newfh, struct iatt *stbuf, struct iatt *postparent, @@ -99,9 +93,8 @@ extern void nfs3_prep_access3args (access3args *args, struct nfs3_fh *fh); extern void -nfs3_fill_access3res (access3res *res, nfsstat3 status, struct iatt *buf, - uint32_t accbits, uid_t uid, gid_t gid, - uint64_t deviceid); +nfs3_fill_access3res (access3res *res, nfsstat3 status, int32_t accbits, + int32_t reqaccbits); extern char * nfs3_fhcache_getpath (struct nfs3_state *nfs3, struct nfs3_fh *fh); @@ -257,7 +250,7 @@ extern int nfs3_cached_inode_opened (xlator_t *nfsxl, inode_t *inode); extern void -nfs3_log_common_res (uint32_t xid, char *op, nfsstat3 stat, int pstat); +nfs3_log_common_res (uint32_t xid, int op, nfsstat3 stat, int pstat); extern void nfs3_log_readlink_res (uint32_t xid, nfsstat3 stat, int pstat, char *linkpath); @@ -271,7 +264,7 @@ nfs3_log_write_res (uint32_t xid, nfsstat3 stat, int pstat, count3 count, int stable, uint64_t wverf); extern void -nfs3_log_newfh_res (uint32_t xid, char *op, nfsstat3 stat, int pstat, +nfs3_log_newfh_res (uint32_t xid, int op, nfsstat3 stat, int pstat, struct nfs3_fh *newfh); extern void @@ -332,18 +325,13 @@ nfs3_fh_resolve_and_resume (nfs3_call_state_t *cs, struct nfs3_fh *fh, char *entry, nfs3_resume_fn_t resum_fn); extern int -nfs3_file_open_and_resume (nfs3_call_state_t *cs, nfs3_resume_fn_t resume); - -extern int -nfs3_dir_open_and_resume (nfs3_call_state_t *cs, nfs3_resume_fn_t resume); - -extern int nfs3_verify_dircookie (struct nfs3_state *nfs3, fd_t *dirfd, cookie3 cookie, uint64_t cverf, nfsstat3 *stat); extern int -nfs3_fdcache_remove (struct nfs3_state *nfs3, fd_t *fd); - -extern int nfs3_is_parentdir_entry (char *entry); + +uint32_t +nfs3_request_to_accessbits (int32_t accbits); + #endif diff --git a/xlators/nfs/server/src/nfs3.c b/xlators/nfs/server/src/nfs3.c index 7fed84d50..f914c3193 100644 --- a/xlators/nfs/server/src/nfs3.c +++ b/xlators/nfs/server/src/nfs3.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _CONFIG_H @@ -32,12 +23,15 @@ #include "nfs3.h" #include "mem-pool.h" #include "logging.h" +#include "nfs-common.h" #include "nfs-fops.h" #include "nfs-inodes.h" #include "nfs-generics.h" #include "nfs3-helpers.h" #include "nfs-mem-types.h" - +#include "nfs.h" +#include "xdr-rpc.h" +#include "xdr-generic.h" #include <sys/socket.h> #include <sys/uio.h> @@ -48,6 +42,8 @@ do { \ if ((str)) { \ if (strlen ((str)) > (len)) { \ + gf_log (GF_NFS3, GF_LOG_ERROR, "strlen "\ + "too long"); \ status = NFS3ERR_NAMETOOLONG; \ retval = -ENAMETOOLONG; \ goto label; \ @@ -57,8 +53,8 @@ #define nfs3_validate_nfs3_state(request, state, status, label, retval) \ do { \ - state = nfs_rpcsvc_request_program_private (request); \ - if (!nfs3) { \ + state = rpcsvc_request_program_private (request); \ + if (!state) { \ gf_log (GF_NFS3, GF_LOG_ERROR, "NFSv3 state " \ "missing from RPC request"); \ status = NFS3ERR_SERVERFAULT; \ @@ -84,6 +80,7 @@ __nfs3_get_export_by_index (struct nfs3_state *nfs3, uuid_t exportid) } exp = NULL; + gf_log (GF_NFS, GF_LOG_ERROR, "searchindex=%d not found", searchindex); found: return exp; } @@ -128,8 +125,7 @@ nfs3_export_access (struct nfs3_state *nfs3, uuid_t exportid) int ret = GF_NFS3_VOLACCESS_RO; struct nfs3_export *exp = NULL; - if (!nfs3) - return ret; + GF_VALIDATE_OR_GOTO (GF_NFS3, nfs3, err); exp = __nfs3_get_export_by_exportid (nfs3, exportid); @@ -147,7 +143,7 @@ err: #define nfs3_check_rw_volaccess(nfs3state, exid, status, label) \ do { \ if (nfs3_export_access (nfs3state,exid)!=GF_NFS3_VOLACCESS_RW){\ - gf_log (GF_NFS3, GF_LOG_TRACE, "No read-write access");\ + gf_log (GF_NFS3, GF_LOG_ERROR, "No read-write access");\ status = NFS3ERR_ROFS; \ goto label; \ } \ @@ -161,8 +157,8 @@ nfs3_fh_to_xlator (struct nfs3_state *nfs3, struct nfs3_fh *fh) xlator_t *vol = NULL; struct nfs3_export *exp = NULL; - if ((!nfs3) || (!fh)) - return vol; + GF_VALIDATE_OR_GOTO (GF_NFS3, nfs3, out); + GF_VALIDATE_OR_GOTO (GF_NFS3, fh, out); exp = __nfs3_get_export_by_exportid (nfs3, fh->exportid); if (!exp) @@ -174,35 +170,98 @@ out: } -#define nfs3_map_fh_to_volume(nfs3state, handle, rqst, volume, status, label) \ +int +nfs3_is_root_looked_up (struct nfs3_state *nfs3, struct nfs3_fh *rootfh) +{ + struct nfs3_export *exp = NULL; + int ret = 0; + + GF_VALIDATE_OR_GOTO (GF_NFS3, nfs3, out); + GF_VALIDATE_OR_GOTO (GF_NFS3, rootfh, out); + + exp = __nfs3_get_export_by_exportid (nfs3, rootfh->exportid); + if (!exp) + goto out; + + ret = exp->rootlookedup; +out: + return ret; +} + + +int +nfs3_set_root_looked_up (struct nfs3_state *nfs3, struct nfs3_fh *rootfh) +{ + struct nfs3_export *exp = NULL; + int ret = 0; + + GF_VALIDATE_OR_GOTO (GF_NFS3, nfs3, out); + GF_VALIDATE_OR_GOTO (GF_NFS3, rootfh, out); + + exp = __nfs3_get_export_by_exportid (nfs3, rootfh->exportid); + if (!exp) + goto out; + + exp->rootlookedup = 1; +out: + return ret; +} + + +#define nfs3_map_fh_to_volume(nfs3state, handle, req, volume, status, label) \ do { \ + char exportid[256], gfid[256]; \ + rpc_transport_t *trans = NULL; \ volume = nfs3_fh_to_xlator ((nfs3state), handle); \ if (!volume) { \ - gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to map " \ - "FH to vol"); \ + uuid_unparse (handle->exportid, exportid); \ + uuid_unparse (handle->gfid, gfid); \ + trans = rpcsvc_request_transport (req); \ + GF_LOG_OCCASIONALLY (nfs3state->occ_logger, \ + GF_NFS3, GF_LOG_ERROR, "Failed to map " \ + "FH to vol: client=%s, exportid=%s, " \ + "gfid=%s", trans->peerinfo.identifier, \ + exportid, gfid); \ + GF_LOG_OCCASIONALLY (nfs3state->occ_logger, \ + GF_NFS3, GF_LOG_ERROR, "Stale nfs " \ + "client %s must be trying to connect to"\ + " a deleted volume, please unmount it.",\ + trans->peerinfo.identifier); \ status = NFS3ERR_STALE; \ goto label; \ } else { \ - gf_log (GF_NFS3, GF_LOG_TRACE, "FH to Volume: %s"\ - ,volume->name); \ - nfs_rpcsvc_request_set_private (req, volume); \ + gf_log (GF_NFS3, GF_LOG_TRACE, "FH to Volume:" \ + "%s", volume->name); \ + rpcsvc_request_set_private (req, volume); \ } \ } while (0); \ #define nfs3_validate_gluster_fh(handle, status, errlabel) \ do { \ - if ((handle)) { \ - if (!nfs3_fh_validate (handle)) { \ - status = NFS3ERR_BADHANDLE; \ - goto errlabel; \ - } \ + if (!nfs3_fh_validate (handle)) { \ + gf_log (GF_NFS3, GF_LOG_ERROR, "Bad Handle"); \ + status = NFS3ERR_BADHANDLE; \ + goto errlabel; \ } \ } while (0) \ #define nfs3_check_fh_resolve_status(cst, nfstat, erlabl) \ do { \ + xlator_t *xlatorp = NULL; \ + char buf[256], gfid[256]; \ + rpc_transport_t *trans = NULL; \ if ((cst)->resolve_ret < 0) { \ + trans = rpcsvc_request_transport (cst->req); \ + xlatorp = nfs3_fh_to_xlator (cst->nfs3state, \ + &cst->resolvefh); \ + uuid_unparse (cst->resolvefh.gfid, gfid); \ + snprintf (buf, sizeof (buf), "(%s) %s : %s", \ + trans->peerinfo.identifier, \ + xlatorp ? xlatorp->name : "ERR", \ + gfid ); \ + gf_log (GF_NFS3, GF_LOG_ERROR, "%s: %s", \ + strerror(cst->resolve_errno), buf); \ nfstat = nfs3_errno_to_nfsstat3 (cst->resolve_errno);\ goto erlabl; \ } \ @@ -210,8 +269,21 @@ out: #define nfs3_check_new_fh_resolve_status(cst, nfstat, erlabl) \ do { \ + xlator_t *xlatorp = NULL; \ + char buf[256], gfid[256]; \ + rpc_transport_t *trans = NULL; \ if (((cst)->resolve_ret < 0) && \ ((cst)->resolve_errno != ENOENT)) { \ + trans = rpcsvc_request_transport (cst->req); \ + xlatorp = nfs3_fh_to_xlator (cst->nfs3state, \ + &cst->resolvefh); \ + uuid_unparse (cst->resolvefh.gfid, gfid); \ + snprintf (buf, sizeof (buf), "(%s) %s : %s", \ + trans->peerinfo.identifier, \ + xlatorp ? xlatorp->name : "ERR", \ + gfid); \ + gf_log (GF_NFS3, GF_LOG_ERROR, "%s: %s", \ + strerror(cst->resolve_errno), buf); \ nfstat = nfs3_errno_to_nfsstat3 (cs->resolve_errno);\ goto erlabl; \ } \ @@ -225,8 +297,8 @@ __nfs3_get_volume_id (struct nfs3_state *nfs3, xlator_t *xl, int ret = -1; struct nfs3_export *exp = NULL; - if ((!nfs3) || (!xl)) - return ret; + GF_VALIDATE_OR_GOTO (GF_NFS3, nfs3, out); + GF_VALIDATE_OR_GOTO (GF_NFS3, xl, out); list_for_each_entry (exp, &nfs3->exports, explist) { if (exp->subvol == xl) { @@ -265,6 +337,16 @@ out: } while (0) \ +#define nfs3_volume_started_check(nf3stt, vlm, rtval, erlbl) \ + do { \ + if ((!nfs_subvolume_started (nfs_state (nf3stt->nfsx), vlm))){\ + gf_log (GF_NFS3, GF_LOG_ERROR, "Volume is disabled: %s",\ + vlm->name); \ + rtval = RPCSVC_ACTOR_IGNORE; \ + goto erlbl; \ + } \ + } while (0) \ + int nfs3_export_sync_trusted (struct nfs3_state *nfs3, uuid_t exportid) @@ -272,8 +354,7 @@ nfs3_export_sync_trusted (struct nfs3_state *nfs3, uuid_t exportid) struct nfs3_export *exp = NULL; int ret = 0; - if (!nfs3) - return ret; + GF_VALIDATE_OR_GOTO (GF_NFS3, nfs3, err); exp = __nfs3_get_export_by_exportid (nfs3, exportid); if (!exp) @@ -291,8 +372,7 @@ nfs3_export_write_trusted (struct nfs3_state *nfs3, uuid_t exportid) struct nfs3_export *exp = NULL; int ret = 0; - if (!nfs3) - return ret; + GF_VALIDATE_OR_GOTO (GF_NFS3, nfs3, err); exp = __nfs3_get_export_by_exportid (nfs3, exportid); if (!exp) @@ -330,12 +410,15 @@ nfs3_call_state_init (struct nfs3_state *s, rpcsvc_request_t *req, xlator_t *v) { nfs3_call_state_t *cs = NULL; - if ((!s) || (!req) || (!v)) - return NULL; + GF_VALIDATE_OR_GOTO (GF_NFS3, s, err); + GF_VALIDATE_OR_GOTO (GF_NFS3, req, err); + GF_VALIDATE_OR_GOTO (GF_NFS3, v, err); cs = (nfs3_call_state_t *) mem_get (s->localpool); - if (!cs) + if (!cs) { + gf_log (GF_NFS3, GF_LOG_ERROR, "out of memory"); return NULL; + } memset (cs, 0, sizeof (*cs)); INIT_LIST_HEAD (&cs->entries.list); @@ -345,29 +428,25 @@ nfs3_call_state_init (struct nfs3_state *s, rpcsvc_request_t *req, xlator_t *v) cs->vol = v; cs->nfsx = s->nfsx; cs->nfs3state = s; - +err: return cs; } void nfs3_call_state_wipe (nfs3_call_state_t *cs) { - struct nfs3_state *nfs3 = NULL; if (!cs) return; - nfs3 = cs->nfs3state; if (cs->fd) { gf_log (GF_NFS3, GF_LOG_TRACE, "fd 0x%lx ref: %d", (long)cs->fd, cs->fd->refcount); fd_unref (cs->fd); } - if (cs->resolventry) - GF_FREE (cs->resolventry); + GF_FREE (cs->resolventry); - if (cs->pathname) - GF_FREE (cs->pathname); + GF_FREE (cs->pathname); if (!list_empty (&cs->entries.list)) gf_dirent_free (&cs->entries); @@ -376,8 +455,12 @@ nfs3_call_state_wipe (nfs3_call_state_t *cs) nfs_loc_wipe (&cs->resolvedloc); if (cs->iob) iobuf_unref (cs->iob); + if (cs->iobref) + iobref_unref (cs->iobref); + if (cs->trans) + rpc_transport_unref (cs->trans); memset (cs, 0, sizeof (*cs)); - mem_put (nfs3->localpool, cs); + mem_put (cs); /* Already refd by fd_lookup, so no need to ref again. */ } @@ -403,7 +486,7 @@ nfs3_serialize_reply (rpcsvc_request_t *req, void *arg, nfs3_serializer sfunc, struct iobuf *iob = NULL; ssize_t retlen = -1; - nfs3 = (struct nfs3_state *)nfs_rpcsvc_request_program_private (req); + nfs3 = (struct nfs3_state *)rpcsvc_request_program_private (req); if (!nfs3) { gf_log (GF_NFS3, GF_LOG_ERROR, "NFSv3 state not found in RPC" " request"); @@ -413,6 +496,8 @@ nfs3_serialize_reply (rpcsvc_request_t *req, void *arg, nfs3_serializer sfunc, /* First, get the io buffer into which the reply in arg will * be serialized. */ + /* TODO: get rid of 'sfunc' and use 'xdrproc_t' so we + can have 'xdr_sizeof' */ iob = iobuf_get (nfs3->iobpool); if (!iob) { gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to get iobuf"); @@ -451,6 +536,7 @@ nfs3svc_submit_reply (rpcsvc_request_t *req, void *arg, nfs3_serializer sfunc) struct iovec outmsg = {0, }; struct iobuf *iob = NULL; int ret = -1; + struct iobref *iobref = NULL; if (!req) return -1; @@ -461,14 +547,20 @@ nfs3svc_submit_reply (rpcsvc_request_t *req, void *arg, nfs3_serializer sfunc) goto ret; } - /* Then, submit the message for transmission. */ - ret = nfs_rpcsvc_submit_message (req, outmsg, iob); + iobref = iobref_new (); + if (!iobref) { + gf_log (GF_NFS3, GF_LOG_ERROR, "failed on iobref_new()"); + goto ret; + } - /* Now that we've done our job of handing the message to the RPC layer - * we can safely unref the iob in the hope that RPC layer must have - * ref'ed the iob on receiving into the txlist. - */ - iobuf_unref (iob); + ret = iobref_add (iobref, iob); + if (ret) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to add iob to iobref"); + goto ret; + } + + /* Then, submit the message for transmission. */ + ret = rpcsvc_submit_message (req, &outmsg, 1, NULL, 0, iobref); if (ret == -1) { gf_log (GF_NFS3, GF_LOG_ERROR, "Reply submission failed"); goto ret; @@ -476,6 +568,14 @@ nfs3svc_submit_reply (rpcsvc_request_t *req, void *arg, nfs3_serializer sfunc) ret = 0; ret: + /* Now that we've done our job of handing the message to the RPC layer + * we can safely unref the iob in the hope that RPC layer must have + * ref'ed the iob on receiving into the txlist. + */ + if (NULL != iob) + iobuf_unref (iob); + if (NULL != iobref) + iobref_unref (iobref); return ret; } @@ -483,11 +583,12 @@ ret: int nfs3svc_submit_vector_reply (rpcsvc_request_t *req, void *arg, nfs3_serializer sfunc, struct iovec *payload, - int vcount, struct iobref *piobref) + int vcount, struct iobref *iobref) { struct iovec outmsg = {0, }; struct iobuf *iob = NULL; int ret = -1; + int new_iobref = 0; if (!req) return -1; @@ -495,25 +596,43 @@ nfs3svc_submit_vector_reply (rpcsvc_request_t *req, void *arg, iob = nfs3_serialize_reply (req, arg, sfunc, &outmsg); if (!iob) { gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to serialize reply"); - goto err; + goto ret; + } + if (iobref == NULL) { + iobref = iobref_new (); + if (!iobref) { + gf_log (GF_NFS3, GF_LOG_ERROR, "failed on iobref_new"); + goto ret; + } + new_iobref = 1; } - ret = nfs_rpcsvc_request_attach_vector (req, outmsg, iob, NULL, 0); - iobuf_unref (iob); - - if (piobref) - ret = nfs_rpcsvc_request_attach_vectors (req, payload, vcount, - piobref); + ret = iobref_add (iobref, iob); + if (ret) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to add iob to iobref"); + goto ret; + } - if (ret == -1) - goto err; - ret = nfs_rpcsvc_submit_vectors (req); -err: + /* Then, submit the message for transmission. */ + ret = rpcsvc_submit_message (req, &outmsg, 1, payload, vcount, iobref); + if (ret == -1) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Reply submission failed"); + goto ret; + } + ret = 0; +ret: + /* Now that we've done our job of handing the message to the RPC layer + * we can safely unref the iob in the hope that RPC layer must have + * ref'ed the iob on receiving into the txlist. + */ + if (NULL != iob) + iobuf_unref (iob); + if (new_iobref) + iobref_unref (iobref); return ret; } - uint64_t nfs3_request_xlator_deviceid (rpcsvc_request_t *rq) { @@ -525,8 +644,8 @@ nfs3_request_xlator_deviceid (rpcsvc_request_t *rq) if (!rq) return 0; - xl = nfs_rpcsvc_request_private (rq); - nfs3 = nfs_rpcsvc_request_program_private (rq); + xl = rpcsvc_request_private (rq); + nfs3 = rpcsvc_request_program_private (rq); if (gf_nfs_dvm_off (nfs_state (nfs3->nfsx))) devid = (uint64_t)nfs_xlator_to_xlid (nfs3->exportslist, xl); else { @@ -544,8 +663,7 @@ nfs3svc_null (rpcsvc_request_t *req) struct iovec dummyvec = {0, }; if (!req) return RPCSVC_ACTOR_ERROR; - - nfs_rpcsvc_submit_generic (req, dummyvec, NULL); + rpcsvc_submit_generic (req, &dummyvec, 1, NULL, 0, NULL); return RPCSVC_ACTOR_SUCCESS; } @@ -576,10 +694,23 @@ nfs3svc_getattr_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs = frame->local; - if (op_ret == -1) - status = nfs3_errno_to_nfsstat3 (op_errno); + /* + * Somewhat counter-intuitively, we don't need to look for sh-failed + * here. Failing this getattr will generate a new lookup from the + * client, and nfs_fop_lookup_cbk will detect any self-heal failures. + */ + + if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + status = nfs3_cbk_errno_status (op_ret, op_errno); + } + else { + nfs_fix_generation(this,inode); + } - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "GETATTR", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_GETATTR, status, op_errno); nfs3_getattr_reply (cs->req, status, buf); @@ -591,17 +722,22 @@ nfs3svc_getattr_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t nfs3svc_getattr_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct iatt *buf) + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata) { nfsstat3 status = NFS3_OK; nfs3_call_state_t *cs = NULL; cs = frame->local; - if (op_ret == -1) - status = nfs3_errno_to_nfsstat3 (op_errno); + if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + status = nfs3_cbk_errno_status (op_ret, op_errno); + } - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "GETATTR", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_GETATTR, status, op_errno); nfs3_getattr_reply (cs->req, status, buf); @@ -618,6 +754,9 @@ nfs3_getattr_resume (void *carg) int ret = -EFAULT; nfs_user_t nfu = {0, }; nfs3_call_state_t *cs = NULL; + uint64_t raw_ctx = 0; + struct nfs_inode_ctx *ictx = NULL; + struct nfs_state *priv = NULL; if (!carg) return ret; @@ -630,14 +769,42 @@ nfs3_getattr_resume (void *carg) * for the root to have been looked up when the getattr on the root is * sent. AND, this causes a problem for stat-prefetch in that it * expects even the root inode to have been looked up. - */ - if (cs->resolvedloc.inode->ino == 1) + + if (__is_root_gfid (cs->resolvedloc.inode->gfid)) ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, nfs3svc_getattr_lookup_cbk, cs); else ret = nfs_stat (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - nfs3svc_getattr_stat_cbk, cs); + */ + + if (cs->hardresolved) { + ret = -EFAULT; + stat = NFS3_OK; + goto nfs3err; + } + + /* + * If brick state changed, we need to force a proper lookup cycle (as + * would happen in native protocol) to do self-heal checks. We detect + * this by comparing the generation number for the last successful + * creation/lookup on the inode to the current number, so inodes that + * haven't been validated since the state change are affected. + */ + if (inode_ctx_get(cs->resolvedloc.inode,cs->nfsx,&raw_ctx) == 0) { + ictx = (struct nfs_inode_ctx *)raw_ctx; + priv = cs->nfsx->private; + if (ictx->generation != priv->generation) { + ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, + &cs->resolvedloc, + nfs3svc_getattr_lookup_cbk, cs); + goto check_err; + } + } + ret = nfs_stat (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3svc_getattr_stat_cbk, cs); + +check_err: if (ret < 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Stat fop failed: %s: %s", cs->oploc.path, strerror (-ret)); @@ -646,9 +813,9 @@ nfs3_getattr_resume (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), - "GETATTR", stat, -ret); - nfs3_getattr_reply (cs->req, stat, NULL); + nfs3_log_common_res (rpcsvc_request_xid (cs->req), + NFS3_GETATTR, stat, -ret); + nfs3_getattr_reply (cs->req, stat, &cs->stbuf); nfs3_call_state_wipe (cs); ret = 0; } @@ -666,13 +833,14 @@ nfs3_getattr (rpcsvc_request_t *req, struct nfs3_fh *fh) struct nfs3_state *nfs3 = NULL; nfs3_call_state_t *cstate = NULL; - if ((!req) || (!fh)) - return -1; + GF_VALIDATE_OR_GOTO (GF_NFS3, req, out); + GF_VALIDATE_OR_GOTO (GF_NFS3, fh, out); - nfs3_log_common_call (nfs_rpcsvc_request_xid (req), "GETATTR", fh); + nfs3_log_common_call (rpcsvc_request_xid (req), "GETATTR", fh); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_handle_call_state_init (nfs3, cstate, req, vol, stat, nfs3err); ret = nfs3_fh_resolve_and_resume (cstate, fh, NULL,nfs3_getattr_resume); @@ -681,13 +849,13 @@ nfs3_getattr (rpcsvc_request_t *req, struct nfs3_fh *fh) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "GETATTR", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_GETATTR, stat, -ret); nfs3_getattr_reply (req, stat, NULL); ret = 0; nfs3_call_state_wipe (cstate); } - +out: return ret; } @@ -703,16 +871,16 @@ nfs3svc_getattr (rpcsvc_request_t *req) return ret; nfs3_prep_getattr3args (&args, &fh); - if (xdr_to_getattr3args (req->msg, &args) <= 0) { + if (xdr_to_getattr3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_getattr (req, &fh); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "GETATTR procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -739,7 +907,7 @@ nfs3_setattr_reply (rpcsvc_request_t *req, nfsstat3 stat, struct iatt *preop, int32_t nfs3svc_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 iatt *postbuf, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; struct iatt *prestat = NULL; @@ -747,7 +915,10 @@ nfs3svc_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -762,7 +933,7 @@ nfs3svc_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, stat = NFS3_OK; nfs3err: - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "SETATTR", stat, + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_SETATTR, stat, op_errno); nfs3_setattr_reply (cs->req, stat, prestat, postbuf); nfs3_call_state_wipe (cs); @@ -774,7 +945,7 @@ nfs3err: int32_t nfs3svc_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, struct iatt *preop, - struct iatt *postop) + struct iatt *postop, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; int ret = -1; @@ -784,28 +955,25 @@ nfs3svc_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } - /* If the first stat was got from the guarded setattr callback, then - * we'll need to use that stat instead of the preop returned here. + prebuf = preop; + /* Store the current preop in case we need to send a truncate, + * in which case the preop to be returned will be this one. */ - if (cs->preparent.ia_ino != 0) - prebuf = &cs->preparent; - else { - prebuf = preop; - /* Store the current preop in case we need to send a truncate, - * in which case the preop to be returned will be this one. - */ - cs->preparent = *preop; - } + cs->preparent = *preop; /* Only truncate if the size is not already same as the requested * truncation and also only if this is not a directory. */ if ((gf_attr_size_set (cs->setattr_valid)) && - (!IA_ISDIR (postop->ia_type))) { + (!IA_ISDIR (postop->ia_type)) && + (preop->ia_size != cs->stbuf.ia_size)) { nfs_request_user_init (&nfu, cs->req); ret = nfs_truncate (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, cs->stbuf.ia_size, nfs3svc_truncate_cbk,cs); @@ -819,8 +987,8 @@ nfs3svc_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), - "SETATTR", stat, op_errno); + nfs3_log_common_res (rpcsvc_request_xid (cs->req), + NFS3_SETATTR, stat, op_errno); nfs3_setattr_reply (cs->req, stat, prebuf, postop); nfs3_call_state_wipe (cs); } @@ -832,7 +1000,8 @@ nfs3err: int32_t nfs3svc_setattr_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct iatt *buf) + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata) { int ret = -EFAULT; @@ -842,12 +1011,15 @@ nfs3svc_setattr_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } if (buf->ia_ctime != cs->timestamp.seconds) { - gf_log (GF_NFS3, GF_LOG_TRACE, "Timestamps not in sync"); + gf_log (GF_NFS3, GF_LOG_ERROR, "Timestamps not in sync"); stat = NFS3ERR_NOT_SYNC; goto nfs3err; } @@ -862,8 +1034,8 @@ nfs3svc_setattr_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), - "SETATTR", stat, op_errno); + nfs3_log_common_res (rpcsvc_request_xid (cs->req), + NFS3_SETATTR, stat, op_errno); nfs3_setattr_reply (cs->req, stat, NULL, NULL); nfs3_call_state_wipe (cs); } @@ -886,22 +1058,17 @@ nfs3_setattr_resume (void *carg) cs = (nfs3_call_state_t *)carg; nfs3_check_fh_resolve_status (cs, stat, nfs3err); nfs_request_user_init (&nfu, cs->req); - /* If no ctime check is required, head straight to setting the attrs. */ - if (cs->sattrguardcheck) - ret = nfs_stat (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - nfs3svc_setattr_stat_cbk, cs); - else - ret = nfs_setattr (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - &cs->stbuf, cs->setattr_valid, - nfs3svc_setattr_cbk, cs); + ret = nfs_setattr (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + &cs->stbuf, cs->setattr_valid, + nfs3svc_setattr_cbk, cs); if (ret < 0) stat = nfs3_errno_to_nfsstat3 (-ret); nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), - "SETATTR", stat, -ret); + nfs3_log_common_res (rpcsvc_request_xid (cs->req), + NFS3_SETATTR, stat, -ret); nfs3_setattr_reply (cs->req, stat, NULL, NULL); nfs3_call_state_wipe (cs); } @@ -920,15 +1087,16 @@ nfs3_setattr (rpcsvc_request_t *req, struct nfs3_fh *fh, sattr3 *sattr, struct nfs3_state *nfs3 = NULL; nfs3_call_state_t *cs = NULL; - if ((!req) || (!fh) || (!sattr) || (!guard)) { - gf_log (GF_NFS3, GF_LOG_ERROR, "Bad arguments"); - return -1; - } + GF_VALIDATE_OR_GOTO (GF_NFS3, req, out); + GF_VALIDATE_OR_GOTO (GF_NFS3, fh, out); + GF_VALIDATE_OR_GOTO (GF_NFS3, sattr, out); + GF_VALIDATE_OR_GOTO (GF_NFS3, guard, out); - nfs3_log_common_call (nfs_rpcsvc_request_xid (req), "SETATTR", fh); + nfs3_log_common_call (rpcsvc_request_xid (req), "SETATTR", fh); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_check_rw_volaccess (nfs3, fh->exportid, stat, nfs3err); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); @@ -946,6 +1114,7 @@ nfs3_setattr (rpcsvc_request_t *req, struct nfs3_fh *fh, sattr3 *sattr, if (!cs->setattr_valid) { ret = -EINVAL; /* Force a reply */ stat = NFS3_OK; + gf_log (GF_NFS3, GF_LOG_ERROR, "cs->setattr_valid is invalid"); goto nfs3err; } @@ -955,7 +1124,7 @@ nfs3_setattr (rpcsvc_request_t *req, struct nfs3_fh *fh, sattr3 *sattr, nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "SETATTR", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_SETATTR, stat, -ret); nfs3_setattr_reply (req, stat, NULL, NULL); nfs3_call_state_wipe (cs); @@ -964,7 +1133,7 @@ nfs3err: */ ret = 0; } - +out: return ret; } @@ -977,20 +1146,19 @@ nfs3svc_setattr (rpcsvc_request_t *req) setattr3args args; int ret = RPCSVC_ACTOR_ERROR; - if (!req) - return ret; + GF_VALIDATE_OR_GOTO (GF_NFS3, req, rpcerr); nfs3_prep_setattr3args (&args, &fh); - if (xdr_to_setattr3args (req->msg, &args) <= 0) { + if (xdr_to_setattr3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_setattr (req, &fh, &args.new_attributes, &args.guard); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "SETATTR procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -1013,6 +1181,36 @@ nfs3_lookup_reply (rpcsvc_request_t *req, nfsstat3 stat, struct nfs3_fh *newfh, (nfs3_serializer)xdr_serialize_lookup3res); } +int +nfs3_lookup_resume (void *carg); + + +int +nfs3_fresh_lookup (nfs3_call_state_t *cs) +{ + int ret = -EFAULT; + char *oldresolventry = NULL; + + GF_VALIDATE_OR_GOTO (GF_NFS3, cs, err); + gf_log (GF_NFS3, GF_LOG_DEBUG, "inode needs fresh lookup"); + inode_unlink (cs->resolvedloc.inode, cs->resolvedloc.parent, + cs->resolventry); + nfs_loc_wipe (&cs->resolvedloc); + + /* Store pointer to currently allocated resolventry because it gets over + * written in fh_resolve_and_resume. + */ + oldresolventry = cs->resolventry; + cs->lookuptype = GF_NFS3_FRESH; + ret = nfs3_fh_resolve_and_resume (cs, &cs->resolvefh, cs->resolventry, + nfs3_lookup_resume); + /* Allocated in the previous call to fh_resolve_and_resume using the + * same call_state. + */ + GF_FREE (oldresolventry); +err: + return ret; +} int nfs3svc_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, @@ -1022,21 +1220,37 @@ nfs3svc_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, struct nfs3_fh newfh = {{0}, }; nfsstat3 status = NFS3_OK; nfs3_call_state_t *cs = NULL; + inode_t *oldinode = NULL; cs = frame->local; if (op_ret == -1) { - status = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, + (op_errno == ENOENT ? GF_LOG_TRACE : GF_LOG_WARNING), + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + status = nfs3_cbk_errno_status (op_ret, op_errno); goto xmit_res; } nfs3_fh_build_child_fh (&cs->parent, buf, &newfh); - + oldinode = inode_link (inode, cs->resolvedloc.parent, + cs->resolvedloc.name, buf); xmit_res: - nfs3_log_newfh_res (nfs_rpcsvc_request_xid (cs->req), "LOOKUP", status, + /* Only send fresh lookup if it was a revalidate that failed. */ + if ((op_ret == -1) && (nfs3_is_revalidate_lookup (cs))) { + op_ret = nfs3_fresh_lookup (cs); + goto out; + } + + nfs3_log_newfh_res (rpcsvc_request_xid (cs->req), NFS3_LOOKUP, status, op_errno, &newfh); nfs3_lookup_reply (cs->req, status, &newfh, buf, postparent); nfs3_call_state_wipe (cs); - +out: + if (oldinode) { + inode_lookup (oldinode); + inode_unref (oldinode); + } return 0; } @@ -1055,7 +1269,10 @@ nfs3svc_lookup_parentdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs = frame->local; if (op_ret == -1) { - status = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + status = nfs3_cbk_errno_status (op_ret, op_errno); goto xmit_res; } @@ -1078,7 +1295,7 @@ nfs3svc_lookup_parentdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } xmit_res: - nfs3_log_newfh_res (nfs_rpcsvc_request_xid (cs->req), "LOOKUP", status, + nfs3_log_newfh_res (rpcsvc_request_xid (cs->req), NFS3_LOOKUP, status, op_errno, &newfh); nfs3_lookup_reply (cs->req, status, &newfh, buf, postparent); nfs3_call_state_wipe (cs); @@ -1097,8 +1314,11 @@ nfs3_lookup_parentdir_resume (void *carg) nfs3_call_state_t *cs = NULL; inode_t *parent = NULL; - if (!carg) - return ret; + if (!carg) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Invalid argument," + " carg value NULL"); + return EINVAL; + } cs = (nfs3_call_state_t *)carg; nfs3_check_fh_resolve_status (cs, stat, nfs3err); @@ -1129,10 +1349,14 @@ nfs3_lookup_parentdir_resume (void *carg) if (!nfs3_fh_is_root_fh (&cs->fh)) { parent = inode_ref (cs->resolvedloc.parent); nfs_loc_wipe (&cs->resolvedloc); - ret = nfs_inode_loc_fill (parent, &cs->resolvedloc); + ret = nfs_inode_loc_fill (parent, &cs->resolvedloc, + NFS_RESOLVE_CREATE); - if (ret < 0) + if (ret < 0) { + gf_log (GF_NFS3, GF_LOG_ERROR, "nfs_inode_loc_fill" + " error"); goto errtostat; + } } ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, @@ -1143,7 +1367,7 @@ errtostat: nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "LOOKUP", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_LOOKUP, stat, -ret); nfs3_lookup_reply (cs->req, stat, NULL, NULL, NULL); nfs3_call_state_wipe (cs); @@ -1163,14 +1387,25 @@ nfs3_lookup_resume (void *carg) int ret = -EFAULT; nfs_user_t nfu = {0, }; nfs3_call_state_t *cs = NULL; + struct nfs3_fh newfh = {{0},}; - if (!carg) - return ret; + if (!carg) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Invalid argument," + " carg value NULL"); + return EINVAL; + } cs = (nfs3_call_state_t *)carg; nfs3_check_fh_resolve_status (cs, stat, nfs3err); - nfs_request_user_init (&nfu, cs->req); cs->parent = cs->resolvefh; + + if (cs->hardresolved) { + stat = NFS3_OK; + nfs3_fh_build_child_fh (&cs->parent, &cs->stbuf, &newfh); + goto nfs3err; + } + + nfs_request_user_init (&nfu, cs->req); ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, nfs3svc_lookup_cbk, cs); if (ret < 0) @@ -1178,9 +1413,10 @@ nfs3_lookup_resume (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "LOOKUP", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_LOOKUP, stat, -ret); - nfs3_lookup_reply (cs->req, stat, NULL, NULL, NULL); + nfs3_lookup_reply (cs->req, stat, &newfh, &cs->stbuf, + &cs->postparent); nfs3_call_state_wipe (cs); } @@ -1197,12 +1433,11 @@ nfs3_lookup (rpcsvc_request_t *req, struct nfs3_fh *fh, int fhlen, char *name) struct nfs3_state *nfs3 = NULL; nfs3_call_state_t *cs = NULL; - if ((!req) || (!fh) || (!name)) { - gf_log (GF_NFS3, GF_LOG_ERROR, "Bad arguments"); - return -1; - } + GF_VALIDATE_OR_GOTO (GF_NFS3, req, out); + GF_VALIDATE_OR_GOTO (GF_NFS3, fh, out); + GF_VALIDATE_OR_GOTO (GF_NFS3, name, out); - nfs3_log_fh_entry_call (nfs_rpcsvc_request_xid (req), "LOOKUP", fh, + nfs3_log_fh_entry_call (rpcsvc_request_xid (req), "LOOKUP", fh, name); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); if (nfs3_solaris_zerolen_fh (fh, fhlen)) @@ -1211,21 +1446,21 @@ nfs3_lookup (rpcsvc_request_t *req, struct nfs3_fh *fh, int fhlen, char *name) nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_strlen_or_goto (name, NFS_NAME_MAX, nfs3err, stat, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); - if (!nfs3_is_parentdir_entry (name)) - ret = nfs3_fh_resolve_and_resume (cs, fh, name, - nfs3_lookup_resume); - else - ret = nfs3_fh_resolve_and_resume (cs, fh, NULL, - nfs3_lookup_parentdir_resume); + cs->lookuptype = GF_NFS3_REVALIDATE; + ret = nfs3_fh_resolve_and_resume (cs, fh, name, + nfs3_lookup_resume); - if (ret < 0) + if (ret < 0) { + gf_log (GF_NFS, GF_LOG_ERROR, "failed to start hard reslove"); stat = nfs3_errno_to_nfsstat3 (-ret); + } nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "LOOKUP", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_LOOKUP, stat, -ret); nfs3_lookup_reply (req, stat, NULL, NULL, NULL); @@ -1235,7 +1470,7 @@ nfs3err: */ ret = 0; } - +out: return ret; } @@ -1248,20 +1483,19 @@ nfs3svc_lookup (rpcsvc_request_t *req) lookup3args args; int ret = RPCSVC_ACTOR_ERROR; - if (!req) - return ret; + GF_VALIDATE_OR_GOTO (GF_NFS, req, rpcerr); nfs3_prep_lookup3args (&args, &fh, name); - if (xdr_to_lookup3args (req->msg, &args) <= 0) { + if (xdr_to_lookup3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_lookup (req, &fh, args.what.dir.data.data_len, name); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "LOOKUP procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -1271,16 +1505,12 @@ rpcerr: int -nfs3_access_reply (rpcsvc_request_t *req, nfsstat3 status, struct iatt *buf, - uint32_t accbits) +nfs3_access_reply (rpcsvc_request_t *req, nfsstat3 status, int32_t accbits, + int32_t reqaccbits) { access3res res; - uint64_t deviceid = 0; - deviceid = nfs3_request_xlator_deviceid (req); - nfs3_fill_access3res (&res, status, buf, accbits, - nfs_rpcsvc_request_uid (req), - nfs_rpcsvc_request_gid (req), deviceid); + nfs3_fill_access3res (&res, status, accbits, reqaccbits); nfs3svc_submit_reply (req, &res, (nfs3_serializer)xdr_serialize_access3res); return 0; @@ -1289,19 +1519,22 @@ nfs3_access_reply (rpcsvc_request_t *req, nfsstat3 status, struct iatt *buf, int32_t nfs3svc_access_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct iatt *buf) + int32_t op_ret, int32_t op_errno, dict_t *xdata) { nfsstat3 status = NFS3_OK; nfs3_call_state_t *cs = NULL; cs = frame->local; - if (op_ret == -1) - status = nfs3_errno_to_nfsstat3 (op_errno); - - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "ACCESS", status, + if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + status = nfs3_cbk_errno_status (op_ret, op_errno); + } + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_ACCESS, status, op_errno); - nfs3_access_reply (cs->req, status, buf, cs->accessbits); + nfs3_access_reply (cs->req, status, op_errno, cs->accessbits); nfs3_call_state_wipe (cs); return 0; @@ -1315,23 +1548,26 @@ nfs3_access_resume (void *carg) nfs_user_t nfu = {0, }; nfs3_call_state_t *cs = NULL; - if (!carg) - return ret; + if (!carg) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Invalid argument," + " carg value NULL"); + return EINVAL; + } cs = (nfs3_call_state_t *)carg; nfs3_check_fh_resolve_status (cs, stat, nfs3err); cs->fh = cs->resolvefh; nfs_request_user_init (&nfu, cs->req); - ret = nfs_stat (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - nfs3svc_access_cbk, cs); + ret = nfs_access (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + cs->accessbits, nfs3svc_access_cbk, cs); if (ret < 0) stat = nfs3_errno_to_nfsstat3 (-ret); nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "ACCESS", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_ACCESS, stat, -ret); - nfs3_access_reply (cs->req, stat, NULL, 0); + nfs3_access_reply (cs->req, stat, 0, 0); nfs3_call_state_wipe (cs); ret = 0; } @@ -1349,13 +1585,13 @@ nfs3_access (rpcsvc_request_t *req, struct nfs3_fh *fh, uint32_t accbits) int ret = -EFAULT; nfs3_call_state_t *cs = NULL; - if ((!req) || (!fh)) - return -1; - - nfs3_log_common_call (nfs_rpcsvc_request_xid (req), "ACCESS", fh); + GF_VALIDATE_OR_GOTO (GF_NFS, req, out); + GF_VALIDATE_OR_GOTO (GF_NFS, fh, out); + nfs3_log_common_call (rpcsvc_request_xid (req), "ACCESS", fh); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); cs->accessbits = accbits; @@ -1365,13 +1601,13 @@ nfs3_access (rpcsvc_request_t *req, struct nfs3_fh *fh, uint32_t accbits) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "ACCESS", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_ACCESS, stat, -ret); - nfs3_access_reply (req, stat, NULL, 0); + nfs3_access_reply (req, stat, 0, 0); nfs3_call_state_wipe (cs); ret = 0; } - +out: return ret; } @@ -1387,16 +1623,16 @@ nfs3svc_access (rpcsvc_request_t *req) return ret; nfs3_prep_access3args (&args, &fh); - if (xdr_to_access3args (req->msg, &args) <= 0) { + if (xdr_to_access3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_access (req, &fh, args.access); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "ACCESS procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -1424,21 +1660,24 @@ nfs3_readlink_reply (rpcsvc_request_t *req, nfsstat3 stat, char *path, int32_t nfs3svc_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 iatt *buf, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; nfs3_call_state_t *cs = NULL; cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } stat = NFS3_OK; nfs3err: - nfs3_log_readlink_res (nfs_rpcsvc_request_xid (cs->req), stat, op_errno, + nfs3_log_readlink_res (rpcsvc_request_xid (cs->req), stat, op_errno, (char *)path); nfs3_readlink_reply (cs->req, stat, (char *)path, buf); nfs3_call_state_wipe (cs); @@ -1468,8 +1707,8 @@ nfs3_readlink_resume (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), - "READLINK", stat, -ret); + nfs3_log_common_res (rpcsvc_request_xid (cs->req), + NFS3_READLINK, stat, -ret); nfs3_readlink_reply (cs->req, stat, NULL, NULL); nfs3_call_state_wipe (cs); } @@ -1492,10 +1731,11 @@ nfs3_readlink (rpcsvc_request_t *req, struct nfs3_fh *fh) return -1; } - nfs3_log_common_call (nfs_rpcsvc_request_xid (req), "READLINK", fh); + nfs3_log_common_call (rpcsvc_request_xid (req), "READLINK", fh); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); ret = nfs3_fh_resolve_and_resume (cs, fh, NULL, nfs3_readlink_resume); @@ -1504,7 +1744,7 @@ nfs3_readlink (rpcsvc_request_t *req, struct nfs3_fh *fh) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "READLINK", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_READLINK, stat, -ret); nfs3_readlink_reply (req, stat, NULL, NULL); nfs3_call_state_wipe (cs); @@ -1513,7 +1753,7 @@ nfs3err: */ ret = 0; } - +out: return ret; } @@ -1529,16 +1769,16 @@ nfs3svc_readlink (rpcsvc_request_t *req) return ret; nfs3_prep_readlink3args (&args, &fh); - if (xdr_to_readlink3args (req->msg, &args) <= 0) { + if (xdr_to_readlink3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_readlink (req, &fh); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "READLINK procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -1558,17 +1798,19 @@ nfs3_read_reply (rpcsvc_request_t *req, nfsstat3 stat, count3 count, deviceid = nfs3_request_xlator_deviceid (req); nfs3_fill_read3res (&res, stat, count, poststat, is_eof, deviceid); if (stat == NFS3_OK) { - nfs_xdr_vector_round_up (vec, vcount, count); + xdr_vector_round_up (vec, vcount, count); /* iob can be zero if the file size was zero. If so, op_ret * would be 0 and count = 0. */ + if (count != 0) { nfs3svc_submit_vector_reply (req, (void *)&res, (nfs3_serializer) xdr_serialize_read3res_nocopy, vec, vcount, iobref); } else - nfs3svc_submit_reply (req, (void *)&res, + + nfs3svc_submit_reply (req, (void *)&res, (nfs3_serializer) xdr_serialize_read3res_nocopy); } else @@ -1583,7 +1825,8 @@ nfs3_read_reply (rpcsvc_request_t *req, nfsstat3 stat, count3 count, int32_t nfs3svc_read_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) + int32_t count, struct iatt *stbuf, struct iobref *iobref, + dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; int is_eof = 0; @@ -1591,7 +1834,10 @@ nfs3svc_read_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto err; } else stat = NFS3_OK; @@ -1600,7 +1846,7 @@ nfs3svc_read_cbk (call_frame_t *frame, void *cookie, xlator_t *this, is_eof = 1; err: - nfs3_log_read_res (nfs_rpcsvc_request_xid (cs->req), stat, op_errno, + nfs3_log_read_res (rpcsvc_request_xid (cs->req), stat, op_errno, op_ret, is_eof, vector, count); nfs3_read_reply (cs->req, stat, op_ret, vector, count, iobref, stbuf, is_eof); @@ -1630,7 +1876,7 @@ nfs3_read_fd_resume (void *carg) stat = nfs3_errno_to_nfsstat3 (-ret); nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "READ", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_READ, stat, -ret); nfs3_read_reply (cs->req, stat, 0, NULL, 0, NULL, NULL, 0); nfs3_call_state_wipe (cs); @@ -1646,19 +1892,25 @@ nfs3_read_resume (void *carg) nfsstat3 stat = NFS3ERR_SERVERFAULT; int ret = -EFAULT; nfs3_call_state_t *cs = NULL; + fd_t *fd = NULL; if (!carg) return ret; cs = (nfs3_call_state_t *)carg; nfs3_check_fh_resolve_status (cs, stat, nfs3err); - ret = nfs3_file_open_and_resume (cs, nfs3_read_fd_resume); - if (ret < 0) - stat = nfs3_errno_to_nfsstat3 (-ret); + fd = fd_anonymous (cs->resolvedloc.inode); + if (!fd) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to create anonymous fd"); + goto nfs3err; + } + cs->fd = fd; + nfs3_read_fd_resume (cs); + ret = 0; nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "READ", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_READ, stat, -ret); nfs3_read_reply (cs->req, stat, 0, NULL,0, NULL, NULL, 0); nfs3_call_state_wipe (cs); @@ -1682,11 +1934,12 @@ nfs3_read (rpcsvc_request_t *req, struct nfs3_fh *fh, offset3 offset, return -1; } - nfs3_log_rw_call (nfs_rpcsvc_request_xid (req), "READ", fh, offset, + nfs3_log_rw_call (rpcsvc_request_xid (req), "READ", fh, offset, count, -1); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); cs->datacount = count; @@ -1697,13 +1950,13 @@ nfs3_read (rpcsvc_request_t *req, struct nfs3_fh *fh, offset3 offset, nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "READ", stat, + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_READ, stat, -ret); nfs3_read_reply (req, stat, 0, NULL,0, NULL, NULL, 0); nfs3_call_state_wipe (cs); ret = 0; } - +out: return ret; } @@ -1719,16 +1972,16 @@ nfs3svc_read (rpcsvc_request_t *req) return ret; nfs3_prep_read3args (&args, &fh); - if (xdr_to_read3args (req->msg, &args) <= 0) { + if (xdr_to_read3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_read (req, &fh, args.offset, args.count); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "READ procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -1757,21 +2010,24 @@ nfs3_write_reply (rpcsvc_request_t *req, nfsstat3 stat, count3 count, int32_t nfs3svc_write_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 iatt *postbuf, dict_t *xdata) { struct nfs3_state *nfs3 = NULL; nfsstat3 stat = NFS3ERR_SERVERFAULT; nfs3_call_state_t *cs = NULL; cs = frame->local; - nfs3 = nfs_rpcsvc_request_program_private (cs->req); + nfs3 = rpcsvc_request_program_private (cs->req); - if (op_ret == -1) - stat = nfs3_errno_to_nfsstat3 (op_errno); - else + if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); + } else stat = NFS3_OK; - nfs3_log_write_res (nfs_rpcsvc_request_xid (cs->req), stat, op_errno, + nfs3_log_write_res (rpcsvc_request_xid (cs->req), stat, op_errno, cs->maxcount, cs->writetype, nfs3->serverstart); nfs3_write_reply (cs->req, stat, cs->maxcount, cs->writetype, nfs3->serverstart, &cs->stbuf, postbuf); @@ -1780,41 +2036,6 @@ nfs3svc_write_fsync_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } -/* - * If this logic determines that the write should return a reply to the client - * after this function, the return value is -1 and the writetype is reset to - * the type of write we want to signify to the client. - * - * In case the write should continue to serve the request according to the type - * of stable write, a 0 is returned and writetype is left as it is. - */ -int -nfs3_write_how (int *writetype, int write_trusted, int sync_trusted) -{ - int ret = -1; - - if (*writetype == UNSTABLE) { - /* On an UNSTABLE write, only return STABLE when trusted-write - * is set. TW is also set when trusted-sync is set. - */ - if (write_trusted) - *writetype = FILE_SYNC; - - goto err; - } else if ((*writetype == DATA_SYNC) || (*writetype == FILE_SYNC)) { - - /* On a STABLE write, if sync-trusted is on, only then, return - * without syncing. - */ - if (sync_trusted) - goto err; - } - - ret = 0; -err: - return ret; -} - /* * Before going into the write reply logic, here is a matrix that shows the @@ -1850,55 +2071,33 @@ err: int32_t nfs3svc_write_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 iatt *postbuf, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; - int ret = -EFAULT; - nfs_user_t nfu = {0, }; nfs3_call_state_t *cs = NULL; struct nfs3_state *nfs3 = NULL; - int write_trusted = 0; - int sync_trusted = 0; cs = frame->local; - nfs3 = nfs_rpcsvc_request_program_private (cs->req); + nfs3 = rpcsvc_request_program_private (cs->req); if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto err; } stat = NFS3_OK; cs->maxcount = op_ret; - write_trusted = nfs3_export_write_trusted (cs->nfs3state, - cs->resolvefh.exportid); - sync_trusted = nfs3_export_sync_trusted (cs->nfs3state, - cs->resolvefh.exportid); - ret = nfs3_write_how (&cs->writetype, write_trusted, sync_trusted); - if (ret == -1) - goto err; - - nfs_request_user_init (&nfu, cs->req); - /* Store the current preattr so that this can be used as the pre attr - * when fsync returns. We dont want to use the preattr in fsync because - * the write fop happened before the fsync. - */ - cs->stbuf = *prebuf; - ret = nfs_fsync (cs->nfsx, cs->vol, &nfu, cs->fd, 0, - nfs3svc_write_fsync_cbk, cs); - if (ret < 0) - stat = nfs3_errno_to_nfsstat3 (-ret); - err: - if (ret < 0) { - nfs3_log_write_res (nfs_rpcsvc_request_xid (cs->req), stat, - op_errno, cs->maxcount, cs->writetype, - nfs3->serverstart); - nfs3_write_reply (cs->req, stat, cs->maxcount, - cs->writetype, nfs3->serverstart, prebuf, - postbuf); - nfs3_call_state_wipe (cs); - } + nfs3_log_write_res (rpcsvc_request_xid (cs->req), stat, + op_errno, cs->maxcount, cs->writetype, + nfs3->serverstart); + nfs3_write_reply (cs->req, stat, cs->maxcount, + cs->writetype, nfs3->serverstart, prebuf, + postbuf); + nfs3_call_state_wipe (cs); return 0; } @@ -1926,8 +2125,9 @@ __nfs3_write_resume (nfs3_call_state_t *cs) * opaque data buffers to multiples of 4 bytes. */ cs->datavec.iov_len = cs->datacount; - ret = nfs_write (cs->nfsx, cs->vol, &nfu, cs->fd, cs->iob, &cs->datavec, - 1, cs->dataoffset, nfs3svc_write_cbk, cs); + ret = nfs_write (cs->nfsx, cs->vol, &nfu, cs->fd, cs->iobref, + &cs->datavec, 1, cs->dataoffset, nfs3svc_write_cbk, + cs); return ret; } @@ -1939,46 +2139,45 @@ nfs3_write_resume (void *carg) nfsstat3 stat = NFS3ERR_SERVERFAULT; int ret = -EFAULT; nfs3_call_state_t *cs = NULL; + fd_t *fd = NULL; if (!carg) return ret; cs = (nfs3_call_state_t *)carg; nfs3_check_fh_resolve_status (cs, stat, nfs3err); - - ret = __nfs3_write_resume (cs); - if (ret < 0) - stat = nfs3_errno_to_nfsstat3 (-ret); -nfs3err: - if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "WRITE", - stat, -ret); - nfs3_write_reply (cs->req, stat, 0, cs->writetype, 0, NULL, - NULL); - nfs3_call_state_wipe (cs); + fd = fd_anonymous (cs->resolvedloc.inode); + if (!fd) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to create anonymous fd"); + goto nfs3err; } - return ret; -} - -int -nfs3_write_open_resume (void *carg) -{ - nfsstat3 stat = NFS3ERR_SERVERFAULT; - int ret = -EFAULT; - nfs3_call_state_t *cs = NULL; + cs->fd = fd; /* Gets unrefd when the call state is wiped. */ - if (!carg) - return ret; +/* + enum stable_how { + UNSTABLE = 0, + DATA_SYNC = 1, + FILE_SYNC = 2, + }; +*/ + switch (cs->writetype) { + case UNSTABLE: + break; + case DATA_SYNC: + fd->flags |= O_DSYNC; + break; + case FILE_SYNC: + fd->flags |= O_SYNC; + break; + } - cs = (nfs3_call_state_t *)carg; - nfs3_check_fh_resolve_status (cs, stat, nfs3err); - ret = nfs3_file_open_and_resume (cs, nfs3_write_resume); + ret = __nfs3_write_resume (cs); if (ret < 0) stat = nfs3_errno_to_nfsstat3 (-ret); nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "WRITE", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_WRITE, stat, -ret); nfs3_write_reply (cs->req, stat, 0, cs->writetype, 0, NULL, NULL); @@ -1988,11 +2187,10 @@ nfs3err: } - int nfs3_write (rpcsvc_request_t *req, struct nfs3_fh *fh, offset3 offset, count3 count, stable_how stable, struct iovec payload, - struct iobuf *iob) + struct iobref *iobref) { xlator_t *vol = NULL; nfsstat3 stat = NFS3ERR_SERVERFAULT; @@ -2005,33 +2203,34 @@ nfs3_write (rpcsvc_request_t *req, struct nfs3_fh *fh, offset3 offset, return -1; } - nfs3_log_rw_call (nfs_rpcsvc_request_xid (req), "WRITE", fh, offset, + nfs3_log_rw_call (rpcsvc_request_xid (req), "WRITE", fh, offset, count, stable); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_check_rw_volaccess (nfs3, fh->exportid, stat, nfs3err); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); cs->datacount = count; cs->dataoffset = offset; cs->writetype = stable; - cs->iob = iob; + cs->iobref = iobref; cs->datavec = payload; - ret = nfs3_fh_resolve_and_resume (cs, fh, NULL, nfs3_write_open_resume); + ret = nfs3_fh_resolve_and_resume (cs, fh, NULL, nfs3_write_resume); if (ret < 0) stat = nfs3_errno_to_nfsstat3 (-ret); nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "WRITE", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_WRITE, stat, -ret); nfs3_write_reply (req, stat, 0, stable, 0, NULL, NULL); nfs3_call_state_wipe (cs); ret = 0; } - +out: return ret; } @@ -2043,99 +2242,47 @@ nfs3err: int -nfs3svc_write_vecsizer (rpcsvc_request_t *req, ssize_t *readsize, int *newbuf) +nfs3svc_write_vecsizer (int state, ssize_t *readsize, char *base_addr, + char *curr_addr) { - ssize_t ret = RPCSVC_ACTOR_ERROR; - int state = 0; - uint32_t fhlen = 0; - uint32_t fhlen_n = 0; - write3args *args = NULL; - - if (!req) - return ret; + int ret = 0; + uint32_t fhlen = 0; + uint32_t fhlen_n = 0; - state = (long)nfs_rpcsvc_request_private (req); - *newbuf = 0; if (state == 0) { - nfs_rpcsvc_request_set_private (req, NFS3_VECWRITE_READFHLEN); + ret = NFS3_VECWRITE_READFHLEN; *readsize = 4; - ret = 0; } else if (state == NFS3_VECWRITE_READFHLEN) { - fhlen_n = *(uint32_t *)req->msg.iov_base; + fhlen_n = *(uint32_t *)(curr_addr - 4); fhlen = ntohl (fhlen_n); - *readsize = nfs_xdr_length_round_up (fhlen, NFS3_FHSIZE); - nfs_rpcsvc_request_set_private (req, NFS3_VECWRITE_READFH); - ret = 0; + *readsize = xdr_length_round_up (fhlen, NFS3_FHSIZE); + ret = NFS3_VECWRITE_READFH; } else if (state == NFS3_VECWRITE_READFH) { *readsize = NFS3_WRITE_POSTFH_SIZE; - nfs_rpcsvc_request_set_private (req, NFS3_VECWRITE_READREST); - ret = 0; + ret = NFS3_VECWRITE_READREST; } else if (state == NFS3_VECWRITE_READREST) { - args = GF_CALLOC (1, sizeof (*args), gf_nfs_mt_write3args); - if (!args) - goto rpcerr; - - if (xdr_to_write3args_nocopy (req->msg, args, NULL) <= 0) { - gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); - goto rpcerr; - } - nfs_rpcsvc_request_set_private (req, args); - ret = nfs_xdr_length_round_up (args->data.data_len, 1048576); - *readsize = ret; - *newbuf = 1; ret = 0; - } - -rpcerr: - return ret; -} - - -int -nfs3svc_write_vec (rpcsvc_request_t *req, struct iobuf *iob) -{ - write3args *args = NULL; - int ret = RPCSVC_ACTOR_ERROR; - struct iovec payload = {0, }; - struct nfs3_fh fh = {{0}, }; - - if ((!req) || (!iob)) - return ret; - - args = nfs_rpcsvc_request_private (req); - iobuf_to_iovec (iob, &payload); - iobuf_ref (iob); - memcpy (&fh, args->file.data.data_val, args->file.data.data_len); - ret = nfs3_write (req, &fh, args->offset, args->count, args->stable, - payload,iob); - xdr_free_write3args_nocopy (args); - GF_FREE (args); - if (ret < 0) { - gf_log (GF_NFS3, GF_LOG_ERROR, "WRITE procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); - ret = RPCSVC_ACTOR_ERROR; - } + *readsize = 0; + } else + gf_log ("nfs", GF_LOG_ERROR, "state wrong"); return ret; } - int nfs3svc_write (rpcsvc_request_t *req) { struct nfs3_fh fh = {{0}, }; write3args args; int ret = RPCSVC_ACTOR_ERROR; - struct iovec payload = {0, }; if (!req) return ret; nfs3_prep_write3args (&args, &fh); - if (xdr_to_write3args_nocopy (req->msg, &args, &payload) <= 0) { + if (xdr_to_write3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } @@ -2144,12 +2291,12 @@ nfs3svc_write (rpcsvc_request_t *req) * ourselves because the RPC call handler who called us will unref its * own ref of the record's iobuf when it is done handling the request. */ - nfs_rpcsvc_request_record_ref (req); + ret = nfs3_write (req, &fh, args.offset, args.count, args.stable, - payload, nfs_rpcsvc_request_record_iob (req)); - if (ret < 0) { + req->msg[1], rpcsvc_request_iobref_ref (req)); + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "WRITE procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -2178,20 +2325,23 @@ nfs3_create_reply (rpcsvc_request_t *req, nfsstat3 stat, struct nfs3_fh *newfh, int32_t nfs3svc_create_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, - struct iatt *preop, struct iatt *postop) + struct iatt *preop, struct iatt *postop, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; nfs3_call_state_t *cs = NULL; cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } stat = NFS3_OK; nfs3err: - nfs3_log_newfh_res (nfs_rpcsvc_request_xid (cs->req), "CREATE", stat, + nfs3_log_newfh_res (rpcsvc_request_xid (cs->req), NFS3_CREATE, stat, op_errno, &cs->fh); nfs3_create_reply (cs->req, stat, &cs->fh, postop, &cs->preparent, &cs->postparent); @@ -2205,20 +2355,26 @@ int32_t nfs3svc_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 iatt *postparent, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; int ret = -EFAULT; nfs_user_t nfu = {0, }; nfs3_call_state_t *cs = NULL; + inode_t *oldinode = NULL; cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } nfs3_fh_build_child_fh (&cs->parent, buf, &cs->fh); + oldinode = inode_link (inode, cs->resolvedloc.parent, + cs->resolvedloc.name, buf); /* Means no attributes were required to be set. */ if (!cs->setattr_valid) { @@ -2230,14 +2386,20 @@ nfs3svc_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs->preparent = *preparent; cs->postparent = *postparent; nfs_request_user_init (&nfu, cs->req); + uuid_copy (cs->resolvedloc.gfid, inode->gfid); ret = nfs_setattr (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc,&cs->stbuf, cs->setattr_valid, nfs3svc_create_setattr_cbk, cs); if (ret < 0) stat = nfs3_errno_to_nfsstat3 (-ret); nfs3err: + if (oldinode) { + inode_lookup (oldinode); + inode_unref (oldinode); + } + if (ret < 0) { - nfs3_log_newfh_res (nfs_rpcsvc_request_xid (cs->req), "CREATE", + nfs3_log_newfh_res (rpcsvc_request_xid (cs->req), NFS3_CREATE, stat, op_errno, &cs->fh); nfs3_create_reply (cs->req, stat, &cs->fh, buf, preparent, postparent); @@ -2253,16 +2415,30 @@ nfs3_create_common (nfs3_call_state_t *cs) int ret = -EFAULT; int flags = 0; nfs_user_t nfu = {0, }; + uid_t uid = 0; + gid_t gid = 0; if (!cs) return ret; - if ((cs->createmode == UNCHECKED) || (cs->createmode = EXCLUSIVE)) - flags = O_RDWR; - else if (cs->createmode == GUARDED) + if (cs->createmode == GUARDED) flags = (O_RDWR | O_EXCL); + else + flags = O_RDWR; - nfs_request_user_init (&nfu, cs->req); + if (gf_attr_uid_set (cs->setattr_valid)) { + uid = cs->stbuf.ia_uid; + cs->setattr_valid &= ~GF_SET_ATTR_UID; + } else + uid = rpcsvc_request_uid (cs->req); + + if (gf_attr_gid_set (cs->setattr_valid)) { + gid = cs->stbuf.ia_gid; + cs->setattr_valid &= ~GF_SET_ATTR_GID; + } else + gid = rpcsvc_request_gid (cs->req); + + nfs_request_primary_user_init (&nfu, cs->req, uid, gid); /* We can avoid sending the setattr call later if only the mode is * required to be set. This is possible because the create fop allows * us to specify a mode arg. @@ -2282,7 +2458,8 @@ nfs3_create_common (nfs3_call_state_t *cs) int32_t nfs3svc_create_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct iatt *buf) + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata) { int ret = -EFAULT; nfsstat3 stat = NFS3ERR_SERVERFAULT; @@ -2292,21 +2469,35 @@ nfs3svc_create_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs = frame->local; nfs_request_user_init (&nfu, cs->req); if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); ret = -op_errno; - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } - if (cs->preparent.ia_mtime == buf->ia_mtime) + if ((cs->stbuf.ia_mtime == buf->ia_mtime) && + (cs->stbuf.ia_atime == buf->ia_atime)) { + gf_log (GF_NFS3, GF_LOG_DEBUG, + "Create req retransmitted verf %x %x", + cs->stbuf.ia_mtime, cs->stbuf.ia_atime); stat = NFS3_OK; - else + nfs3_fh_build_child_fh (&cs->parent, buf, &cs->fh); + } else { + gf_log (GF_NFS3, GF_LOG_DEBUG, + "File already exist new_verf %x %x" + "old_verf %x %x", cs->stbuf.ia_mtime, + cs->stbuf.ia_atime, + buf->ia_mtime, buf->ia_atime); stat = NFS3ERR_EXIST; + } nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "CREATE", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_CREATE, stat, op_errno); - nfs3_create_reply (cs->req, stat, NULL, NULL, NULL, NULL); + nfs3_create_reply (cs->req, stat, &cs->fh, buf, NULL, NULL); nfs3_call_state_wipe (cs); } @@ -2323,9 +2514,15 @@ nfs3_create_exclusive (nfs3_call_state_t *cs) if (!cs) return ret; - /* HACK warning. */ - cs->preparent.ia_mtime = cs->cookieverf; - cs->preparent.ia_atime = 9669; + /* Storing verifier as a mtime and atime attribute, to store it + * in stable storage */ + memcpy (&cs->stbuf.ia_atime, &cs->cookieverf, + sizeof (cs->stbuf.ia_atime)); + memcpy (&cs->stbuf.ia_mtime, + ((char *) &cs->cookieverf) + sizeof (cs->stbuf.ia_atime), + sizeof (cs->stbuf.ia_mtime)); + cs->setattr_valid |= GF_SET_ATTR_ATIME; + cs->setattr_valid |= GF_SET_ATTR_MTIME; nfs_request_user_init (&nfu, cs->req); /* If the file already existed we need to get that attributes so we can @@ -2339,15 +2536,7 @@ nfs3_create_exclusive (nfs3_call_state_t *cs) goto nfs3err; } - if (cs->setattr_valid & GF_SET_ATTR_MODE) { - cs->setattr_valid &= ~GF_SET_ATTR_MODE; - ret = nfs_create (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - O_RDWR, cs->mode, nfs3svc_create_cbk, cs); - } else - ret = nfs_create (cs->nfsx, cs->vol, &nfu, &cs->oploc, O_RDWR, - NFS_DEFAULT_CREATE_MODE, nfs3svc_create_cbk, - cs); - + ret = nfs3_create_common (cs); nfs3err: return ret; } @@ -2376,7 +2565,7 @@ nfs3_create_resume (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "CREATE", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_CREATE, stat, -ret); nfs3_create_reply (cs->req, stat, NULL, NULL, NULL, NULL); nfs3_call_state_wipe (cs); @@ -2398,17 +2587,22 @@ nfs3_create (rpcsvc_request_t *req, struct nfs3_fh *dirfh, char *name, if ((!req) || (!dirfh) || (!name) || (!sattr)) return -1; - nfs3_log_create_call (nfs_rpcsvc_request_xid (req), dirfh, name, mode); + nfs3_log_create_call (rpcsvc_request_xid (req), dirfh, name, mode); nfs3_validate_gluster_fh (dirfh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_validate_strlen_or_goto (name, NFS_NAME_MAX, nfs3err, stat, ret); nfs3_map_fh_to_volume (nfs3, dirfh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_check_rw_volaccess (nfs3, dirfh->exportid, stat, nfs3err); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); cs->cookieverf = cverf; - cs->setattr_valid = nfs3_sattr3_to_setattr_valid (sattr, NULL, - &cs->mode); + /*In Exclusive create client is supposed to send cverf instead of + * sattr*/ + if (mode != EXCLUSIVE) + cs->setattr_valid = nfs3_sattr3_to_setattr_valid (sattr, + &cs->stbuf, + &cs->mode); cs->createmode = mode; cs->parent = *dirfh; @@ -2418,13 +2612,13 @@ nfs3_create (rpcsvc_request_t *req, struct nfs3_fh *dirfh, char *name, nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "CREATE", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_CREATE, stat, -ret); nfs3_create_reply (req, stat, NULL, NULL, NULL, NULL); nfs3_call_state_wipe (cs); ret = 0; } - +out: return ret; } @@ -2432,28 +2626,31 @@ nfs3err: int nfs3svc_create (rpcsvc_request_t *req) { - char name[NFS_PATH_MAX]; - struct nfs3_fh dirfh = {{0}, }; - create3args args; - int ret = RPCSVC_ACTOR_ERROR; - uint64_t cverf = 0; + char name[NFS_PATH_MAX]; + struct nfs3_fh dirfh = {{0}, }; + create3args args; + int ret = RPCSVC_ACTOR_ERROR; + uint64_t cverf = 0; + uint64_t *cval; if (!req) return ret; nfs3_prep_create3args (&args, &dirfh, name); - if (xdr_to_create3args (req->msg, &args) <= 0) { + if (xdr_to_create3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } - cverf = *(uint64_t *)args.how.createhow3_u.verf; + cval = (uint64_t *)args.how.createhow3_u.verf; + cverf = *cval; + ret = nfs3_create (req, &dirfh, name, args.how.mode, &args.how.createhow3_u.obj_attributes, cverf); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "CREATE procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -2481,20 +2678,23 @@ nfs3_mkdir_reply (rpcsvc_request_t *req, nfsstat3 stat, struct nfs3_fh *fh, int32_t nfs3svc_mkdir_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, - struct iatt *preop, struct iatt *postop) + struct iatt *preop, struct iatt *postop, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; nfs3_call_state_t *cs = NULL; cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } stat = NFS3_OK; nfs3err: - nfs3_log_newfh_res (nfs_rpcsvc_request_xid (cs->req), "MKDIR", stat, + nfs3_log_newfh_res (rpcsvc_request_xid (cs->req), NFS3_MKDIR, stat, op_errno, &cs->fh); nfs3_mkdir_reply (cs->req, stat, &cs->fh, postop, &cs->preparent, &cs->postparent); @@ -2508,7 +2708,7 @@ int32_t nfs3svc_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 iatt *postparent, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; int ret = -EFAULT; @@ -2517,7 +2717,10 @@ nfs3svc_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -2539,7 +2742,7 @@ nfs3svc_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, nfs3err: if (ret < 0) { - nfs3_log_newfh_res (nfs_rpcsvc_request_xid (cs->req), "MKDIR", + nfs3_log_newfh_res (rpcsvc_request_xid (cs->req), NFS3_MKDIR, stat, op_errno, &cs->fh); nfs3_mkdir_reply (cs->req, stat, &cs->fh, buf, preparent, postparent); @@ -2578,7 +2781,7 @@ nfs3_mkdir_resume (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "MKDIR", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_MKDIR, stat, -ret); nfs3_mkdir_reply (cs->req, stat, NULL, NULL, NULL, NULL); nfs3_call_state_wipe (cs); @@ -2604,17 +2807,18 @@ nfs3_mkdir (rpcsvc_request_t *req, struct nfs3_fh *dirfh, char *name, return -1; } - nfs3_log_fh_entry_call (nfs_rpcsvc_request_xid (req), "MKDIR", dirfh, + nfs3_log_fh_entry_call (rpcsvc_request_xid (req), "MKDIR", dirfh, name); nfs3_validate_gluster_fh (dirfh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_validate_strlen_or_goto (name, NFS_NAME_MAX, nfs3err, stat, ret); nfs3_map_fh_to_volume (nfs3, dirfh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_check_rw_volaccess (nfs3, dirfh->exportid, stat, nfs3err); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); cs->parent = *dirfh; - cs->setattr_valid = nfs3_sattr3_to_setattr_valid (sattr, NULL, + cs->setattr_valid = nfs3_sattr3_to_setattr_valid (sattr, &cs->stbuf, &cs->mode); ret = nfs3_fh_resolve_and_resume (cs, dirfh, name, nfs3_mkdir_resume); if (ret < 0) @@ -2622,13 +2826,13 @@ nfs3_mkdir (rpcsvc_request_t *req, struct nfs3_fh *dirfh, char *name, nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "MKDIR", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_MKDIR, stat, -ret); nfs3_mkdir_reply (req, stat, NULL, NULL, NULL, NULL); nfs3_call_state_wipe (cs); ret = 0; } - +out: return ret; } @@ -2644,16 +2848,16 @@ nfs3svc_mkdir (rpcsvc_request_t *req) if (!req) return ret; nfs3_prep_mkdir3args (&args, &dirfh, name); - if (xdr_to_mkdir3args (req->msg, &args) <= 0) { + if (xdr_to_mkdir3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_mkdir (req, &dirfh, name, &args.attributes); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "MKDIR procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -2684,14 +2888,17 @@ int32_t nfs3svc_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 iatt *postparent, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; nfs3_call_state_t *cs = NULL; cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -2699,7 +2906,7 @@ nfs3svc_symlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, stat = NFS3_OK; nfs3err: - nfs3_log_newfh_res (nfs_rpcsvc_request_xid (cs->req), "SYMLINK", stat, + nfs3_log_newfh_res (rpcsvc_request_xid (cs->req), NFS3_SYMLINK, stat, op_errno, &cs->fh); nfs3_symlink_reply (cs->req, stat, &cs->fh, buf, preparent, postparent); @@ -2729,8 +2936,8 @@ nfs3_symlink_resume (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), - "SYMLINK", stat, -ret); + nfs3_log_common_res (rpcsvc_request_xid (cs->req), + NFS3_SYMLINK, stat, -ret); nfs3_symlink_reply (cs->req, stat, NULL, NULL, NULL, NULL); nfs3_call_state_wipe (cs); } @@ -2754,12 +2961,13 @@ nfs3_symlink (rpcsvc_request_t *req, struct nfs3_fh *dirfh, char *name, return -1; } - nfs3_log_symlink_call (nfs_rpcsvc_request_xid (req), dirfh, name, + nfs3_log_symlink_call (rpcsvc_request_xid (req), dirfh, name, target); nfs3_validate_gluster_fh (dirfh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_validate_strlen_or_goto (name, NFS_NAME_MAX, nfs3err, stat, ret); nfs3_map_fh_to_volume (nfs3, dirfh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_check_rw_volaccess (nfs3, dirfh->exportid, stat, nfs3err); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); @@ -2777,7 +2985,7 @@ nfs3_symlink (rpcsvc_request_t *req, struct nfs3_fh *dirfh, char *name, nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "SYMLINK", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_SYMLINK, stat, -ret); nfs3_symlink_reply (req, stat, NULL, NULL, NULL, NULL); nfs3_call_state_wipe (cs); @@ -2786,7 +2994,7 @@ nfs3err: */ ret = 0; } - +out: return ret; } @@ -2803,17 +3011,17 @@ nfs3svc_symlink (rpcsvc_request_t *req) if (!req) return ret; nfs3_prep_symlink3args (&args, &dirfh, name, target); - if (xdr_to_symlink3args (req->msg, &args) <= 0) { + if (xdr_to_symlink3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_symlink (req, &dirfh, name, target, &args.symlink.symlink_attributes); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "SYMLINK procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -2842,20 +3050,23 @@ nfs3_mknod_reply (rpcsvc_request_t *req, nfsstat3 stat, struct nfs3_fh *fh, int32_t nfs3svc_mknod_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, - struct iatt *preop, struct iatt *postop) + struct iatt *preop, struct iatt *postop, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; nfs3_call_state_t *cs = NULL; cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } stat = NFS3_OK; nfs3err: - nfs3_log_newfh_res (nfs_rpcsvc_request_xid (cs->req), "MKNOD", stat, + nfs3_log_newfh_res (rpcsvc_request_xid (cs->req), NFS3_MKNOD, stat, op_errno, &cs->fh); nfs3_mknod_reply (cs->req, stat, &cs->fh, postop, &cs->preparent, &cs->postparent); @@ -2869,7 +3080,7 @@ int32_t nfs3svc_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 iatt *postparent, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; int ret = -1; @@ -2878,7 +3089,10 @@ nfs3svc_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -2900,7 +3114,7 @@ nfs3svc_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this, stat = nfs3_errno_to_nfsstat3 (-ret); nfs3err: if (ret < 0) { - nfs3_log_newfh_res (nfs_rpcsvc_request_xid (cs->req), "MKNOD", + nfs3_log_newfh_res (rpcsvc_request_xid (cs->req), NFS3_MKNOD, stat, op_errno, &cs->fh); nfs3_mknod_reply (cs->req, stat, &cs->fh, buf, preparent, @@ -2999,7 +3213,7 @@ nfs3_mknod_resume (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "MKNOD", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_MKNOD, stat, -ret); nfs3_mknod_reply (cs->req, stat, NULL, NULL, NULL, NULL); nfs3_call_state_wipe (cs); @@ -3026,12 +3240,13 @@ nfs3_mknod (rpcsvc_request_t *req, struct nfs3_fh *fh, char *name, return -1; } - nfs3_log_mknod_call (nfs_rpcsvc_request_xid (req), fh, name, + nfs3_log_mknod_call (rpcsvc_request_xid (req), fh, name, nodedata->type); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_validate_strlen_or_goto (name, NFS_NAME_MAX, nfs3err, stat, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_check_rw_volaccess (nfs3, fh->exportid, stat, nfs3err); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); @@ -3041,13 +3256,15 @@ nfs3_mknod (rpcsvc_request_t *req, struct nfs3_fh *fh, char *name, case NF3BLK: cs->devnums = nodedata->mknoddata3_u.device.spec; sattr = &nodedata->mknoddata3_u.device.dev_attributes; - cs->setattr_valid = nfs3_sattr3_to_setattr_valid (sattr, NULL, + cs->setattr_valid = nfs3_sattr3_to_setattr_valid (sattr, + &cs->stbuf, &cs->mode); break; case NF3SOCK: case NF3FIFO: sattr = &nodedata->mknoddata3_u.pipe_attributes; - cs->setattr_valid = nfs3_sattr3_to_setattr_valid (sattr, NULL, + cs->setattr_valid = nfs3_sattr3_to_setattr_valid (sattr, + &cs->stbuf, &cs->mode); break; default: @@ -3062,7 +3279,7 @@ nfs3_mknod (rpcsvc_request_t *req, struct nfs3_fh *fh, char *name, nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "MKNOD", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_MKNOD, stat, -ret); nfs3_mknod_reply (req, stat, NULL, NULL, NULL, NULL); /* Ret must be 0 after this so that the caller does not @@ -3071,7 +3288,7 @@ nfs3err: nfs3_call_state_wipe (cs); ret = 0; } - +out: return ret; } @@ -3087,16 +3304,16 @@ nfs3svc_mknod (rpcsvc_request_t *req) if (!req) return ret; nfs3_prep_mknod3args (&args, &fh, name); - if (xdr_to_mknod3args (req->msg, &args) <= 0) { + if (xdr_to_mknod3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_mknod (req, &fh, name, &args.what); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "MKNOD procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -3123,36 +3340,23 @@ nfs3_remove_reply (rpcsvc_request_t *req, nfsstat3 stat, struct iatt *preparent int32_t nfs3svc_remove_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 iatt *postparent, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; - fd_t *openfd = NULL; nfs3_call_state_t *cs = NULL; - struct nfs3_state *nfs3 = NULL; cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); - goto do_not_unref_cached_fd; + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); } - stat = NFS3_OK; - /* Close any cached fds so that when any currently active write - * finishes, the file is finally removed. - */ - openfd = fd_lookup (cs->resolvedloc.inode, 0); - nfs3 = nfs_rpcsvc_request_program_private (cs->req); - if (openfd) { - fd_unref (openfd); - nfs3_fdcache_remove (nfs3, openfd); - } - - /* This is the unref equivalent of the ref done when the inode was - * created on a lookup or a create request. - * The inode is finally unrefed in call state wipe. - */ - inode_unref (cs->resolvedloc.inode); -do_not_unref_cached_fd: - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "REMOVE", stat, + + if (op_ret == 0) + stat = NFS3_OK; + + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_REMOVE, stat, op_errno); nfs3_remove_reply (cs->req, stat, preparent, postparent); nfs3_call_state_wipe (cs); @@ -3201,7 +3405,7 @@ nfs3_remove_resume (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "REMOVE", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_REMOVE, stat, -ret); nfs3_remove_reply (cs->req, stat, NULL, NULL); nfs3_call_state_wipe (cs); @@ -3225,12 +3429,13 @@ nfs3_remove (rpcsvc_request_t *req, struct nfs3_fh *fh, char *name) return -1; } - nfs3_log_fh_entry_call (nfs_rpcsvc_request_xid (req), "REMOVE", fh, + nfs3_log_fh_entry_call (rpcsvc_request_xid (req), "REMOVE", fh, name); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_validate_strlen_or_goto (name, NFS_NAME_MAX, nfs3err, stat, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_check_rw_volaccess (nfs3, fh->exportid, stat, nfs3err); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); @@ -3240,7 +3445,7 @@ nfs3_remove (rpcsvc_request_t *req, struct nfs3_fh *fh, char *name) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "REMOVE", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_REMOVE, stat, -ret); nfs3_remove_reply (req, stat, NULL, NULL); nfs3_call_state_wipe (cs); @@ -3249,7 +3454,7 @@ nfs3err: */ ret = 0; } - +out: return ret; } @@ -3265,16 +3470,16 @@ nfs3svc_remove (rpcsvc_request_t *req) if (!req) return ret; nfs3_prep_remove3args (&args, &fh, name); - if (xdr_to_remove3args (req->msg, &args) <= 0) { + if (xdr_to_remove3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_remove (req, &fh, name); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "REMOVE procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -3301,20 +3506,22 @@ nfs3_rmdir_reply (rpcsvc_request_t *req, nfsstat3 stat, struct iatt *preparent, int32_t nfs3svc_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 iatt *postparent, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; nfs3_call_state_t *cs = NULL; cs = frame->local; - if (op_ret == -1) - stat = nfs3_errno_to_nfsstat3 (op_errno); - else { - inode_unref (cs->resolvedloc.inode); + if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); + } else { stat = NFS3_OK; } - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "RMDIR", stat, + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_RMDIR, stat, op_errno); nfs3_rmdir_reply (cs->req, stat, preparent, postparent); nfs3_call_state_wipe (cs); @@ -3343,7 +3550,7 @@ nfs3_rmdir_resume (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "RMDIR", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_RMDIR, stat, -ret); nfs3_rmdir_reply (cs->req, stat, NULL, NULL); nfs3_call_state_wipe (cs); @@ -3368,12 +3575,13 @@ nfs3_rmdir (rpcsvc_request_t *req, struct nfs3_fh *fh, char *name) return -1; } - nfs3_log_fh_entry_call (nfs_rpcsvc_request_xid (req), "RMDIR", fh, + nfs3_log_fh_entry_call (rpcsvc_request_xid (req), "RMDIR", fh, name); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_validate_strlen_or_goto (name, NFS_NAME_MAX, nfs3err, stat, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_check_rw_volaccess (nfs3, fh->exportid, stat, nfs3err); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); @@ -3383,7 +3591,7 @@ nfs3_rmdir (rpcsvc_request_t *req, struct nfs3_fh *fh, char *name) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "RMDIR", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_RMDIR, stat, -ret); nfs3_rmdir_reply (req, stat, NULL, NULL); nfs3_call_state_wipe (cs); @@ -3392,7 +3600,7 @@ nfs3err: */ ret = 0; } - +out: return ret; } @@ -3408,16 +3616,16 @@ nfs3svc_rmdir (rpcsvc_request_t *req) if (!req) return ret; nfs3_prep_rmdir3args (&args, &fh, name); - if (xdr_to_rmdir3args (req->msg, &args) <= 0) { + if (xdr_to_rmdir3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_rmdir (req, &fh, name); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "RMDIR procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -3450,34 +3658,26 @@ int32_t nfs3svc_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 iatt *prenewparent, struct iatt *postnewparent, + dict_t *xdata) { int ret = -EFAULT; nfsstat3 stat = NFS3ERR_SERVERFAULT; nfs3_call_state_t *cs = NULL; - fd_t *openfd = NULL; cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: rename %s -> %s => -1 (%s)", + rpcsvc_request_xid (cs->req), cs->oploc.path, + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } stat = NFS3_OK; - /* Close any cached fds so that when any currently active writes to the - * dst finish, the file is finally removed. - * - * This logic works because we know resolvedloc contains dst, which is - * resolved after src - */ - openfd = fd_lookup (cs->resolvedloc.inode, 0); - if (openfd) { - fd_unref (openfd); - nfs3_fdcache_remove (cs->nfs3state, openfd); - } - nfs3err: - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "RENAME", stat, + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_RENAME, stat, -ret); nfs3_rename_reply (cs->req, stat, buf, preoldparent, postoldparent, prenewparent, postnewparent); @@ -3508,7 +3708,7 @@ nfs3_rename_resume_dst (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "RENAME", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_RENAME, stat, -ret); nfs3_rename_reply (cs->req, stat, NULL, NULL, NULL, NULL, NULL); nfs3_call_state_wipe (cs); @@ -3536,6 +3736,7 @@ nfs3_rename_resume_src (void *carg) */ nfs_loc_copy (&cs->oploc, &cs->resolvedloc); nfs_loc_wipe (&cs->resolvedloc); + GF_FREE (cs->resolventry); ret = nfs3_fh_resolve_and_resume (cs, &cs->fh, cs->pathname, nfs3_rename_resume_dst); @@ -3544,7 +3745,7 @@ nfs3_rename_resume_src (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "RENAME", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_RENAME, stat, -ret); nfs3_rename_reply (cs->req, stat, NULL, NULL, NULL, NULL, NULL); nfs3_call_state_wipe (cs); @@ -3569,7 +3770,7 @@ nfs3_rename (rpcsvc_request_t *req, struct nfs3_fh *olddirfh, char *oldname, return -1; } - nfs3_log_rename_call (nfs_rpcsvc_request_xid (req), olddirfh, oldname, + nfs3_log_rename_call (rpcsvc_request_xid (req), olddirfh, oldname, newdirfh, newname); nfs3_validate_gluster_fh (olddirfh, stat, nfs3err); nfs3_validate_gluster_fh (newdirfh, stat, nfs3err); @@ -3577,6 +3778,7 @@ nfs3_rename (rpcsvc_request_t *req, struct nfs3_fh *olddirfh, char *oldname, nfs3_validate_strlen_or_goto(oldname, NFS_NAME_MAX, nfs3err, stat, ret); nfs3_validate_strlen_or_goto(newname, NFS_NAME_MAX, nfs3err, stat, ret); nfs3_map_fh_to_volume (nfs3, olddirfh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_check_rw_volaccess (nfs3, olddirfh->exportid, stat, nfs3err); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); @@ -3598,7 +3800,7 @@ nfs3_rename (rpcsvc_request_t *req, struct nfs3_fh *olddirfh, char *oldname, nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "RENAME", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_RENAME, stat, -ret); nfs3_rename_reply (req, stat, NULL, NULL, NULL, NULL, NULL); nfs3_call_state_wipe (cs); @@ -3607,7 +3809,7 @@ nfs3err: */ ret = 0; } - +out: return ret; } @@ -3625,16 +3827,16 @@ nfs3svc_rename (rpcsvc_request_t *req) if (!req) return ret; nfs3_prep_rename3args (&args, &olddirfh, oldname, &newdirfh, newname); - if (xdr_to_rename3args (req->msg, &args) <= 0) { + if (xdr_to_rename3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_rename (req, &olddirfh, oldname, &newdirfh, newname); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "RENAME procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -3663,18 +3865,22 @@ int32_t nfs3svc_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 iatt *postparent, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; nfs3_call_state_t *cs = NULL; cs = frame->local; - if (op_ret == -1) - stat = nfs3_errno_to_nfsstat3 (op_errno); - else + if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: link %s <- %s => -1 (%s)", + rpcsvc_request_xid (cs->req), cs->oploc.path, + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); + } else stat = NFS3_OK; - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "LINK", stat, + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_LINK, stat, op_errno); nfs3_link_reply (cs->req, stat, buf, preparent, postparent); nfs3_call_state_wipe (cs); @@ -3705,7 +3911,7 @@ nfs3_link_resume_lnk (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "LINK", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_LINK, stat, -ret); nfs3_link_reply (cs->req, stat, NULL, NULL, NULL); nfs3_call_state_wipe (cs); @@ -3736,7 +3942,7 @@ nfs3_link_resume_tgt (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "LINK", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_LINK, stat, -ret); nfs3_link_reply (cs->req, stat, NULL, NULL, NULL); nfs3_call_state_wipe (cs); @@ -3766,6 +3972,7 @@ nfs3_link (rpcsvc_request_t *req, struct nfs3_fh *targetfh, nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_validate_strlen_or_goto(newname, NFS_NAME_MAX, nfs3err, stat, ret); nfs3_map_fh_to_volume (nfs3, dirfh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_check_rw_volaccess (nfs3, dirfh->exportid, stat, nfs3err); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); @@ -3784,7 +3991,7 @@ nfs3_link (rpcsvc_request_t *req, struct nfs3_fh *targetfh, nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "LINK", stat, + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_LINK, stat, -ret); nfs3_link_reply (req, stat, NULL, NULL, NULL); nfs3_call_state_wipe (cs); @@ -3793,7 +4000,7 @@ nfs3err: */ ret = 0; } - +out: return ret; } @@ -3809,16 +4016,16 @@ nfs3svc_link (rpcsvc_request_t *req) if (!req) return ret; nfs3_prep_link3args (&args, &targetfh, &dirfh, newpath); - if (xdr_to_link3args (req->msg, &args) <= 0) { + if (xdr_to_link3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_link (req, &targetfh, &dirfh, newpath); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "LINK procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -3867,7 +4074,8 @@ nfs3_readdir_reply (rpcsvc_request_t *req, nfsstat3 stat, struct nfs3_fh *dirfh, int32_t nfs3svc_readdir_fstat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct iatt *buf) + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; int is_eof = 0; @@ -3875,7 +4083,10 @@ nfs3svc_readdir_fstat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -3889,26 +4100,15 @@ nfs3svc_readdir_fstat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, stat = NFS3_OK; nfs3err: - - /* On end-of-directory, unref the fd to have it removed from the cache - * and also unbind it from the fd so that any subsequent request on the - * on the directory do not get this fd when fd_lookup is called in - * dir open resume path. - */ - if (is_eof) { - gf_log (GF_NFS3, GF_LOG_TRACE, "EOF REF: %d", cs->fd->refcount); - fd_unref_unbind (cs->fd); - } - if (cs->maxcount == 0) { - nfs3_log_readdir_res (nfs_rpcsvc_request_xid (cs->req), stat, + nfs3_log_readdir_res (rpcsvc_request_xid (cs->req), stat, op_errno, (uintptr_t)cs->fd, cs->dircount, is_eof); nfs3_readdir_reply (cs->req, stat, &cs->parent, (uintptr_t)cs->fd, buf, &cs->entries, cs->dircount, is_eof); } else { - nfs3_log_readdirp_res (nfs_rpcsvc_request_xid (cs->req), stat, + nfs3_log_readdirp_res (rpcsvc_request_xid (cs->req), stat, op_errno, (uintptr_t)cs->fd, cs->dircount, cs->maxcount, is_eof); nfs3_readdirp_reply (cs->req, stat, &cs->parent, @@ -3917,7 +4117,10 @@ nfs3err: cs->maxcount, is_eof); } - gf_log (GF_NFS3, GF_LOG_TRACE, "CS WIPE REF: %d", cs->fd->refcount); + if (is_eof) { + /* do nothing */ + } + nfs3_call_state_wipe (cs); return 0; } @@ -3925,7 +4128,8 @@ nfs3err: int32_t nfs3svc_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, gf_dirent_t *entries) + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries, + dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; int ret = -EFAULT; @@ -3934,7 +4138,10 @@ nfs3svc_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs = frame->local; if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto err; } @@ -3954,12 +4161,12 @@ err: goto ret; if (cs->maxcount == 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), - "READDIR", stat, op_errno); + nfs3_log_common_res (rpcsvc_request_xid (cs->req), + NFS3_READDIR, stat, op_errno); nfs3_readdir_reply (cs->req, stat, NULL, 0, NULL, NULL, 0, 0); } else { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), - "READDIRP", stat, op_errno); + nfs3_log_common_res (rpcsvc_request_xid (cs->req), + NFS3_READDIRP, stat, op_errno); nfs3_readdirp_reply (cs->req, stat, NULL, 0, NULL, NULL, 0, 0, 0); } @@ -3968,7 +4175,6 @@ err: * so that next time the dir is read, we'll get any changed directory * entries. */ - fd_unref_unbind (cs->fd); nfs3_call_state_wipe (cs); ret: return 0; @@ -4003,7 +4209,7 @@ nfs3_readdir_read_resume (void *carg) cs = (nfs3_call_state_t *)carg; nfs3_check_fh_resolve_status (cs, stat, nfs3err); - nfs3 = nfs_rpcsvc_request_program_private (cs->req); + nfs3 = rpcsvc_request_program_private (cs->req); ret = nfs3_verify_dircookie (nfs3, cs->fd, cs->cookie, cs->cookieverf, &stat); if (ret < 0) /* Stat already set by verifier function above. */ @@ -4015,13 +4221,13 @@ nfs3_readdir_read_resume (void *carg) nfs3err: if (ret < 0) { if (cs->maxcount == 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), - "READDIR", stat, -ret); + nfs3_log_common_res (rpcsvc_request_xid (cs->req), + NFS3_READDIR, stat, -ret); nfs3_readdir_reply (cs->req, stat, NULL, 0, NULL, NULL, 0, 0); } else { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), - "READDIRP", stat, -ret); + nfs3_log_common_res (rpcsvc_request_xid (cs->req), + NFS3_READDIRP, stat, -ret); nfs3_readdirp_reply (cs->req, stat, NULL, 0, NULL, NULL, 0, 0, 0); } @@ -4032,32 +4238,72 @@ nfs3err: } +int32_t +nfs3svc_readdir_opendir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, + dict_t *xdata) +{ + /* + * We don't really need this, it's just an artifact of forcing the + * opendir to happen. + */ + if (fd) { + fd_unref(fd); + } + + return 0; +} + + int nfs3_readdir_open_resume (void *carg) { nfsstat3 stat = NFS3ERR_SERVERFAULT; int ret = -EFAULT; nfs3_call_state_t *cs = NULL; + nfs_user_t nfu = {0, }; if (!carg) return ret; cs = (nfs3_call_state_t *)carg; nfs3_check_fh_resolve_status (cs, stat, nfs3err); - ret = nfs3_dir_open_and_resume (cs, nfs3_readdir_read_resume); + cs->fd = fd_anonymous (cs->resolvedloc.inode); + if (!cs->fd) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Faile to create anonymous fd"); + goto nfs3err; + } + + /* + * NFS client will usually send us a readdirp without an opendir, + * which would cause us to skip our usual self-heal checks which occur + * in opendir for native protocol. To make sure those checks do happen, + * our most reliable option is to do our own opendir for any readdirp + * at the beginning of the directory. + */ + if (cs->cookie == 0) { + nfs_request_user_init (&nfu, cs->req); + ret = nfs_opendir (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3svc_readdir_opendir_cbk, cs); + if (ret < 0) { + gf_log (GF_NFS3, GF_LOG_ERROR, "auto-opendir failed"); + } + } + + ret = nfs3_readdir_read_resume (cs); if (ret < 0) stat = nfs3_errno_to_nfsstat3 (-ret); nfs3err: if (ret < 0) { if (cs->maxcount == 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), - "READDIR", stat, -ret); + nfs3_log_common_res (rpcsvc_request_xid (cs->req), + NFS3_READDIR, stat, -ret); nfs3_readdir_reply (cs->req, stat, NULL, 0, NULL, NULL, 0, 0); } else { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), - "READDIRP", stat, -ret); + nfs3_log_common_res (rpcsvc_request_xid (cs->req), + NFS3_READDIRP, stat, -ret); nfs3_readdirp_reply (cs->req, stat, NULL, 0, NULL, NULL, 0, 0, 0); } @@ -4084,11 +4330,12 @@ nfs3_readdir (rpcsvc_request_t *req, struct nfs3_fh *fh, cookie3 cookie, return -1; } - nfs3_log_readdir_call (nfs_rpcsvc_request_xid (req), fh, dircount, + nfs3_log_readdir_call (rpcsvc_request_xid (req), fh, dircount, maxcount); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); cs->cookieverf = cverf; @@ -4104,13 +4351,13 @@ nfs3_readdir (rpcsvc_request_t *req, struct nfs3_fh *fh, cookie3 cookie, nfs3err: if (ret < 0) { if (maxcount == 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), - "READDIR", stat, -ret); + nfs3_log_common_res (rpcsvc_request_xid (req), + NFS3_READDIR, stat, -ret); nfs3_readdir_reply (req, stat, NULL, 0, NULL, NULL, 0, 0); } else { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), - "READDIRP", stat, -ret); + nfs3_log_common_res (rpcsvc_request_xid (req), + NFS3_READDIRP, stat, -ret); nfs3_readdirp_reply (req, stat, NULL, 0, NULL, NULL, 0, 0, 0); } @@ -4120,7 +4367,7 @@ nfs3err: ret = 0; nfs3_call_state_wipe (cs); } - +out: return ret; } @@ -4132,21 +4379,23 @@ nfs3svc_readdir (rpcsvc_request_t *req) struct nfs3_fh fh = {{0},}; int ret = RPCSVC_ACTOR_ERROR; uint64_t verf = 0; + uint64_t *cval; if (!req) return ret; nfs3_prep_readdir3args (&ra, &fh); - if (xdr_to_readdir3args (req->msg, &ra) <= 0) { + if (xdr_to_readdir3args (req->msg[0], &ra) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } + cval = (uint64_t *) ra.cookieverf; + verf = *cval; - verf = *(uint64_t *)ra.cookieverf; ret = nfs3_readdir (req, &fh, ra.cookie, verf, ra.count, 0); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "READDIR procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -4162,22 +4411,24 @@ nfs3svc_readdirp (rpcsvc_request_t *req) struct nfs3_fh fh = {{0},}; int ret = RPCSVC_ACTOR_ERROR; uint64_t cverf = 0; + uint64_t *cval; if (!req) return ret; nfs3_prep_readdirp3args (&ra, &fh); - if (xdr_to_readdirp3args (req->msg, &ra) <= 0) { + if (xdr_to_readdirp3args (req->msg[0], &ra) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } + cval = (uint64_t *) ra.cookieverf; + cverf = *cval; - cverf = *(uint64_t *)ra.cookieverf; ret = nfs3_readdir (req, &fh, ra.cookie, cverf, ra.dircount, ra.maxcount); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "READDIRP procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -4203,18 +4454,22 @@ nfs3_fsstat_reply (rpcsvc_request_t *req, nfsstat3 stat, struct statvfs *fsbuf, int32_t nfs3_fsstat_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct iatt *buf) + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; nfs3_call_state_t *cs = NULL; cs = frame->local; - if (op_ret == -1) - stat = nfs3_errno_to_nfsstat3 (op_errno); - else + if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); + } else stat = NFS3_OK; - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "FSTAT", stat, + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_FSSTAT, stat, op_errno); nfs3_fsstat_reply (cs->req, stat, &cs->fsstat, buf); nfs3_call_state_wipe (cs); @@ -4224,7 +4479,8 @@ nfs3_fsstat_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t nfs3_fsstat_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct statvfs *buf) + int32_t op_ret, int32_t op_errno, struct statvfs *buf, + dict_t *xdata) { nfs_user_t nfu = {0, }; int ret = -EFAULT; @@ -4233,8 +4489,11 @@ nfs3_fsstat_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs = frame->local; if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); ret = -op_errno; - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto err; } @@ -4250,7 +4509,7 @@ nfs3_fsstat_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "FSTAT", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_FSSTAT, stat, -ret); nfs3_fsstat_reply (cs->req, stat, NULL, NULL); nfs3_call_state_wipe (cs); @@ -4282,7 +4541,7 @@ nfs3_fsstat_resume (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "FSTAT", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_FSSTAT, stat, -ret); nfs3_fsstat_reply (cs->req, stat, NULL, NULL); nfs3_call_state_wipe (cs); @@ -4307,10 +4566,11 @@ nfs3_fsstat (rpcsvc_request_t *req, struct nfs3_fh *fh) return -1; } - nfs3_log_common_call (nfs_rpcsvc_request_xid (req), "FSSTAT", fh); + nfs3_log_common_call (rpcsvc_request_xid (req), "FSSTAT", fh); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); ret = nfs3_fh_resolve_and_resume (cs, fh, NULL, nfs3_fsstat_resume); @@ -4319,7 +4579,7 @@ nfs3_fsstat (rpcsvc_request_t *req, struct nfs3_fh *fh) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "FSTAT", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_FSSTAT, stat, -ret); nfs3_fsstat_reply (req, stat, NULL, NULL); nfs3_call_state_wipe (cs); @@ -4328,7 +4588,7 @@ nfs3err: */ ret = 0; } - +out: return ret; } @@ -4343,16 +4603,16 @@ nfs3svc_fsstat (rpcsvc_request_t *req) if (!req) return ret; nfs3_prep_fsstat3args (&args, &fh); - if (xdr_to_fsstat3args (req->msg, &args) <= 0) { + if (xdr_to_fsstat3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_fsstat (req, &fh); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "FSTAT procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -4369,7 +4629,7 @@ nfs3_fsinfo_reply (rpcsvc_request_t *req, nfsstat3 status, struct iatt *fsroot) uint64_t deviceid = 0; deviceid = nfs3_request_xlator_deviceid (req); - nfs3 = nfs_rpcsvc_request_program_private (req); + nfs3 = rpcsvc_request_program_private (req); nfs3_fill_fsinfo3res (nfs3, &res, status, fsroot, deviceid); nfs3svc_submit_reply (req, &res, @@ -4380,19 +4640,23 @@ nfs3_fsinfo_reply (rpcsvc_request_t *req, nfsstat3 status, struct iatt *fsroot) int32_t nfs3svc_fsinfo_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct iatt *buf) + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata) { nfsstat3 status = NFS3ERR_SERVERFAULT; nfs3_call_state_t *cs = NULL; cs = frame->local; - if (op_ret == -1) - status = nfs3_errno_to_nfsstat3 (op_errno); - else + if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + status = nfs3_cbk_errno_status (op_ret, op_errno); + }else status = NFS3_OK; - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "FSINFO", status, + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_FSINFO, status, op_errno); nfs3_fsinfo_reply (cs->req, status, buf); @@ -4425,7 +4689,7 @@ nfs3_fsinfo_resume (void *carg) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "FSINFO", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_FSINFO, stat, -ret); nfs3_fsinfo_reply (cs->req, stat, NULL); nfs3_call_state_wipe (cs); @@ -4449,10 +4713,11 @@ nfs3_fsinfo (rpcsvc_request_t *req, struct nfs3_fh *fh) return -1; } - nfs3_log_common_call (nfs_rpcsvc_request_xid (req), "FSINFO", fh); + nfs3_log_common_call (rpcsvc_request_xid (req), "FSINFO", fh); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); ret = nfs3_fh_resolve_and_resume (cs, fh, NULL, nfs3_fsinfo_resume); @@ -4461,13 +4726,13 @@ nfs3_fsinfo (rpcsvc_request_t *req, struct nfs3_fh *fh) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "FSINFO", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_FSINFO, stat, -ret); nfs3_fsinfo_reply (req, stat, NULL); nfs3_call_state_wipe (cs); ret = 0; } - +out: return ret; } @@ -4483,16 +4748,16 @@ nfs3svc_fsinfo (rpcsvc_request_t *req) return ret; nfs3_prep_fsinfo3args (&args, &root); - if (xdr_to_fsinfo3args (req->msg, &args) <= 0) { + if (xdr_to_fsinfo3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding arguments"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_fsinfo (req, &root); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "FSINFO procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -4517,16 +4782,20 @@ nfs3_pathconf_reply (rpcsvc_request_t *req, nfsstat3 stat, struct iatt *buf) int32_t nfs3svc_pathconf_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct iatt *buf) + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata) { struct iatt *sbuf = NULL; nfs3_call_state_t *cs = NULL; nfsstat3 stat = NFS3ERR_SERVERFAULT; cs = frame->local; - if (op_ret == -1) - stat = nfs3_errno_to_nfsstat3 (op_errno); - else { + if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); + } else { /* If stat fop failed, we can still send the other components * in a pathconf reply. */ @@ -4534,7 +4803,7 @@ nfs3svc_pathconf_cbk (call_frame_t *frame, void *cookie, xlator_t *this, stat = NFS3_OK; } - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "PATHCONF", stat, + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_PATHCONF, stat, op_errno); nfs3_pathconf_reply (cs->req, stat, sbuf); nfs3_call_state_wipe (cs); @@ -4563,8 +4832,8 @@ nfs3_pathconf_resume (void *carg) stat = nfs3_errno_to_nfsstat3 (-ret); nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), - "PATHCONF", stat, -ret); + nfs3_log_common_res (rpcsvc_request_xid (cs->req), + NFS3_PATHCONF, stat, -ret); nfs3_pathconf_reply (cs->req, stat, NULL); nfs3_call_state_wipe (cs); } @@ -4586,10 +4855,11 @@ nfs3_pathconf (rpcsvc_request_t *req, struct nfs3_fh *fh) return -1; } - nfs3_log_common_call (nfs_rpcsvc_request_xid (req), "PATHCONF", fh); + nfs3_log_common_call (rpcsvc_request_xid (req), "PATHCONF", fh); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); ret = nfs3_fh_resolve_and_resume (cs, fh, NULL, nfs3_pathconf_resume); @@ -4598,7 +4868,7 @@ nfs3_pathconf (rpcsvc_request_t *req, struct nfs3_fh *fh) nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "PATHCONF", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_PATHCONF, stat, -ret); nfs3_pathconf_reply (req, stat, NULL); nfs3_call_state_wipe (cs); @@ -4607,7 +4877,7 @@ nfs3err: */ ret = 0; } - +out: return ret; } @@ -4622,16 +4892,16 @@ nfs3svc_pathconf (rpcsvc_request_t *req) if (!req) return ret; nfs3_prep_pathconf3args (&args, &fh); - if (xdr_to_pathconf3args (req->msg, &args) <= 0) { + if (xdr_to_pathconf3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_pathconf (req, &fh); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "PATHCONF procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -4657,23 +4927,25 @@ nfs3_commit_reply (rpcsvc_request_t *req, nfsstat3 stat, uint64_t wverf, int32_t nfs3svc_commit_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct iatt *prebuf, - struct iatt *postbuf) + int32_t op_ret, int32_t op_errno, dict_t *xdata) { nfsstat3 stat = NFS3ERR_SERVERFAULT; nfs3_call_state_t *cs = NULL; struct nfs3_state *nfs3 = NULL; cs = frame->local; - if (op_ret == -1) - stat = nfs3_errno_to_nfsstat3 (op_errno); - else + if (op_ret == -1) { + gf_log (GF_NFS, GF_LOG_WARNING, + "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), + cs->resolvedloc.path, strerror (op_errno)); + stat = nfs3_cbk_errno_status (op_ret, op_errno); + } else stat = NFS3_OK; - nfs3 = nfs_rpcsvc_request_program_private (cs->req); - nfs3_log_commit_res (nfs_rpcsvc_request_xid (cs->req), stat, op_errno, + nfs3 = rpcsvc_request_program_private (cs->req); + nfs3_log_commit_res (rpcsvc_request_xid (cs->req), stat, op_errno, nfs3->serverstart); - nfs3_commit_reply (cs->req, stat, nfs3->serverstart, prebuf, postbuf); + nfs3_commit_reply (cs->req, stat, nfs3->serverstart, NULL, NULL); nfs3_call_state_wipe (cs); return 0; @@ -4700,14 +4972,14 @@ nfs3_commit_resume (void *carg) } nfs_request_user_init (&nfu, cs->req); - ret = nfs_fsync (cs->nfsx, cs->vol, &nfu, cs->fd, 0, + ret = nfs_flush (cs->nfsx, cs->vol, &nfu, cs->fd, nfs3svc_commit_cbk, cs); if (ret < 0) stat = nfs3_errno_to_nfsstat3 (-ret); nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "COMMIT", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_COMMIT, stat, -ret); nfs3_commit_reply (cs->req, stat, cs->nfs3state->serverstart, NULL, NULL); @@ -4715,7 +4987,7 @@ nfs3err: ret = 0; } - return ret; + return 0; } @@ -4731,13 +5003,18 @@ nfs3_commit_open_resume (void *carg) cs = (nfs3_call_state_t *)carg; nfs3_check_fh_resolve_status (cs, stat, nfs3err); + cs->fd = fd_anonymous (cs->resolvedloc.inode); + if (!cs->fd) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to create anonymous fd."); + goto nfs3err; + } - ret = nfs3_file_open_and_resume (cs, nfs3_commit_resume); + ret = nfs3_commit_resume (cs); if (ret < 0) stat = nfs3_errno_to_nfsstat3 (-ret); nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (cs->req), "COMMIT", + nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_COMMIT, stat, -ret); nfs3_commit_reply (cs->req, stat, 0, NULL, NULL); nfs3_call_state_wipe (cs); @@ -4763,11 +5040,12 @@ nfs3_commit (rpcsvc_request_t *req, struct nfs3_fh *fh, offset3 offset, return -1; } - nfs3_log_rw_call (nfs_rpcsvc_request_xid (req), "COMMIT", fh, offset, + nfs3_log_rw_call (rpcsvc_request_xid (req), "COMMIT", fh, offset, count, -1); nfs3_validate_gluster_fh (fh, stat, nfs3err); nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret); nfs3_map_fh_to_volume (nfs3, fh, req, vol, stat, nfs3err); + nfs3_volume_started_check (nfs3, vol, ret, out); nfs3_check_rw_volaccess (nfs3, fh->exportid, stat, nfs3err); nfs3_handle_call_state_init (nfs3, cs, req, vol, stat, nfs3err); @@ -4780,13 +5058,13 @@ nfs3_commit (rpcsvc_request_t *req, struct nfs3_fh *fh, offset3 offset, nfs3err: if (ret < 0) { - nfs3_log_common_res (nfs_rpcsvc_request_xid (req), "COMMIT", + nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_COMMIT, stat, -ret); nfs3_commit_reply (req, stat, 0, NULL, NULL); nfs3_call_state_wipe (cs); ret = 0; } - +out: return ret; } @@ -4802,16 +5080,16 @@ nfs3svc_commit (rpcsvc_request_t *req) if (!req) return ret; nfs3_prep_commit3args (&args, &fh); - if (xdr_to_commit3args (req->msg, &args) <= 0) { + if (xdr_to_commit3args (req->msg[0], &args) <= 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Error decoding args"); - nfs_rpcsvc_request_seterr (req, GARBAGE_ARGS); + rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } ret = nfs3_commit (req, &fh, args.offset, args.count); - if (ret < 0) { + if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { gf_log (GF_NFS3, GF_LOG_ERROR, "COMMIT procedure failed"); - nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + rpcsvc_request_seterr (req, SYSTEM_ERR); ret = RPCSVC_ACTOR_ERROR; } @@ -4821,28 +5099,28 @@ rpcerr: rpcsvc_actor_t nfs3svc_actors[NFS3_PROC_COUNT] = { - {"NULL", NFS3_NULL, nfs3svc_null, NULL, NULL}, - {"GETATTR", NFS3_GETATTR, nfs3svc_getattr,NULL, NULL}, - {"SETATTR", NFS3_SETATTR, nfs3svc_setattr,NULL, NULL}, - {"LOOKUP", NFS3_LOOKUP, nfs3svc_lookup, NULL, NULL}, - {"ACCESS", NFS3_ACCESS, nfs3svc_access, NULL, NULL}, - {"READLINK", NFS3_READLINK, nfs3svc_readlink,NULL, NULL}, - {"READ", NFS3_READ, nfs3svc_read, NULL, NULL}, - {"WRITE", NFS3_WRITE, nfs3svc_write, nfs3svc_write_vec, nfs3svc_write_vecsizer}, - {"CREATE", NFS3_CREATE, nfs3svc_create, NULL, NULL}, - {"MKDIR", NFS3_MKDIR, nfs3svc_mkdir, NULL, NULL}, - {"SYMLINK", NFS3_SYMLINK, nfs3svc_symlink,NULL, NULL}, - {"MKNOD", NFS3_MKNOD, nfs3svc_mknod, NULL, NULL}, - {"REMOVE", NFS3_REMOVE, nfs3svc_remove, NULL, NULL}, - {"RMDIR", NFS3_RMDIR, nfs3svc_rmdir, NULL, NULL}, - {"RENAME", NFS3_RENAME, nfs3svc_rename, NULL, NULL}, - {"LINK", NFS3_LINK, nfs3svc_link, NULL, NULL}, - {"READDIR", NFS3_READDIR, nfs3svc_readdir,NULL, NULL}, - {"READDIRPLUS", NFS3_READDIRP, nfs3svc_readdirp,NULL, NULL}, - {"FSSTAT", NFS3_FSSTAT, nfs3svc_fsstat, NULL, NULL}, - {"FSINFO", NFS3_FSINFO, nfs3svc_fsinfo, NULL, NULL}, - {"PATHCONF", NFS3_PATHCONF, nfs3svc_pathconf,NULL, NULL}, - {"COMMIT", NFS3_COMMIT, nfs3svc_commit, NULL, NULL} + {"NULL", NFS3_NULL, nfs3svc_null, NULL, 0, DRC_IDEMPOTENT}, + {"GETATTR", NFS3_GETATTR, nfs3svc_getattr, NULL, 0, DRC_IDEMPOTENT}, + {"SETATTR", NFS3_SETATTR, nfs3svc_setattr, NULL, 0, DRC_NON_IDEMPOTENT}, + {"LOOKUP", NFS3_LOOKUP, nfs3svc_lookup, NULL, 0, DRC_IDEMPOTENT}, + {"ACCESS", NFS3_ACCESS, nfs3svc_access, NULL, 0, DRC_IDEMPOTENT}, + {"READLINK", NFS3_READLINK, nfs3svc_readlink, NULL, 0, DRC_IDEMPOTENT}, + {"READ", NFS3_READ, nfs3svc_read, NULL, 0, DRC_IDEMPOTENT}, + {"WRITE", NFS3_WRITE, nfs3svc_write, nfs3svc_write_vecsizer, 0, DRC_NON_IDEMPOTENT}, + {"CREATE", NFS3_CREATE, nfs3svc_create, NULL, 0, DRC_NON_IDEMPOTENT}, + {"MKDIR", NFS3_MKDIR, nfs3svc_mkdir, NULL, 0, DRC_NON_IDEMPOTENT}, + {"SYMLINK", NFS3_SYMLINK, nfs3svc_symlink, NULL, 0, DRC_NON_IDEMPOTENT}, + {"MKNOD", NFS3_MKNOD, nfs3svc_mknod, NULL, 0, DRC_NON_IDEMPOTENT}, + {"REMOVE", NFS3_REMOVE, nfs3svc_remove, NULL, 0, DRC_NON_IDEMPOTENT}, + {"RMDIR", NFS3_RMDIR, nfs3svc_rmdir, NULL, 0, DRC_NON_IDEMPOTENT}, + {"RENAME", NFS3_RENAME, nfs3svc_rename, NULL, 0, DRC_NON_IDEMPOTENT}, + {"LINK", NFS3_LINK, nfs3svc_link, NULL, 0, DRC_NON_IDEMPOTENT}, + {"READDIR", NFS3_READDIR, nfs3svc_readdir, NULL, 0, DRC_IDEMPOTENT}, + {"READDIRPLUS", NFS3_READDIRP, nfs3svc_readdirp, NULL, 0, DRC_IDEMPOTENT}, + {"FSSTAT", NFS3_FSSTAT, nfs3svc_fsstat, NULL, 0, DRC_IDEMPOTENT}, + {"FSINFO", NFS3_FSINFO, nfs3svc_fsinfo, NULL, 0, DRC_IDEMPOTENT}, + {"PATHCONF", NFS3_PATHCONF, nfs3svc_pathconf, NULL, 0, DRC_IDEMPOTENT}, + {"COMMIT", NFS3_COMMIT, nfs3svc_commit, NULL, 0, DRC_IDEMPOTENT} }; @@ -4851,8 +5129,6 @@ rpcsvc_program_t nfs3prog = { .prognum = NFS_PROGRAM, .progver = NFS_V3, .progport = GF_NFS3_PORT, - .progaddrfamily = AF_INET, - .proghost = NULL, .actors = nfs3svc_actors, .numactors = NFS3_PROC_COUNT, @@ -4861,21 +5137,48 @@ rpcsvc_program_t nfs3prog = { .min_auth = AUTH_NULL, }; +/* + * This function rounds up the input value to multiple of 4096. Min and Max + * supported I/O size limits are 4KB (GF_NFS3_FILE_IO_SIZE_MIN) and + * 1MB (GF_NFS3_FILE_IO_SIZE_MAX). + */ +void +nfs3_iosize_roundup_4KB (uint64_t *ioszptr) +{ + uint64_t iosize; + uint64_t iopages; + + if (!ioszptr) + return; + + iosize = *ioszptr; + iopages = (iosize + GF_NFS3_IO_SIZE -1) >> GF_NFS3_IO_SHIFT; + iosize = (iopages * GF_NFS3_IO_SIZE); + + /* Double check - boundary conditions */ + if (iosize < GF_NFS3_FILE_IO_SIZE_MIN) { + iosize = GF_NFS3_FILE_IO_SIZE_MIN; + } else if (iosize > GF_NFS3_FILE_IO_SIZE_MAX) { + iosize = GF_NFS3_FILE_IO_SIZE_MAX; + } + + *ioszptr = iosize; +} int -nfs3_init_options (struct nfs3_state *nfs3, xlator_t *nfsx) +nfs3_init_options (struct nfs3_state *nfs3, dict_t *options) { int ret = -1; char *optstr = NULL; uint64_t size64 = 0; - if ((!nfs3) || (!nfsx)) + if ((!nfs3) || (!options)) return -1; /* nfs3.read-size */ nfs3->readsize = GF_NFS3_RTPREF; - if (dict_get (nfsx->options, "nfs3.read-size")) { - ret = dict_get_str (nfsx->options, "nfs3.read-size", &optstr); + if (dict_get (options, "nfs3.read-size")) { + ret = dict_get_str (options, "nfs3.read-size", &optstr); if (ret < 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to read " " option: nfs3.read-size"); @@ -4884,19 +5187,21 @@ nfs3_init_options (struct nfs3_state *nfs3, xlator_t *nfsx) } ret = gf_string2bytesize (optstr, &size64); - nfs3->readsize = size64; if (ret == -1) { gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to format" " option: nfs3.read-size"); ret = -1; goto err; } + + nfs3_iosize_roundup_4KB (&size64); + nfs3->readsize = size64; } /* nfs3.write-size */ nfs3->writesize = GF_NFS3_WTPREF; - if (dict_get (nfsx->options, "nfs3.write-size")) { - ret = dict_get_str (nfsx->options, "nfs3.write-size", &optstr); + if (dict_get (options, "nfs3.write-size")) { + ret = dict_get_str (options, "nfs3.write-size", &optstr); if (ret < 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to read " " option: nfs3.write-size"); @@ -4905,19 +5210,21 @@ nfs3_init_options (struct nfs3_state *nfs3, xlator_t *nfsx) } ret = gf_string2bytesize (optstr, &size64); - nfs3->writesize = size64; if (ret == -1) { gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to format" " option: nfs3.write-size"); ret = -1; goto err; } + + nfs3_iosize_roundup_4KB (&size64); + nfs3->writesize = size64; } /* nfs3.readdir.size */ nfs3->readdirsize = GF_NFS3_DTPREF; - if (dict_get (nfsx->options, "nfs3.readdir-size")) { - ret = dict_get_str (nfsx->options,"nfs3.readdir-size", &optstr); + if (dict_get (options, "nfs3.readdir-size")) { + ret = dict_get_str (options,"nfs3.readdir-size", &optstr); if (ret < 0) { gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to read" " option: nfs3.readdir-size"); @@ -4926,15 +5233,16 @@ nfs3_init_options (struct nfs3_state *nfs3, xlator_t *nfsx) } ret = gf_string2bytesize (optstr, &size64); - nfs3->readdirsize = size64; if (ret == -1) { gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to format" " option: nfs3.readdir-size"); ret = -1; goto err; } - } + nfs3_iosize_roundup_4KB (&size64); + nfs3->readdirsize = size64; + } /* We want to use the size of the biggest param for the io buffer size. */ @@ -4945,7 +5253,7 @@ nfs3_init_options (struct nfs3_state *nfs3, xlator_t *nfsx) nfs3->iobsize = nfs3->readdirsize; /* But this is the true size of each iobuf. We need this size to - * accomodate the NFS headers also in the same buffer. */ + * accommodate the NFS headers also in the same buffer. */ nfs3->iobsize = nfs3->iobsize * 2; /* mem-factor */ @@ -4955,9 +5263,10 @@ err: return ret; } - int -nfs3_init_subvolume_options (struct nfs3_state *nfs3, struct nfs3_export *exp) +nfs3_init_subvolume_options (xlator_t *nfsx, + struct nfs3_export *exp, + dict_t *options) { int ret = -1; char *optstr = NULL; @@ -4965,14 +5274,20 @@ nfs3_init_subvolume_options (struct nfs3_state *nfs3, struct nfs3_export *exp) char *name = NULL; gf_boolean_t boolt = _gf_false; uuid_t volumeid = {0, }; - dict_t *options = NULL; - if ((!exp) || (!nfs3)) + if ((!nfsx) || (!exp)) return -1; - options = nfs3->nfsx->options; + /* For init, fetch options from xlator but for + * reconfigure, take the parameter */ + if (!options) + options = nfsx->options; + + if (!options) + return (-1); + uuid_clear (volumeid); - if (gf_nfs_dvm_off (nfs_state (nfs3->nfsx))) + if (gf_nfs_dvm_off (nfs_state (nfsx))) goto no_dvm; ret = snprintf (searchkey, 1024, "nfs3.%s.volume-id",exp->subvol->name); @@ -5138,7 +5453,7 @@ nfs3_init_subvolume (struct nfs3_state *nfs3, xlator_t *subvol) INIT_LIST_HEAD (&exp->explist); gf_log (GF_NFS3, GF_LOG_TRACE, "Initing state: %s", exp->subvol->name); - ret = nfs3_init_subvolume_options (nfs3, exp); + ret = nfs3_init_subvolume_options (nfs3->nfsx, exp, NULL); if (ret == -1) { gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to init subvol"); goto exp_free; @@ -5190,7 +5505,7 @@ nfs3_init_state (xlator_t *nfsx) struct nfs3_state *nfs3 = NULL; int ret = -1; unsigned int localpool = 0; - + struct nfs_state *nfs = NULL; if (!nfsx) return NULL; @@ -5202,7 +5517,8 @@ nfs3_init_state (xlator_t *nfsx) return NULL; } - ret = nfs3_init_options (nfs3, nfsx); + nfs = nfsx->private; + ret = nfs3_init_options (nfs3, nfsx->options); if (ret == -1) { gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to init options"); goto ret; @@ -5234,6 +5550,13 @@ nfs3_init_state (xlator_t *nfsx) LOCK_INIT (&nfs3->fdlrulock); nfs3->fdcount = 0; + ret = rpcsvc_create_listeners (nfs->rpcsvc, nfsx->options, nfsx->name); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "Unable to create listeners"); + goto free_localpool; + } + + nfs->nfs3state = nfs3; ret = 0; free_localpool: @@ -5269,4 +5592,39 @@ nfs3svc_init (xlator_t *nfsx) return &nfs3prog; } +int +nfs3_reconfigure_state (xlator_t *nfsx, dict_t *options) +{ + int ret = -1; + struct nfs3_export *exp = NULL; + struct nfs_state *nfs = NULL; + struct nfs3_state *nfs3 = NULL; + if ((!nfsx) || (!nfsx->private) || (!options)) + goto out; + + nfs = (struct nfs_state *)nfsx->private; + nfs3 = nfs->nfs3state; + if (!nfs3) + goto out; + + ret = nfs3_init_options (nfs3, options); + if (ret) { + gf_log (GF_NFS3, GF_LOG_ERROR, + "Failed to reconfigure options"); + goto out; + } + + list_for_each_entry (exp, &nfs3->exports, explist) { + ret = nfs3_init_subvolume_options (nfsx, exp, options); + if (ret) { + gf_log (GF_NFS3, GF_LOG_ERROR, + "Failed to reconfigure subvol options"); + goto out; + } + } + + ret = 0; +out: + return ret; +} diff --git a/xlators/nfs/server/src/nfs3.h b/xlators/nfs/server/src/nfs3.h index a43fdc4af..0c35445a4 100644 --- a/xlators/nfs/server/src/nfs3.h +++ b/xlators/nfs/server/src/nfs3.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2011 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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _NFS3_H_ @@ -34,11 +25,12 @@ #include "nfs-common.h" #include "xdr-nfs3.h" #include "mem-pool.h" - +#include "nlm4.h" +#include "acl3-xdr.h" +#include "acl3.h" #include <sys/statvfs.h> #define GF_NFS3 GF_NFS"-nfsv3" -#define GF_NFS3_PORT 38467 #define GF_NFS3_DEFAULT_MEMFACTOR 15 #define GF_NFS3_IOBPOOL_MULT GF_NFS_CONCURRENT_OPS_MULT @@ -47,16 +39,39 @@ /* Static values used for FSINFO -FIXME: This should be configurable */ -#define GF_NFS3_RTMAX (64 * GF_UNIT_KB) -#define GF_NFS3_RTPREF (64 * GF_UNIT_KB) -#define GF_NFS3_RTMULT (4 * GF_UNIT_KB) -#define GF_NFS3_WTMAX (64 * GF_UNIT_KB) -#define GF_NFS3_WTPREF (64 * GF_UNIT_KB) -#define GF_NFS3_WTMULT (4 * GF_UNIT_KB) -#define GF_NFS3_DTMIN (4 * GF_UNIT_KB) -#define GF_NFS3_DTPREF (64 * GF_UNIT_KB) -#define GF_NFS3_MAXFILE (1 * GF_UNIT_PB) + * To change the maximum rsize and wsize supported by the NFS client, adjust + * GF_NFS3_FILE_IO_SIZE_MAX. The Gluster NFS server defaults to 1MB(1048576) + * (same as kernel NFS server). For slower network, rsize/wsize can be trimmed + * to 16/32/64-KB. rsize and wsize can be tuned through nfs.read-size and + * nfs.write-size respectively. + * + * NB: For Kernel-NFS, NFS_MAX_FILE_IO_SIZE is 1048576U (1MB). + */ +#define GF_NFS3_FILE_IO_SIZE_MAX (1 * GF_UNIT_MB) /* 1048576 */ +#define GF_NFS3_FILE_IO_SIZE_MIN (4 * GF_UNIT_KB) /* 4096 */ + +#define GF_NFS3_FILE_IO_SIZE_DEF GF_NFS3_FILE_IO_SIZE_MAX + +#define GF_NFS3_RTMAX GF_NFS3_FILE_IO_SIZE_MAX +#define GF_NFS3_RTMIN GF_NFS3_FILE_IO_SIZE_MIN +#define GF_NFS3_RTPREF GF_NFS3_FILE_IO_SIZE_DEF +#define GF_NFS3_RTMULT GF_NFS3_FILE_IO_SIZE_MIN + +#define GF_NFS3_WTMAX GF_NFS3_FILE_IO_SIZE_MAX +#define GF_NFS3_WTMIN GF_NFS3_FILE_IO_SIZE_MIN +#define GF_NFS3_WTPREF GF_NFS3_FILE_IO_SIZE_DEF +#define GF_NFS3_WTMULT GF_NFS3_FILE_IO_SIZE_MIN + +/* This can be tuned through nfs.readdir-size */ +#define GF_NFS3_DTMAX GF_NFS3_FILE_IO_SIZE_MAX +#define GF_NFS3_DTMIN GF_NFS3_FILE_IO_SIZE_MIN +#define GF_NFS3_DTPREF GF_NFS3_FILE_IO_SIZE_DEF + +#define GF_NFS3_MAXFILESIZE (1 * GF_UNIT_PB) + +#define GF_NFS3_IO_SIZE 4096 /* 4-KB */ +#define GF_NFS3_IO_SHIFT 12 /* 2^12 = 4KB */ + /* FIXME: Handle time resolutions */ #define GF_NFS3_TIMEDELTA_SECS {1,0} #define GF_NFS3_TIMEDELTA_NSECS {0,1} @@ -88,12 +103,13 @@ struct nfs3_export { int access; int trusted_sync; int trusted_write; + int rootlookedup; }; #define GF_NFS3_DEFAULT_VOLACCESS (GF_NFS3_VOLACCESS_RW) /* The NFSv3 protocol state */ -struct nfs3_state { +typedef struct nfs3_state { /* The NFS xlator pointer. The NFS xlator can be running * multiple versions of the NFS protocol. @@ -118,21 +134,48 @@ struct nfs3_state { uint64_t serverstart; /* NFSv3 Protocol configurables */ - size_t readsize; - size_t writesize; - size_t readdirsize; + uint64_t readsize; + uint64_t writesize; + uint64_t readdirsize; /* Size of the iobufs used, depends on the sizes of the three params * above. */ - size_t iobsize; + uint64_t iobsize; unsigned int memfactor; struct list_head fdlru; gf_lock_t fdlrulock; int fdcount; -}; + uint32_t occ_logger; +} nfs3_state_t; + +typedef enum nfs3_lookup_type { + GF_NFS3_REVALIDATE = 1, + GF_NFS3_FRESH, +} nfs3_lookup_type_t; + +typedef union args_ { + nlm4_stat nlm4_stat; + nlm4_holder nlm4_holder; + nlm4_lock nlm4_lock; + nlm4_share nlm4_share; + nlm4_testrply nlm4_testrply; + nlm4_testres nlm4_testres; + nlm4_testargs nlm4_testargs; + nlm4_res nlm4_res; + nlm4_lockargs nlm4_lockargs; + nlm4_cancargs nlm4_cancargs; + nlm4_unlockargs nlm4_unlockargs; + nlm4_shareargs nlm4_shareargs; + nlm4_shareres nlm4_shareres; + nlm4_freeallargs nlm4_freeallargs; + getaclargs getaclargs; + setaclargs setaclargs; + getaclreply getaclreply; + setaclreply setaclreply; +} args; typedef int (*nfs3_resume_fn_t) (void *cs); @@ -179,6 +222,7 @@ struct nfs3_local { count3 datacount; offset3 dataoffset; struct iobuf *iob; + struct iobref *iobref; createmode3 createmode; uint64_t cookieverf; int sattrguardcheck; @@ -190,6 +234,7 @@ struct nfs3_local { mode_t mode; /* NFSv3 FH resolver state */ + int hardresolved; struct nfs3_fh resolvefh; loc_t resolvedloc; int resolve_ret; @@ -197,8 +242,33 @@ struct nfs3_local { int hashidx; fd_t *resolve_dir_fd; char *resolventry; + nfs3_lookup_type_t lookuptype; + gf_dirent_t *hashmatch; + gf_dirent_t *entrymatch; + off_t lastentryoffset; + struct flock flock; + args args; + nlm4_lkowner_t lkowner; + char cookiebytes[1024]; + struct nfs3_fh lockfh; + int monitor; + rpc_transport_t *trans; + call_frame_t *frame; + + /* ACL */ + aclentry aclentry[NFS_ACL_MAX_ENTRIES]; + aclentry daclentry[NFS_ACL_MAX_ENTRIES]; + int aclcount; + char aclxattr[NFS_ACL_MAX_ENTRIES*8 + 4]; + int daclcount; + char daclxattr[NFS_ACL_MAX_ENTRIES*8 + 4]; }; +#define nfs3_is_revalidate_lookup(cst) ((cst)->lookuptype == GF_NFS3_REVALIDATE) +#define nfs3_lookup_op(cst) (rpcsvc_request_procnum(cst->req) == NFS3_LOOKUP) +#define nfs3_create_op(cst) (rpcsvc_request_procnum(cst->req) == NFS3_CREATE) +#define nfs3_create_exclusive_op(cst) ((cst)->createmode == EXCLUSIVE) + typedef struct nfs3_local nfs3_call_state_t; /* Queue of ops waiting for open fop to return. */ @@ -207,9 +277,9 @@ struct inode_op_queue { pthread_mutex_t qlock; }; - - - extern rpcsvc_program_t * nfs3svc_init (xlator_t *nfsx); + +extern int +nfs3_reconfigure_state (xlator_t *nfsx, dict_t *options); #endif diff --git a/xlators/nfs/server/src/nlm4.c b/xlators/nfs/server/src/nlm4.c new file mode 100644 index 000000000..5c5d87412 --- /dev/null +++ b/xlators/nfs/server/src/nlm4.c @@ -0,0 +1,2525 @@ +/* + Copyright (c) 2012 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "defaults.h" +#include "rpcsvc.h" +#include "dict.h" +#include "xlator.h" +#include "nfs.h" +#include "mem-pool.h" +#include "logging.h" +#include "nfs-fops.h" +#include "inode.h" +#include "mount3.h" +#include "nfs3.h" +#include "nfs-mem-types.h" +#include "nfs3-helpers.h" +#include "nfs3-fh.h" +#include "nlm4.h" +#include "nlm4-xdr.h" +#include "msg-nfs3.h" +#include "nfs-generics.h" +#include "rpc-clnt.h" +#include "nsm-xdr.h" +#include "nlmcbk-xdr.h" +#include "run.h" +#include <unistd.h> +#include <rpc/pmap_clnt.h> +#include <rpc/rpc.h> +#include <rpc/xdr.h> +#include <statedump.h> + +/* TODO: + * 1) 2 opens racing .. creating an fd leak. + * 2) use mempool for nlmclnt - destroy if no fd exists, create during 1st call + */ + +typedef ssize_t (*nlm4_serializer) (struct iovec outmsg, void *args); + +extern void nfs3_call_state_wipe (nfs3_call_state_t *cs); + +struct list_head nlm_client_list; +gf_lock_t nlm_client_list_lk; + +/* race on this is harmless */ +int nlm_grace_period = 50; + +#define nlm4_validate_nfs3_state(request, state, status, label, retval) \ + do { \ + state = rpcsvc_request_program_private (request); \ + if (!state) { \ + gf_log (GF_NLM, GF_LOG_ERROR, "NFSv3 state " \ + "missing from RPC request"); \ + rpcsvc_request_seterr (req, SYSTEM_ERR); \ + status = nlm4_failed; \ + goto label; \ + } \ + } while (0); \ + +nfs3_call_state_t * +nfs3_call_state_init (struct nfs3_state *s, rpcsvc_request_t *req, xlator_t *v); + +#define nlm4_handle_call_state_init(nfs3state, calls, rq, opstat, errlabel)\ + do { \ + calls = nlm4_call_state_init ((nfs3state), (rq)); \ + if (!calls) { \ + gf_log (GF_NLM, GF_LOG_ERROR, "Failed to " \ + "init call state"); \ + opstat = nlm4_failed; \ + rpcsvc_request_seterr (req, SYSTEM_ERR); \ + goto errlabel; \ + } \ + } while (0) \ + +#define nlm4_validate_gluster_fh(handle, status, errlabel) \ + do { \ + if (!nfs3_fh_validate (handle)) { \ + status = nlm4_stale_fh; \ + goto errlabel; \ + } \ + } while (0) \ + +xlator_t * +nfs3_fh_to_xlator (struct nfs3_state *nfs3, struct nfs3_fh *fh); + +#define nlm4_map_fh_to_volume(nfs3state, handle, req, volume, status, label) \ + do { \ + char exportid[256], gfid[256]; \ + rpc_transport_t *trans = NULL; \ + volume = nfs3_fh_to_xlator ((nfs3state), &handle); \ + if (!volume) { \ + uuid_unparse (handle.exportid, exportid); \ + uuid_unparse (handle.gfid, gfid); \ + trans = rpcsvc_request_transport (req); \ + gf_log (GF_NLM, GF_LOG_ERROR, "Failed to map " \ + "FH to vol: client=%s, exportid=%s, gfid=%s",\ + trans->peerinfo.identifier, exportid, \ + gfid); \ + gf_log (GF_NLM, GF_LOG_ERROR, \ + "Stale nfs client %s must be trying to "\ + "connect to a deleted volume, please " \ + "unmount it.", trans->peerinfo.identifier);\ + status = nlm4_stale_fh; \ + goto label; \ + } else { \ + gf_log (GF_NLM, GF_LOG_TRACE, "FH to Volume: %s"\ + ,volume->name); \ + rpcsvc_request_set_private (req, volume); \ + } \ + } while (0); \ + +#define nlm4_volume_started_check(nfs3state, vlm, rtval, erlbl) \ + do { \ + if ((!nfs_subvolume_started (nfs_state (nfs3state->nfsx), vlm))){\ + gf_log (GF_NLM, GF_LOG_ERROR, "Volume is disabled: %s",\ + vlm->name); \ + rtval = RPCSVC_ACTOR_IGNORE; \ + goto erlbl; \ + } \ + } while (0) \ + +#define nlm4_check_fh_resolve_status(cst, nfstat, erlabl) \ + do { \ + xlator_t *xlatorp = NULL; \ + char buf[256], gfid[256]; \ + rpc_transport_t *trans = NULL; \ + if ((cst)->resolve_ret < 0) { \ + trans = rpcsvc_request_transport (cst->req); \ + xlatorp = nfs3_fh_to_xlator (cst->nfs3state, \ + &cst->resolvefh); \ + uuid_unparse (cst->resolvefh.gfid, gfid); \ + snprintf (buf, sizeof (buf), "(%s) %s : %s", \ + trans->peerinfo.identifier, \ + xlatorp ? xlatorp->name : "ERR", \ + gfid); \ + gf_log (GF_NLM, GF_LOG_ERROR, "Unable to resolve FH"\ + ": %s", buf); \ + nfstat = nlm4_errno_to_nlm4stat (cst->resolve_errno);\ + goto erlabl; \ + } \ + } while (0) \ + + +void +nlm4_prep_nlm4_testargs (nlm4_testargs *args, struct nfs3_fh *fh, + nlm4_lkowner_t *oh, char *cookiebytes) +{ + memset (args, 0, sizeof (*args)); + args->alock.fh.n_bytes = (void *)fh; + args->alock.oh.n_bytes = (void *)oh; + args->cookie.n_bytes = (void *)cookiebytes; +} + +void +nlm4_prep_nlm4_lockargs (nlm4_lockargs *args, struct nfs3_fh *fh, + nlm4_lkowner_t *oh, char *cookiebytes) +{ + memset (args, 0, sizeof (*args)); + args->alock.fh.n_bytes = (void *)fh; + args->alock.oh.n_bytes = (void *)oh; + args->cookie.n_bytes = (void *)cookiebytes; +} + +void +nlm4_prep_nlm4_cancargs (nlm4_cancargs *args, struct nfs3_fh *fh, + nlm4_lkowner_t *oh, char *cookiebytes) +{ + memset (args, 0, sizeof (*args)); + args->alock.fh.n_bytes = (void *)fh; + args->alock.oh.n_bytes = (void *)oh; + args->cookie.n_bytes = (void *)cookiebytes; +} + +void +nlm4_prep_nlm4_unlockargs (nlm4_unlockargs *args, struct nfs3_fh *fh, + nlm4_lkowner_t *oh, char *cookiebytes) +{ + memset (args, 0, sizeof (*args)); + args->alock.fh.n_bytes = (void *)fh; + args->alock.oh.n_bytes = (void *)oh; + args->cookie.n_bytes = (void *)cookiebytes; +} + +void +nlm4_prep_shareargs (nlm4_shareargs *args, struct nfs3_fh *fh, + nlm4_lkowner_t *oh, char *cookiebytes) +{ + memset (args, 0, sizeof (*args)); + args->share.fh.n_bytes = (void *)fh; + args->share.oh.n_bytes = (void *)oh; + args->cookie.n_bytes = (void *)cookiebytes; +} + +void +nlm4_prep_freeallargs (nlm4_freeallargs *args, nlm4_lkowner_t *oh) +{ + memset (args, 0, sizeof (*args)); + args->name = (void *)oh; +} + +void +nlm_copy_lkowner (gf_lkowner_t *dst, netobj *src) +{ + dst->len = src->n_len; + memcpy (dst->data, src->n_bytes, dst->len); +} + +int +nlm_is_oh_same_lkowner (gf_lkowner_t *a, netobj *b) +{ + if (!a || !b) { + gf_log (GF_NLM, GF_LOG_ERROR, "invalid args"); + return -1; + } + + return (a->len == b->n_len && + !memcmp (a->data, b->n_bytes, a->len)); +} + +nlm4_stats +nlm4_errno_to_nlm4stat (int errnum) +{ + nlm4_stats stat = nlm4_denied; + + switch (errnum) { + case 0: + stat = nlm4_granted; + break; + case EROFS: + stat = nlm4_rofs; + break; + case ESTALE: + stat = nlm4_stale_fh; + break; + case ENOLCK: + stat = nlm4_failed; + break; + default: + stat = nlm4_denied; + break; + } + + return stat; +} + +nfs3_call_state_t * +nlm4_call_state_init (struct nfs3_state *s, rpcsvc_request_t *req) +{ + nfs3_call_state_t *cs = NULL; + + if ((!s) || (!req)) + return NULL; + + cs = (nfs3_call_state_t *) mem_get (s->localpool); + if (!cs) + return NULL; + + memset (cs, 0, sizeof (*cs)); + INIT_LIST_HEAD (&cs->entries.list); + INIT_LIST_HEAD (&cs->openwait_q); + cs->operrno = EINVAL; + cs->req = req; + cs->nfsx = s->nfsx; + cs->nfs3state = s; + cs->monitor = 1; + + return cs; +} + +int +nlm_monitor (char *caller_name) +{ + nlm_client_t *nlmclnt = NULL; + int monitor = -1; + + LOCK (&nlm_client_list_lk); + list_for_each_entry (nlmclnt, &nlm_client_list, nlm_clients) { + if (!strcmp(caller_name, nlmclnt->caller_name)) { + monitor = nlmclnt->nsm_monitor; + nlmclnt->nsm_monitor = 1; + break; + } + } + UNLOCK (&nlm_client_list_lk); + + if (monitor == -1) + gf_log (GF_NLM, GF_LOG_ERROR, "%s was not found in " + "the nlmclnt list", caller_name); + + return monitor; +} + +rpc_clnt_t * +nlm_get_rpc_clnt (char *caller_name) +{ + nlm_client_t *nlmclnt = NULL; + int nlmclnt_found = 0; + rpc_clnt_t *rpc_clnt = NULL; + + LOCK (&nlm_client_list_lk); + list_for_each_entry (nlmclnt, &nlm_client_list, nlm_clients) { + if (!strcmp(caller_name, nlmclnt->caller_name)) { + nlmclnt_found = 1; + break; + } + } + if (!nlmclnt_found) + goto ret; + if (nlmclnt->rpc_clnt) + rpc_clnt = rpc_clnt_ref (nlmclnt->rpc_clnt); +ret: + UNLOCK (&nlm_client_list_lk); + return rpc_clnt; +} + +int +nlm_set_rpc_clnt (rpc_clnt_t *rpc_clnt, char *caller_name) +{ + nlm_client_t *nlmclnt = NULL; + int nlmclnt_found = 0; + int ret = -1; + + LOCK (&nlm_client_list_lk); + list_for_each_entry (nlmclnt, &nlm_client_list, nlm_clients) { + if (!strcmp(caller_name, nlmclnt->caller_name)) { + nlmclnt_found = 1; + break; + } + } + + if (!nlmclnt_found) { + nlmclnt = GF_CALLOC (1, sizeof(*nlmclnt), + gf_nfs_mt_nlm4_nlmclnt); + if (nlmclnt == NULL) + goto ret; + + INIT_LIST_HEAD(&nlmclnt->fdes); + INIT_LIST_HEAD(&nlmclnt->nlm_clients); + INIT_LIST_HEAD(&nlmclnt->shares); + + list_add (&nlmclnt->nlm_clients, &nlm_client_list); + nlmclnt->caller_name = gf_strdup (caller_name); + } + + if (nlmclnt->rpc_clnt == NULL) { + nlmclnt->rpc_clnt = rpc_clnt_ref (rpc_clnt); + } + ret = 0; +ret: + UNLOCK (&nlm_client_list_lk); + return ret; +} + +int +nlm_unset_rpc_clnt (rpc_clnt_t *rpc) +{ + nlm_client_t *nlmclnt = NULL; + rpc_clnt_t *rpc_clnt = NULL; + + LOCK (&nlm_client_list_lk); + list_for_each_entry (nlmclnt, &nlm_client_list, nlm_clients) { + if (rpc == nlmclnt->rpc_clnt) { + rpc_clnt = nlmclnt->rpc_clnt; + nlmclnt->rpc_clnt = NULL; + break; + } + } + UNLOCK (&nlm_client_list_lk); + if (rpc_clnt == NULL) { + return -1; + } + if (rpc_clnt) { + /* cleanup the saved-frames before last unref */ + rpc_clnt_connection_cleanup (&rpc_clnt->conn); + + rpc_clnt_unref (rpc_clnt); + } + return 0; +} + +int +nlm_add_nlmclnt (char *caller_name) +{ + nlm_client_t *nlmclnt = NULL; + int nlmclnt_found = 0; + int ret = -1; + + LOCK (&nlm_client_list_lk); + list_for_each_entry (nlmclnt, &nlm_client_list, nlm_clients) { + if (!strcmp(caller_name, nlmclnt->caller_name)) { + nlmclnt_found = 1; + break; + } + } + if (!nlmclnt_found) { + nlmclnt = GF_CALLOC (1, sizeof(*nlmclnt), + gf_nfs_mt_nlm4_nlmclnt); + if (nlmclnt == NULL) { + gf_log (GF_NLM, GF_LOG_DEBUG, "malloc error"); + goto ret; + } + + INIT_LIST_HEAD(&nlmclnt->fdes); + INIT_LIST_HEAD(&nlmclnt->nlm_clients); + INIT_LIST_HEAD(&nlmclnt->shares); + + list_add (&nlmclnt->nlm_clients, &nlm_client_list); + nlmclnt->caller_name = gf_strdup (caller_name); + } + ret = 0; +ret: + UNLOCK (&nlm_client_list_lk); + return ret; +} + +int +nlm4svc_submit_reply (rpcsvc_request_t *req, void *arg, nlm4_serializer sfunc) +{ + struct iovec outmsg = {0, }; + struct iobuf *iob = NULL; + struct nfs3_state *nfs3 = NULL; + int ret = -1; + ssize_t msglen = 0; + struct iobref *iobref = NULL; + + if (!req) + return -1; + + nfs3 = (struct nfs3_state *)rpcsvc_request_program_private (req); + if (!nfs3) { + gf_log (GF_NLM, GF_LOG_ERROR, "mount state not found"); + goto ret; + } + + /* First, get the io buffer into which the reply in arg will + * be serialized. + */ + iob = iobuf_get (nfs3->iobpool); + if (!iob) { + gf_log (GF_NLM, GF_LOG_ERROR, "Failed to get iobuf"); + goto ret; + } + + iobuf_to_iovec (iob, &outmsg); + /* Use the given serializer to translate the give C structure in arg + * to XDR format which will be written into the buffer in outmsg. + */ + msglen = sfunc (outmsg, arg); + if (msglen < 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Failed to encode message"); + goto ret; + } + outmsg.iov_len = msglen; + + iobref = iobref_new (); + if (iobref == NULL) { + gf_log (GF_NLM, GF_LOG_ERROR, "Failed to get iobref"); + goto ret; + } + + ret = iobref_add (iobref, iob); + if (ret) { + gf_log (GF_NLM, GF_LOG_ERROR, "Failed to add iob to iobref"); + goto ret; + } + + /* Then, submit the message for transmission. */ + ret = rpcsvc_submit_message (req, &outmsg, 1, NULL, 0, iobref); + if (ret == -1) { + gf_log (GF_NLM, GF_LOG_ERROR, "Reply submission failed"); + goto ret; + } + + ret = 0; +ret: + if (iob) + iobuf_unref (iob); + if (iobref) + iobref_unref (iobref); + + return ret; +} + +typedef int (*nlm4_resume_fn_t) (void *cs); + +int32_t +nlm4_file_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata) +{ + nfs3_call_state_t *cs = frame->local; + + if (op_ret == 0) + fd_bind (cs->fd); + cs->resolve_ret = op_ret; + cs->resume_fn (cs); + frame->local = NULL; + STACK_DESTROY (frame->root); + return 0; +} + +void * +nsm_monitor(void *arg) +{ + CLIENT *clnt = NULL; + enum clnt_stat ret; + struct mon nsm_mon; + struct sm_stat_res res; + struct timeval tout = { 5, 0 }; + char *host = NULL; + + host = arg; + nsm_mon.mon_id.mon_name = gf_strdup(host); + nsm_mon.mon_id.my_id.my_name = gf_strdup("localhost"); + nsm_mon.mon_id.my_id.my_prog = NLMCBK_PROGRAM; + nsm_mon.mon_id.my_id.my_vers = NLMCBK_V1; + nsm_mon.mon_id.my_id.my_proc = NLMCBK_SM_NOTIFY; + /* nothing to put in the private data */ +#define SM_PROG 100024 +#define SM_VERS 1 +#define SM_MON 2 + + /* create a connection to nsm on the localhost */ + clnt = clnt_create("localhost", SM_PROG, SM_VERS, "tcp"); + if(!clnt) + { + gf_log (GF_NLM, GF_LOG_ERROR, "%s", + clnt_spcreateerror ("Clnt_create()")); + goto out; + } + + ret = clnt_call(clnt, SM_MON, + (xdrproc_t) xdr_mon, (caddr_t) & nsm_mon, + (xdrproc_t) xdr_sm_stat_res, (caddr_t) & res, tout); + if(ret != RPC_SUCCESS) + { + gf_log (GF_NLM, GF_LOG_ERROR, "clnt_call(): %s", + clnt_sperrno(ret)); + goto out; + } + if(res.res_stat != STAT_SUCC) + { + gf_log (GF_NLM, GF_LOG_ERROR, "clnt_call(): %s", + clnt_sperrno(ret)); + goto out; + } + +out: + GF_FREE(nsm_mon.mon_id.mon_name); + GF_FREE(nsm_mon.mon_id.my_id.my_name); + if (clnt != NULL) + clnt_destroy(clnt); + return NULL; +} + +nlm_client_t * +__nlm_get_uniq (char *caller_name) +{ + nlm_client_t *nlmclnt = NULL; + + if (!caller_name) + return NULL; + + list_for_each_entry (nlmclnt, &nlm_client_list, nlm_clients) { + if (!strcmp(caller_name, nlmclnt->caller_name)) + return nlmclnt; + } + + return NULL; +} + +nlm_client_t * +nlm_get_uniq (char *caller_name) +{ + nlm_client_t *nlmclnt = NULL; + + LOCK (&nlm_client_list_lk); + nlmclnt = __nlm_get_uniq (caller_name); + UNLOCK (&nlm_client_list_lk); + + return nlmclnt; +} + + +int +nlm4_file_open_and_resume(nfs3_call_state_t *cs, nlm4_resume_fn_t resume) +{ + fd_t *fd = NULL; + int ret = -1; + int flags = 0; + nlm_client_t *nlmclnt = NULL; + call_frame_t *frame = NULL; + + if (cs->args.nlm4_lockargs.exclusive == _gf_false) + flags = O_RDONLY; + else + flags = O_WRONLY; + + nlmclnt = nlm_get_uniq (cs->args.nlm4_lockargs.alock.caller_name); + if (nlmclnt == NULL) { + gf_log (GF_NLM, GF_LOG_ERROR, "nlm_get_uniq() returned NULL"); + ret = -ENOLCK; + goto err; + } + cs->resume_fn = resume; + fd = fd_lookup_uint64 (cs->resolvedloc.inode, (uint64_t)nlmclnt); + if (fd) { + cs->fd = fd; + cs->resolve_ret = 0; + cs->resume_fn(cs); + ret = 0; + goto err; + } + + fd = fd_create_uint64 (cs->resolvedloc.inode, (uint64_t)nlmclnt); + if (fd == NULL) { + gf_log (GF_NLM, GF_LOG_ERROR, "fd_create_uint64() returned NULL"); + ret = -ENOLCK; + goto err; + } + + cs->fd = fd; + + frame = create_frame (cs->nfsx, cs->nfsx->ctx->pool); + if (!frame) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to create frame"); + ret = -ENOMEM; + goto err; + } + + frame->root->pid = NFS_PID; + frame->root->uid = rpcsvc_request_uid (cs->req); + frame->root->gid = rpcsvc_request_gid (cs->req); + frame->local = cs; + nfs_fix_groups (cs->nfsx, frame->root); + + STACK_WIND_COOKIE (frame, nlm4_file_open_cbk, cs->vol, cs->vol, + cs->vol->fops->open, &cs->resolvedloc, flags, + cs->fd, NULL); + ret = 0; +err: + return ret; +} + +int +nlm4_generic_reply (rpcsvc_request_t *req, netobj cookie, nlm4_stats stat) +{ + nlm4_res res; + + memset (&res, 0, sizeof (res)); + res.cookie = cookie; + res.stat.stat = stat; + + nlm4svc_submit_reply (req, (void *)&res, + (nlm4_serializer)xdr_serialize_nlm4_res); + return 0; +} + +int +nlm4svc_null (rpcsvc_request_t *req) +{ + struct iovec dummyvec = {0, }; + + if (!req) { + gf_log (GF_NLM, GF_LOG_ERROR, "Got NULL request!"); + return 0; + } + rpcsvc_submit_generic (req, &dummyvec, 1, NULL, 0, NULL); + return 0; +} + +int +nlm4_gf_flock_to_holder (nlm4_holder *holder, struct gf_flock *flock) +{ + switch (flock->l_type) { + case GF_LK_F_WRLCK: + holder->exclusive = 1; + break; + } + + holder->svid = flock->l_pid; + holder->l_offset = flock->l_start; + holder->l_len = flock->l_len; + return 0; +} + +int +nlm4_lock_to_gf_flock (struct gf_flock *flock, nlm4_lock *lock, int excl) +{ + flock->l_pid = lock->svid; + flock->l_start = lock->l_offset; + flock->l_len = lock->l_len; + if (excl) + flock->l_type = F_WRLCK; + else + flock->l_type = F_RDLCK; + flock->l_whence = SEEK_SET; + nlm_copy_lkowner (&flock->l_owner, &lock->oh); + return 0; +} + +rpc_clnt_procedure_t nlm4_clnt_actors[NLM4_PROC_COUNT] = { + [NLM4_NULL] = {"NULL", NULL}, + [NLM4_GRANTED] = {"GRANTED", NULL}, +}; + +char *nlm4_clnt_names[NLM4_PROC_COUNT] = { + [NLM4_NULL] = "NULL", + [NLM4_GRANTED] = "GRANTED", +}; + +rpc_clnt_prog_t nlm4clntprog = { + .progname = "NLMv4", + .prognum = NLM_PROGRAM, + .progver = NLM_V4, + .numproc = NLM4_PROC_COUNT, + .proctable = nlm4_clnt_actors, + .procnames = nlm4_clnt_names, +}; + +int +nlm4_test_reply (nfs3_call_state_t *cs, nlm4_stats stat, struct gf_flock *flock) +{ + nlm4_testres res; + + memset (&res, 0, sizeof (res)); + res.cookie = cs->args.nlm4_testargs.cookie; + res.stat.stat = stat; + if (stat == nlm4_denied) + nlm4_gf_flock_to_holder (&res.stat.nlm4_testrply_u.holder, + flock); + + nlm4svc_submit_reply (cs->req, (void *)&res, + (nlm4_serializer)xdr_serialize_nlm4_testres); + return 0; +} + +int +nlm4svc_test_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct gf_flock *flock, + dict_t *xdata) +{ + nlm4_stats stat = nlm4_denied; + nfs3_call_state_t *cs = NULL; + + cs = frame->local; + if (op_ret == -1) { + stat = nlm4_errno_to_nlm4stat (op_errno); + goto err; + } else if (flock->l_type == F_UNLCK) + stat = nlm4_granted; + +err: + nlm4_test_reply (cs, stat, flock); + nfs3_call_state_wipe (cs); + return 0; +} + +int +nlm4_test_fd_resume (void *carg) +{ + int ret = -EFAULT; + nfs_user_t nfu = {0, }; + nfs3_call_state_t *cs = NULL; + struct gf_flock flock = {0, }; + + if (!carg) + return ret; + + cs = (nfs3_call_state_t *)carg; + nfs_request_user_init (&nfu, cs->req); + nlm4_lock_to_gf_flock (&flock, &cs->args.nlm4_testargs.alock, + cs->args.nlm4_testargs.exclusive); + nlm_copy_lkowner (&nfu.lk_owner, &cs->args.nlm4_testargs.alock.oh); + ret = nfs_lk (cs->nfsx, cs->vol, &nfu, cs->fd, F_GETLK, &flock, + nlm4svc_test_cbk, cs); + + return ret; +} + + +int +nlm4_test_resume (void *carg) +{ + nlm4_stats stat = nlm4_failed; + int ret = -1; + nfs3_call_state_t *cs = NULL; + fd_t *fd = NULL; + + if (!carg) + return ret; + + cs = (nfs3_call_state_t *)carg; + nlm4_check_fh_resolve_status (cs, stat, nlm4err); + fd = fd_anonymous (cs->resolvedloc.inode); + if (!fd) + goto nlm4err; + cs->fd = fd; + ret = nlm4_test_fd_resume (cs); + +nlm4err: + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to open_and_resume"); + stat = nlm4_errno_to_nlm4stat (-ret); + nlm4_test_reply (cs, stat, NULL); + nfs3_call_state_wipe (cs); + } + + return ret; +} + +int +nlm4svc_test (rpcsvc_request_t *req) +{ + xlator_t *vol = NULL; + nlm4_stats stat = nlm4_failed; + struct nfs_state *nfs = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + int ret = RPCSVC_ACTOR_ERROR; + struct nfs3_fh fh = {{0}, }; + + if (!req) + return ret; + + nlm4_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + nlm4_handle_call_state_init (nfs->nfs3state, cs, req, + stat, rpcerr); + + nlm4_prep_nlm4_testargs (&cs->args.nlm4_testargs, &fh, &cs->lkowner, + cs->cookiebytes); + if (xdr_to_nlm4_testargs(req->msg[0], &cs->args.nlm4_testargs) <= 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; + } + + nlm4_validate_gluster_fh (&fh, stat, nlm4err); + nlm4_map_fh_to_volume (cs->nfs3state, fh, req, vol, stat, nlm4err); + + if (nlm_grace_period) { + gf_log (GF_NLM, GF_LOG_WARNING, "NLM in grace period"); + stat = nlm4_denied_grace_period; + nlm4_test_reply (cs, stat, NULL); + nfs3_call_state_wipe (cs); + return 0; + } + + cs->vol = vol; + nlm4_volume_started_check (nfs3, vol, ret, rpcerr); + + ret = nfs3_fh_resolve_and_resume (cs, &fh, + NULL, nlm4_test_resume); + +nlm4err: + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to resolve and resume"); + nlm4_test_reply (cs, stat, NULL); + nfs3_call_state_wipe (cs); + return 0; + } + +rpcerr: + if (ret < 0) + nfs3_call_state_wipe (cs); + + return ret; +} + +int +nlm4svc_send_granted_cbk (struct rpc_req *req, struct iovec *iov, int count, + void *myframe) +{ + STACK_DESTROY (((call_frame_t*)myframe)->root); + return 0; +} + +void +nlm4svc_send_granted (nfs3_call_state_t *cs); + +int +nlm_rpcclnt_notify (struct rpc_clnt *rpc_clnt, void *mydata, + rpc_clnt_event_t fn, void *data) +{ + int ret = 0; + char *caller_name = NULL; + nfs3_call_state_t *cs = NULL; + + cs = mydata; + caller_name = cs->args.nlm4_lockargs.alock.caller_name; + + switch (fn) { + case RPC_CLNT_CONNECT: + ret = nlm_set_rpc_clnt (rpc_clnt, caller_name); + if (ret == -1) { + gf_log (GF_NLM, GF_LOG_ERROR, "Failed to set rpc clnt"); + goto err; + } + rpc_clnt_unref (rpc_clnt); + nlm4svc_send_granted (cs); + + break; + + case RPC_CLNT_MSG: + break; + + case RPC_CLNT_DISCONNECT: + nlm_unset_rpc_clnt (rpc_clnt); + break; + } + + err: + return 0; +} + +void * +nlm4_establish_callback (void *csarg) +{ + int ret = -1; + nfs3_call_state_t *cs = NULL; + union gf_sock_union sock_union; + dict_t *options = NULL; + char peerip[INET6_ADDRSTRLEN+1] = {0}; + char *portstr = NULL; + char myip[INET6_ADDRSTRLEN+1] = {0}; + rpc_clnt_t *rpc_clnt = NULL; + int port = -1; + + + cs = (nfs3_call_state_t *) csarg; + glusterfs_this_set (cs->nfsx); + + rpc_transport_get_peeraddr (cs->trans, NULL, 0, &sock_union.storage, + sizeof (sock_union.storage)); + + switch (sock_union.sa.sa_family) { + case AF_INET6: + /* can not come here as NLM listens on IPv4 */ + gf_log (GF_NLM, GF_LOG_ERROR, "NLM is not supported on IPv6 in" + " this release"); + goto err; +/* + inet_ntop (AF_INET6, + &((struct sockaddr_in6 *)sockaddr)->sin6_addr, + peerip, INET6_ADDRSTRLEN+1); + break; +*/ + case AF_INET: + inet_ntop (AF_INET, &sock_union.sin.sin_addr, peerip, + INET6_ADDRSTRLEN+1); + inet_ntop (AF_INET, &(((struct sockaddr_in *)&cs->trans->myinfo.sockaddr)->sin_addr), + myip, INET6_ADDRSTRLEN + 1); + + break; + default: + break; + /* FIXME: handle the error */ + } + + /* looks like libc rpc supports only ipv4 */ + port = pmap_getport (&sock_union.sin, NLM_PROGRAM, + NLM_V4, IPPROTO_TCP); + + if (port == 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Unable to get NLM port of the " + "client. Is the firewall running on client?"); + goto err; + } + + options = dict_new(); + ret = dict_set_str (options, "transport-type", "socket"); + if (ret == -1) { + gf_log (GF_NLM, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + + ret = dict_set_dynstr (options, "remote-host", gf_strdup (peerip)); + if (ret == -1) { + gf_log (GF_NLM, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + + ret = gf_asprintf (&portstr, "%d", port); + if (ret == -1) + goto err; + + ret = dict_set_dynstr (options, "remote-port", + portstr); + if (ret == -1) { + gf_log (GF_NLM, GF_LOG_ERROR, "dict_set_dynstr error"); + goto err; + } + + /* needed in case virtual IP is used */ + ret = dict_set_dynstr (options, "transport.socket.source-addr", + gf_strdup (myip)); + if (ret == -1) + goto err; + + ret = dict_set_str (options, "auth-null", "on"); + if (ret == -1) { + gf_log (GF_NLM, GF_LOG_ERROR, "dict_set_dynstr error"); + goto err; + } + + /* TODO: is 32 frames in transit enough ? */ + rpc_clnt = rpc_clnt_new (options, cs->nfsx->ctx, "NLM-client", 32); + if (rpc_clnt == NULL) { + gf_log (GF_NLM, GF_LOG_ERROR, "rpc_clnt NULL"); + goto err; + } + + ret = rpc_clnt_register_notify (rpc_clnt, nlm_rpcclnt_notify, cs); + if (ret == -1) { + gf_log (GF_NLM, GF_LOG_ERROR,"rpc_clnt_register_connect error"); + goto err; + } + + /* After this connect succeeds, granted msg is sent in notify */ + ret = rpc_transport_connect (rpc_clnt->conn.trans, port); + + if (ret == -1 && EINPROGRESS == errno) + ret = 0; + +err: + if (ret == -1 && rpc_clnt) { + rpc_clnt_unref (rpc_clnt); + } + + return rpc_clnt; +} + +void +nlm4svc_send_granted (nfs3_call_state_t *cs) +{ + int ret = -1; + rpc_clnt_t *rpc_clnt = NULL; + struct iovec outmsg = {0, }; + nlm4_testargs testargs; + struct iobuf *iobuf = NULL; + struct iobref *iobref = NULL; + char peerip[INET6_ADDRSTRLEN+1]; + union gf_sock_union sock_union; + + rpc_clnt = nlm_get_rpc_clnt (cs->args.nlm4_lockargs.alock.caller_name); + if (rpc_clnt == NULL) { + nlm4_establish_callback ((void*)cs); + return; + } + + rpc_transport_get_peeraddr (cs->trans, NULL, 0, &sock_union.storage, + sizeof (sock_union.storage)); + + switch (sock_union.sa.sa_family) { + case AF_INET6: + inet_ntop (AF_INET6, &sock_union.sin6.sin6_addr, peerip, + INET6_ADDRSTRLEN+1); + break; + case AF_INET: + inet_ntop (AF_INET, &sock_union.sin.sin_addr, peerip, + INET6_ADDRSTRLEN+1); + break; + default: + break; + } + + testargs.cookie = cs->args.nlm4_lockargs.cookie; + testargs.exclusive = cs->args.nlm4_lockargs.exclusive; + testargs.alock = cs->args.nlm4_lockargs.alock; + + iobuf = iobuf_get (cs->nfs3state->iobpool); + if (!iobuf) { + gf_log (GF_NLM, GF_LOG_ERROR, "Failed to get iobuf"); + goto ret; + } + + iobuf_to_iovec (iobuf, &outmsg); + /* Use the given serializer to translate the give C structure in arg + * to XDR format which will be written into the buffer in outmsg. + */ + outmsg.iov_len = xdr_serialize_nlm4_testargs (outmsg, &testargs); + + iobref = iobref_new (); + if (iobref == NULL) { + gf_log (GF_NLM, GF_LOG_ERROR, "Failed to get iobref"); + goto ret; + } + + ret = iobref_add (iobref, iobuf); + if (ret) { + gf_log (GF_NLM, GF_LOG_ERROR, "Failed to add iob to iobref"); + goto ret; + } + + ret = rpc_clnt_submit (rpc_clnt, &nlm4clntprog, NLM4_GRANTED, + nlm4svc_send_granted_cbk, &outmsg, 1, + NULL, 0, iobref, cs->frame, NULL, 0, + NULL, 0, NULL); + + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "rpc_clnt_submit error"); + goto ret; + } +ret: + if (iobref) + iobref_unref (iobref); + if (iobuf) + iobuf_unref (iobuf); + + rpc_clnt_unref (rpc_clnt); + nfs3_call_state_wipe (cs); + return; +} + +int +nlm_cleanup_fds (char *caller_name) +{ + int nlmclnt_found = 0; + nlm_fde_t *fde = NULL, *tmp = NULL; + nlm_client_t *nlmclnt = NULL; + + LOCK (&nlm_client_list_lk); + list_for_each_entry (nlmclnt, + &nlm_client_list, nlm_clients) { + if (!strcmp(caller_name, nlmclnt->caller_name)) { + nlmclnt_found = 1; + break; + } + } + + if (!nlmclnt_found) + goto ret; + + if (list_empty (&nlmclnt->fdes)) + goto ret; + + list_for_each_entry_safe (fde, tmp, &nlmclnt->fdes, fde_list) { + fd_unref (fde->fd); + list_del (&fde->fde_list); + GF_FREE (fde); + } + +ret: + UNLOCK (&nlm_client_list_lk); + return 0; +} + +void +nlm_search_and_delete (fd_t *fd, char *caller_name) +{ + nlm_fde_t *fde = NULL; + nlm_client_t *nlmclnt = NULL; + int nlmclnt_found = 0; + int fde_found = 0; + int transit_cnt = 0; + + LOCK (&nlm_client_list_lk); + list_for_each_entry (nlmclnt, + &nlm_client_list, nlm_clients) { + if (!strcmp(caller_name, nlmclnt->caller_name)) { + nlmclnt_found = 1; + break; + } + } + + if (!nlmclnt_found) + goto ret; + + list_for_each_entry (fde, &nlmclnt->fdes, fde_list) { + if (fde->fd == fd) { + fde_found = 1; + break; + } + } + + if (!fde_found) + goto ret; + transit_cnt = fde->transit_cnt; + if (transit_cnt) + goto ret; + list_del (&fde->fde_list); + +ret: + UNLOCK (&nlm_client_list_lk); + + if (fde_found && !transit_cnt) { + fd_unref (fde->fd); + GF_FREE (fde); + } + return; +} + +int +nlm_dec_transit_count (fd_t *fd, char *caller_name) +{ + nlm_fde_t *fde = NULL; + nlm_client_t *nlmclnt = NULL; + int nlmclnt_found = 0; + int fde_found = 0; + int transit_cnt = -1; + + LOCK (&nlm_client_list_lk); + list_for_each_entry (nlmclnt, + &nlm_client_list, nlm_clients) { + if (!strcmp(caller_name, nlmclnt->caller_name)) { + nlmclnt_found = 1; + break; + } + } + + if (!nlmclnt_found) { + gf_log (GF_NLM, GF_LOG_ERROR, "nlmclnt not found"); + nlmclnt = NULL; + goto ret; + } + + list_for_each_entry (fde, &nlmclnt->fdes, fde_list) { + if (fde->fd == fd) { + fde_found = 1; + break; + } + } + + if (fde_found) { + transit_cnt = --fde->transit_cnt; + goto ret; + } +ret: + + UNLOCK (&nlm_client_list_lk); + return transit_cnt; +} + + +nlm_client_t * +nlm_search_and_add (fd_t *fd, char *caller_name) +{ + nlm_fde_t *fde = NULL; + nlm_client_t *nlmclnt = NULL; + int nlmclnt_found = 0; + int fde_found = 0; + + LOCK (&nlm_client_list_lk); + list_for_each_entry (nlmclnt, + &nlm_client_list, nlm_clients) { + if (!strcmp(caller_name, nlmclnt->caller_name)) { + nlmclnt_found = 1; + break; + } + } + + if (!nlmclnt_found) { + gf_log (GF_NLM, GF_LOG_ERROR, "nlmclnt not found"); + nlmclnt = NULL; + goto ret; + } + + list_for_each_entry (fde, &nlmclnt->fdes, fde_list) { + if (fde->fd == fd) { + fde_found = 1; + break; + } + } + + if (fde_found) + goto ret; + + fde = GF_CALLOC (1, sizeof (*fde), gf_nfs_mt_nlm4_fde); + + fde->fd = fd_ref (fd); + list_add (&fde->fde_list, &nlmclnt->fdes); +ret: + if (nlmclnt_found && fde) + fde->transit_cnt++; + UNLOCK (&nlm_client_list_lk); + return nlmclnt; +} + +int +nlm4svc_lock_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct gf_flock *flock, + dict_t *xdata) +{ + nlm4_stats stat = nlm4_denied; + int transit_cnt = -1; + char *caller_name = NULL; + nfs3_call_state_t *cs = NULL; + pthread_t thr; + + cs = frame->local; + caller_name = cs->args.nlm4_lockargs.alock.caller_name; + transit_cnt = nlm_dec_transit_count (cs->fd, caller_name); + + if (op_ret == -1) { + if (transit_cnt == 0) + nlm_search_and_delete (cs->fd, caller_name); + stat = nlm4_errno_to_nlm4stat (op_errno); + goto err; + } else { + stat = nlm4_granted; + if (cs->monitor && !nlm_monitor (caller_name)) { + /* FIXME: handle nsm_monitor failure */ + pthread_create (&thr, NULL, nsm_monitor, (void*)caller_name); + } + } + +err: + if (cs->args.nlm4_lockargs.block) { + cs->frame = copy_frame (frame); + frame->local = NULL; + nlm4svc_send_granted (cs); + } else { + nlm4_generic_reply (cs->req, cs->args.nlm4_lockargs.cookie, + stat); + nfs3_call_state_wipe (cs); + } + return 0; +} + +int +nlm4_lock_fd_resume (void *carg) +{ + nlm4_stats stat = nlm4_denied; + int ret = -EFAULT; + nfs_user_t nfu = {0, }; + nfs3_call_state_t *cs = NULL; + struct gf_flock flock = {0, }; + + if (!carg) + return ret; + + cs = (nfs3_call_state_t *)carg; + nlm4_check_fh_resolve_status (cs, stat, nlm4err); + (void) nlm_search_and_add (cs->fd, + cs->args.nlm4_lockargs.alock.caller_name); + nfs_request_user_init (&nfu, cs->req); + nlm4_lock_to_gf_flock (&flock, &cs->args.nlm4_lockargs.alock, + cs->args.nlm4_lockargs.exclusive); + nlm_copy_lkowner (&nfu.lk_owner, &cs->args.nlm4_lockargs.alock.oh); + if (cs->args.nlm4_lockargs.block) { + nlm4_generic_reply (cs->req, cs->args.nlm4_lockargs.cookie, + nlm4_blocked); + ret = nfs_lk (cs->nfsx, cs->vol, &nfu, cs->fd, F_SETLKW, + &flock, nlm4svc_lock_cbk, cs); + /* FIXME: handle error from nfs_lk() specially by just + * cleaning up cs and unblock the client lock request. + */ + ret = 0; + } else + ret = nfs_lk (cs->nfsx, cs->vol, &nfu, cs->fd, F_SETLK, + &flock, nlm4svc_lock_cbk, cs); + +nlm4err: + if (ret < 0) { + stat = nlm4_errno_to_nlm4stat (-ret); + gf_log (GF_NLM, GF_LOG_ERROR, "unable to call lk()"); + nlm4_generic_reply (cs->req, cs->args.nlm4_lockargs.cookie, + stat); + nfs3_call_state_wipe (cs); + } + + return ret; +} + + +int +nlm4_lock_resume (void *carg) +{ + nlm4_stats stat = nlm4_failed; + int ret = -1; + nfs3_call_state_t *cs = NULL; + + if (!carg) + return ret; + + cs = (nfs3_call_state_t *)carg; + nlm4_check_fh_resolve_status (cs, stat, nlm4err); + ret = nlm4_file_open_and_resume (cs, nlm4_lock_fd_resume); + +nlm4err: + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to open and resume"); + stat = nlm4_errno_to_nlm4stat (-ret); + nlm4_generic_reply (cs->req, cs->args.nlm4_lockargs.cookie, + stat); + nfs3_call_state_wipe (cs); + } + + return ret; +} + +int +nlm4svc_lock_common (rpcsvc_request_t *req, int mon) +{ + int ret = RPCSVC_ACTOR_ERROR; + nlm4_stats stat = nlm4_failed; + struct nfs3_fh fh = {{0}, }; + xlator_t *vol = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + struct nfs_state *nfs = NULL; + + if (!req) + return ret; + + nlm4_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + nlm4_handle_call_state_init (nfs->nfs3state, cs, req, + stat, rpcerr); + + nlm4_prep_nlm4_lockargs (&cs->args.nlm4_lockargs, &cs->lockfh, + &cs->lkowner, cs->cookiebytes); + if (xdr_to_nlm4_lockargs(req->msg[0], &cs->args.nlm4_lockargs) <= 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; + } + + fh = cs->lockfh; + cs->monitor = mon; + nlm4_validate_gluster_fh (&fh, stat, nlm4err); + nlm4_map_fh_to_volume (cs->nfs3state, fh, req, vol, stat, nlm4err); + + if (nlm_grace_period && !cs->args.nlm4_lockargs.reclaim) { + gf_log (GF_NLM, GF_LOG_WARNING, "NLM in grace period"); + stat = nlm4_denied_grace_period; + nlm4_generic_reply (req, cs->args.nlm4_unlockargs.cookie, stat); + nfs3_call_state_wipe (cs); + return 0; + } + + cs->vol = vol; + cs->trans = rpcsvc_request_transport_ref(req); + nlm4_volume_started_check (nfs3, vol, ret, rpcerr); + + ret = nlm_add_nlmclnt (cs->args.nlm4_lockargs.alock.caller_name); + + ret = nfs3_fh_resolve_and_resume (cs, &fh, + NULL, nlm4_lock_resume); + +nlm4err: + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to resolve and resume"); + nlm4_generic_reply (cs->req, cs->args.nlm4_lockargs.cookie, + stat); + nfs3_call_state_wipe (cs); + return 0; + } + +rpcerr: + if (ret < 0) { + nfs3_call_state_wipe (cs); + } + + return ret; +} + +int +nlm4svc_lock (rpcsvc_request_t *req) +{ + return nlm4svc_lock_common (req, 1); +} + +int +nlm4svc_nm_lock (rpcsvc_request_t *req) +{ + return nlm4svc_lock_common (req, 0); +} + +int +nlm4svc_cancel_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct gf_flock *flock, + dict_t *xdata) +{ + nlm4_stats stat = nlm4_denied; + nfs3_call_state_t *cs = NULL; + + cs = frame->local; + if (op_ret == -1) { + stat = nlm4_errno_to_nlm4stat (op_errno); + goto err; + } else + stat = nlm4_granted; + +err: + nlm4_generic_reply (cs->req, cs->args.nlm4_cancargs.cookie, + stat); + nfs3_call_state_wipe (cs); + return 0; +} + +int +nlm4_cancel_fd_resume (void *carg) +{ + int ret = -EFAULT; + nfs_user_t nfu = {0, }; + nfs3_call_state_t *cs = NULL; + struct gf_flock flock = {0, }; + + if (!carg) + return ret; + + cs = (nfs3_call_state_t *)carg; + nfs_request_user_init (&nfu, cs->req); + nlm4_lock_to_gf_flock (&flock, &cs->args.nlm4_cancargs.alock, + cs->args.nlm4_cancargs.exclusive); + nlm_copy_lkowner (&nfu.lk_owner, &cs->args.nlm4_cancargs.alock.oh); + flock.l_type = F_UNLCK; + ret = nfs_lk (cs->nfsx, cs->vol, &nfu, cs->fd, F_SETLK, + &flock, nlm4svc_cancel_cbk, cs); + + return ret; +} + +int +nlm4_cancel_resume (void *carg) +{ + nlm4_stats stat = nlm4_failed; + int ret = -EFAULT; + nfs3_call_state_t *cs = NULL; + nlm_client_t *nlmclnt = NULL; + + if (!carg) + return ret; + + cs = (nfs3_call_state_t *)carg; + nlm4_check_fh_resolve_status (cs, stat, nlm4err); + + nlmclnt = nlm_get_uniq (cs->args.nlm4_cancargs.alock.caller_name); + if (nlmclnt == NULL) { + gf_log (GF_NLM, GF_LOG_ERROR, "nlm_get_uniq() returned NULL"); + goto nlm4err; + } + cs->fd = fd_lookup_uint64 (cs->resolvedloc.inode, (uint64_t)nlmclnt); + if (cs->fd == NULL) { + gf_log (GF_NLM, GF_LOG_ERROR, "fd_lookup_uint64 retrned NULL"); + goto nlm4err; + } + ret = nlm4_cancel_fd_resume (cs); + +nlm4err: + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_WARNING, "unable to unlock_fd_resume()"); + stat = nlm4_errno_to_nlm4stat (-ret); + nlm4_generic_reply (cs->req, cs->args.nlm4_cancargs.cookie, + stat); + + nfs3_call_state_wipe (cs); + } + /* clean up is taken care of */ + return 0; +} + +int +nlm4svc_cancel (rpcsvc_request_t *req) +{ + xlator_t *vol = NULL; + nlm4_stats stat = nlm4_failed; + struct nfs_state *nfs = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + int ret = RPCSVC_ACTOR_ERROR; + struct nfs3_fh fh = {{0}, }; + + if (!req) + return ret; + + nlm4_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + nlm4_handle_call_state_init (nfs->nfs3state, cs, req, + stat, rpcerr); + + nlm4_prep_nlm4_cancargs (&cs->args.nlm4_cancargs, &fh, &cs->lkowner, + cs->cookiebytes); + if (xdr_to_nlm4_cancelargs(req->msg[0], &cs->args.nlm4_cancargs) <= 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; + } + + nlm4_validate_gluster_fh (&fh, stat, nlm4err); + nlm4_map_fh_to_volume (cs->nfs3state, fh, req, vol, stat, nlm4err); + + if (nlm_grace_period) { + gf_log (GF_NLM, GF_LOG_WARNING, "NLM in grace period"); + stat = nlm4_denied_grace_period; + nlm4_generic_reply (req, cs->args.nlm4_unlockargs.cookie, stat); + nfs3_call_state_wipe (cs); + return 0; + } + + cs->vol = vol; + nlm4_volume_started_check (nfs3, vol, ret, rpcerr); + + ret = nfs3_fh_resolve_and_resume (cs, &fh, + NULL, nlm4_cancel_resume); + +nlm4err: + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to resolve and resume"); + nlm4_generic_reply (cs->req, cs->args.nlm4_cancargs.cookie, + stat); + nfs3_call_state_wipe (cs); + return 0; + } + +rpcerr: + if (ret < 0) { + nfs3_call_state_wipe (cs); + } + return ret; +} + +int +nlm4svc_unlock_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct gf_flock *flock, + dict_t *xdata) +{ + nlm4_stats stat = nlm4_denied; + nfs3_call_state_t *cs = NULL; + + cs = frame->local; + if (op_ret == -1) { + stat = nlm4_errno_to_nlm4stat (op_errno); + goto err; + } else { + stat = nlm4_granted; + if (flock->l_type == F_UNLCK) + nlm_search_and_delete (cs->fd, + cs->args.nlm4_unlockargs.alock.caller_name); + } + +err: + nlm4_generic_reply (cs->req, cs->args.nlm4_unlockargs.cookie, stat); + nfs3_call_state_wipe (cs); + return 0; +} + +int +nlm4_unlock_fd_resume (void *carg) +{ + int ret = -EFAULT; + nfs_user_t nfu = {0, }; + nfs3_call_state_t *cs = NULL; + struct gf_flock flock = {0, }; + + if (!carg) + return ret; + cs = (nfs3_call_state_t *)carg; + nfs_request_user_init (&nfu, cs->req); + nlm4_lock_to_gf_flock (&flock, &cs->args.nlm4_unlockargs.alock, 0); + nlm_copy_lkowner (&nfu.lk_owner, &cs->args.nlm4_unlockargs.alock.oh); + flock.l_type = F_UNLCK; + ret = nfs_lk (cs->nfsx, cs->vol, &nfu, cs->fd, F_SETLK, + &flock, nlm4svc_unlock_cbk, cs); + + return ret; +} + +int +nlm4_unlock_resume (void *carg) +{ + nlm4_stats stat = nlm4_failed; + int ret = -1; + nfs3_call_state_t *cs = NULL; + nlm_client_t *nlmclnt = NULL; + + if (!carg) + return ret; + + cs = (nfs3_call_state_t *)carg; + nlm4_check_fh_resolve_status (cs, stat, nlm4err); + + nlmclnt = nlm_get_uniq (cs->args.nlm4_unlockargs.alock.caller_name); + if (nlmclnt == NULL) { + stat = nlm4_granted; + gf_log (GF_NLM, GF_LOG_WARNING, "nlm_get_uniq() returned NULL"); + goto nlm4err; + } + cs->fd = fd_lookup_uint64 (cs->resolvedloc.inode, (uint64_t)nlmclnt); + if (cs->fd == NULL) { + stat = nlm4_granted; + gf_log (GF_NLM, GF_LOG_WARNING, "fd_lookup_uint64() returned " + "NULL"); + goto nlm4err; + } + ret = nlm4_unlock_fd_resume (cs); + +nlm4err: + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_WARNING, "unable to unlock_fd_resume"); + stat = nlm4_errno_to_nlm4stat (-ret); + nlm4_generic_reply (cs->req, cs->args.nlm4_unlockargs.cookie, + stat); + + nfs3_call_state_wipe (cs); + } + /* we have already taken care of cleanup */ + return 0; +} + +int +nlm4svc_unlock (rpcsvc_request_t *req) +{ + xlator_t *vol = NULL; + nlm4_stats stat = nlm4_failed; + struct nfs_state *nfs = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + int ret = RPCSVC_ACTOR_ERROR; + struct nfs3_fh fh = {{0}, }; + + if (!req) + return ret; + + nlm4_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + nlm4_handle_call_state_init (nfs->nfs3state, cs, req, + stat, rpcerr); + + nlm4_prep_nlm4_unlockargs (&cs->args.nlm4_unlockargs, &fh, &cs->lkowner, + cs->cookiebytes); + if (xdr_to_nlm4_unlockargs(req->msg[0], &cs->args.nlm4_unlockargs) <= 0) + { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; + } + + nlm4_validate_gluster_fh (&fh, stat, nlm4err); + nlm4_map_fh_to_volume (cs->nfs3state, fh, req, vol, stat, nlm4err); + + if (nlm_grace_period) { + gf_log (GF_NLM, GF_LOG_WARNING, "NLM in grace period"); + stat = nlm4_denied_grace_period; + nlm4_generic_reply (req, cs->args.nlm4_unlockargs.cookie, stat); + nfs3_call_state_wipe (cs); + return 0; + } + + cs->vol = vol; + /* FIXME: check if trans is being used at all for unlock */ + cs->trans = rpcsvc_request_transport_ref(req); + nlm4_volume_started_check (nfs3, vol, ret, rpcerr); + + ret = nfs3_fh_resolve_and_resume (cs, &fh, + NULL, nlm4_unlock_resume); + +nlm4err: + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to resolve and resume"); + nlm4_generic_reply (req, cs->args.nlm4_unlockargs.cookie, stat); + nfs3_call_state_wipe (cs); + return 0; + } + +rpcerr: + if (ret < 0) { + nfs3_call_state_wipe (cs); + } + return ret; +} + +int +nlm4_share_reply (nfs3_call_state_t *cs, nlm4_stats stat) +{ + nlm4_shareres res = {{0}, 0, 0}; + + if (!cs) + return -1; + + res.cookie = cs->args.nlm4_shareargs.cookie; + res.stat = stat; + res.sequence = 0; + + nlm4svc_submit_reply (cs->req, (void *)&res, + (nlm4_serializer)xdr_serialize_nlm4_shareres); + return 0; +} + +nlm_share_t * +nlm4_share_new () +{ + nlm_share_t *share = NULL; + + share = GF_CALLOC (1, sizeof (nlm_share_t), + gf_nfs_mt_nlm4_share); + if (!share) + goto out; + + INIT_LIST_HEAD (&share->client_list); + INIT_LIST_HEAD (&share->inode_list); + out: + return share; +} + +int +nlm4_add_share_to_inode (nlm_share_t *share) +{ + int ret = -1; + uint64_t ctx = 0; + struct list_head *head = NULL; + xlator_t *this = NULL; + inode_t *inode = NULL; + struct nfs_inode_ctx *ictx = NULL; + struct nfs_state *priv = NULL; + + this = THIS; + priv = this->private; + inode = share->inode; + ret = inode_ctx_get (inode, this, &ctx); + + if (ret == -1) { + ictx = GF_CALLOC (1, sizeof (struct nfs_inode_ctx), + gf_nfs_mt_inode_ctx); + if (!ictx ) { + gf_log (this->name, GF_LOG_ERROR, + "could not allocate nfs inode ctx"); + ret = -1; + goto out; + } + ictx->generation = priv->generation; + + head = &ictx->shares; + INIT_LIST_HEAD (head); + + ret = inode_ctx_put (inode, this, (uint64_t)ictx); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "could not store share list"); + goto out; + } + } + else { + ictx = (struct nfs_inode_ctx *)ctx; + head = &ictx->shares; + } + + list_add (&share->inode_list, head); + + out: + if (ret && head) + GF_FREE (head); + + return ret; +} + +int +nlm4_approve_share_reservation (nfs3_call_state_t *cs) +{ + int ret = -1; + uint64_t ctx = 0; + fsh_mode req_mode = 0; + fsh_access req_access = 0; + inode_t *inode = NULL; + nlm_share_t *share = NULL; + struct list_head *head = NULL; + struct nfs_inode_ctx *ictx = NULL; + + if (!cs) + goto out; + + inode = cs->resolvedloc.inode; + + ret = inode_ctx_get (inode, THIS, &ctx); + if (ret) { + ret = 0; + goto out; + } + ictx = (struct nfs_inode_ctx *)ctx; + + head = &ictx->shares; + if (!head || list_empty (head)) + goto out; + + req_mode = cs->args.nlm4_shareargs.share.mode; + req_access = cs->args.nlm4_shareargs.share.access; + + list_for_each_entry (share, head, inode_list) { + ret = (((req_mode & share->access) == 0) && + ((req_access & share->mode) == 0)); + if (!ret) { + ret = -1; + goto out; + } + } + ret = 0; + + out: + return ret; +} + +int +nlm4_create_share_reservation (nfs3_call_state_t *cs) +{ + int ret = -1; + nlm_share_t *share = NULL; + nlm_client_t *client = NULL; + inode_t *inode = NULL; + + LOCK (&nlm_client_list_lk); + + inode = inode_ref (cs->resolvedloc.inode); + if (!inode) { + gf_log (GF_NLM, GF_LOG_ERROR, "inode not found"); + goto out; + } + + client = __nlm_get_uniq (cs->args.nlm4_shareargs.share.caller_name); + if (!client) { + /* DO NOT add client. the client is supposed + to be here, since nlm4svc_share adds it */ + gf_log (GF_NLM, GF_LOG_ERROR, "client not found"); + goto out; + } + + ret = nlm4_approve_share_reservation (cs); + if (ret) + goto out; + + share = nlm4_share_new (); + if (!share) { + ret = -1; + goto out; + } + + share->inode = inode; + share->mode = cs->args.nlm4_shareargs.share.mode; + share->access = cs->args.nlm4_shareargs.share.access; + nlm_copy_lkowner (&share->lkowner, + &cs->args.nlm4_shareargs.share.oh); + + ret = nlm4_add_share_to_inode (share); + if (ret) + goto out; + + list_add (&share->client_list, &client->shares); + + out: + if (ret && inode) { + inode_unref (inode); + GF_FREE (share); + } + + UNLOCK (&nlm_client_list_lk); + return ret; +} + +/* + SHARE and UNSHARE calls DO NOT perform STACK_WIND, + the (non-monitored) share reservations are maintained + at *nfs xlator level only*, in memory +*/ +int +nlm4_share_resume (void *call_state) +{ + int ret = -1; + nlm4_stats stat = nlm4_failed; + nfs3_call_state_t *cs = NULL; + + if (!call_state) + return ret; + + cs = (nfs3_call_state_t *)call_state; + nlm4_check_fh_resolve_status (cs, stat, out); + + ret = nlm4_create_share_reservation (cs); + if (!ret) + stat = nlm4_granted; + + out: + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; +} + +int +nlm4svc_share (rpcsvc_request_t *req) +{ + nlm4_stats stat = nlm4_failed; + xlator_t *vol = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + struct nfs_state *nfs = NULL; + struct nfs3_fh fh = {{0}, }; + int ret = RPCSVC_ACTOR_ERROR; + + if (!req) + return ret; + + nlm4_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + nlm4_handle_call_state_init (nfs->nfs3state, cs, req, + stat, rpcerr); + + nlm4_prep_shareargs (&cs->args.nlm4_shareargs, &cs->lockfh, + &cs->lkowner, cs->cookiebytes); + + if (xdr_to_nlm4_shareargs (req->msg[0], + &cs->args.nlm4_shareargs) <= 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding SHARE args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; + } + + fh = cs->lockfh; + nlm4_validate_gluster_fh (&fh, stat, nlm4err); + nlm4_map_fh_to_volume (cs->nfs3state, fh, req, + vol, stat, nlm4err); + + if (nlm_grace_period && !cs->args.nlm4_shareargs.reclaim) { + gf_log (GF_NLM, GF_LOG_DEBUG, "NLM in grace period"); + stat = nlm4_denied_grace_period; + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; + } + + cs->vol = vol; + cs->trans = rpcsvc_request_transport_ref(req); + nlm4_volume_started_check (nfs3, vol, ret, rpcerr); + + ret = nlm_add_nlmclnt (cs->args.nlm4_shareargs.share.caller_name); + + ret = nfs3_fh_resolve_and_resume (cs, &fh, NULL, nlm4_share_resume); + + nlm4err: + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "SHARE call failed"); + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; + } + + rpcerr: + if (ret < 0) + nfs3_call_state_wipe (cs); + + return ret; +} + +int +nlm4_remove_share_reservation (nfs3_call_state_t *cs) +{ + int ret = -1; + uint64_t ctx = 0; + fsh_mode req_mode = 0; + fsh_access req_access = 0; + nlm_share_t *share = NULL; + nlm_share_t *tmp = NULL; + nlm_client_t *client = NULL; + char *caller = NULL; + inode_t *inode = NULL; + xlator_t *this = NULL; + struct list_head *head = NULL; + nlm4_shareargs *args = NULL; + struct nfs_inode_ctx *ictx = NULL; + + LOCK (&nlm_client_list_lk); + + args = &cs->args.nlm4_shareargs; + caller = args->share.caller_name; + + client = __nlm_get_uniq (caller); + if (!client) { + gf_log (GF_NLM, GF_LOG_ERROR, + "client not found: %s", caller); + goto out; + } + + inode = cs->resolvedloc.inode; + if (!inode) { + gf_log (GF_NLM, GF_LOG_ERROR, + "inode not found: client: %s", caller); + goto out; + } + + this = THIS; + ret = inode_ctx_get (inode, this, &ctx); + if (ret) { + gf_log (GF_NLM, GF_LOG_ERROR, + "no shares found for inode:" + "gfid: %s; client: %s", + inode->gfid, caller); + goto out; + } + ictx = (struct nfs_inode_ctx *)ctx; + + head = &ictx->shares; + if (list_empty (head)) { + ret = -1; + goto out; + } + + ret = 0; + req_mode = args->share.mode; + req_access = args->share.access; + + list_for_each_entry_safe (share, tmp, head, inode_list) { + ret = ((req_mode == share->mode) && + (req_access == share->access) && + nlm_is_oh_same_lkowner (&share->lkowner, &args->share.oh)); + if (ret) { + list_del (&share->client_list); + list_del (&share->inode_list); + inode_unref (share->inode); + GF_FREE (share); + break; + } + } + + ret = 0; + out: + UNLOCK (&nlm_client_list_lk); + return ret; + +} + +int +nlm4_unshare_resume (void *call_state) +{ + int ret = -1; + nlm4_stats stat = nlm4_failed; + nfs3_call_state_t *cs = NULL; + + if (!call_state) + return ret; + + cs = (nfs3_call_state_t *)call_state; + + nlm4_check_fh_resolve_status (cs, stat, out); + ret = nlm4_remove_share_reservation (cs); + if (!ret) + stat = nlm4_granted; + + out: + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; +} + +int +nlm4svc_unshare (rpcsvc_request_t *req) +{ + nlm4_stats stat = nlm4_failed; + xlator_t *vol = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + struct nfs_state *nfs = NULL; + struct nfs3_fh fh = {{0}, }; + int ret = RPCSVC_ACTOR_ERROR; + + if (!req) + return ret; + + nlm4_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + nlm4_handle_call_state_init (nfs->nfs3state, cs, req, + stat, rpcerr); + + nlm4_prep_shareargs (&cs->args.nlm4_shareargs, &cs->lockfh, + &cs->lkowner, cs->cookiebytes); + + if (xdr_to_nlm4_shareargs (req->msg[0], + &cs->args.nlm4_shareargs) <= 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding UNSHARE args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; + } + + fh = cs->lockfh; + nlm4_validate_gluster_fh (&fh, stat, nlm4err); + nlm4_map_fh_to_volume (cs->nfs3state, fh, req, + vol, stat, nlm4err); + + if (nlm_grace_period && !cs->args.nlm4_shareargs.reclaim) { + gf_log (GF_NLM, GF_LOG_DEBUG, "NLM in grace period"); + stat = nlm4_denied_grace_period; + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; + } + + cs->vol = vol; + cs->trans = rpcsvc_request_transport_ref(req); + nlm4_volume_started_check (nfs3, vol, ret, rpcerr); + + ret = nfs3_fh_resolve_and_resume (cs, &fh, NULL, + nlm4_unshare_resume); + + nlm4err: + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "UNSHARE call failed"); + nlm4_share_reply (cs, stat); + ret = 0; + return 0; + } + + rpcerr: + if (ret < 0) + nfs3_call_state_wipe (cs); + + return ret; +} + +int +nlm4_free_all_shares (char *caller_name) +{ + nlm_share_t *share = NULL; + nlm_share_t *tmp = NULL; + nlm_client_t *client = NULL; + + LOCK (&nlm_client_list_lk); + + client = __nlm_get_uniq (caller_name); + if (!client) { + gf_log (GF_NLM, GF_LOG_DEBUG, + "client not found: %s", caller_name); + goto out; + } + + list_for_each_entry_safe (share, tmp, &client->shares, client_list) { + list_del (&share->inode_list); + list_del (&share->client_list); + inode_unref (share->inode); + GF_FREE (share); + } + out: + UNLOCK (&nlm_client_list_lk); + return 0; +} + +int +nlm4svc_free_all (rpcsvc_request_t *req) +{ + int ret = RPCSVC_ACTOR_ERROR; + nlm4_stats stat = nlm4_failed; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + struct nfs_state *nfs = NULL; + + nlm4_validate_nfs3_state (req, nfs3, stat, err, ret); + nfs = nfs_state (nfs3->nfsx); + nlm4_handle_call_state_init (nfs->nfs3state, cs, + req, stat, err); + + nlm4_prep_freeallargs (&cs->args.nlm4_freeallargs, + &cs->lkowner); + + if (xdr_to_nlm4_freeallargs (req->msg[0], + &cs->args.nlm4_freeallargs) <= 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding FREE_ALL args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto err; + } + + ret = nlm4_free_all_shares (cs->args.nlm4_freeallargs.name); + if (ret) + goto err; + + ret = nlm_cleanup_fds (cs->args.nlm4_freeallargs.name); + if (ret) + goto err; + + err: + nfs3_call_state_wipe (cs); + if (ret) + gf_log (GF_NLM, GF_LOG_DEBUG, + "error in free all; stat: %d", stat); + return ret; + +} + +void +nlm4svc_sm_notify (struct nlm_sm_status *status) +{ + gf_log (GF_NLM, GF_LOG_INFO, "sm_notify: %s, state: %d", + status->mon_name, + status->state); + nlm_cleanup_fds (status->mon_name); +} + +rpcsvc_actor_t nlm4svc_actors[NLM4_PROC_COUNT] = { + /* 0 */ + {"NULL", NLM4_NULL, nlm4svc_null, NULL, 0, DRC_IDEMPOTENT}, + {"TEST", NLM4_TEST, nlm4svc_test, NULL, 0, DRC_IDEMPOTENT}, + {"LOCK", NLM4_LOCK, nlm4svc_lock, NULL, 0, DRC_NON_IDEMPOTENT}, + {"CANCEL", NLM4_CANCEL, nlm4svc_cancel, NULL, 0, DRC_NON_IDEMPOTENT}, + {"UNLOCK", NLM4_UNLOCK, nlm4svc_unlock, NULL, 0, DRC_NON_IDEMPOTENT}, + /* 5 */ + {"GRANTED", NLM4_GRANTED, NULL, NULL, 0, DRC_NA}, + {"TEST", NLM4_TEST_MSG, NULL, NULL, 0, DRC_NA}, + {"LOCK", NLM4_LOCK_MSG, NULL, NULL, 0, DRC_NA}, + {"CANCEL", NLM4_CANCEL_MSG, NULL, NULL, 0, DRC_NA}, + {"UNLOCK", NLM4_UNLOCK_MSG, NULL, NULL, 0, DRC_NA}, + /* 10 */ + {"GRANTED", NLM4_GRANTED_MSG, NULL, NULL, 0, DRC_NA}, + {"TEST", NLM4_TEST_RES, NULL, NULL, 0, DRC_NA}, + {"LOCK", NLM4_LOCK_RES, NULL, NULL, 0, DRC_NA}, + {"CANCEL", NLM4_CANCEL_RES, NULL, NULL, 0, DRC_NA}, + {"UNLOCK", NLM4_UNLOCK_RES, NULL, NULL, 0, DRC_NA}, + /* 15 ; procedures 17,18,19 are not defined by nlm */ + {"GRANTED", NLM4_GRANTED_RES, NULL, NULL, 0, DRC_NA}, + {"SM_NOTIFY", NLM4_SM_NOTIFY, NULL, NULL, 0, DRC_NA}, + {"SEVENTEEN", NLM4_SEVENTEEN, NULL, NULL, 0, DRC_NA}, + {"EIGHTEEN", NLM4_EIGHTEEN, NULL, NULL, 0, DRC_NA}, + {"NINETEEN", NLM4_NINETEEN, NULL, NULL, 0, DRC_NA}, + /* 20 */ + {"SHARE", NLM4_SHARE, nlm4svc_share, NULL, 0, DRC_NON_IDEMPOTENT}, + {"UNSHARE", NLM4_UNSHARE, nlm4svc_unshare, NULL, 0, DRC_NON_IDEMPOTENT}, + {"NM_LOCK", NLM4_NM_LOCK, nlm4svc_nm_lock, NULL, 0, DRC_NON_IDEMPOTENT}, + {"FREE_ALL", NLM4_FREE_ALL, nlm4svc_free_all, NULL, 0, DRC_IDEMPOTENT}, +}; + +rpcsvc_program_t nlm4prog = { + .progname = "NLM4", + .prognum = NLM_PROGRAM, + .progver = NLM_V4, + .progport = GF_NLM4_PORT, + .actors = nlm4svc_actors, + .numactors = NLM4_PROC_COUNT, + .min_auth = AUTH_NULL, +}; + + +int +nlm4_init_state (xlator_t *nfsx) +{ + return 0; +} + +extern void *nsm_thread (void *argv); + +void nlm_grace_period_over(void *arg) +{ + nlm_grace_period = 0; +} + +rpcsvc_program_t * +nlm4svc_init(xlator_t *nfsx) +{ + struct nfs3_state *ns = NULL; + struct nfs_state *nfs = NULL; + dict_t *options = NULL; + int ret = -1; + char *portstr = NULL; + pthread_t thr; + struct timespec timeout = {0,}; + FILE *pidfile = NULL; + pid_t pid = -1; + static gf_boolean_t nlm4_inited = _gf_false; + + /* Already inited */ + if (nlm4_inited) + return &nlm4prog; + + nfs = (struct nfs_state*)nfsx->private; + + ns = nfs->nfs3state; + if (!ns) { + gf_log (GF_NLM, GF_LOG_ERROR, "NLM4 init failed"); + goto err; + } + nlm4prog.private = ns; + + options = dict_new (); + + ret = gf_asprintf (&portstr, "%d", GF_NLM4_PORT); + if (ret == -1) + goto err; + + ret = dict_set_dynstr (options, "transport.socket.listen-port", + portstr); + if (ret == -1) + goto err; + ret = dict_set_str (options, "transport-type", "socket"); + if (ret == -1) { + gf_log (GF_NLM, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + + if (nfs->allow_insecure) { + ret = dict_set_str (options, "rpc-auth-allow-insecure", "on"); + if (ret == -1) { + gf_log (GF_NLM, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + ret = dict_set_str (options, "rpc-auth.ports.insecure", "on"); + if (ret == -1) { + gf_log (GF_NLM, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + } + + ret = dict_set_str (options, "transport.address-family", "inet"); + if (ret == -1) { + gf_log (GF_NLM, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + + ret = rpcsvc_create_listeners (nfs->rpcsvc, options, "NLM"); + if (ret == -1) { + gf_log (GF_NLM, GF_LOG_ERROR, "Unable to create listeners"); + dict_unref (options); + goto err; + } + INIT_LIST_HEAD(&nlm_client_list); + LOCK_INIT (&nlm_client_list_lk); + + /* unlink sm-notify.pid so that when we restart rpc.statd/sm-notify + * it thinks that the machine has restarted and sends NOTIFY to clients. + */ + ret = unlink ("/var/run/sm-notify.pid"); + if (ret == -1 && errno != ENOENT) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to unlink sm-notify"); + goto err; + } + /* temporary work around to restart statd, not distro/OS independant. + * Need to figure out a more graceful way + * killall will cause problems on solaris. + */ + + pidfile = fopen ("/var/run/rpc.statd.pid", "r"); + if (pidfile) { + ret = fscanf (pidfile, "%d", &pid); + if (ret <= 0) { + gf_log (GF_NLM, GF_LOG_WARNING, "unable to get pid of " + "rpc.statd"); + ret = runcmd ("killall", "-9", "rpc.statd", NULL); + } else + kill (pid, SIGKILL); + + fclose (pidfile); + } else { + gf_log (GF_NLM, GF_LOG_WARNING, "opening the pid file of " + "rpc.statd failed (%s)", strerror (errno)); + /* if ret == -1, do nothing - case either statd was not + * running or was running in valgrind mode + */ + ret = runcmd ("killall", "-9", "rpc.statd", NULL); + } + + ret = unlink ("/var/run/rpc.statd.pid"); + if (ret == -1 && errno != ENOENT) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to unlink rpc.statd"); + goto err; + } + + ret = runcmd ("/sbin/rpc.statd", NULL); + if (ret == -1) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to start rpc.statd"); + goto err; + } + pthread_create (&thr, NULL, nsm_thread, (void*)NULL); + + timeout.tv_sec = nlm_grace_period; + timeout.tv_nsec = 0; + + gf_timer_call_after (nfsx->ctx, timeout, nlm_grace_period_over, NULL); + nlm4_inited = _gf_true; + return &nlm4prog; +err: + return NULL; +} + +int32_t +nlm_priv (xlator_t *this) +{ + int32_t ret = -1; + uint32_t client_count = 0; + uint64_t file_count = 0; + nlm_client_t *client = NULL; + nlm_fde_t *fde = NULL; + char key[GF_DUMP_MAX_BUF_LEN] = {0}; + char gfid_str[64] = {0}; + + gf_proc_dump_add_section("nfs.nlm"); + + if (TRY_LOCK (&nlm_client_list_lk)) + goto out; + + list_for_each_entry (client, &nlm_client_list, nlm_clients) { + + gf_proc_dump_build_key (key, "client", "%d.hostname", client_count); + gf_proc_dump_write (key, "%s\n", client->caller_name); + + file_count = 0; + list_for_each_entry (fde, &client->fdes, fde_list) { + gf_proc_dump_build_key (key, "file", "%ld.gfid", file_count); + memset (gfid_str, 0, 64); + uuid_utoa_r (fde->fd->inode->gfid, gfid_str); + gf_proc_dump_write (key, "%s", gfid_str); + file_count++; + } + + gf_proc_dump_build_key (key, "client", "files-locked"); + gf_proc_dump_write (key, "%ld\n", file_count); + client_count++; + } + + gf_proc_dump_build_key (key, "nlm", "client-count"); + gf_proc_dump_write (key, "%d", client_count); + ret = 0; + UNLOCK (&nlm_client_list_lk); + + out: + if (ret) { + gf_proc_dump_build_key (key, "nlm", "statedump_error"); + gf_proc_dump_write (key, "Unable to dump nlm state because " + "nlm_client_list_lk lock couldn't be acquired"); + } + + return ret; +} diff --git a/xlators/nfs/server/src/nlm4.h b/xlators/nfs/server/src/nlm4.h new file mode 100644 index 000000000..9b5d54081 --- /dev/null +++ b/xlators/nfs/server/src/nlm4.h @@ -0,0 +1,77 @@ +/* + Copyright (c) 2012 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _NLM4_H_ +#define _NLM4_H_ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <signal.h> +#include "rpcsvc.h" +#include "dict.h" +#include "xlator.h" +#include "iobuf.h" +#include "nfs.h" +#include "list.h" +#include "xdr-nfs3.h" +#include "locking.h" +#include "nfs3-fh.h" +#include "uuid.h" +#include "nlm4-xdr.h" +#include "lkowner.h" + +/* Registered with portmap */ +#define GF_NLM4_PORT 38468 +#define GF_NLM GF_NFS"-NLM" + +extern rpcsvc_program_t * +nlm4svc_init (xlator_t *nfsx); + +extern int +nlm4_init_state (xlator_t *nfsx); + +#define NLM_PROGRAM 100021 +#define NLM_V4 4 + +typedef struct nlm4_lwowner { + char temp[1024]; +} nlm4_lkowner_t; + +typedef struct nlm_client { + struct sockaddr_storage sa; + pid_t uniq; + struct list_head nlm_clients; + struct list_head fdes; + struct list_head shares; + struct rpc_clnt *rpc_clnt; + char *caller_name; + int nsm_monitor; +} nlm_client_t; + +typedef struct nlm_share { + struct list_head client_list; + struct list_head inode_list; + gf_lkowner_t lkowner; + inode_t *inode; + fsh_mode mode; + fsh_access access; +} nlm_share_t; + +typedef struct nlm_fde { + struct list_head fde_list; + fd_t *fd; + int transit_cnt; +} nlm_fde_t; + +#endif diff --git a/xlators/nfs/server/src/nlmcbk_svc.c b/xlators/nfs/server/src/nlmcbk_svc.c new file mode 100644 index 000000000..e1b588765 --- /dev/null +++ b/xlators/nfs/server/src/nlmcbk_svc.c @@ -0,0 +1,117 @@ +/* + Copyright (c) 2012 Gluster, Inc. <http://www.gluster.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. +*/ + +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "nlmcbk-xdr.h" +#include "nlm4.h" +#include "logging.h" +#include <stdio.h> +#include <stdlib.h> +#include <rpc/pmap_clnt.h> +#include <string.h> +#include <memory.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#ifndef SIG_PF +#define SIG_PF void(*)(int) +#endif + +void +nlm4svc_sm_notify (struct nlm_sm_status *status); + +void *nlmcbk_sm_notify_0_svc(struct nlm_sm_status *status, struct svc_req *req) +{ + nlm4svc_sm_notify (status); + return NULL; +} + +static void +nlmcbk_program_0(struct svc_req *rqstp, register SVCXPRT *transp) +{ + union { + struct nlm_sm_status nlmcbk_sm_notify_0_arg; + } argument; + char *result; + xdrproc_t _xdr_argument, _xdr_result; + char *(*local)(char *, struct svc_req *); + + switch (rqstp->rq_proc) { + case NULLPROC: + (void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL); + return; + + case NLMCBK_SM_NOTIFY: + _xdr_argument = (xdrproc_t) xdr_nlm_sm_status; + _xdr_result = (xdrproc_t) xdr_void; + local = (char *(*)(char *, struct svc_req *)) nlmcbk_sm_notify_0_svc; + break; + + default: + svcerr_noproc (transp); + return; + } + memset ((char *)&argument, 0, sizeof (argument)); + if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { + svcerr_decode (transp); + return; + } + result = (*local)((char *)&argument, rqstp); + if (!svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) { + svcerr_systemerr (transp); + } + + if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to free arguments"); + return; + } + return; +} + +void * +nsm_thread (void *argv) +{ + register SVCXPRT *transp; + int ret = 0; + + ret = pmap_unset (NLMCBK_PROGRAM, NLMCBK_V1); + if (ret == 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "pmap_unset failed"); + return NULL; + } + transp = svcudp_create(RPC_ANYSOCK); + if (transp == NULL) { + gf_log (GF_NLM, GF_LOG_ERROR, "cannot create udp service."); + return NULL; + } + if (!svc_register(transp, NLMCBK_PROGRAM, NLMCBK_V1, nlmcbk_program_0, IPPROTO_UDP)) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to register (NLMCBK_PROGRAM, NLMCBK_V0, udp)."); + return NULL; + } + + transp = svctcp_create(RPC_ANYSOCK, 0, 0); + if (transp == NULL) { + gf_log (GF_NLM, GF_LOG_ERROR, "cannot create tcp service."); + return NULL; + } + if (!svc_register(transp, NLMCBK_PROGRAM, NLMCBK_V1, nlmcbk_program_0, IPPROTO_TCP)) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to register (NLMCBK_PROGRAM, NLMCBK_V0, tcp)."); + return NULL; + } + + svc_run (); + gf_log (GF_NLM, GF_LOG_ERROR, "svc_run returned"); + return NULL; + /* NOTREACHED */ +} |
