diff options
author | Jeff Darcy <jdarcy@redhat.com> | 2014-04-28 14:18:50 +0000 |
---|---|---|
committer | Jeff Darcy <jdarcy@redhat.com> | 2014-04-28 14:18:50 +0000 |
commit | e139b4d0ba2286c0d4d44ba81260c2b287016019 (patch) | |
tree | 0a21f0761528e0f79da0a9f67106eb128ace0cf7 /rpc/rpc-lib/src/rpcsvc.c | |
parent | 73b60c87ca7f62517a8466431f5a8cf167589c8c (diff) | |
parent | f2bac9f9d5b9956969ddd25a54bc636b82f6923e (diff) |
Conflicts:
rpc/xdr/src/glusterfs3-xdr.c
rpc/xdr/src/glusterfs3-xdr.h
xlators/features/changelog/src/Makefile.am
xlators/features/changelog/src/changelog-helpers.h
xlators/features/changelog/src/changelog.c
xlators/mgmt/glusterd/src/glusterd-sm.c
Change-Id: I9972a5e6184503477eb77a8b56c50a4db4eec3e2
Diffstat (limited to 'rpc/rpc-lib/src/rpcsvc.c')
-rw-r--r-- | rpc/rpc-lib/src/rpcsvc.c | 200 |
1 files changed, 160 insertions, 40 deletions
diff --git a/rpc/rpc-lib/src/rpcsvc.c b/rpc/rpc-lib/src/rpcsvc.c index 8be64c18a..1c13048f2 100644 --- a/rpc/rpc-lib/src/rpcsvc.c +++ b/rpc/rpc-lib/src/rpcsvc.c @@ -29,6 +29,7 @@ #include "rpc-common-xdr.h" #include "syncop.h" #include "rpc-drc.h" +#include "protocol-common.h" #include <errno.h> #include <pthread.h> @@ -59,6 +60,9 @@ int rpcsvc_notify (rpc_transport_t *trans, void *mydata, rpc_transport_event_t event, void *data, ...); +static int +match_subnet_v4 (const char *addrtok, const char *ipaddr); + rpcsvc_notify_wrapper_t * rpcsvc_notify_wrapper_alloc (void) { @@ -129,32 +133,67 @@ rpcsvc_get_program_vector_sizer (rpcsvc_t *svc, uint32_t prognum, return NULL; } +gf_boolean_t +rpcsvc_can_outstanding_req_be_ignored (rpcsvc_request_t *req) +{ + /* + * If outstanding_rpc_limit is reached because of blocked locks and + * throttling is attempted then no unlock requests will be received. So + * the outstanding request count will never change i.e. it will always + * be equal to the limit. This also leads to ping timer expiry on + * client. + */ + + /* + * This is a hack and a necessity until grantedlock == fop completion. + * Ideally if we get a blocking lock request which cannot be granted + * right now, we should unwind the fop saying “request registered, will + * notify you when granted”, which is very hard to implement at the + * moment. Until we bring in such mechanism, we will need to live with + * not rate-limiting INODELK/ENTRYLK/LK fops + */ + + if ((req->prognum == GLUSTER_FOP_PROGRAM) && + (req->progver == GLUSTER_FOP_VERSION)) { + if ((req->procnum == GFS3_OP_INODELK) || + (req->procnum == GFS3_OP_FINODELK) || + (req->procnum == GFS3_OP_ENTRYLK) || + (req->procnum == GFS3_OP_FENTRYLK) || + (req->procnum == GFS3_OP_LK)) + return _gf_true; + } + return _gf_false; +} + int -rpcsvc_request_outstanding (rpcsvc_t *svc, rpc_transport_t *trans, int delta) +rpcsvc_request_outstanding (rpcsvc_request_t *req, int delta) { int ret = 0; int old_count = 0; int new_count = 0; int limit = 0; - pthread_mutex_lock (&trans->lock); + if (rpcsvc_can_outstanding_req_be_ignored (req)) + return 0; + + pthread_mutex_lock (&req->trans->lock); { - limit = svc->outstanding_rpc_limit; + limit = req->svc->outstanding_rpc_limit; if (!limit) goto unlock; - old_count = trans->outstanding_rpc_count; - trans->outstanding_rpc_count += delta; - new_count = trans->outstanding_rpc_count; + old_count = req->trans->outstanding_rpc_count; + req->trans->outstanding_rpc_count += delta; + new_count = req->trans->outstanding_rpc_count; if (old_count <= limit && new_count > limit) - ret = rpc_transport_throttle (trans, _gf_true); + ret = rpc_transport_throttle (req->trans, _gf_true); if (old_count > limit && new_count <= limit) - ret = rpc_transport_throttle (trans, _gf_false); + ret = rpc_transport_throttle (req->trans, _gf_false); } unlock: - pthread_mutex_unlock (&trans->lock); + pthread_mutex_unlock (&req->trans->lock); return ret; } @@ -315,7 +354,8 @@ rpcsvc_request_destroy (rpcsvc_request_t *req) to the client. It is time to decrement the outstanding request counter by 1. */ - rpcsvc_request_outstanding (req->svc, req->trans, -1); + if (req->prognum) //Only for initialized requests + rpcsvc_request_outstanding (req, -1); rpc_transport_unref (req->trans); @@ -397,12 +437,6 @@ rpcsvc_request_create (rpcsvc_t *svc, rpc_transport_t *trans, goto err; } - /* We just received a new request from the wire. Account for - it in the outsanding request counter to make sure we don't - ingest too many concurrent requests from the same client. - */ - ret = rpcsvc_request_outstanding (svc, trans, +1); - msgbuf = msg->vector[0].iov_base; msglen = msg->vector[0].iov_len; @@ -420,19 +454,28 @@ rpcsvc_request_create (rpcsvc_t *svc, rpc_transport_t *trans, ret = -1; rpcsvc_request_init (svc, trans, &rpcmsg, progmsg, msg, req); - gf_log (GF_RPCSVC, GF_LOG_TRACE, "received rpc-message (XID: 0x%lx, " - "Ver: %ld, Program: %ld, ProgVers: %ld, Proc: %ld) from" - " rpc-transport (%s)", rpc_call_xid (&rpcmsg), + gf_log (GF_RPCSVC, GF_LOG_TRACE, "received rpc-message " + "(XID: 0x%" GF_PRI_RPC_XID ", Ver: %" GF_PRI_RPC_VERSION ", Program: %" GF_PRI_RPC_PROG_ID ", " + "ProgVers: %" GF_PRI_RPC_PROG_VERS ", Proc: %" GF_PRI_RPC_PROC ") " + "from rpc-transport (%s)", rpc_call_xid (&rpcmsg), rpc_call_rpcvers (&rpcmsg), rpc_call_program (&rpcmsg), rpc_call_progver (&rpcmsg), rpc_call_progproc (&rpcmsg), trans->name); + /* We just received a new request from the wire. Account for + it in the outsanding request counter to make sure we don't + ingest too many concurrent requests from the same client. + */ + if (req->prognum) //Only for initialized requests + ret = rpcsvc_request_outstanding (req, +1); + if (rpc_call_rpcvers (&rpcmsg) != 2) { /* LOG- TODO: print rpc version, also print the peerinfo from transport */ gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC version not supported " - "(XID: 0x%lx, Ver: %ld, Prog: %ld, ProgVers: %ld, " - "Proc: %ld) from trans (%s)", rpc_call_xid (&rpcmsg), + "(XID: 0x%" GF_PRI_RPC_XID ", Ver: %" GF_PRI_RPC_VERSION ", Program: %" GF_PRI_RPC_PROG_ID ", " + "ProgVers: %" GF_PRI_RPC_PROG_VERS ", Proc: %" GF_PRI_RPC_PROC ") " + "from trans (%s)", rpc_call_xid (&rpcmsg), rpc_call_rpcvers (&rpcmsg), rpc_call_program (&rpcmsg), rpc_call_progver (&rpcmsg), rpc_call_progproc (&rpcmsg), trans->name); @@ -448,8 +491,9 @@ rpcsvc_request_create (rpcsvc_t *svc, rpc_transport_t *trans, */ rpcsvc_request_seterr (req, AUTH_ERROR); gf_log (GF_RPCSVC, GF_LOG_ERROR, "auth failed on request. " - "(XID: 0x%lx, Ver: %ld, Prog: %ld, ProgVers: %ld, " - "Proc: %ld) from trans (%s)", rpc_call_xid (&rpcmsg), + "(XID: 0x%" GF_PRI_RPC_XID ", Ver: %" GF_PRI_RPC_VERSION ", Program: %" GF_PRI_RPC_PROG_ID ", " + "ProgVers: %" GF_PRI_RPC_PROG_VERS ", Proc: %" GF_PRI_RPC_PROC ") " + "from trans (%s)", rpc_call_xid (&rpcmsg), rpc_call_rpcvers (&rpcmsg), rpc_call_program (&rpcmsg), rpc_call_progver (&rpcmsg), rpc_call_progproc (&rpcmsg), trans->name); @@ -794,15 +838,9 @@ err: return txrecord; } -static inline int -rpcsvc_get_callid (rpcsvc_t *rpc) -{ - return GF_UNIVERSAL_ANSWER; -} - int rpcsvc_fill_callback (int prognum, int progver, int procnum, int payload, - uint64_t xid, struct rpc_msg *request) + uint32_t xid, struct rpc_msg *request) { int ret = -1; @@ -867,9 +905,9 @@ out: return txrecord; } -struct iobuf * +static struct iobuf * rpcsvc_callback_build_record (rpcsvc_t *rpc, int prognum, int progver, - int procnum, size_t payload, uint64_t xid, + int procnum, size_t payload, u_long xid, struct iovec *recbuf) { struct rpc_msg request = {0, }; @@ -889,7 +927,7 @@ rpcsvc_callback_build_record (rpcsvc_t *rpc, int prognum, int progver, &request); if (ret == -1) { gf_log ("rpcsvc", GF_LOG_WARNING, "cannot build a rpc-request " - "xid (%"PRIu64")", xid); + "xid (%" GF_PRI_RPC_XID ")", xid); goto out; } @@ -936,7 +974,6 @@ rpcsvc_callback_submit (rpcsvc_t *rpc, rpc_transport_t *trans, rpc_transport_req_t req; int ret = -1; int proglen = 0; - uint64_t callid = 0; if (!rpc) { goto out; @@ -944,15 +981,14 @@ rpcsvc_callback_submit (rpcsvc_t *rpc, rpc_transport_t *trans, memset (&req, 0, sizeof (req)); - callid = rpcsvc_get_callid (rpc); - if (proghdr) { proglen += iov_length (proghdr, proghdrcount); } request_iob = rpcsvc_callback_build_record (rpc, prog->prognum, prog->progver, procnum, - proglen, callid, + proglen, + GF_UNIVERSAL_ANSWER, &rpchdr); if (!request_iob) { gf_log ("rpcsvc", GF_LOG_WARNING, @@ -1253,7 +1289,7 @@ rpcsvc_program_register_portmap (rpcsvc_program_t *newprog, uint32_t port) if (!(pmap_set (newprog->prognum, newprog->progver, IPPROTO_TCP, port))) { gf_log (GF_RPCSVC, GF_LOG_ERROR, "Could not register with" - " portmap"); + " portmap %d %d %u", newprog->prognum, newprog->progver, port); goto out; } @@ -2181,6 +2217,13 @@ rpcsvc_transport_peer_check_search (dict_t *options, char *pattern, goto err; } + /* Compare IPv4 subnetwork */ + if (strchr (addrtok, '/')) { + ret = match_subnet_v4 (addrtok, ip); + if (ret == 0) + goto err; + } + addrtok = strtok_r (NULL, ",", &svptr); } @@ -2327,8 +2370,20 @@ rpcsvc_auth_check (rpcsvc_t *svc, char *volname, ret = dict_get_str (options, srchstr, &reject_str); GF_FREE (srchstr); - if (reject_str == NULL && !strcmp ("*", allow_str)) - return RPCSVC_AUTH_ACCEPT; + + /* + * If "reject_str" is being set as '*' (anonymous), then NFS-server + * would reject everything. If the "reject_str" is not set and + * "allow_str" is set as '*' (anonymous), then NFS-server would + * accept mount requests from all clients. + */ + if (reject_str != NULL) { + if (!strcmp ("*", reject_str)) + return RPCSVC_AUTH_REJECT; + } else { + if (!strcmp ("*", allow_str)) + return RPCSVC_AUTH_ACCEPT; + } /* Non-default rule, authenticate */ if (!get_host_name (client_ip, &ip)) @@ -2461,6 +2516,71 @@ out: return addrstr; } +/* + * match_subnet_v4() takes subnetwork address pattern and checks + * if the target IPv4 address has the same network address with + * the help of network mask. + * + * Returns 0 for SUCCESS and -1 otherwise. + * + * NB: Validation of subnetwork address pattern is not required + * as it's already being done at the time of CLI SET. + */ +static int +match_subnet_v4 (const char *addrtok, const char *ipaddr) +{ + char *slash = NULL; + char *netaddr = NULL; + long prefixlen = -1; + int ret = -1; + uint32_t shift = 0; + struct sockaddr_in sin1 = {0, }; + struct sockaddr_in sin2 = {0, }; + struct sockaddr_in mask = {0, }; + + /* Copy the input */ + netaddr = gf_strdup (addrtok); + if (netaddr == NULL) /* ENOMEM */ + goto out; + + /* Find the network socket addr of target */ + if (inet_pton (AF_INET, ipaddr, &sin1.sin_addr) == 0) + goto out; + + /* Find the network socket addr of subnet pattern */ + slash = strchr (netaddr, '/'); + *slash = '\0'; + if (inet_pton (AF_INET, netaddr, &sin2.sin_addr) == 0) + goto out; + + /* + * Find the network mask in network byte order. + * NB: 32 : Max len of IPv4 address. + */ + prefixlen = atoi (slash + 1); + shift = 32 - (uint32_t)prefixlen; + mask.sin_addr.s_addr = htonl ((uint32_t)~0 << shift); + + /* + * Check if both have same network address. + * Extract the network address from the IP addr by applying the + * network mask. If they match, return SUCCESS. i.e. + * + * (x == y) <=> (x ^ y == 0) + * (x & y) ^ (x & z) <=> x & (y ^ z) + * + * ((ip1 & mask) == (ip2 & mask)) <=> ((mask & (ip1 ^ ip2)) == 0) + */ + if (((mask.sin_addr.s_addr) & + (sin1.sin_addr.s_addr ^ sin2.sin_addr.s_addr)) != 0) + goto out; + + ret = 0; /* SUCCESS */ +out: + GF_FREE (netaddr); + return ret; +} + rpcsvc_actor_t gluster_dump_actors[] = { [GF_DUMP_NULL] = {"NULL", GF_DUMP_NULL, NULL, NULL, 0, DRC_NA}, |