diff options
Diffstat (limited to 'xlators/nfs/server')
26 files changed, 2360 insertions, 980 deletions
diff --git a/xlators/nfs/server/src/Makefile.am b/xlators/nfs/server/src/Makefile.am index 9bbfc071a..62fbf6535 100644 --- a/xlators/nfs/server/src/Makefile.am +++ b/xlators/nfs/server/src/Makefile.am @@ -1,7 +1,7 @@ xlator_LTLIBRARIES = server.la xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/nfs nfsrpclibdir = $(top_srcdir)/rpc/rpc-lib/src -server_la_LDFLAGS = -module -avoidversion +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 @@ -14,7 +14,7 @@ noinst_HEADERS = nfs.h nfs-common.h nfs-fops.h nfs-inodes.h nfs-generics.h \ AM_CPPFLAGS = $(GF_CPPFLAGS) \ -DLIBDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/auth\" \ -I$(top_srcdir)/libglusterfs/src \ - -I$(nfsrpclibdir) -I$(CONTRIBDIR)/rbtree\ + -I$(nfsrpclibdir) -I$(CONTRIBDIR)/rbtree \ -I$(top_srcdir)/rpc/xdr/src/ AM_CFLAGS = -Wall $(GF_CFLAGS) diff --git a/xlators/nfs/server/src/acl3.c b/xlators/nfs/server/src/acl3.c index 46431a475..08b099b4e 100644 --- a/xlators/nfs/server/src/acl3.c +++ b/xlators/nfs/server/src/acl3.c @@ -113,8 +113,10 @@ nfs3_fh_to_xlator (struct nfs3_state *nfs3, struct nfs3_fh *fh); xlatorp = nfs3_fh_to_xlator (cst->nfs3state, \ &cst->resolvefh); \ uuid_unparse (cst->resolvefh.gfid, gfid); \ - sprintf (buf, "(%s) %s : %s", trans->peerinfo.identifier,\ - xlatorp ? xlatorp->name : "ERR", 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);\ @@ -126,9 +128,9 @@ nfs3_fh_to_xlator (struct nfs3_state *nfs3, struct nfs3_fh *fh); do { \ calls = nfs3_call_state_init ((nfs3state), (rq), v); \ if (!calls) { \ - gf_log (GF_NLM, GF_LOG_ERROR, "Failed to " \ + gf_log (GF_ACL, GF_LOG_ERROR, "Failed to " \ "init call state"); \ - opstat = nlm4_failed; \ + opstat = NFS3ERR_SERVERFAULT; \ rpcsvc_request_seterr (req, SYSTEM_ERR); \ goto errlabel; \ } \ @@ -138,10 +140,11 @@ nfs3_fh_to_xlator (struct nfs3_state *nfs3, struct nfs3_fh *fh); 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; + 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) @@ -166,7 +169,12 @@ acl3svc_submit_reply (rpcsvc_request_t *req, void *arg, acl3_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_ACL, GF_LOG_ERROR, "Failed to encode message"); + goto ret; + } + outmsg.iov_len = msglen; iobref = iobref_new (); if (iobref == NULL) { @@ -174,7 +182,11 @@ acl3svc_submit_reply (rpcsvc_request_t *req, void *arg, acl3_serializer sfunc) goto ret; } - iobref_add (iobref, iob); + 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); @@ -228,20 +240,25 @@ acl3_getacl_cbk (call_frame_t *frame, void *cookie, xlator_t *this, 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_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto err; } - getaclreply = &cs->args.getaclreply; getaclreply->aclentry.aclentry_val = cs->aclentry; getaclreply->daclentry.daclentry_val = cs->daclentry; /* FIXME: use posix_acl_from_xattr() */ - data = dict_get (dict, "system.posix_acl_access"); + data = dict_get (dict, POSIX_ACL_ACCESS_XATTR); if (data && (p = data_to_bin (data))) { - /* POSIX_ACL_XATTR_VERSION */ + /* POSIX_ACL_VERSION */ p++; while ((char *)p < (data->data + data->len)) { getaclreply->aclentry.aclentry_val[i].type = *(*(short **)&p)++; @@ -253,9 +270,9 @@ acl3_getacl_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } i = 0; - data = dict_get (dict, "system.posix_acl_default"); + data = dict_get (dict, POSIX_ACL_DEFAULT_XATTR); if (data && (p = data_to_bin (data))) { - /* POSIX_ACL_XATTR_VERSION */ + /* POSIX_ACL_VERSION */ p++; while ((char *)p < (data->data + data->len)) { getaclreply->daclentry.daclentry_val[i].type = *(*(short **)&p)++; @@ -271,7 +288,8 @@ acl3_getacl_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; err: - getaclreply->status = stat; + if (getaclreply) + getaclreply->status = stat; acl3_getacl_reply (cs, getaclreply); nfs3_call_state_wipe (cs); return 0; @@ -288,14 +306,20 @@ acl3_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, 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_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto err; } - getaclreply = &cs->args.getaclreply; - getaclreply->attr_follows = 1; getaclreply->attr = nfs3_stat_to_fattr3 (buf); getaclreply->mask = 0xf; @@ -303,7 +327,7 @@ acl3_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, ret = nfs_getxattr (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, NULL, NULL, acl3_getacl_cbk, cs); if (ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto err; } return 0; @@ -377,7 +401,7 @@ acl3svc_getacl (rpcsvc_request_t *req) vol, stat, rpcerr); cs->vol = vol; - acl3_volume_started_check (nfs3, vol, ret, rpcerr); + acl3_volume_started_check (nfs3, vol, ret, acl3err); ret = nfs3_fh_resolve_and_resume (cs, fhp, NULL, acl3_getacl_resume); @@ -385,9 +409,11 @@ acl3svc_getacl (rpcsvc_request_t *req) acl3err: if (ret < 0) { gf_log (GF_ACL, GF_LOG_ERROR, "unable to resolve and resume"); - cs->args.getaclreply.status = stat; - acl3_getacl_reply (cs, &cs->args.getaclreply); - nfs3_call_state_wipe (cs); + if (cs) { + cs->args.getaclreply.status = stat; + acl3_getacl_reply (cs, &cs->args.getaclreply); + nfs3_call_state_wipe (cs); + } return 0; } @@ -403,7 +429,8 @@ acl3_setacl_cbk (call_frame_t *frame, void *cookie, nfs3_call_state_t *cs = NULL; cs = frame->local; if (op_ret < 0) { - cs->args.setaclreply.status = nfs3_errno_to_nfsstat3 (op_errno); + nfsstat3 status = nfs3_cbk_errno_status (op_ret, op_errno); + cs->args.setaclreply.status = status; } acl3svc_submit_reply (cs->req, (void *)&cs->args.setaclreply, @@ -422,17 +449,16 @@ acl3_setacl_resume (void *carg) 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, "system.posix_acl_access", cs->aclxattr, + 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, "system.posix_acl_default", cs->daclxattr, - cs->daclcount * 8 + 4); + 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); @@ -464,12 +490,24 @@ acl3svc_setacl (rpcsvc_request_t *req) struct nfs3_fh fh; struct nfs3_fh *fhp = NULL; setaclargs setaclargs; - aclentry aclentry[NFS_ACL_MAX_ENTRIES]; - struct aclentry daclentry[NFS_ACL_MAX_ENTRIES]; - int *p = NULL, i = 0; + 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); @@ -500,19 +538,58 @@ acl3svc_setacl (rpcsvc_request_t *req) (cs->daclcount > NFS_ACL_MAX_ENTRIES)) goto acl3err; /* FIXME: use posix_acl_to_xattr() */ - p = (int *)cs->aclxattr; - *(*(int **)&p)++ = POSIX_ACL_XATTR_VERSION; + /* 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++) { - *(*(short **)&p)++ = aclentry[i].type; - *(*(short **)&p)++ = aclentry[i].perm; - *(*(int **)&p)++ = aclentry[i].uid; + 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++; } - p = (int *)cs->daclxattr; - *(*(int **)&p)++ = POSIX_ACL_XATTR_VERSION; + + /* 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++) { - *(*(short **)&p)++ = daclentry[i].type; - *(*(short **)&p)++ = daclentry[i].perm; - *(*(int **)&p)++ = daclentry[i].uid; + 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++; } @@ -526,19 +603,23 @@ acl3err: 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}, @@ -548,7 +629,7 @@ rpcsvc_actor_t acl3svc_actors[ACL3_PROC_COUNT] = { rpcsvc_program_t acl3prog = { .progname = "ACL3", .prognum = ACL_PROGRAM, - .progver = ACL_V3, + .progver = ACLV3_VERSION, .progport = GF_NFS3_PORT, .actors = acl3svc_actors, .numactors = ACL3_PROC_COUNT, @@ -563,6 +644,11 @@ acl3svc_init(xlator_t *nfsx) 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; @@ -608,13 +694,14 @@ acl3svc_init(xlator_t *nfsx) goto err; } - rpcsvc_create_listeners (nfs->rpcsvc, options, "ACL"); + 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 index b668723c8..e0e61281a 100644 --- a/xlators/nfs/server/src/acl3.h +++ b/xlators/nfs/server/src/acl3.h @@ -11,18 +11,19 @@ #ifndef _ACL3_H #define _ACL3_H +#include "glusterfs-acl.h" + #define GF_ACL3_PORT 38469 #define GF_ACL GF_NFS"-ACL" -#define ACL_PROGRAM 100227 -#define ACL_V3 3 - -#define ACL_USER_OBJ 0x1 -#define ACL_GROUP_OBJ 0x4 -#define ACL_OTHER_OBJ 0x20 +/* + * 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 POSIX_ACL_XATTR_VERSION 0x0002 -#define NFS_ACL_MAX_ENTRIES 1024 +#define NFS_ACL_MAX_ENTRIES 1024 rpcsvc_program_t * acl3svc_init(xlator_t *nfsx); diff --git a/xlators/nfs/server/src/mount3.c b/xlators/nfs/server/src/mount3.c index efd74aa58..b0824bf10 100644 --- a/xlators/nfs/server/src/mount3.c +++ b/xlators/nfs/server/src/mount3.c @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 @@ -39,26 +30,71 @@ #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) @@ -84,7 +120,12 @@ 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) { @@ -92,12 +133,14 @@ mnt3svc_submit_reply (rpcsvc_request_t *req, void *arg, mnt3_serializer sfunc) goto ret; } - iobref_add (iobref, iob); + 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 = rpcsvc_submit_message (req, &outmsg, 1, NULL, 0, iobref); - iobuf_unref (iob); - iobref_unref (iobref); if (ret == -1) { gf_log (GF_MNT, GF_LOG_ERROR, "Reply submission failed"); goto ret; @@ -105,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; } @@ -188,14 +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; @@ -205,14 +517,24 @@ 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 = rpcsvc_transport_peername (req->trans, me->hostname, MNTPATHLEN); if (ret == -1) - goto free_err; + goto free_err2; colon = strrchr (me->hostname, ':'); if (colon) { @@ -220,10 +542,37 @@ mnt3svc_update_mountlist (struct mount3_state *ms, rpcsvc_request_t *req, } 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); @@ -242,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); @@ -251,6 +601,7 @@ __mnt3_get_volume_id (struct mount3_state *ms, xlator_t *mntxl, } out: + UNLOCK (&ms->mountlock); return ret; } @@ -271,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; @@ -293,7 +644,15 @@ mnt3svc_lookup_mount_cbk (call_frame_t *frame, void *cookie, 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; @@ -303,7 +662,7 @@ 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) { @@ -467,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; @@ -476,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; @@ -484,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'; @@ -514,7 +873,9 @@ __mnt3_resolve_export_subdir_comp (mnt3_resolve_t *mres) 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; @@ -526,7 +887,7 @@ __mnt3_resolve_export_subdir_comp (mnt3_resolve_t *mres) if ((ret < 0) && (ret != -2)) { gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve and create " "inode: parent gfid %s, entry %s", - uuid_utoa (mres->resolveloc.inode->gfid), nextcomp); + uuid_utoa (gfid), nextcomp); ret = -EFAULT; goto err; } @@ -554,6 +915,7 @@ 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; @@ -571,15 +933,23 @@ 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", @@ -622,7 +992,9 @@ __mnt3_resolve_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; @@ -645,6 +1017,132 @@ 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_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) @@ -656,6 +1154,16 @@ mnt3_resolve_subdir (rpcsvc_request_t *req, struct mount3_state *ms, if ((!req) || (!ms) || (!exp) || (!subdir)) return ret; + /* 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) { gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation failed"); @@ -665,7 +1173,7 @@ mnt3_resolve_subdir (rpcsvc_request_t *req, struct mount3_state *ms, mres->exp = exp; mres->mstate = ms; mres->req = req; - strcpy (mres->remainingdir, 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 @@ -740,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 */ @@ -753,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; } @@ -781,8 +1291,7 @@ mnt3_check_client_net (struct mount3_state *ms, rpcsvc_request_t *req, gai_strerror (ret)); } - ret = rpcsvc_transport_peer_check (svc->options, targetxl->name, - trans); + ret = rpcsvc_auth_check (svc, targetxl->name, trans); if (ret == RPCSVC_AUTH_REJECT) { gf_log (GF_MNT, GF_LOG_INFO, "Peer %s not allowed", peer); goto err; @@ -977,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) { @@ -987,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); @@ -996,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), @@ -1018,9 +1531,6 @@ __build_mountlist (struct mount3_state *ms, int *count) } else prev = mlist; - if (!first) - first = mlist; - (*count)++; } @@ -1097,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; - - if (dirpath[0] == '/') - exname = dirpath+1; - else - exname = dirpath; + nfs = (struct nfs_state *)ms->nfsx->private; - 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; } @@ -1305,6 +1819,10 @@ mnt3_xlchildren_to_exports (rpcsvc_t *svc, struct mount3_state *ms) 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 @@ -1320,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) { @@ -1328,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 = rpcsvc_volume_allowed (svc->options, ent->vol->name); - if (addrstr) - addrstr = gf_strdup (addrstr); - else - addrstr = gf_strdup ("No Access"); - elist->ex_groups = GF_CALLOC (1, sizeof (struct groupnode), gf_nfs_mt_groupnode); if (!elist->ex_groups) { @@ -1345,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; @@ -1465,12 +1986,13 @@ mount3udp_add_mountlist (char *host, dirpath *expname) while (*export == '/') export++; - strcpy (me->exname, export); - strcpy (me->hostname, host); + 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; @@ -1486,11 +2008,155 @@ mount3udp_delete_mountlist (char *hostname, dirpath *expname) export = (char *)expname; while (*export == '/') export++; - __mnt3svc_umount (ms, export, hostname); + 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) @@ -1508,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); @@ -1517,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; } @@ -1535,8 +2213,9 @@ mnt3_init_export_ent (struct mount3_state *ms, xlator_t *xl, char *exportpath, ret = snprintf (exp->expname, alloclen, "/%s", xl->name); } if (ret < 0) { - gf_log (xl->name, GF_LOG_WARNING, - "failed to get the export name"); + 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 @@ -1544,7 +2223,16 @@ mnt3_init_export_ent (struct mount3_state *ms, xlator_t *xl, char *exportpath, */ 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; } @@ -1705,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) { @@ -1745,8 +2436,11 @@ __mnt3_init_dir_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) { @@ -1844,18 +2538,20 @@ out: } rpcsvc_actor_t mnt3svc_actors[MOUNT3_PROC_COUNT] = { - {"NULL", MOUNT3_NULL, mnt3svc_null, NULL, 0}, - {"MNT", MOUNT3_MNT, mnt3svc_mnt, NULL, 0}, - {"DUMP", MOUNT3_DUMP, mnt3svc_dump, NULL, 0}, - {"UMNT", MOUNT3_UMNT, mnt3svc_umnt, NULL, 0}, - {"UMNTALL", MOUNT3_UMNTALL, mnt3svc_umntall, NULL, 0}, - {"EXPORT", MOUNT3_EXPORT, mnt3svc_export, NULL, 0} + {"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", @@ -1865,6 +2561,7 @@ rpcsvc_program_t mnt3prog = { .actors = mnt3svc_actors, .numactors = MOUNT3_PROC_COUNT, .min_auth = AUTH_NULL, + .synctask = _gf_true, }; @@ -1920,7 +2617,7 @@ mnt3svc_init (xlator_t *nfsx) } } - rpcsvc_create_listeners (nfs->rpcsvc, options, nfsx->name); + 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); @@ -1937,12 +2634,12 @@ err: rpcsvc_actor_t mnt1svc_actors[MOUNT1_PROC_COUNT] = { - {"NULL", MOUNT1_NULL, mnt3svc_null, NULL, 0}, - {{0, 0}, }, - {"DUMP", MOUNT1_DUMP, mnt3svc_dump, NULL, 0}, - {"UMNT", MOUNT1_UMNT, mnt3svc_umnt, NULL, 0}, - {{0, 0}, }, - {"EXPORT", MOUNT1_EXPORT, mnt3svc_export, NULL, 0} + {"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 = { @@ -1953,6 +2650,7 @@ rpcsvc_program_t mnt1prog = { .actors = mnt1svc_actors, .numactors = MOUNT1_PROC_COUNT, .min_auth = AUTH_NULL, + .synctask = _gf_true, }; @@ -2007,7 +2705,7 @@ mnt1svc_init (xlator_t *nfsx) } } - rpcsvc_create_listeners (nfs->rpcsvc, options, nfsx->name); + 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); @@ -2018,3 +2716,44 @@ mnt1svc_init (xlator_t *nfsx) 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 c0eae3644..7fc16ed57 100644 --- a/xlators/nfs/server/src/mount3.h +++ b/xlators/nfs/server/src/mount3.h @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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_ @@ -53,6 +44,12 @@ mnt1svc_init (xlator_t *nfsx); 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. */ @@ -68,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; @@ -75,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; @@ -101,8 +110,8 @@ struct mount3_state { gf_lock_t mountlock; /* Set to 0 if exporting full volumes is disabled. On by default. */ - int export_volumes; - int export_dirs; + gf_boolean_t export_volumes; + gf_boolean_t export_dirs; }; #define gf_mnt3_export_dirs(mst) ((mst)->export_dirs) diff --git a/xlators/nfs/server/src/mount3udp_svc.c b/xlators/nfs/server/src/mount3udp_svc.c index aa38b1cc4..fb59e282c 100644 --- a/xlators/nfs/server/src/mount3udp_svc.c +++ b/xlators/nfs/server/src/mount3udp_svc.c @@ -2,19 +2,10 @@ Copyright (c) 2012 Gluster, Inc. <http://www.gluster.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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. */ diff --git a/xlators/nfs/server/src/nfs-common.c b/xlators/nfs/server/src/nfs-common.c index b3853ded5..f74396ee8 100644 --- a/xlators/nfs/server/src/nfs-common.c +++ b/xlators/nfs/server/src/nfs-common.c @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 @@ -94,7 +85,7 @@ nfs_mntpath_to_xlator (xlator_list_t *cl, char *path) 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] == '/') diff --git a/xlators/nfs/server/src/nfs-common.h b/xlators/nfs/server/src/nfs-common.h index f74bb3187..2e97f1563 100644 --- a/xlators/nfs/server/src/nfs-common.h +++ b/xlators/nfs/server/src/nfs-common.h @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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_ diff --git a/xlators/nfs/server/src/nfs-fops.c b/xlators/nfs/server/src/nfs-fops.c index df09d22bb..236b80c76 100644 --- a/xlators/nfs/server/src/nfs-fops.c +++ b/xlators/nfs/server/src/nfs-fops.c @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 @@ -191,6 +182,12 @@ 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]; @@ -385,19 +382,6 @@ nfs_fop_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, { struct nfs_fop_local *local = NULL; fop_lookup_cbk_t progcbk; - char *sh_fail_val = NULL; - - /* - * With native protocol, self-heal failures would be detected during - * open. NFS doesn't issue that open when revalidating cache, so we - * have to check for failures here instead. - */ - if (dict_get_str(xattr,"sh-failed",&sh_fail_val) == 0) { - if (strcmp(sh_fail_val,"1") == 0) { - op_ret = -1; - op_errno = EIO; - } - } if (op_ret == 0) { nfs_fix_generation(this,inode); @@ -1379,7 +1363,7 @@ 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, 0, srciobref, NULL); + fd, vector, count, offset, fd->flags, srciobref, NULL); ret = 0; err: if (ret < 0) { diff --git a/xlators/nfs/server/src/nfs-fops.h b/xlators/nfs/server/src/nfs-fops.h index 3ada863de..44e99c66b 100644 --- a/xlators/nfs/server/src/nfs-fops.h +++ b/xlators/nfs/server/src/nfs-fops.h @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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_ @@ -120,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;\ diff --git a/xlators/nfs/server/src/nfs-generics.c b/xlators/nfs/server/src/nfs-generics.c index 7f79bba9b..cb32b7f1b 100644 --- a/xlators/nfs/server/src/nfs-generics.c +++ b/xlators/nfs/server/src/nfs-generics.c @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 diff --git a/xlators/nfs/server/src/nfs-generics.h b/xlators/nfs/server/src/nfs-generics.h index 34e203a62..01876d68e 100644 --- a/xlators/nfs/server/src/nfs-generics.h +++ b/xlators/nfs/server/src/nfs-generics.h @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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_ diff --git a/xlators/nfs/server/src/nfs-inodes.c b/xlators/nfs/server/src/nfs-inodes.c index c9bf37206..63d5e8a19 100644 --- a/xlators/nfs/server/src/nfs-inodes.c +++ b/xlators/nfs/server/src/nfs-inodes.c @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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; } @@ -572,9 +563,7 @@ nfs_inode_opendir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, 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); diff --git a/xlators/nfs/server/src/nfs-inodes.h b/xlators/nfs/server/src/nfs-inodes.h index 7c962b339..ba7a57124 100644 --- a/xlators/nfs/server/src/nfs-inodes.h +++ b/xlators/nfs/server/src/nfs-inodes.h @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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_ diff --git a/xlators/nfs/server/src/nfs-mem-types.h b/xlators/nfs/server/src/nfs-mem-types.h index 005598c1f..450b6f2fe 100644 --- a/xlators/nfs/server/src/nfs-mem-types.h +++ b/xlators/nfs/server/src/nfs-mem-types.h @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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. */ @@ -54,6 +45,8 @@ enum gf_nfs_mem_types_ { 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 8fa69af6b..75c8fe44e 100644 --- a/xlators/nfs/server/src/nfs.c +++ b/xlators/nfs/server/src/nfs.c @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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. @@ -43,10 +34,206 @@ #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. */ @@ -123,7 +310,7 @@ nfs_init_versions (struct nfs_state *nfs, xlator_t *this) ret = -1; goto err; } -// prog->actorxl = this; + version->program = prog; if (nfs->override_portnum) prog->progport = nfs->override_portnum; @@ -132,17 +319,21 @@ nfs_init_versions (struct nfs_state *nfs, xlator_t *this) 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 (rpcsvc_register_portmap_enabled(nfs->rpcsvc)) { + if (nfs->register_portmap) { ret = rpcsvc_program_register_portmap (prog, prog->progport); if (ret == -1) { - gf_log (GF_NFS, GF_LOG_ERROR, "Program registration failed"); + gf_log (GF_NFS, GF_LOG_ERROR, + "Program %s registration failed", + prog->progname); goto err; } } + } ret = 0; @@ -159,22 +350,22 @@ 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; } @@ -187,11 +378,13 @@ nfs_add_all_initiators (struct nfs_state *nfs) } } - ret = nfs_add_initer (&nfs->versions, acl3svc_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; @@ -527,10 +720,11 @@ nfs_init_state (xlator_t *this) 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); @@ -586,19 +780,17 @@ nfs_init_state (xlator_t *this) } nfs->enable_nlm = _gf_true; - if (!dict_get_str (this->options, "nfs.nlm", &optstr)) { - - ret = gf_string2boolean (optstr, &boolt); - if (ret < 0) { - gf_log (GF_NFS, GF_LOG_ERROR, "Failed to parse" - " bool string"); - goto free_foppool; - } + 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; + } - if (boolt == _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; @@ -682,6 +874,15 @@ nfs_init_state (xlator_t *this) 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 */ @@ -747,10 +948,10 @@ nfs_init_state (xlator_t *this) 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 (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. " @@ -765,6 +966,8 @@ nfs_init_state (xlator_t *this) goto free_foppool; } + nfs->register_portmap = rpcsvc_register_portmap_enabled (nfs->rpcsvc); + this->private = (void *)nfs; INIT_LIST_HEAD (&nfs->versions); nfs->generation = 1965; @@ -786,6 +989,243 @@ free_rpcsvc: return nfs; } +int +nfs_drc_init (xlator_t *this) +{ + int ret = -1; + rpcsvc_t *svc = NULL; + + svc = ((struct nfs_state *)(this->private))->rpcsvc; + if (!svc) + goto out; + + ret = rpcsvc_drc_init (svc, this->options); + + out: + return ret; +} + +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); + } + + /* 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) { @@ -841,7 +1281,9 @@ init (xlator_t *this) { goto err; } - gf_log (GF_NFS, GF_LOG_INFO, "NFS service started"); + ret = nfs_drc_init (this); + if (ret == 0) + gf_log (GF_NFS, GF_LOG_INFO, "NFS service started"); err: return ret; @@ -996,7 +1438,22 @@ nlm_priv (xlator_t *this); int32_t nfs_priv (xlator_t *this) { - return nlm_priv (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; } @@ -1004,7 +1461,7 @@ struct xlator_cbks cbks = { .forget = nfs_forget, }; -struct xlator_fops fops = { }; +struct xlator_fops fops; struct xlator_dumpops dumpops = { .priv = nfs_priv, @@ -1019,29 +1476,53 @@ struct xlator_dumpops dumpops = { 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" - " 4KB." + .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" - " 4KB." + .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 " @@ -1056,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 " @@ -1065,25 +1547,40 @@ struct volume_options options[] = { }, { .key = {"nfs3.*.export-dir"}, .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." + "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 " @@ -1091,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" @@ -1098,12 +1596,14 @@ 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 " @@ -1113,6 +1613,7 @@ struct volume_options options[] = { }, { .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 overriding defaults" " and general setting for AUTH_UNIX scheme. Must " @@ -1122,6 +1623,7 @@ 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 overriding defaults" " and general setting for AUTH_NULL. Must always be " @@ -1130,6 +1632,7 @@ struct volume_options options[] = { }, { .key = {"rpc-auth.addr.allow"}, .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 allowed. This allows users to " @@ -1137,6 +1640,7 @@ struct volume_options options[] = { }, { .key = {"rpc-auth.addr.reject"}, .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 allowed. This allows users to" @@ -1144,6 +1648,7 @@ struct volume_options options[] = { }, { .key = {"rpc-auth.addr.*.allow"}, .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 allowed. This allows users to " @@ -1151,6 +1656,7 @@ struct volume_options options[] = { }, { .key = {"rpc-auth.addr.*.reject"}, .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 allowed. This allows users to" @@ -1158,6 +1664,7 @@ 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. This is a" "global setting in case insecure ports are to be " @@ -1165,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 enable or disable insecure ports for " - "a specific subvolume and to override the global setting " - " set by the previous option." + "a specific subvolume and to override the global " + "setting set by the previous option." }, { .key = {"rpc-auth.addr.namelookup"}, .type = GF_OPTION_TYPE_BOOL, + .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 rpc-auth.addr.* filters. In some " + " 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. By default, " - " name lookup is off" + "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. " @@ -1198,22 +1709,34 @@ 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." + "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, + .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 = {"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." }, @@ -1221,6 +1744,7 @@ struct volume_options options[] = { .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. " @@ -1231,12 +1755,14 @@ struct volume_options options[] = { }, { .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'" @@ -1244,9 +1770,20 @@ struct volume_options options[] = { { .key = {"nfs.mount-udp"}, .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", .description = "set the option to 'on' to enable mountd on UDP. " - "Needed by Solaris NFS clients if NLM support is" - "needed" + "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, @@ -1266,7 +1803,23 @@ struct volume_options options[] = { .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 7d5163dfe..00c7f8046 100644 --- a/xlators/nfs/server/src/nfs.h +++ b/xlators/nfs/server/src/nfs.h @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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__ @@ -45,7 +36,7 @@ #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 @@ -86,12 +77,15 @@ struct nfs_state { 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 { diff --git a/xlators/nfs/server/src/nfs3-fh.c b/xlators/nfs/server/src/nfs3-fh.c index eb8223924..e199c56dc 100644 --- a/xlators/nfs/server/src/nfs3-fh.c +++ b/xlators/nfs/server/src/nfs3-fh.c @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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,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; } @@ -58,6 +55,8 @@ 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; uuid_copy (fh->gfid, buf->ia_gfid); } @@ -112,17 +111,17 @@ nfs3_fh_is_root_fh (struct nfs3_fh *fh) 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; - sprintf (str, "FH: exportid %s, gfid %s", - uuid_utoa_r (fh->exportid, exportid), - uuid_utoa_r (fh->gfid, gfid)); + snprintf (str, len, "FH: exportid %s, gfid %s", + uuid_utoa_r (fh->exportid, exportid), + uuid_utoa_r (fh->gfid, gfid)); } void @@ -161,6 +160,8 @@ nfs3_build_fh (inode_t *inode, uuid_t exportid, struct nfs3_fh *newfh) 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; diff --git a/xlators/nfs/server/src/nfs3-fh.h b/xlators/nfs/server/src/nfs3-fh.h index a9002afe7..1049cdc96 100644 --- a/xlators/nfs/server/src/nfs3-fh.h +++ b/xlators/nfs/server/src/nfs3-fh.h @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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,7 +26,9 @@ * 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_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]) @@ -45,9 +38,9 @@ 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 @@ -63,6 +56,11 @@ struct nfs3_fh { /* File/dir gfid. */ uuid_t gfid; + /* 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},} @@ -90,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, diff --git a/xlators/nfs/server/src/nfs3-helpers.c b/xlators/nfs/server/src/nfs3-helpers.c index fbfd17d1a..9059fc341 100644 --- a/xlators/nfs/server/src/nfs3-helpers.c +++ b/xlators/nfs/server/src/nfs3-helpers.c @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 @@ -265,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, @@ -284,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)) @@ -353,6 +361,7 @@ nfs3_stat_to_fattr3 (struct iatt *buf) fa.mtime.seconds = buf->ia_mtime; fa.mtime.nseconds = buf->ia_mtime_nsec; +out: return fa; } @@ -496,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; @@ -591,7 +600,8 @@ nfs3_request_to_accessbits (int32_t accbits) return acc_request; } void -nfs3_fill_access3res (access3res *res, nfsstat3 status, int32_t accbits) +nfs3_fill_access3res (access3res *res, nfsstat3 status, int32_t accbits, + int32_t reqaccbits) { uint32_t accres = 0; @@ -602,7 +612,8 @@ nfs3_fill_access3res (access3res *res, nfsstat3 status, int32_t accbits) accres = nfs3_accessbits (accbits); - res->access3res_u.resok.access = accres; + /* do not answer what was not asked */ + res->access3res_u.resok.access = accres & reqaccbits; } void @@ -1605,13 +1616,14 @@ err: void nfs3_stat_to_errstr (uint32_t xid, char *op, nfsstat3 stat, int pstat, - char *errstr) + char *errstr, size_t len) { if ((!op) || (!errstr)) return; - sprintf (errstr, "XID: %x, %s: NFS: %d(%s), POSIX: %d(%s)", xid, op, - stat, nfsstat3_strerror (stat), pstat, strerror (pstat)); + snprintf (errstr, len, "XID: %x, %s: NFS: %d(%s), POSIX: %d(%s)", + xid, op,stat, nfsstat3_strerror (stat), pstat, + strerror (pstat)); } void @@ -1619,10 +1631,10 @@ 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; + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; - nfs3_fh_to_str (fh, fhstr); + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s", xid, op, fhstr); } @@ -1634,9 +1646,9 @@ nfs3_log_fh_entry_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); + 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); } @@ -1649,10 +1661,10 @@ nfs3_log_rename_call (uint32_t xid, struct nfs3_fh *src, char *sname, char sfhstr[1024]; char dfhstr[1024]; - if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (src, sfhstr); - nfs3_fh_to_str (dst, dfhstr); + 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); @@ -1670,9 +1682,9 @@ nfs3_log_create_call (uint32_t xid, struct nfs3_fh *fh, char *name, char unchkd[] = "UNCHECKED"; char guarded[] = "GUARDED"; - if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (fh, fhstr); + 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) @@ -1695,9 +1707,9 @@ nfs3_log_mknod_call (uint32_t xid, struct nfs3_fh *fh, char *name, int type) char sock[] = "SOCK"; char fifo[] = "FIFO"; - if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (fh, fhstr); + 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) @@ -1718,9 +1730,9 @@ nfs3_log_symlink_call (uint32_t xid, struct nfs3_fh *fh, char *name, char *tgt) { char fhstr[1024]; - if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (fh, fhstr); + 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); } @@ -1733,10 +1745,10 @@ nfs3_log_link_call (uint32_t xid, struct nfs3_fh *fh, char *name, char dfhstr[1024]; char tfhstr[1024]; - if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (fh, dfhstr); - nfs3_fh_to_str (tgt, tfhstr); + 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); } @@ -1748,9 +1760,9 @@ nfs3_log_rw_call (uint32_t xid, char *op, struct nfs3_fh *fh, offset3 offt, { char fhstr[1024]; - if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (fh, fhstr); + 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, @@ -3381,11 +3393,11 @@ void nfs3_log_common_res (uint32_t xid, int op, nfsstat3 stat, int pstat) { char errstr[1024]; - int ll = nfs3_loglevel (op, stat); + int ll = nfs3_loglevel (op, stat); - if (THIS->ctx->log.loglevel < ll) - return; - nfs3_stat_to_errstr (xid, nfs3op_strings[op].str, stat, pstat, 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); } @@ -3393,14 +3405,14 @@ void nfs3_log_readlink_res (uint32_t xid, nfsstat3 stat, int pstat, char *linkpath) { char errstr[1024]; - int ll = nfs3_loglevel (NFS3_READLINK, stat); + int ll = nfs3_loglevel (NFS3_READLINK, stat); - if (THIS->ctx->log.loglevel < ll) - return; + if (THIS->ctx->log.loglevel < ll) + return; - nfs3_stat_to_errstr (xid, "READLINK", stat, pstat, errstr); + nfs3_stat_to_errstr (xid, "READLINK", stat, pstat, errstr, sizeof (errstr)); gf_log (GF_NFS3, ll, "%s, target: %s", - errstr, linkpath); + errstr, linkpath); } @@ -3409,12 +3421,12 @@ 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; + int ll = GF_LOG_DEBUG; ll = nfs3_loglevel (NFS3_READ, stat); - if (THIS->ctx->log.loglevel < ll) - return; - nfs3_stat_to_errstr (xid, "READ", stat, pstat, errstr); + if (THIS->ctx->log.loglevel < ll) + return; + nfs3_stat_to_errstr (xid, "READ", stat, pstat, errstr, sizeof (errstr)); if (vec) gf_log (GF_NFS3, ll, "%s, count: %"PRIu32", is_eof:" " %d, vector: count: %d, len: %zd", errstr, count, @@ -3430,12 +3442,12 @@ 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); + int ll = nfs3_loglevel (NFS3_WRITE, stat); - if (THIS->ctx->log.loglevel < ll) - return; + if (THIS->ctx->log.loglevel < ll) + return; - nfs3_stat_to_errstr (xid, "WRITE", stat, pstat, errstr); + 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); @@ -3448,12 +3460,12 @@ nfs3_log_newfh_res (uint32_t xid, int op, nfsstat3 stat, int pstat, { char errstr[1024]; char fhstr[1024]; - int ll = nfs3_loglevel (op, stat); + int ll = nfs3_loglevel (op, stat); - if (THIS->ctx->log.loglevel < ll) - return; - nfs3_stat_to_errstr (xid, nfs3op_strings[op].str, 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, nfs3_loglevel (op, stat), "%s, %s", errstr, fhstr); } @@ -3464,11 +3476,11 @@ 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); + int ll = nfs3_loglevel (NFS3_READDIR, stat); - if (THIS->ctx->log.loglevel < ll) - return; - nfs3_stat_to_errstr (xid, "READDIR", stat, pstat, errstr); + 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); } @@ -3481,9 +3493,9 @@ nfs3_log_readdirp_res (uint32_t xid, nfsstat3 stat, int pstat, uint64_t cverf, char errstr[1024]; int ll = nfs3_loglevel (NFS3_READDIRP, stat); - if (THIS->ctx->log.loglevel < ll) - return; - nfs3_stat_to_errstr (xid, "READDIRPLUS", stat, pstat, errstr); + 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); @@ -3496,9 +3508,9 @@ nfs3_log_commit_res (uint32_t xid, nfsstat3 stat, int pstat, uint64_t wverf) char errstr[1024]; int ll = nfs3_loglevel (NFS3_COMMIT, stat); - if (THIS->ctx->log.loglevel < ll) - return; - nfs3_stat_to_errstr (xid, "COMMIT", stat, pstat, errstr); + 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); } @@ -3509,10 +3521,10 @@ nfs3_log_readdir_call (uint32_t xid, struct nfs3_fh *fh, count3 dircount, { char fhstr[1024]; - if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) - return; + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; - nfs3_fh_to_str (fh, fhstr); + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); if (maxcount == 0) gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, READDIR: args: %s," diff --git a/xlators/nfs/server/src/nfs3-helpers.h b/xlators/nfs/server/src/nfs3-helpers.h index 67935d143..4de1d5623 100644 --- a/xlators/nfs/server/src/nfs3-helpers.h +++ b/xlators/nfs/server/src/nfs3-helpers.h @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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,7 +93,8 @@ extern void nfs3_prep_access3args (access3args *args, struct nfs3_fh *fh); extern void -nfs3_fill_access3res (access3res *res, nfsstat3 status, int32_t accbits); +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); diff --git a/xlators/nfs/server/src/nfs3.c b/xlators/nfs/server/src/nfs3.c index 7c01d0301..f914c3193 100644 --- a/xlators/nfs/server/src/nfs3.c +++ b/xlators/nfs/server/src/nfs3.c @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 @@ -226,32 +217,32 @@ out: uuid_unparse (handle->exportid, exportid); \ uuid_unparse (handle->gfid, gfid); \ trans = rpcsvc_request_transport (req); \ - gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to map " \ - "FH to vol: client=%s, exportid=%s, gfid=%s",\ - trans->peerinfo.identifier, exportid, \ - gfid); \ - gf_log (GF_NFS3, GF_LOG_ERROR, \ - "Stale nfs client %s must be trying to "\ - "connect to a deleted volume, please " \ - "unmount it.", trans->peerinfo.identifier);\ + 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); \ - 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)) { \ - gf_log (GF_NFS3, GF_LOG_ERROR, "Bad 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) \ @@ -265,10 +256,12 @@ out: xlatorp = nfs3_fh_to_xlator (cst->nfs3state, \ &cst->resolvefh); \ uuid_unparse (cst->resolvefh.gfid, gfid); \ - sprintf (buf, "(%s) %s : %s", trans->peerinfo.identifier,\ - xlatorp ? xlatorp->name : "ERR", gfid); \ - gf_log (GF_NFS3, GF_LOG_ERROR, "Unable to resolve FH"\ - ": %s", buf); \ + 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; \ } \ @@ -285,10 +278,12 @@ out: xlatorp = nfs3_fh_to_xlator (cst->nfs3state, \ &cst->resolvefh); \ uuid_unparse (cst->resolvefh.gfid, gfid); \ - sprintf (buf, "(%s) %s : %s", trans->peerinfo.identifier,\ - xlatorp ? xlatorp->name : "ERR", gfid); \ - gf_log (GF_NFS3, GF_LOG_ERROR, "Unable to resolve FH"\ - ": %s", buf); \ + 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; \ } \ @@ -554,23 +549,18 @@ nfs3svc_submit_reply (rpcsvc_request_t *req, void *arg, nfs3_serializer sfunc) iobref = iobref_new (); if (!iobref) { - iobuf_unref (iob); gf_log (GF_NFS3, GF_LOG_ERROR, "failed on iobref_new()"); goto ret; } - iobref_add (iobref, 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); - - /* 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); - iobref_unref (iobref); - if (ret == -1) { gf_log (GF_NFS3, GF_LOG_ERROR, "Reply submission failed"); goto ret; @@ -578,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; } @@ -609,19 +607,14 @@ nfs3svc_submit_vector_reply (rpcsvc_request_t *req, void *arg, new_iobref = 1; } - iobref_add (iobref, 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, payload, vcount, iobref); - - /* 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); - if (new_iobref) - iobref_unref (iobref); - if (ret == -1) { gf_log (GF_NFS3, GF_LOG_ERROR, "Reply submission failed"); goto ret; @@ -629,6 +622,14 @@ nfs3svc_submit_vector_reply (rpcsvc_request_t *req, void *arg, 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; } @@ -703,7 +704,7 @@ nfs3svc_getattr_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - status = nfs3_errno_to_nfsstat3 (op_errno); + status = nfs3_cbk_errno_status (op_ret, op_errno); } else { nfs_fix_generation(this,inode); @@ -733,7 +734,7 @@ nfs3svc_getattr_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - status = nfs3_errno_to_nfsstat3 (op_errno); + status = nfs3_cbk_errno_status (op_ret, op_errno); } nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_GETATTR, @@ -917,7 +918,7 @@ nfs3svc_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -957,7 +958,7 @@ nfs3svc_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -971,7 +972,8 @@ nfs3svc_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, * 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); @@ -1012,7 +1014,7 @@ nfs3svc_setattr_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -1226,7 +1228,7 @@ nfs3svc_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, (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_errno_to_nfsstat3 (op_errno); + status = nfs3_cbk_errno_status (op_ret, op_errno); goto xmit_res; } @@ -1270,7 +1272,7 @@ nfs3svc_lookup_parentdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - status = nfs3_errno_to_nfsstat3 (op_errno); + status = nfs3_cbk_errno_status (op_ret, op_errno); goto xmit_res; } @@ -1312,7 +1314,11 @@ nfs3_lookup_parentdir_resume (void *carg) nfs3_call_state_t *cs = NULL; inode_t *parent = NULL; - GF_VALIDATE_OR_GOTO (GF_NFS3, carg, nfs3err); + 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); @@ -1383,7 +1389,11 @@ nfs3_lookup_resume (void *carg) nfs3_call_state_t *cs = NULL; struct nfs3_fh newfh = {{0},}; - GF_VALIDATE_OR_GOTO (GF_NFS3, carg, nfs3err); + 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); @@ -1495,11 +1505,12 @@ rpcerr: int -nfs3_access_reply (rpcsvc_request_t *req, nfsstat3 status, int32_t accbits) +nfs3_access_reply (rpcsvc_request_t *req, nfsstat3 status, int32_t accbits, + int32_t reqaccbits) { access3res res; - nfs3_fill_access3res (&res, status, accbits); + nfs3_fill_access3res (&res, status, accbits, reqaccbits); nfs3svc_submit_reply (req, &res, (nfs3_serializer)xdr_serialize_access3res); return 0; @@ -1519,11 +1530,11 @@ nfs3svc_access_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - status = nfs3_errno_to_nfsstat3 (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, op_errno); + nfs3_access_reply (cs->req, status, op_errno, cs->accessbits); nfs3_call_state_wipe (cs); return 0; @@ -1537,7 +1548,11 @@ nfs3_access_resume (void *carg) nfs_user_t nfu = {0, }; nfs3_call_state_t *cs = NULL; - GF_VALIDATE_OR_GOTO (GF_NFS3, carg, nfs3err); + 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); @@ -1552,7 +1567,7 @@ nfs3err: if (ret < 0) { nfs3_log_common_res (rpcsvc_request_xid (cs->req), NFS3_ACCESS, stat, -ret); - nfs3_access_reply (cs->req, stat, 0); + nfs3_access_reply (cs->req, stat, 0, 0); nfs3_call_state_wipe (cs); ret = 0; } @@ -1588,7 +1603,7 @@ nfs3err: if (ret < 0) { nfs3_log_common_res (rpcsvc_request_xid (req), NFS3_ACCESS, stat, -ret); - nfs3_access_reply (req, stat, 0); + nfs3_access_reply (req, stat, 0, 0); nfs3_call_state_wipe (cs); ret = 0; } @@ -1655,7 +1670,7 @@ nfs3svc_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -1822,7 +1837,7 @@ nfs3svc_read_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto err; } else stat = NFS3_OK; @@ -2008,7 +2023,7 @@ nfs3svc_write_fsync_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); } else stat = NFS3_OK; @@ -2021,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 @@ -2094,12 +2074,8 @@ nfs3svc_write_cbk (call_frame_t *frame, void *cookie, xlator_t *this, 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 = rpcsvc_request_program_private (cs->req); @@ -2107,42 +2083,21 @@ nfs3svc_write_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (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 (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; } @@ -2198,6 +2153,25 @@ nfs3_write_resume (void *carg) } cs->fd = fd; /* Gets unrefd when the call state is wiped. */ + +/* + 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; + } + ret = __nfs3_write_resume (cs); if (ret < 0) stat = nfs3_errno_to_nfsstat3 (-ret); @@ -2361,7 +2335,7 @@ nfs3svc_create_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -2394,7 +2368,7 @@ nfs3svc_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -2499,7 +2473,7 @@ nfs3svc_create_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, "%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; } @@ -2670,13 +2644,7 @@ nfs3svc_create (rpcsvc_request_t *req) } cval = (uint64_t *)args.how.createhow3_u.verf; - if (cval) - cverf = *cval; - else { - gf_log(GF_NFS3, GF_LOG_ERROR, - "Error getting createverf3 from args"); - goto rpcerr; - } + cverf = *cval; ret = nfs3_create (req, &dirfh, name, args.how.mode, &args.how.createhow3_u.obj_attributes, cverf); @@ -2720,7 +2688,7 @@ nfs3svc_mkdir_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -2752,7 +2720,7 @@ nfs3svc_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -2930,7 +2898,7 @@ nfs3svc_symlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -3092,7 +3060,7 @@ nfs3svc_mknod_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -3124,7 +3092,7 @@ nfs3svc_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -3382,7 +3350,7 @@ nfs3svc_remove_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); } if (op_ret == 0) @@ -3548,7 +3516,7 @@ nfs3svc_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); } else { stat = NFS3_OK; } @@ -3703,7 +3671,7 @@ nfs3svc_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, "%x: rename %s -> %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->oploc.path, cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -3908,7 +3876,7 @@ nfs3svc_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this, "%x: link %s <- %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->oploc.path, cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); } else stat = NFS3_OK; @@ -4118,7 +4086,7 @@ nfs3svc_readdir_fstat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto nfs3err; } @@ -4173,7 +4141,7 @@ nfs3svc_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); goto err; } @@ -4270,12 +4238,30 @@ 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; @@ -4288,6 +4274,22 @@ nfs3_readdir_open_resume (void *carg) 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); @@ -4387,16 +4389,8 @@ nfs3svc_readdir (rpcsvc_request_t *req) rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } - cval = (uint64_t *) ra.cookieverf; - - if (cval) - verf = *cval; - else { - gf_log(GF_NFS3, GF_LOG_ERROR, - "Error getting cookieverf from readdir args"); - goto rpcerr; - } + verf = *cval; ret = nfs3_readdir (req, &fh, ra.cookie, verf, ra.count, 0); if ((ret < 0) && (ret != RPCSVC_ACTOR_IGNORE)) { @@ -4427,16 +4421,8 @@ nfs3svc_readdirp (rpcsvc_request_t *req) rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } - cval = (uint64_t *) ra.cookieverf; - - if (cval) - cverf = *cval; - else { - gf_log (GF_NFS3, GF_LOG_ERROR, - "Error getting cookieverf from readdirp args"); - goto rpcerr; - } + cverf = *cval; ret = nfs3_readdir (req, &fh, ra.cookie, cverf, ra.dircount, ra.maxcount); @@ -4479,7 +4465,7 @@ nfs3_fsstat_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); } else stat = NFS3_OK; @@ -4507,7 +4493,7 @@ nfs3_fsstat_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, "%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; } @@ -4666,7 +4652,7 @@ nfs3svc_fsinfo_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - status = nfs3_errno_to_nfsstat3 (op_errno); + status = nfs3_cbk_errno_status (op_ret, op_errno); }else status = NFS3_OK; @@ -4808,7 +4794,7 @@ nfs3svc_pathconf_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (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. @@ -4952,7 +4938,7 @@ nfs3svc_commit_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (GF_NFS, GF_LOG_WARNING, "%x: %s => -1 (%s)", rpcsvc_request_xid (cs->req), cs->resolvedloc.path, strerror (op_errno)); - stat = nfs3_errno_to_nfsstat3 (op_errno); + stat = nfs3_cbk_errno_status (op_ret, op_errno); } else stat = NFS3_OK; @@ -5113,28 +5099,28 @@ rpcerr: rpcsvc_actor_t nfs3svc_actors[NFS3_PROC_COUNT] = { - {"NULL", NFS3_NULL, nfs3svc_null, NULL, 0}, - {"GETATTR", NFS3_GETATTR, nfs3svc_getattr,NULL, 0}, - {"SETATTR", NFS3_SETATTR, nfs3svc_setattr,NULL, 0}, - {"LOOKUP", NFS3_LOOKUP, nfs3svc_lookup, NULL, 0}, - {"ACCESS", NFS3_ACCESS, nfs3svc_access, NULL, 0}, - {"READLINK", NFS3_READLINK, nfs3svc_readlink,NULL, 0}, - {"READ", NFS3_READ, nfs3svc_read, NULL, 0}, - {"WRITE", NFS3_WRITE, nfs3svc_write, nfs3svc_write_vecsizer, 0}, - {"CREATE", NFS3_CREATE, nfs3svc_create, NULL, 0}, - {"MKDIR", NFS3_MKDIR, nfs3svc_mkdir, NULL, 0}, - {"SYMLINK", NFS3_SYMLINK, nfs3svc_symlink,NULL, 0}, - {"MKNOD", NFS3_MKNOD, nfs3svc_mknod, NULL, 0}, - {"REMOVE", NFS3_REMOVE, nfs3svc_remove, NULL, 0}, - {"RMDIR", NFS3_RMDIR, nfs3svc_rmdir, NULL, 0}, - {"RENAME", NFS3_RENAME, nfs3svc_rename, NULL, 0}, - {"LINK", NFS3_LINK, nfs3svc_link, NULL, 0}, - {"READDIR", NFS3_READDIR, nfs3svc_readdir,NULL, 0}, - {"READDIRPLUS", NFS3_READDIRP, nfs3svc_readdirp,NULL, 0}, - {"FSSTAT", NFS3_FSSTAT, nfs3svc_fsstat, NULL, 0}, - {"FSINFO", NFS3_FSINFO, nfs3svc_fsinfo, NULL, 0}, - {"PATHCONF", NFS3_PATHCONF, nfs3svc_pathconf,NULL, 0}, - {"COMMIT", NFS3_COMMIT, nfs3svc_commit, NULL, 0} + {"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} }; @@ -5151,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"); @@ -5174,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"); @@ -5195,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"); @@ -5216,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. */ @@ -5245,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; @@ -5255,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); @@ -5428,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; @@ -5493,7 +5518,7 @@ nfs3_init_state (xlator_t *nfsx) } nfs = nfsx->private; - ret = nfs3_init_options (nfs3, nfsx); + ret = nfs3_init_options (nfs3, nfsx->options); if (ret == -1) { gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to init options"); goto ret; @@ -5525,7 +5550,7 @@ nfs3_init_state (xlator_t *nfsx) LOCK_INIT (&nfs3->fdlrulock); nfs3->fdcount = 0; - rpcsvc_create_listeners (nfs->rpcsvc, nfsx->options, nfsx->name); + 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; @@ -5567,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 111542bc6..0c35445a4 100644 --- a/xlators/nfs/server/src/nfs3.h +++ b/xlators/nfs/server/src/nfs3.h @@ -2,19 +2,10 @@ 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 General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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_ @@ -48,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} @@ -120,20 +134,21 @@ typedef 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 { @@ -262,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 index 4ee3596fd..5c5d87412 100644 --- a/xlators/nfs/server/src/nlm4.c +++ b/xlators/nfs/server/src/nlm4.c @@ -2,19 +2,10 @@ Copyright (c) 2012 Gluster, Inc. <http://www.gluster.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 @@ -149,8 +140,10 @@ nfs3_fh_to_xlator (struct nfs3_state *nfs3, struct nfs3_fh *fh); xlatorp = nfs3_fh_to_xlator (cst->nfs3state, \ &cst->resolvefh); \ uuid_unparse (cst->resolvefh.gfid, gfid); \ - sprintf (buf, "(%s) %s : %s", trans->peerinfo.identifier,\ - xlatorp ? xlatorp->name : "ERR", 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);\ @@ -235,7 +228,7 @@ nlm_is_oh_same_lkowner (gf_lkowner_t *a, netobj *b) !memcmp (a->data, b->n_bytes, a->len)); } -nfsstat3 +nlm4_stats nlm4_errno_to_nlm4stat (int errnum) { nlm4_stats stat = nlm4_denied; @@ -345,13 +338,12 @@ nlm_set_rpc_clnt (rpc_clnt_t *rpc_clnt, char *caller_name) break; } } + if (!nlmclnt_found) { nlmclnt = GF_CALLOC (1, sizeof(*nlmclnt), gf_nfs_mt_nlm4_nlmclnt); - if (nlmclnt == NULL) { - gf_log (GF_NLM, GF_LOG_ERROR, "mem-alloc error"); + if (nlmclnt == NULL) goto ret; - } INIT_LIST_HEAD(&nlmclnt->fdes); INIT_LIST_HEAD(&nlmclnt->nlm_clients); @@ -360,6 +352,7 @@ nlm_set_rpc_clnt (rpc_clnt_t *rpc_clnt, char *caller_name) 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); } @@ -434,10 +427,11 @@ 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; + 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) @@ -462,7 +456,12 @@ nlm4svc_submit_reply (rpcsvc_request_t *req, void *arg, nlm4_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_NLM, GF_LOG_ERROR, "Failed to encode message"); + goto ret; + } + outmsg.iov_len = msglen; iobref = iobref_new (); if (iobref == NULL) { @@ -470,7 +469,11 @@ nlm4svc_submit_reply (rpcsvc_request_t *req, void *arg, nlm4_serializer sfunc) goto ret; } - iobref_add (iobref, iob); + 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); @@ -594,9 +597,15 @@ 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"); @@ -630,16 +639,13 @@ nlm4_file_open_and_resume(nfs3_call_state_t *cs, nlm4_resume_fn_t resume) } frame->root->pid = NFS_PID; - frame->root->uid = 0; - frame->root->gid = 0; + frame->root->uid = rpcsvc_request_uid (cs->req); + frame->root->gid = rpcsvc_request_gid (cs->req); frame->local = cs; - /* - * This is the only place that we call STACK_WIND without nfs_fix_groups, - * because in this particular case the relevant identify is in lk_owner and - * we don't care about the fields that nfs_fix_groups would set up. - */ + 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, O_RDWR, + cs->vol->fops->open, &cs->resolvedloc, flags, cs->fd, NULL); ret = 0; err: @@ -880,50 +886,64 @@ nlm4svc_send_granted_cbk (struct rpc_req *req, struct iovec *iov, int count, return 0; } -int nlm_rpcclnt_notify (struct rpc_clnt *rpc, void *mydata, - rpc_clnt_event_t fn, void *data) +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) { - nlm_condmutex_t *cm = NULL; - int ret; - cm = mydata; + 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 = pthread_cond_broadcast (&cm->cond); - if (ret!=0) - gf_log (GF_NLM, GF_LOG_ERROR, "cond_broadcast error %s", - strerror (errno)); + 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); + nlm_unset_rpc_clnt (rpc_clnt); break; } + + err: return 0; } -void -nlm4svc_send_granted (nfs3_call_state_t *cs); - void * nlm4_establish_callback (void *csarg) { - nfs3_call_state_t *cs = NULL; - union gf_sock_union sock_union; - dict_t *options = NULL; - char peerip[INET6_ADDRSTRLEN+1], *portstr = NULL; - rpc_clnt_t *rpc_clnt = NULL; - int port = -1; - int ret = -1; - char *caller_name = NULL; + 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); - caller_name = cs->args.nlm4_lockargs.alock.caller_name; - 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 */ @@ -939,6 +959,9 @@ nlm4_establish_callback (void *csarg) 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; @@ -978,6 +1001,13 @@ nlm4_establish_callback (void *csarg) 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"); @@ -990,32 +1020,25 @@ nlm4_establish_callback (void *csarg) gf_log (GF_NLM, GF_LOG_ERROR, "rpc_clnt NULL"); goto err; } - nlm_condmutex_t *cm; - cm = GF_CALLOC (1, sizeof(*cm), gf_nfs_mt_nlm4_cm); - pthread_mutex_init (&cm->mutex, NULL); - pthread_cond_init (&cm->cond, NULL); - ret = rpc_clnt_register_notify (rpc_clnt, nlm_rpcclnt_notify, - cm); + + 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); - pthread_cond_wait (&cm->cond, &cm->mutex); - pthread_mutex_destroy (&cm->mutex); - GF_FREE (cm); - rpc_clnt_set_connected (&rpc_clnt->conn); - ret = nlm_set_rpc_clnt (rpc_clnt, caller_name); - if (ret == -1) { - gf_log (GF_NLM, GF_LOG_ERROR, "dict_set_ptr error"); - goto err; - } - nlm4svc_send_granted (cs); + + if (ret == -1 && EINPROGRESS == errno) + ret = 0; + err: - if (rpc_clnt) { + if (ret == -1 && rpc_clnt) { rpc_clnt_unref (rpc_clnt); } - return NULL; + + return rpc_clnt; } void @@ -1028,12 +1051,17 @@ nlm4svc_send_granted (nfs3_call_state_t *cs) struct iobuf *iobuf = NULL; struct iobref *iobref = NULL; char peerip[INET6_ADDRSTRLEN+1]; - pthread_t thr; 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, @@ -1042,15 +1070,9 @@ nlm4svc_send_granted (nfs3_call_state_t *cs) case AF_INET: inet_ntop (AF_INET, &sock_union.sin.sin_addr, peerip, INET6_ADDRSTRLEN+1); + break; default: break; - /* FIXME: handle the error */ - } - - rpc_clnt = nlm_get_rpc_clnt (cs->args.nlm4_lockargs.alock.caller_name); - if (rpc_clnt == NULL) { - pthread_create (&thr, NULL, nlm4_establish_callback, (void*)cs); - return; } testargs.cookie = cs->args.nlm4_lockargs.cookie; @@ -1075,13 +1097,15 @@ nlm4svc_send_granted (nfs3_call_state_t *cs) goto ret; } - iobref_add (iobref, iobuf); + 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, + nlm4svc_send_granted_cbk, &outmsg, 1, + NULL, 0, iobref, cs->frame, NULL, 0, NULL, 0, NULL); if (ret < 0) { @@ -1276,12 +1300,11 @@ nlm4svc_lock_cbk (call_frame_t *frame, void *cookie, xlator_t *this, cs = frame->local; caller_name = cs->args.nlm4_lockargs.alock.caller_name; - transit_cnt = nlm_dec_transit_count (cs->fd, - 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); + nlm_search_and_delete (cs->fd, caller_name); stat = nlm4_errno_to_nlm4stat (op_errno); goto err; } else { @@ -1295,6 +1318,7 @@ nlm4svc_lock_cbk (call_frame_t *frame, void *cookie, xlator_t *this, 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, @@ -1797,7 +1821,7 @@ nlm4_add_share_to_inode (nlm_share_t *share) inode = share->inode; ret = inode_ctx_get (inode, this, &ctx); - if (ret || !head) { + if (ret == -1) { ictx = GF_CALLOC (1, sizeof (struct nfs_inode_ctx), gf_nfs_mt_inode_ctx); if (!ictx ) { @@ -2269,34 +2293,34 @@ nlm4svc_sm_notify (struct nlm_sm_status *status) rpcsvc_actor_t nlm4svc_actors[NLM4_PROC_COUNT] = { /* 0 */ - {"NULL", NLM4_NULL, nlm4svc_null, NULL}, - {"TEST", NLM4_TEST, nlm4svc_test, NULL}, - {"LOCK", NLM4_LOCK, nlm4svc_lock, NULL}, - {"CANCEL", NLM4_CANCEL, nlm4svc_cancel, NULL}, - {"UNLOCK", NLM4_UNLOCK, nlm4svc_unlock, NULL}, + {"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}, - {"TEST", NLM4_TEST_MSG, NULL, NULL}, - {"LOCK", NLM4_LOCK_MSG, NULL, NULL}, - {"CANCEL", NLM4_CANCEL_MSG, NULL, NULL}, - {"UNLOCK", NLM4_UNLOCK_MSG, NULL, NULL}, + {"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}, - {"TEST", NLM4_TEST_RES, NULL, NULL}, - {"LOCK", NLM4_LOCK_RES, NULL, NULL}, - {"CANCEL", NLM4_CANCEL_RES, NULL, NULL}, - {"UNLOCK", NLM4_UNLOCK_RES, NULL, NULL}, + {"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}, - {"SM_NOTIFY", NLM4_SM_NOTIFY, NULL, NULL}, - {"SEVENTEEN", NLM4_SEVENTEEN, NULL, NULL}, - {"EIGHTEEN", NLM4_EIGHTEEN, NULL, NULL}, - {"NINETEEN", NLM4_NINETEEN, NULL, NULL}, + {"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}, - {"UNSHARE", NLM4_UNSHARE, nlm4svc_unshare, NULL}, - {"NM_LOCK", NLM4_NM_LOCK, nlm4svc_nm_lock, NULL}, - {"FREE_ALL", NLM4_FREE_ALL, nlm4svc_free_all, NULL}, + {"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 = { @@ -2332,9 +2356,14 @@ nlm4svc_init(xlator_t *nfsx) int ret = -1; char *portstr = NULL; pthread_t thr; - struct timeval timeout = {0,}; + 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; @@ -2380,7 +2409,7 @@ nlm4svc_init(xlator_t *nfsx) goto err; } - rpcsvc_create_listeners (nfs->rpcsvc, options, "NLM"); + 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); @@ -2436,7 +2465,10 @@ nlm4svc_init(xlator_t *nfsx) 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; diff --git a/xlators/nfs/server/src/nlm4.h b/xlators/nfs/server/src/nlm4.h index 0cc82f162..9b5d54081 100644 --- a/xlators/nfs/server/src/nlm4.h +++ b/xlators/nfs/server/src/nlm4.h @@ -2,19 +2,10 @@ Copyright (c) 2012 Gluster, Inc. <http://www.gluster.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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_ @@ -83,9 +74,4 @@ typedef struct nlm_fde { int transit_cnt; } nlm_fde_t; -typedef struct { - pthread_cond_t cond; - pthread_mutex_t mutex; -} nlm_condmutex_t; - #endif diff --git a/xlators/nfs/server/src/nlmcbk_svc.c b/xlators/nfs/server/src/nlmcbk_svc.c index 5401dc39b..e1b588765 100644 --- a/xlators/nfs/server/src/nlmcbk_svc.c +++ b/xlators/nfs/server/src/nlmcbk_svc.c @@ -2,19 +2,10 @@ Copyright (c) 2012 Gluster, Inc. <http://www.gluster.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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. */ /* @@ -92,10 +83,14 @@ void * nsm_thread (void *argv) { register SVCXPRT *transp; + int ret = 0; - pmap_unset (NLMCBK_PROGRAM, NLMCBK_V1); - - transp = svcudp_create(RPC_ANYSOCK); + 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; |
