diff options
Diffstat (limited to 'xlators/nfs/server/src/nlm4.c')
| -rw-r--r-- | xlators/nfs/server/src/nlm4.c | 1239 |
1 files changed, 953 insertions, 286 deletions
diff --git a/xlators/nfs/server/src/nlm4.c b/xlators/nfs/server/src/nlm4.c index 9fd374b1f..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 @@ -48,6 +39,7 @@ #include <rpc/pmap_clnt.h> #include <rpc/rpc.h> #include <rpc/xdr.h> +#include <statedump.h> /* TODO: * 1) 2 opens racing .. creating an fd leak. @@ -148,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);\ @@ -199,14 +193,42 @@ nlm4_prep_nlm4_unlockargs (nlm4_unlockargs *args, struct nfs3_fh *fh, } void +nlm4_prep_shareargs (nlm4_shareargs *args, struct nfs3_fh *fh, + nlm4_lkowner_t *oh, char *cookiebytes) +{ + memset (args, 0, sizeof (*args)); + args->share.fh.n_bytes = (void *)fh; + args->share.oh.n_bytes = (void *)oh; + args->cookie.n_bytes = (void *)cookiebytes; +} + +void +nlm4_prep_freeallargs (nlm4_freeallargs *args, nlm4_lkowner_t *oh) +{ + memset (args, 0, sizeof (*args)); + args->name = (void *)oh; +} + +void nlm_copy_lkowner (gf_lkowner_t *dst, netobj *src) { dst->len = src->n_len; memcpy (dst->data, src->n_bytes, dst->len); } +int +nlm_is_oh_same_lkowner (gf_lkowner_t *a, netobj *b) +{ + if (!a || !b) { + gf_log (GF_NLM, GF_LOG_ERROR, "invalid args"); + return -1; + } -nfsstat3 + return (a->len == b->n_len && + !memcmp (a->data, b->n_bytes, a->len)); +} + +nlm4_stats nlm4_errno_to_nlm4stat (int errnum) { nlm4_stats stat = nlm4_denied; @@ -251,10 +273,34 @@ nlm4_call_state_init (struct nfs3_state *s, rpcsvc_request_t *req) cs->req = req; cs->nfsx = s->nfsx; cs->nfs3state = s; + cs->monitor = 1; return cs; } +int +nlm_monitor (char *caller_name) +{ + nlm_client_t *nlmclnt = NULL; + int monitor = -1; + + LOCK (&nlm_client_list_lk); + list_for_each_entry (nlmclnt, &nlm_client_list, nlm_clients) { + if (!strcmp(caller_name, nlmclnt->caller_name)) { + monitor = nlmclnt->nsm_monitor; + nlmclnt->nsm_monitor = 1; + break; + } + } + UNLOCK (&nlm_client_list_lk); + + if (monitor == -1) + gf_log (GF_NLM, GF_LOG_ERROR, "%s was not found in " + "the nlmclnt list", caller_name); + + return monitor; +} + rpc_clnt_t * nlm_get_rpc_clnt (char *caller_name) { @@ -284,8 +330,6 @@ nlm_set_rpc_clnt (rpc_clnt_t *rpc_clnt, char *caller_name) nlm_client_t *nlmclnt = NULL; int nlmclnt_found = 0; int ret = -1; - rpc_clnt_t *rpc_clnt_old = NULL; - char *old_name = NULL; LOCK (&nlm_client_list_lk); list_for_each_entry (nlmclnt, &nlm_client_list, nlm_clients) { @@ -294,38 +338,27 @@ 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_DEBUG, "malloc error"); + if (nlmclnt == NULL) goto ret; - } INIT_LIST_HEAD(&nlmclnt->fdes); INIT_LIST_HEAD(&nlmclnt->nlm_clients); + INIT_LIST_HEAD(&nlmclnt->shares); list_add (&nlmclnt->nlm_clients, &nlm_client_list); + nlmclnt->caller_name = gf_strdup (caller_name); } - rpc_clnt_old = nlmclnt->rpc_clnt; - old_name = nlmclnt->caller_name; - if (rpc_clnt) - nlmclnt->rpc_clnt = rpc_clnt_ref (rpc_clnt); - nlmclnt->caller_name = gf_strdup (caller_name); + if (nlmclnt->rpc_clnt == NULL) { + nlmclnt->rpc_clnt = rpc_clnt_ref (rpc_clnt); + } ret = 0; ret: UNLOCK (&nlm_client_list_lk); - - if (rpc_clnt_old) { - /* cleanup the saved-frames before last unref */ - rpc_clnt_connection_cleanup (&rpc_clnt_old->conn); - - rpc_clnt_unref (rpc_clnt_old); - } - - if (old_name) - GF_FREE (old_name); return ret; } @@ -380,6 +413,7 @@ nlm_add_nlmclnt (char *caller_name) INIT_LIST_HEAD(&nlmclnt->fdes); INIT_LIST_HEAD(&nlmclnt->nlm_clients); + INIT_LIST_HEAD(&nlmclnt->shares); list_add (&nlmclnt->nlm_clients, &nlm_client_list); nlmclnt->caller_name = gf_strdup (caller_name); @@ -393,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) @@ -421,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) { @@ -429,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); @@ -465,15 +509,17 @@ nlm4_file_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; } -int nsm_monitor(char *host) +void * +nsm_monitor(void *arg) { CLIENT *clnt = NULL; enum clnt_stat ret; struct mon nsm_mon; struct sm_stat_res res; struct timeval tout = { 5, 0 }; - int retstat = -1; + char *host = NULL; + host = arg; nsm_mon.mon_id.mon_name = gf_strdup(host); nsm_mon.mon_id.my_id.my_name = gf_strdup("localhost"); nsm_mon.mon_id.my_id.my_prog = NLMCBK_PROGRAM; @@ -508,33 +554,41 @@ int nsm_monitor(char *host) clnt_sperrno(ret)); goto out; } - retstat = 0; + out: GF_FREE(nsm_mon.mon_id.mon_name); GF_FREE(nsm_mon.mon_id.my_id.my_name); if (clnt != NULL) clnt_destroy(clnt); - return retstat; + return NULL; } nlm_client_t * -nlm_get_uniq (char *caller_name) +__nlm_get_uniq (char *caller_name) { nlm_client_t *nlmclnt = NULL; - int nlmclnt_found = 0; - LOCK (&nlm_client_list_lk); + if (!caller_name) + return NULL; + list_for_each_entry (nlmclnt, &nlm_client_list, nlm_clients) { - if (!strcmp(caller_name, nlmclnt->caller_name)) { - nlmclnt_found = 1; - break; - } + if (!strcmp(caller_name, nlmclnt->caller_name)) + return nlmclnt; } + + return NULL; +} + +nlm_client_t * +nlm_get_uniq (char *caller_name) +{ + nlm_client_t *nlmclnt = NULL; + + LOCK (&nlm_client_list_lk); + nlmclnt = __nlm_get_uniq (caller_name); UNLOCK (&nlm_client_list_lk); - if (nlmclnt_found) - return nlmclnt; - else - return NULL; + + return nlmclnt; } @@ -543,15 +597,19 @@ 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"); - cs->resolve_ret = -1; - cs->resume_fn(cs); - ret = -1; + ret = -ENOLCK; goto err; } cs->resume_fn = resume; @@ -567,21 +625,27 @@ nlm4_file_open_and_resume(nfs3_call_state_t *cs, nlm4_resume_fn_t resume) fd = fd_create_uint64 (cs->resolvedloc.inode, (uint64_t)nlmclnt); if (fd == NULL) { gf_log (GF_NLM, GF_LOG_ERROR, "fd_create_uint64() returned NULL"); - cs->resolve_ret = -1; - cs->resume_fn(cs); - ret = -1; + ret = -ENOLCK; goto err; } cs->fd = fd; frame = create_frame (cs->nfsx, cs->nfsx->ctx->pool); + if (!frame) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to create frame"); + ret = -ENOMEM; + goto err; + } + frame->root->pid = NFS_PID; - frame->root->uid = 0; - frame->root->gid = 0; + frame->root->uid = rpcsvc_request_uid (cs->req); + frame->root->gid = rpcsvc_request_gid (cs->req); frame->local = cs; - STACK_WIND_COOKIE (frame, nlm4_file_open_cbk, cs->nfsx, cs->nfsx, - cs->nfsx->fops->open, &cs->resolvedloc, O_RDWR, + nfs_fix_groups (cs->nfsx, frame->root); + + STACK_WIND_COOKIE (frame, nlm4_file_open_cbk, cs->vol, cs->vol, + cs->vol->fops->open, &cs->resolvedloc, flags, cs->fd, NULL); ret = 0; err: @@ -705,7 +769,6 @@ err: int nlm4_test_fd_resume (void *carg) { - nlm4_stats stat = nlm4_denied; int ret = -EFAULT; nfs_user_t nfu = {0, }; nfs3_call_state_t *cs = NULL; @@ -715,21 +778,12 @@ nlm4_test_fd_resume (void *carg) return ret; cs = (nfs3_call_state_t *)carg; - nlm4_check_fh_resolve_status (cs, stat, nlm4err); nfs_request_user_init (&nfu, cs->req); nlm4_lock_to_gf_flock (&flock, &cs->args.nlm4_testargs.alock, cs->args.nlm4_testargs.exclusive); nlm_copy_lkowner (&nfu.lk_owner, &cs->args.nlm4_testargs.alock.oh); ret = nfs_lk (cs->nfsx, cs->vol, &nfu, cs->fd, F_GETLK, &flock, nlm4svc_test_cbk, cs); - if (ret < 0) - stat = nlm4_errno_to_nlm4stat (-ret); -nlm4err: - if (ret < 0) { - gf_log (GF_NLM, GF_LOG_ERROR, "Unable to call lk()"); - nlm4_test_reply (cs, stat, &flock); - nfs3_call_state_wipe (cs); - } return ret; } @@ -749,14 +803,15 @@ nlm4_test_resume (void *carg) cs = (nfs3_call_state_t *)carg; nlm4_check_fh_resolve_status (cs, stat, nlm4err); fd = fd_anonymous (cs->resolvedloc.inode); + if (!fd) + goto nlm4err; cs->fd = fd; ret = nlm4_test_fd_resume (cs); - if (ret < 0) - stat = nlm4_errno_to_nlm4stat (-ret); nlm4err: if (ret < 0) { gf_log (GF_NLM, GF_LOG_ERROR, "unable to open_and_resume"); + stat = nlm4_errno_to_nlm4stat (-ret); nlm4_test_reply (cs, stat, NULL); nfs3_call_state_wipe (cs); } @@ -817,9 +872,9 @@ nlm4err: } rpcerr: - if (ret < 0) { + if (ret < 0) nfs3_call_state_wipe (cs); - } + return ret; } @@ -831,53 +886,65 @@ 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; - struct sockaddr_storage sa; - struct sockaddr *sockaddr = NULL; - 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; - nsm_monitor (caller_name); + rpc_transport_get_peeraddr (cs->trans, NULL, 0, &sock_union.storage, + sizeof (sock_union.storage)); - rpc_transport_get_peeraddr (cs->trans, NULL, 0, &sa, sizeof (sa)); - sockaddr = (struct sockaddr*) &sa; - switch (sockaddr->sa_family) { + switch (sock_union.sa.sa_family) { case AF_INET6: /* can not come here as NLM listens on IPv4 */ gf_log (GF_NLM, GF_LOG_ERROR, "NLM is not supported on IPv6 in" @@ -890,9 +957,11 @@ nlm4_establish_callback (void *csarg) break; */ case AF_INET: - inet_ntop (AF_INET, - &((struct sockaddr_in *)sockaddr)->sin_addr, - peerip, INET6_ADDRSTRLEN+1); + 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; @@ -900,7 +969,7 @@ nlm4_establish_callback (void *csarg) } /* looks like libc rpc supports only ipv4 */ - port = pmap_getport ((struct sockaddr_in*)sockaddr, NLM_PROGRAM, + port = pmap_getport (&sock_union.sin, NLM_PROGRAM, NLM_V4, IPPROTO_TCP); if (port == 0) { @@ -932,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"); @@ -944,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 @@ -982,32 +1051,28 @@ nlm4svc_send_granted (nfs3_call_state_t *cs) struct iobuf *iobuf = NULL; struct iobref *iobref = NULL; char peerip[INET6_ADDRSTRLEN+1]; - pthread_t thr; - struct sockaddr_storage sa; - struct sockaddr *sockaddr = NULL; + 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)); - rpc_transport_get_peeraddr (cs->trans, NULL, 0, &sa, sizeof (sa)); - sockaddr = (struct sockaddr*) &sa; - switch (sockaddr->sa_family) { + switch (sock_union.sa.sa_family) { case AF_INET6: - inet_ntop (AF_INET6, - &((struct sockaddr_in6 *)sockaddr)->sin6_addr, - peerip, INET6_ADDRSTRLEN+1); + inet_ntop (AF_INET6, &sock_union.sin6.sin6_addr, peerip, + INET6_ADDRSTRLEN+1); break; case AF_INET: - inet_ntop (AF_INET, - &((struct sockaddr_in *)sockaddr)->sin_addr, - peerip, INET6_ADDRSTRLEN+1); + 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; @@ -1032,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) { @@ -1225,26 +1292,33 @@ nlm4svc_lock_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, struct gf_flock *flock, dict_t *xdata) { - nlm4_stats stat = nlm4_denied; - nfs3_call_state_t *cs = NULL; - int transit_cnt = -1; + nlm4_stats stat = nlm4_denied; + int transit_cnt = -1; + char *caller_name = NULL; + nfs3_call_state_t *cs = NULL; + pthread_t thr; cs = frame->local; + caller_name = cs->args.nlm4_lockargs.alock.caller_name; + transit_cnt = nlm_dec_transit_count (cs->fd, caller_name); - transit_cnt = nlm_dec_transit_count (cs->fd, - cs->args.nlm4_lockargs.alock.caller_name); if (op_ret == -1) { if (transit_cnt == 0) - nlm_search_and_delete (cs->fd, - cs->args.nlm4_lockargs.alock.caller_name); + nlm_search_and_delete (cs->fd, caller_name); stat = nlm4_errno_to_nlm4stat (op_errno); goto err; - } else + } else { stat = nlm4_granted; + if (cs->monitor && !nlm_monitor (caller_name)) { + /* FIXME: handle nsm_monitor failure */ + pthread_create (&thr, NULL, nsm_monitor, (void*)caller_name); + } + } err: if (cs->args.nlm4_lockargs.block) { cs->frame = copy_frame (frame); + frame->local = NULL; nlm4svc_send_granted (cs); } else { nlm4_generic_reply (cs->req, cs->args.nlm4_lockargs.cookie, @@ -1268,7 +1342,6 @@ nlm4_lock_fd_resume (void *carg) cs = (nfs3_call_state_t *)carg; nlm4_check_fh_resolve_status (cs, stat, nlm4err); - (void) nlm_search_and_add (cs->fd, cs->args.nlm4_lockargs.alock.caller_name); nfs_request_user_init (&nfu, cs->req); @@ -1280,14 +1353,17 @@ nlm4_lock_fd_resume (void *carg) nlm4_blocked); ret = nfs_lk (cs->nfsx, cs->vol, &nfu, cs->fd, F_SETLKW, &flock, nlm4svc_lock_cbk, cs); + /* FIXME: handle error from nfs_lk() specially by just + * cleaning up cs and unblock the client lock request. + */ + ret = 0; } else ret = nfs_lk (cs->nfsx, cs->vol, &nfu, cs->fd, F_SETLK, &flock, nlm4svc_lock_cbk, cs); - if (ret < 0) - stat = nlm4_errno_to_nlm4stat (-ret); nlm4err: if (ret < 0) { + stat = nlm4_errno_to_nlm4stat (-ret); gf_log (GF_NLM, GF_LOG_ERROR, "unable to call lk()"); nlm4_generic_reply (cs->req, cs->args.nlm4_lockargs.cookie, stat); @@ -1302,8 +1378,8 @@ int nlm4_lock_resume (void *carg) { nlm4_stats stat = nlm4_failed; - int ret = -1; - nfs3_call_state_t *cs = NULL; + int ret = -1; + nfs3_call_state_t *cs = NULL; if (!carg) return ret; @@ -1311,12 +1387,11 @@ nlm4_lock_resume (void *carg) cs = (nfs3_call_state_t *)carg; nlm4_check_fh_resolve_status (cs, stat, nlm4err); ret = nlm4_file_open_and_resume (cs, nlm4_lock_fd_resume); - if (ret < 0) - stat = nlm4_errno_to_nlm4stat (-ret); nlm4err: if (ret < 0) { gf_log (GF_NLM, GF_LOG_ERROR, "unable to open and resume"); + stat = nlm4_errno_to_nlm4stat (-ret); nlm4_generic_reply (cs->req, cs->args.nlm4_lockargs.cookie, stat); nfs3_call_state_wipe (cs); @@ -1325,17 +1400,16 @@ nlm4err: return ret; } - int -nlm4svc_lock (rpcsvc_request_t *req) +nlm4svc_lock_common (rpcsvc_request_t *req, int mon) { - xlator_t *vol = NULL; - nlm4_stats stat = nlm4_failed; - struct nfs_state *nfs = NULL; - nfs3_state_t *nfs3 = NULL; - nfs3_call_state_t *cs = NULL; - int ret = RPCSVC_ACTOR_ERROR; - struct nfs3_fh fh = {{0}, }; + int ret = RPCSVC_ACTOR_ERROR; + nlm4_stats stat = nlm4_failed; + struct nfs3_fh fh = {{0}, }; + xlator_t *vol = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + struct nfs_state *nfs = NULL; if (!req) return ret; @@ -1352,7 +1426,9 @@ nlm4svc_lock (rpcsvc_request_t *req) rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } + fh = cs->lockfh; + cs->monitor = mon; nlm4_validate_gluster_fh (&fh, stat, nlm4err); nlm4_map_fh_to_volume (cs->nfs3state, fh, req, vol, stat, nlm4err); @@ -1386,10 +1462,23 @@ rpcerr: if (ret < 0) { nfs3_call_state_wipe (cs); } + return ret; } int +nlm4svc_lock (rpcsvc_request_t *req) +{ + return nlm4svc_lock_common (req, 1); +} + +int +nlm4svc_nm_lock (rpcsvc_request_t *req) +{ + return nlm4svc_lock_common (req, 0); +} + +int nlm4svc_cancel_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, struct gf_flock *flock, dict_t *xdata) @@ -1414,7 +1503,6 @@ err: int nlm4_cancel_fd_resume (void *carg) { - nlm4_stats stat = nlm4_denied; int ret = -EFAULT; nfs_user_t nfu = {0, }; nfs3_call_state_t *cs = NULL; @@ -1424,7 +1512,6 @@ nlm4_cancel_fd_resume (void *carg) return ret; cs = (nfs3_call_state_t *)carg; - nlm4_check_fh_resolve_status (cs, stat, nlm4err); nfs_request_user_init (&nfu, cs->req); nlm4_lock_to_gf_flock (&flock, &cs->args.nlm4_cancargs.alock, cs->args.nlm4_cancargs.exclusive); @@ -1433,16 +1520,105 @@ nlm4_cancel_fd_resume (void *carg) ret = nfs_lk (cs->nfsx, cs->vol, &nfu, cs->fd, F_SETLK, &flock, nlm4svc_cancel_cbk, cs); - if (ret < 0) + return ret; +} + +int +nlm4_cancel_resume (void *carg) +{ + nlm4_stats stat = nlm4_failed; + int ret = -EFAULT; + nfs3_call_state_t *cs = NULL; + nlm_client_t *nlmclnt = NULL; + + if (!carg) + return ret; + + cs = (nfs3_call_state_t *)carg; + nlm4_check_fh_resolve_status (cs, stat, nlm4err); + + nlmclnt = nlm_get_uniq (cs->args.nlm4_cancargs.alock.caller_name); + if (nlmclnt == NULL) { + gf_log (GF_NLM, GF_LOG_ERROR, "nlm_get_uniq() returned NULL"); + goto nlm4err; + } + cs->fd = fd_lookup_uint64 (cs->resolvedloc.inode, (uint64_t)nlmclnt); + if (cs->fd == NULL) { + gf_log (GF_NLM, GF_LOG_ERROR, "fd_lookup_uint64 retrned NULL"); + goto nlm4err; + } + ret = nlm4_cancel_fd_resume (cs); + +nlm4err: + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_WARNING, "unable to unlock_fd_resume()"); stat = nlm4_errno_to_nlm4stat (-ret); + nlm4_generic_reply (cs->req, cs->args.nlm4_cancargs.cookie, + stat); + + nfs3_call_state_wipe (cs); + } + /* clean up is taken care of */ + return 0; +} + +int +nlm4svc_cancel (rpcsvc_request_t *req) +{ + xlator_t *vol = NULL; + nlm4_stats stat = nlm4_failed; + struct nfs_state *nfs = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + int ret = RPCSVC_ACTOR_ERROR; + struct nfs3_fh fh = {{0}, }; + + if (!req) + return ret; + + nlm4_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + nlm4_handle_call_state_init (nfs->nfs3state, cs, req, + stat, rpcerr); + + nlm4_prep_nlm4_cancargs (&cs->args.nlm4_cancargs, &fh, &cs->lkowner, + cs->cookiebytes); + if (xdr_to_nlm4_cancelargs(req->msg[0], &cs->args.nlm4_cancargs) <= 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; + } + + nlm4_validate_gluster_fh (&fh, stat, nlm4err); + nlm4_map_fh_to_volume (cs->nfs3state, fh, req, vol, stat, nlm4err); + + if (nlm_grace_period) { + gf_log (GF_NLM, GF_LOG_WARNING, "NLM in grace period"); + stat = nlm4_denied_grace_period; + nlm4_generic_reply (req, cs->args.nlm4_unlockargs.cookie, stat); + nfs3_call_state_wipe (cs); + return 0; + } + + cs->vol = vol; + nlm4_volume_started_check (nfs3, vol, ret, rpcerr); + + ret = nfs3_fh_resolve_and_resume (cs, &fh, + NULL, nlm4_cancel_resume); + nlm4err: if (ret < 0) { - gf_log (GF_NLM, GF_LOG_ERROR, "unable to call lk()"); + gf_log (GF_NLM, GF_LOG_ERROR, "unable to resolve and resume"); nlm4_generic_reply (cs->req, cs->args.nlm4_cancargs.cookie, stat); nfs3_call_state_wipe (cs); + return 0; } +rpcerr: + if (ret < 0) { + nfs3_call_state_wipe (cs); + } return ret; } @@ -1474,7 +1650,6 @@ err: int nlm4_unlock_fd_resume (void *carg) { - nlm4_stats stat = nlm4_denied; int ret = -EFAULT; nfs_user_t nfu = {0, }; nfs3_call_state_t *cs = NULL; @@ -1483,7 +1658,6 @@ nlm4_unlock_fd_resume (void *carg) if (!carg) return ret; cs = (nfs3_call_state_t *)carg; - nlm4_check_fh_resolve_status (cs, stat, nlm4err); nfs_request_user_init (&nfu, cs->req); nlm4_lock_to_gf_flock (&flock, &cs->args.nlm4_unlockargs.alock, 0); nlm_copy_lkowner (&nfu.lk_owner, &cs->args.nlm4_unlockargs.alock.oh); @@ -1491,21 +1665,11 @@ nlm4_unlock_fd_resume (void *carg) ret = nfs_lk (cs->nfsx, cs->vol, &nfu, cs->fd, F_SETLK, &flock, nlm4svc_unlock_cbk, cs); - if (ret < 0) - stat = nlm4_errno_to_nlm4stat (-ret); -nlm4err: - if (ret < 0) { - gf_log (GF_NLM, GF_LOG_ERROR, "unable to call lk()"); - nlm4_generic_reply (cs->req, cs->args.nlm4_unlockargs.cookie, - stat); - nfs3_call_state_wipe (cs); - } - return ret; } int -nlm4_cancel_resume (void *carg) +nlm4_unlock_resume (void *carg) { nlm4_stats stat = nlm4_failed; int ret = -1; @@ -1518,31 +1682,36 @@ nlm4_cancel_resume (void *carg) cs = (nfs3_call_state_t *)carg; nlm4_check_fh_resolve_status (cs, stat, nlm4err); - nlmclnt = nlm_get_uniq (cs->args.nlm4_cancargs.alock.caller_name); + nlmclnt = nlm_get_uniq (cs->args.nlm4_unlockargs.alock.caller_name); if (nlmclnt == NULL) { - gf_log (GF_NLM, GF_LOG_ERROR, "nlm_get_uniq() returned NULL"); + stat = nlm4_granted; + gf_log (GF_NLM, GF_LOG_WARNING, "nlm_get_uniq() returned NULL"); goto nlm4err; } cs->fd = fd_lookup_uint64 (cs->resolvedloc.inode, (uint64_t)nlmclnt); if (cs->fd == NULL) { - gf_log (GF_NLM, GF_LOG_ERROR, "nlm_get_uniq() returned NULL"); + stat = nlm4_granted; + gf_log (GF_NLM, GF_LOG_WARNING, "fd_lookup_uint64() returned " + "NULL"); goto nlm4err; } - ret = nlm4_cancel_fd_resume (cs); + ret = nlm4_unlock_fd_resume (cs); nlm4err: if (ret < 0) { - gf_log (GF_NLM, GF_LOG_ERROR, "unable to unlock_fd_resume()"); - nlm4_generic_reply (cs->req, cs->args.nlm4_cancargs.cookie, + gf_log (GF_NLM, GF_LOG_WARNING, "unable to unlock_fd_resume"); + stat = nlm4_errno_to_nlm4stat (-ret); + nlm4_generic_reply (cs->req, cs->args.nlm4_unlockargs.cookie, stat); + nfs3_call_state_wipe (cs); } - - return ret; + /* we have already taken care of cleanup */ + return 0; } int -nlm4svc_cancel (rpcsvc_request_t *req) +nlm4svc_unlock (rpcsvc_request_t *req) { xlator_t *vol = NULL; nlm4_stats stat = nlm4_failed; @@ -1560,9 +1729,10 @@ nlm4svc_cancel (rpcsvc_request_t *req) nlm4_handle_call_state_init (nfs->nfs3state, cs, req, stat, rpcerr); - nlm4_prep_nlm4_cancargs (&cs->args.nlm4_cancargs, &fh, &cs->lkowner, - cs->cookiebytes); - if (xdr_to_nlm4_cancelargs(req->msg[0], &cs->args.nlm4_cancargs) <= 0) { + nlm4_prep_nlm4_unlockargs (&cs->args.nlm4_unlockargs, &fh, &cs->lkowner, + cs->cookiebytes); + if (xdr_to_nlm4_unlockargs(req->msg[0], &cs->args.nlm4_unlockargs) <= 0) + { gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding args"); rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; @@ -1580,16 +1750,17 @@ nlm4svc_cancel (rpcsvc_request_t *req) } cs->vol = vol; + /* FIXME: check if trans is being used at all for unlock */ + cs->trans = rpcsvc_request_transport_ref(req); nlm4_volume_started_check (nfs3, vol, ret, rpcerr); ret = nfs3_fh_resolve_and_resume (cs, &fh, - NULL, nlm4_cancel_resume); + NULL, nlm4_unlock_resume); nlm4err: if (ret < 0) { gf_log (GF_NLM, GF_LOG_ERROR, "unable to resolve and resume"); - nlm4_generic_reply (cs->req, cs->args.nlm4_cancargs.cookie, - stat); + nlm4_generic_reply (req, cs->args.nlm4_unlockargs.cookie, stat); nfs3_call_state_wipe (cs); return 0; } @@ -1602,53 +1773,393 @@ rpcerr: } int -nlm4_unlock_resume (void *carg) +nlm4_share_reply (nfs3_call_state_t *cs, nlm4_stats stat) { - nlm4_stats stat = nlm4_failed; - int ret = -1; - nfs3_call_state_t *cs = NULL; - nlm_client_t *nlmclnt = NULL; + nlm4_shareres res = {{0}, 0, 0}; - if (!carg) + if (!cs) + return -1; + + res.cookie = cs->args.nlm4_shareargs.cookie; + res.stat = stat; + res.sequence = 0; + + nlm4svc_submit_reply (cs->req, (void *)&res, + (nlm4_serializer)xdr_serialize_nlm4_shareres); + return 0; +} + +nlm_share_t * +nlm4_share_new () +{ + nlm_share_t *share = NULL; + + share = GF_CALLOC (1, sizeof (nlm_share_t), + gf_nfs_mt_nlm4_share); + if (!share) + goto out; + + INIT_LIST_HEAD (&share->client_list); + INIT_LIST_HEAD (&share->inode_list); + out: + return share; +} + +int +nlm4_add_share_to_inode (nlm_share_t *share) +{ + int ret = -1; + uint64_t ctx = 0; + struct list_head *head = NULL; + xlator_t *this = NULL; + inode_t *inode = NULL; + struct nfs_inode_ctx *ictx = NULL; + struct nfs_state *priv = NULL; + + this = THIS; + priv = this->private; + inode = share->inode; + ret = inode_ctx_get (inode, this, &ctx); + + if (ret == -1) { + ictx = GF_CALLOC (1, sizeof (struct nfs_inode_ctx), + gf_nfs_mt_inode_ctx); + if (!ictx ) { + gf_log (this->name, GF_LOG_ERROR, + "could not allocate nfs inode ctx"); + ret = -1; + goto out; + } + ictx->generation = priv->generation; + + head = &ictx->shares; + INIT_LIST_HEAD (head); + + ret = inode_ctx_put (inode, this, (uint64_t)ictx); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "could not store share list"); + goto out; + } + } + else { + ictx = (struct nfs_inode_ctx *)ctx; + head = &ictx->shares; + } + + list_add (&share->inode_list, head); + + out: + if (ret && head) + GF_FREE (head); + + return ret; +} + +int +nlm4_approve_share_reservation (nfs3_call_state_t *cs) +{ + int ret = -1; + uint64_t ctx = 0; + fsh_mode req_mode = 0; + fsh_access req_access = 0; + inode_t *inode = NULL; + nlm_share_t *share = NULL; + struct list_head *head = NULL; + struct nfs_inode_ctx *ictx = NULL; + + if (!cs) + goto out; + + inode = cs->resolvedloc.inode; + + ret = inode_ctx_get (inode, THIS, &ctx); + if (ret) { + ret = 0; + goto out; + } + ictx = (struct nfs_inode_ctx *)ctx; + + head = &ictx->shares; + if (!head || list_empty (head)) + goto out; + + req_mode = cs->args.nlm4_shareargs.share.mode; + req_access = cs->args.nlm4_shareargs.share.access; + + list_for_each_entry (share, head, inode_list) { + ret = (((req_mode & share->access) == 0) && + ((req_access & share->mode) == 0)); + if (!ret) { + ret = -1; + goto out; + } + } + ret = 0; + + out: + return ret; +} + +int +nlm4_create_share_reservation (nfs3_call_state_t *cs) +{ + int ret = -1; + nlm_share_t *share = NULL; + nlm_client_t *client = NULL; + inode_t *inode = NULL; + + LOCK (&nlm_client_list_lk); + + inode = inode_ref (cs->resolvedloc.inode); + if (!inode) { + gf_log (GF_NLM, GF_LOG_ERROR, "inode not found"); + goto out; + } + + client = __nlm_get_uniq (cs->args.nlm4_shareargs.share.caller_name); + if (!client) { + /* DO NOT add client. the client is supposed + to be here, since nlm4svc_share adds it */ + gf_log (GF_NLM, GF_LOG_ERROR, "client not found"); + goto out; + } + + ret = nlm4_approve_share_reservation (cs); + if (ret) + goto out; + + share = nlm4_share_new (); + if (!share) { + ret = -1; + goto out; + } + + share->inode = inode; + share->mode = cs->args.nlm4_shareargs.share.mode; + share->access = cs->args.nlm4_shareargs.share.access; + nlm_copy_lkowner (&share->lkowner, + &cs->args.nlm4_shareargs.share.oh); + + ret = nlm4_add_share_to_inode (share); + if (ret) + goto out; + + list_add (&share->client_list, &client->shares); + + out: + if (ret && inode) { + inode_unref (inode); + GF_FREE (share); + } + + UNLOCK (&nlm_client_list_lk); + return ret; +} + +/* + SHARE and UNSHARE calls DO NOT perform STACK_WIND, + the (non-monitored) share reservations are maintained + at *nfs xlator level only*, in memory +*/ +int +nlm4_share_resume (void *call_state) +{ + int ret = -1; + nlm4_stats stat = nlm4_failed; + nfs3_call_state_t *cs = NULL; + + if (!call_state) return ret; - cs = (nfs3_call_state_t *)carg; - nlm4_check_fh_resolve_status (cs, stat, nlm4err); + cs = (nfs3_call_state_t *)call_state; + nlm4_check_fh_resolve_status (cs, stat, out); - nlmclnt = nlm_get_uniq (cs->args.nlm4_unlockargs.alock.caller_name); - if (nlmclnt == NULL) { - gf_log (GF_NLM, GF_LOG_ERROR, "nlm_get_uniq() returned NULL"); - goto nlm4err; + ret = nlm4_create_share_reservation (cs); + if (!ret) + stat = nlm4_granted; + + out: + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; +} + +int +nlm4svc_share (rpcsvc_request_t *req) +{ + nlm4_stats stat = nlm4_failed; + xlator_t *vol = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + struct nfs_state *nfs = NULL; + struct nfs3_fh fh = {{0}, }; + int ret = RPCSVC_ACTOR_ERROR; + + if (!req) + return ret; + + nlm4_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + nlm4_handle_call_state_init (nfs->nfs3state, cs, req, + stat, rpcerr); + + nlm4_prep_shareargs (&cs->args.nlm4_shareargs, &cs->lockfh, + &cs->lkowner, cs->cookiebytes); + + if (xdr_to_nlm4_shareargs (req->msg[0], + &cs->args.nlm4_shareargs) <= 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding SHARE args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; } - cs->fd = fd_lookup_uint64 (cs->resolvedloc.inode, (uint64_t)nlmclnt); - if (cs->fd == NULL) { - gf_log (GF_NLM, GF_LOG_ERROR, "fd_lookup_uint64() returned NULL"); - goto nlm4err; + + fh = cs->lockfh; + nlm4_validate_gluster_fh (&fh, stat, nlm4err); + nlm4_map_fh_to_volume (cs->nfs3state, fh, req, + vol, stat, nlm4err); + + if (nlm_grace_period && !cs->args.nlm4_shareargs.reclaim) { + gf_log (GF_NLM, GF_LOG_DEBUG, "NLM in grace period"); + stat = nlm4_denied_grace_period; + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; } - ret = nlm4_unlock_fd_resume (cs); -nlm4err: + cs->vol = vol; + cs->trans = rpcsvc_request_transport_ref(req); + nlm4_volume_started_check (nfs3, vol, ret, rpcerr); + + ret = nlm_add_nlmclnt (cs->args.nlm4_shareargs.share.caller_name); + + ret = nfs3_fh_resolve_and_resume (cs, &fh, NULL, nlm4_share_resume); + + nlm4err: if (ret < 0) { - gf_log (GF_NLM, GF_LOG_ERROR, "unable to unlock_fd_resume"); - nlm4_generic_reply (cs->req, cs->args.nlm4_unlockargs.cookie, - stat); + gf_log (GF_NLM, GF_LOG_ERROR, "SHARE call failed"); + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; + } + rpcerr: + if (ret < 0) nfs3_call_state_wipe (cs); + + return ret; +} + +int +nlm4_remove_share_reservation (nfs3_call_state_t *cs) +{ + int ret = -1; + uint64_t ctx = 0; + fsh_mode req_mode = 0; + fsh_access req_access = 0; + nlm_share_t *share = NULL; + nlm_share_t *tmp = NULL; + nlm_client_t *client = NULL; + char *caller = NULL; + inode_t *inode = NULL; + xlator_t *this = NULL; + struct list_head *head = NULL; + nlm4_shareargs *args = NULL; + struct nfs_inode_ctx *ictx = NULL; + + LOCK (&nlm_client_list_lk); + + args = &cs->args.nlm4_shareargs; + caller = args->share.caller_name; + + client = __nlm_get_uniq (caller); + if (!client) { + gf_log (GF_NLM, GF_LOG_ERROR, + "client not found: %s", caller); + goto out; + } + + inode = cs->resolvedloc.inode; + if (!inode) { + gf_log (GF_NLM, GF_LOG_ERROR, + "inode not found: client: %s", caller); + goto out; + } + + this = THIS; + ret = inode_ctx_get (inode, this, &ctx); + if (ret) { + gf_log (GF_NLM, GF_LOG_ERROR, + "no shares found for inode:" + "gfid: %s; client: %s", + inode->gfid, caller); + goto out; + } + ictx = (struct nfs_inode_ctx *)ctx; + + head = &ictx->shares; + if (list_empty (head)) { + ret = -1; + goto out; + } + + ret = 0; + req_mode = args->share.mode; + req_access = args->share.access; + + list_for_each_entry_safe (share, tmp, head, inode_list) { + ret = ((req_mode == share->mode) && + (req_access == share->access) && + nlm_is_oh_same_lkowner (&share->lkowner, &args->share.oh)); + if (ret) { + list_del (&share->client_list); + list_del (&share->inode_list); + inode_unref (share->inode); + GF_FREE (share); + break; + } } + ret = 0; + out: + UNLOCK (&nlm_client_list_lk); return ret; + } int -nlm4svc_unlock (rpcsvc_request_t *req) +nlm4_unshare_resume (void *call_state) { - xlator_t *vol = NULL; - nlm4_stats stat = nlm4_failed; - struct nfs_state *nfs = NULL; - nfs3_state_t *nfs3 = NULL; - nfs3_call_state_t *cs = NULL; - int ret = RPCSVC_ACTOR_ERROR; - struct nfs3_fh fh = {{0}, }; + int ret = -1; + nlm4_stats stat = nlm4_failed; + nfs3_call_state_t *cs = NULL; + + if (!call_state) + return ret; + + cs = (nfs3_call_state_t *)call_state; + + nlm4_check_fh_resolve_status (cs, stat, out); + ret = nlm4_remove_share_reservation (cs); + if (!ret) + stat = nlm4_granted; + + out: + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; +} + +int +nlm4svc_unshare (rpcsvc_request_t *req) +{ + nlm4_stats stat = nlm4_failed; + xlator_t *vol = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + struct nfs_state *nfs = NULL; + struct nfs3_fh fh = {{0}, }; + int ret = RPCSVC_ACTOR_ERROR; if (!req) return ret; @@ -1658,22 +2169,25 @@ nlm4svc_unlock (rpcsvc_request_t *req) nlm4_handle_call_state_init (nfs->nfs3state, cs, req, stat, rpcerr); - nlm4_prep_nlm4_unlockargs (&cs->args.nlm4_unlockargs, &fh, &cs->lkowner, - cs->cookiebytes); - if (xdr_to_nlm4_unlockargs(req->msg[0], &cs->args.nlm4_unlockargs) <= 0) - { - gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding args"); + nlm4_prep_shareargs (&cs->args.nlm4_shareargs, &cs->lockfh, + &cs->lkowner, cs->cookiebytes); + + if (xdr_to_nlm4_shareargs (req->msg[0], + &cs->args.nlm4_shareargs) <= 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding UNSHARE args"); rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } + fh = cs->lockfh; nlm4_validate_gluster_fh (&fh, stat, nlm4err); - nlm4_map_fh_to_volume (cs->nfs3state, fh, req, vol, stat, nlm4err); + nlm4_map_fh_to_volume (cs->nfs3state, fh, req, + vol, stat, nlm4err); - if (nlm_grace_period) { - gf_log (GF_NLM, GF_LOG_WARNING, "NLM in grace period"); + if (nlm_grace_period && !cs->args.nlm4_shareargs.reclaim) { + gf_log (GF_NLM, GF_LOG_DEBUG, "NLM in grace period"); stat = nlm4_denied_grace_period; - nlm4_generic_reply (req, cs->args.nlm4_unlockargs.cookie, stat); + nlm4_share_reply (cs, stat); nfs3_call_state_wipe (cs); return 0; } @@ -1682,22 +2196,90 @@ nlm4svc_unlock (rpcsvc_request_t *req) cs->trans = rpcsvc_request_transport_ref(req); nlm4_volume_started_check (nfs3, vol, ret, rpcerr); - ret = nfs3_fh_resolve_and_resume (cs, &fh, - NULL, nlm4_unlock_resume); + ret = nfs3_fh_resolve_and_resume (cs, &fh, NULL, + nlm4_unshare_resume); -nlm4err: + nlm4err: if (ret < 0) { - gf_log (GF_NLM, GF_LOG_ERROR, "unable to resolve and resume"); - nlm4_generic_reply (req, cs->args.nlm4_unlockargs.cookie, stat); - nfs3_call_state_wipe (cs); + gf_log (GF_NLM, GF_LOG_ERROR, "UNSHARE call failed"); + nlm4_share_reply (cs, stat); + ret = 0; return 0; } -rpcerr: - if (ret < 0) { + rpcerr: + if (ret < 0) nfs3_call_state_wipe (cs); + + return ret; +} + +int +nlm4_free_all_shares (char *caller_name) +{ + nlm_share_t *share = NULL; + nlm_share_t *tmp = NULL; + nlm_client_t *client = NULL; + + LOCK (&nlm_client_list_lk); + + client = __nlm_get_uniq (caller_name); + if (!client) { + gf_log (GF_NLM, GF_LOG_DEBUG, + "client not found: %s", caller_name); + goto out; } + + list_for_each_entry_safe (share, tmp, &client->shares, client_list) { + list_del (&share->inode_list); + list_del (&share->client_list); + inode_unref (share->inode); + GF_FREE (share); + } + out: + UNLOCK (&nlm_client_list_lk); + return 0; +} + +int +nlm4svc_free_all (rpcsvc_request_t *req) +{ + int ret = RPCSVC_ACTOR_ERROR; + nlm4_stats stat = nlm4_failed; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + struct nfs_state *nfs = NULL; + + nlm4_validate_nfs3_state (req, nfs3, stat, err, ret); + nfs = nfs_state (nfs3->nfsx); + nlm4_handle_call_state_init (nfs->nfs3state, cs, + req, stat, err); + + nlm4_prep_freeallargs (&cs->args.nlm4_freeallargs, + &cs->lkowner); + + if (xdr_to_nlm4_freeallargs (req->msg[0], + &cs->args.nlm4_freeallargs) <= 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding FREE_ALL args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto err; + } + + ret = nlm4_free_all_shares (cs->args.nlm4_freeallargs.name); + if (ret) + goto err; + + ret = nlm_cleanup_fds (cs->args.nlm4_freeallargs.name); + if (ret) + goto err; + + err: + nfs3_call_state_wipe (cs); + if (ret) + gf_log (GF_NLM, GF_LOG_DEBUG, + "error in free all; stat: %d", stat); return ret; + } void @@ -1711,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, NULL}, - {"TEST", NLM4_TEST, nlm4svc_test, NULL, NULL}, - {"LOCK", NLM4_LOCK, nlm4svc_lock, NULL, NULL}, - {"CANCEL", NLM4_CANCEL, nlm4svc_cancel, NULL, NULL}, - {"UNLOCK", NLM4_UNLOCK, nlm4svc_unlock, NULL, 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, NULL}, - {"TEST", NLM4_TEST_MSG, NULL, NULL, NULL}, - {"LOCK", NLM4_LOCK_MSG, NULL, NULL, NULL}, - {"CANCEL", NLM4_CANCEL_MSG, NULL, NULL, NULL}, - {"UNLOCK", NLM4_UNLOCK_MSG, NULL, 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, NULL}, - {"TEST", NLM4_TEST_RES, NULL, NULL, NULL}, - {"LOCK", NLM4_LOCK_RES, NULL, NULL, NULL}, - {"CANCEL", NLM4_CANCEL_RES, NULL, NULL, NULL}, - {"UNLOCK", NLM4_UNLOCK_RES, NULL, NULL, NULL}, - /* 15 ; 17,18,19 are dummy actors */ - {"GRANTED", NLM4_GRANTED_RES, NULL, NULL, NULL}, - {"SM_NOTIFY", NLM4_SM_NOTIFY, NULL, NULL, NULL}, - {"SEVENTEEN", NLM4_SEVENTEEN, NULL, NULL, NULL}, - {"EIGHTEEN", NLM4_EIGHTEEN, NULL, NULL, NULL}, - {"NINETEEN", NLM4_NINETEEN, NULL, 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, 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, NULL, NULL, NULL}, - {"UNSHARE", NLM4_UNSHARE, NULL, NULL, NULL}, - {"NM_LOCK", NLM4_NM_LOCK, NULL, NULL, NULL}, - {"FREE_ALL", NLM4_FREE_ALL, nlm4svc_null, NULL, 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 = { @@ -1774,7 +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; @@ -1820,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); @@ -1839,11 +2428,36 @@ nlm4svc_init(xlator_t *nfsx) } /* temporary work around to restart statd, not distro/OS independant. * Need to figure out a more graceful way + * killall will cause problems on solaris. */ - ret = runcmd ("killall", "-9", "rpc.statd", NULL); - /* if ret == -1, do nothing - case statd was not already running */ - ret = runcmd ("rpc.statd", NULL); + pidfile = fopen ("/var/run/rpc.statd.pid", "r"); + if (pidfile) { + ret = fscanf (pidfile, "%d", &pid); + if (ret <= 0) { + gf_log (GF_NLM, GF_LOG_WARNING, "unable to get pid of " + "rpc.statd"); + ret = runcmd ("killall", "-9", "rpc.statd", NULL); + } else + kill (pid, SIGKILL); + + fclose (pidfile); + } else { + gf_log (GF_NLM, GF_LOG_WARNING, "opening the pid file of " + "rpc.statd failed (%s)", strerror (errno)); + /* if ret == -1, do nothing - case either statd was not + * running or was running in valgrind mode + */ + ret = runcmd ("killall", "-9", "rpc.statd", NULL); + } + + ret = unlink ("/var/run/rpc.statd.pid"); + if (ret == -1 && errno != ENOENT) { + gf_log (GF_NLM, GF_LOG_ERROR, "unable to unlink rpc.statd"); + goto err; + } + + ret = runcmd ("/sbin/rpc.statd", NULL); if (ret == -1) { gf_log (GF_NLM, GF_LOG_ERROR, "unable to start rpc.statd"); goto err; @@ -1851,8 +2465,61 @@ 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; } + +int32_t +nlm_priv (xlator_t *this) +{ + int32_t ret = -1; + uint32_t client_count = 0; + uint64_t file_count = 0; + nlm_client_t *client = NULL; + nlm_fde_t *fde = NULL; + char key[GF_DUMP_MAX_BUF_LEN] = {0}; + char gfid_str[64] = {0}; + + gf_proc_dump_add_section("nfs.nlm"); + + if (TRY_LOCK (&nlm_client_list_lk)) + goto out; + + list_for_each_entry (client, &nlm_client_list, nlm_clients) { + + gf_proc_dump_build_key (key, "client", "%d.hostname", client_count); + gf_proc_dump_write (key, "%s\n", client->caller_name); + + file_count = 0; + list_for_each_entry (fde, &client->fdes, fde_list) { + gf_proc_dump_build_key (key, "file", "%ld.gfid", file_count); + memset (gfid_str, 0, 64); + uuid_utoa_r (fde->fd->inode->gfid, gfid_str); + gf_proc_dump_write (key, "%s", gfid_str); + file_count++; + } + + gf_proc_dump_build_key (key, "client", "files-locked"); + gf_proc_dump_write (key, "%ld\n", file_count); + client_count++; + } + + gf_proc_dump_build_key (key, "nlm", "client-count"); + gf_proc_dump_write (key, "%d", client_count); + ret = 0; + UNLOCK (&nlm_client_list_lk); + + out: + if (ret) { + gf_proc_dump_build_key (key, "nlm", "statedump_error"); + gf_proc_dump_write (key, "Unable to dump nlm state because " + "nlm_client_list_lk lock couldn't be acquired"); + } + + return ret; +} |
