summaryrefslogtreecommitdiffstats
path: root/xlators/nfs/server/src/nlm4.c
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/nfs/server/src/nlm4.c')
-rw-r--r--xlators/nfs/server/src/nlm4.c1239
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;
+}