nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=8:tabstop=8: 00003 * 00004 * Copyright (C) 2012, The Linux Box Corporation 00005 * Contributor : Matt Benjamin <matt@linuxbox.com> 00006 * 00007 * Some portions Copyright CEA/DAM/DIF (2008) 00008 * contributeur : Philippe DENIEL philippe.deniel@cea.fr 00009 * Thomas LEIBOVICI thomas.leibovici@cea.fr 00010 * 00011 * 00012 * This program is free software; you can redistribute it and/or 00013 * modify it under the terms of the GNU Lesser General Public 00014 * License as published by the Free Software Foundation; either 00015 * version 3 of the License, or (at your option) any later version. 00016 * 00017 * This program is distributed in the hope that it will be useful, 00018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00020 * Lesser General Public License for more details. 00021 * 00022 * You should have received a copy of the GNU Lesser General Public 00023 * License along with this library; if not, write to the Free Software 00024 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00025 * 00026 * ------------- 00027 */ 00028 00029 #ifdef HAVE_CONFIG_H 00030 #include "config.h" 00031 #endif 00032 00033 #ifdef _SOLARIS 00034 #include "solaris_port.h" 00035 #endif /* _SOLARIS */ 00036 00037 #include <unistd.h> 00038 #include <sys/types.h> 00039 #include <sys/stat.h> 00040 #include <sys/param.h> 00041 #include <time.h> 00042 #include <pthread.h> 00043 #include <assert.h> 00044 #include <arpa/inet.h> 00045 #include "nlm_list.h" 00046 #include "fsal.h" 00047 #include "nfs_core.h" 00048 #include "log.h" 00049 #include "nfs_rpc_callback.h" 00050 #include "nfs4.h" 00051 #include "gssd.h" 00052 #include "gss_util.h" 00053 #include "krb5_util.h" 00054 #include "sal_data.h" 00055 00069 static pool_t *rpc_call_pool; 00070 00071 /* tried to re-use host_name in nfs_main.c, but linker became confused. 00072 * this is a quick fix */ 00073 static char host_name[MAXHOSTNAMELEN]; 00074 00075 00076 static inline void 00077 nfs_rpc_cb_init_ccache(const char *ccache) 00078 { 00079 int code = 0; 00080 00081 mkdir(ccache, 700); /* XXX */ 00082 ccachesearch[0] = nfs_param.krb5_param.ccache_dir; 00083 00084 code = gssd_refresh_krb5_machine_credential( 00085 host_name, NULL, nfs_param.krb5_param.svc.principal); 00086 if (code) { 00087 LogDebug(COMPONENT_INIT, "gssd_refresh_krb5_machine_credential " 00088 "failed (%d:%d)", code, errno); 00089 goto out; 00090 } 00091 00092 out: 00093 return; 00094 } 00095 00096 /* 00097 * Initialize subsystem 00098 */ 00099 void nfs_rpc_cb_pkginit(void) 00100 { 00101 char localmachine[MAXHOSTNAMELEN]; 00102 00103 /* Create a pool of rpc_call_t */ 00104 rpc_call_pool = pool_init("RPC Call Pool", 00105 sizeof(rpc_call_t), 00106 pool_basic_substrate, 00107 NULL, 00108 nfs_rpc_init_call, 00109 NULL); 00110 if(!(rpc_call_pool)) { 00111 LogCrit(COMPONENT_INIT, 00112 "Error while allocating rpc call pool"); 00113 LogError(COMPONENT_INIT, ERR_SYS, ERR_MALLOC, errno); 00114 Fatal(); 00115 } 00116 00117 /* get host name */ 00118 if(gethostname(localmachine, sizeof(localmachine)) != 0) { 00119 LogCrit(COMPONENT_INIT, "Failed to get local host name"); 00120 } 00121 else 00122 strlcpy(host_name, localmachine, MAXHOSTNAMELEN); 00123 00124 /* ccache */ 00125 nfs_rpc_cb_init_ccache(nfs_param.krb5_param.ccache_dir); 00126 00127 /* sanity check GSSAPI */ 00128 if (gssd_check_mechs() != 0) 00129 LogCrit(COMPONENT_INIT, "sanity check: gssd_check_mechs() failed"); 00130 00131 return; 00132 } 00133 00134 /* 00135 * Shutdown subsystem 00136 */ 00137 void nfs_rpc_cb_pkgshutdown(void) 00138 { 00139 /* do nothing */ 00140 } 00141 00142 /* XXXX this is automatically redundant, but in fact upstream TI-RPC is 00143 * not up-to-date with RFC 5665, will fix (Matt) 00144 * 00145 * (c) 2012, Linux Box Corp 00146 */ 00147 00148 nc_type nfs_netid_to_nc(const char *netid) 00149 { 00150 if (! strncmp(netid, netid_nc_table[_NC_TCP].netid, 00151 netid_nc_table[_NC_TCP].netid_len)) 00152 return(_NC_TCP); 00153 00154 if (! strncmp(netid, netid_nc_table[_NC_TCP6].netid, 00155 netid_nc_table[_NC_TCP6].netid_len)) 00156 return(_NC_TCP6); 00157 00158 if (! strncmp(netid, netid_nc_table[_NC_UDP].netid, 00159 netid_nc_table[_NC_UDP].netid_len)) 00160 return (_NC_UDP); 00161 00162 if (! strncmp(netid, netid_nc_table[_NC_UDP6].netid, 00163 netid_nc_table[_NC_UDP6].netid_len)) 00164 return (_NC_UDP6); 00165 00166 if (! strncmp(netid, netid_nc_table[_NC_RDMA].netid, 00167 netid_nc_table[_NC_RDMA].netid_len)) 00168 return (_NC_RDMA); 00169 00170 if (! strncmp(netid, netid_nc_table[_NC_RDMA6].netid, 00171 netid_nc_table[_NC_RDMA6].netid_len)) 00172 return (_NC_RDMA6); 00173 00174 if (! strncmp(netid, netid_nc_table[_NC_SCTP].netid, 00175 netid_nc_table[_NC_SCTP].netid_len)) 00176 return (_NC_SCTP); 00177 00178 if (! strncmp(netid, netid_nc_table[_NC_SCTP6].netid, 00179 netid_nc_table[_NC_SCTP6].netid_len)) 00180 return (_NC_SCTP6); 00181 00182 return (_NC_ERR); 00183 } 00184 00185 static inline void 00186 setup_client_saddr(nfs_client_id_t *pclientid, const char *uaddr) 00187 { 00188 char addr_buf[SOCK_NAME_MAX]; 00189 uint32_t bytes[11]; 00190 int code; 00191 00192 memset(&pclientid->cid_cb.cid_addr.ss, 0, sizeof(struct sockaddr_storage)); 00193 00194 switch (pclientid->cid_cb.cid_addr.nc) { 00195 case _NC_TCP: 00196 case _NC_RDMA: 00197 case _NC_SCTP: 00198 case _NC_UDP: 00199 /* IPv4 (ws inspired) */ 00200 if (sscanf(uaddr, "%u.%u.%u.%u.%u.%u", 00201 &bytes[1], &bytes[2], &bytes[3], &bytes[4], 00202 &bytes[5], &bytes[6]) == 6) { 00203 struct sockaddr_in *sin = 00204 (struct sockaddr_in *) &pclientid->cid_cb.cid_addr.ss; 00205 snprintf(addr_buf, SOCK_NAME_MAX, "%u.%u.%u.%u", 00206 bytes[1], bytes[2], 00207 bytes[3], bytes[4]); 00208 sin->sin_family = AF_INET; 00209 sin->sin_port = htons((bytes[5]<<8) | bytes[6]); 00210 code = inet_pton(AF_INET, addr_buf, &sin->sin_addr); 00211 if (code != 1) 00212 LogDebug(COMPONENT_NFS_CB, "inet_pton failed (%d %s)", 00213 code, addr_buf); 00214 else 00215 LogDebug(COMPONENT_NFS_CB, "client callback addr:port %s:%d", 00216 addr_buf, ntohs(sin->sin_port)); 00217 } 00218 break; 00219 case _NC_TCP6: 00220 case _NC_RDMA6: 00221 case _NC_SCTP6: 00222 case _NC_UDP6: 00223 /* IPv6 (ws inspired) */ 00224 if (sscanf(uaddr, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x.%u.%u", 00225 &bytes[1], &bytes[2], &bytes[3], &bytes[4], &bytes[5], 00226 &bytes[6], &bytes[7], &bytes[8], 00227 &bytes[9], &bytes[10]) == 10) { 00228 struct sockaddr_in6 *sin6 = 00229 (struct sockaddr_in6 *) &pclientid->cid_cb.cid_addr.ss; 00230 snprintf(addr_buf, SOCK_NAME_MAX, 00231 "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x", 00232 bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], 00233 bytes[6], bytes[7], bytes[8]); 00234 code = inet_pton(AF_INET6, addr_buf, &sin6->sin6_addr); 00235 sin6->sin6_port = htons((bytes[9]<<8) | bytes[10]); 00236 sin6->sin6_family = AF_INET6; 00237 if (code != 1) 00238 LogDebug(COMPONENT_NFS_CB, "inet_pton failed (%d %s)", 00239 code, addr_buf); 00240 else 00241 LogDebug(COMPONENT_NFS_CB, "client callback addr:port %s:%d", 00242 addr_buf, ntohs(sin6->sin6_port)); 00243 } 00244 break; 00245 default: 00246 /* unknown netid */ 00247 break; 00248 }; 00249 } 00250 00251 void nfs_set_client_location(nfs_client_id_t *pclientid, const clientaddr4 *addr4) 00252 { 00253 pclientid->cid_cb.cid_addr.nc = nfs_netid_to_nc(addr4->r_netid); 00254 strlcpy(pclientid->cid_cb.cid_client_r_addr, addr4->r_addr, 00255 SOCK_NAME_MAX); 00256 setup_client_saddr(pclientid, pclientid->cid_cb.cid_client_r_addr); 00257 } 00258 00259 static inline int32_t 00260 nfs_clid_connected_socket(nfs_client_id_t *pclientid, int *fd, int *proto) 00261 { 00262 struct sockaddr_in *sin; 00263 struct sockaddr_in6 *sin6; 00264 int nfd, code = 0; 00265 00266 *fd = 0; 00267 *proto = -1; 00268 00269 switch (pclientid->cid_cb.cid_addr.ss.ss_family) { 00270 case AF_INET: 00271 sin = (struct sockaddr_in *) &pclientid->cid_cb.cid_addr.ss; 00272 switch (pclientid->cid_cb.cid_addr.nc) { 00273 case _NC_TCP: 00274 nfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 00275 *proto = IPPROTO_TCP; 00276 break; 00277 case _NC_UDP: 00278 nfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 00279 *proto = IPPROTO_UDP; 00280 break; 00281 default: 00282 code = EINVAL; 00283 goto out; 00284 break; 00285 } 00286 00287 code = connect(nfd, (struct sockaddr *) sin, 00288 sizeof(struct sockaddr_in)); 00289 if (code == -1) { 00290 LogDebug(COMPONENT_NFS_CB, "connect fail errno %d", errno); 00291 goto out; 00292 } 00293 *fd = nfd; 00294 break; 00295 case AF_INET6: 00296 sin6 = (struct sockaddr_in6 *) &pclientid->cid_cb.cid_addr.ss; 00297 switch (pclientid->cid_cb.cid_addr.nc) { 00298 case _NC_TCP6: 00299 nfd = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); 00300 *proto = IPPROTO_TCP; 00301 break; 00302 case _NC_UDP6: 00303 nfd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); 00304 *proto = IPPROTO_UDP; 00305 break; 00306 default: 00307 code = EINVAL; 00308 goto out; 00309 break; 00310 } 00311 code = connect(nfd, (struct sockaddr *) sin6, 00312 sizeof(struct sockaddr_in6)); 00313 if (code == -1) { 00314 LogDebug(COMPONENT_NFS_CB, "connect fail errno %d", errno); 00315 goto out; 00316 } 00317 *fd = nfd; 00318 break; 00319 default: 00320 code = EINVAL; 00321 break; 00322 } 00323 00324 out: 00325 return (code); 00326 } 00327 00328 /* end refactorable RPC code */ 00329 00330 static inline bool_t 00331 supported_auth_flavor(int flavor) 00332 { 00333 bool_t code = FALSE; 00334 00335 switch (flavor) { 00336 case RPCSEC_GSS: 00337 case AUTH_SYS: 00338 case AUTH_NONE: 00339 code = TRUE; 00340 break; 00341 default: 00342 break; 00343 }; 00344 00345 return (code); 00346 } 00347 00348 /* from kerberos source, gssapi_krb5.c (Umich) */ 00349 gss_OID_desc krb5oid = 00350 {9, "\052\206\110\206\367\022\001\002\002"}; 00351 00352 static inline char * 00353 format_host_principal(rpc_call_channel_t *chan, char *buf, size_t len) 00354 { 00355 char addr_buf[SOCK_NAME_MAX]; 00356 const char *host = NULL; 00357 char *princ = NULL; 00358 00359 switch (chan->type) { 00360 case RPC_CHAN_V40: 00361 { 00362 nfs_client_id_t *pclientid = chan->nvu.v40.pclientid; 00363 switch (chan->nvu.v40.pclientid->cid_cb.cid_addr.ss.ss_family) { 00364 case AF_INET: 00365 { 00366 struct sockaddr_in *sin = (struct sockaddr_in *) &pclientid->cid_cb.cid_addr.ss; 00367 host = inet_ntop(AF_INET, &sin->sin_addr, addr_buf, 00368 INET_ADDRSTRLEN); 00369 break; 00370 } 00371 case AF_INET6: 00372 { 00373 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &pclientid->cid_cb.cid_addr.ss; 00374 host = inet_ntop(AF_INET6, &sin6->sin6_addr, addr_buf, 00375 INET6_ADDRSTRLEN); 00376 break; 00377 } 00378 default: 00379 break; 00380 } 00381 break; 00382 } 00383 case RPC_CHAN_V41: 00384 /* XXX implement */ 00385 goto out; 00386 break; 00387 } 00388 00389 if (host) { 00390 snprintf(buf, len, "nfs@%s", host); 00391 princ = buf; 00392 } 00393 00394 out: 00395 return (princ); 00396 } 00397 00398 static inline void 00399 nfs_rpc_callback_setup_gss(rpc_call_channel_t *chan, 00400 nfs_client_cred_t *cred) 00401 { 00402 AUTH *auth; 00403 char hprinc[MAXPATHLEN]; 00404 int32_t code = 0; 00405 00406 assert(cred->flavor == RPCSEC_GSS); 00407 00408 /* MUST RFC 3530bis, section 3.3.3 */ 00409 chan->gss_sec.svc = cred->auth_union.auth_gss.svc; 00410 chan->gss_sec.qop = cred->auth_union.auth_gss.qop; 00411 00412 /* the GSSAPI k5 mech needs to find an unexpired credential 00413 * for nfs/hostname in an accessible k5ccache */ 00414 code = gssd_refresh_krb5_machine_credential( 00415 host_name, NULL, nfs_param.krb5_param.svc.principal); 00416 if (code) { 00417 LogDebug(COMPONENT_NFS_CB, "gssd_refresh_krb5_machine_credential " 00418 "failed (%d:%d)", code, errno); 00419 goto out; 00420 } 00421 00422 if (! format_host_principal(chan, hprinc, MAXPATHLEN)) { 00423 LogCrit(COMPONENT_NFS_CB, "format_host_principal failed"); 00424 goto out; 00425 } 00426 00427 chan->gss_sec.cred = GSS_C_NO_CREDENTIAL; 00428 chan->gss_sec.req_flags = 0; 00429 00430 if (chan->gss_sec.svc != RPCSEC_GSS_SVC_NONE) { 00431 /* no more lipkey, spkm3 */ 00432 chan->gss_sec.mech = (gss_OID) &krb5oid; 00433 chan->gss_sec.req_flags = GSS_C_MUTUAL_FLAG; /* XXX */ 00434 auth = 00435 authgss_create_default(chan->clnt, 00436 hprinc, 00437 &chan->gss_sec); 00438 /* authgss_create and authgss_create_default return NULL on 00439 * failure, don't assign NULL to clnt->cl_auth */ 00440 if (auth) 00441 chan->clnt->cl_auth = auth; 00442 } 00443 00444 out: 00445 return; 00446 } 00447 00448 static inline bool_t 00449 nfs_rpc_callback_seccreate(rpc_call_channel_t *chan) 00450 { 00451 nfs_client_cred_t *credential = NULL; 00452 bool_t code = TRUE; 00453 AUTH *auth = NULL; 00454 00455 switch (chan->type) { 00456 case RPC_CHAN_V40: 00457 assert(&chan->nvu.v40.pclientid); 00458 credential = &chan->nvu.v40.pclientid->cid_credential; 00459 break; 00460 case RPC_CHAN_V41: 00461 /* XXX implement */ 00462 goto out; 00463 break; 00464 } 00465 00466 switch (credential->flavor) { 00467 case RPCSEC_GSS: 00468 nfs_rpc_callback_setup_gss(chan, credential); 00469 break; 00470 case AUTH_SYS: 00471 auth = authunix_create_default(); 00472 /* XXX see above */ 00473 if (auth) 00474 chan->clnt->cl_auth = auth; 00475 break; 00476 case AUTH_NONE: 00477 break; 00478 default: 00479 /* XXX prevented by forward check */ 00480 break; 00481 } 00482 00483 out: 00484 return (code); 00485 } 00486 00487 /* Create a channel for a new clientid (v4) or session, optionally 00488 * connecting it */ 00489 int nfs_rpc_create_chan_v40(nfs_client_id_t *pclientid, 00490 uint32_t flags) 00491 { 00492 struct netbuf raddr; 00493 int fd, proto, code = 0; 00494 rpc_call_channel_t *chan = &pclientid->cid_cb.cb_u.v40.cb_chan; 00495 00496 00497 00498 assert(! chan->clnt); 00499 00500 /* XXX we MUST error RFC 3530bis, sec. 3.3.3 */ 00501 if (! supported_auth_flavor(pclientid->cid_credential.flavor)) { 00502 code = EINVAL; 00503 goto out; 00504 } 00505 00506 chan->type = RPC_CHAN_V40; 00507 chan->nvu.v40.pclientid = pclientid; 00508 00509 code = nfs_clid_connected_socket(pclientid, &fd, &proto); 00510 if (code) { 00511 LogDebug(COMPONENT_NFS_CB, 00512 "Failed creating socket"); 00513 goto out; 00514 } 00515 00516 raddr.buf = &pclientid->cid_cb.cid_addr.ss; 00517 00518 switch (proto) { 00519 case IPPROTO_TCP: 00520 raddr.maxlen = raddr.len = sizeof(struct sockaddr_in); 00521 chan->clnt = clnt_vc_create(fd, 00522 &raddr, 00523 pclientid->cid_cb.cid_program, 00524 1 /* Errata ID: 2291 */, 00525 0, 0); 00526 break; 00527 case IPPROTO_UDP: 00528 raddr.maxlen = raddr.len = sizeof(struct sockaddr_in6); 00529 chan->clnt = clnt_dg_create(fd, 00530 &raddr, 00531 pclientid->cid_cb.cid_program, 00532 1 /* Errata ID: 2291 */, 00533 0, 0); 00534 break; 00535 default: 00536 break; 00537 } 00538 00539 if (! chan->clnt) { 00540 code = EINVAL; 00541 goto out; 00542 } 00543 00544 /* channel protection */ 00545 if (! nfs_rpc_callback_seccreate(chan)) { 00546 /* XXX */ 00547 code = EINVAL; 00548 } 00549 00550 out: 00551 return (code); 00552 } 00553 00554 rpc_call_channel_t * 00555 nfs_rpc_get_chan(nfs_client_id_t *pclientid, uint32_t flags) 00556 { 00557 /* XXX v41 */ 00558 rpc_call_channel_t *chan = &pclientid->cid_cb.cb_u.v40.cb_chan; 00559 00560 if (! chan->clnt) { 00561 nfs_rpc_create_chan_v40(pclientid, flags); 00562 } 00563 00564 return (chan); 00565 } 00566 00567 /* Dispose a channel. */ 00568 void nfs_rpc_destroy_chan(rpc_call_channel_t *chan) 00569 { 00570 assert(chan); 00571 00572 /* XXX lock, wait for outstanding calls, etc */ 00573 00574 switch (chan->type) { 00575 case RPC_CHAN_V40: 00576 /* channel has a dedicated RPC client */ 00577 if (chan->clnt) { 00578 /* clean up auth, if any */ 00579 if (chan->clnt->cl_auth) 00580 AUTH_DESTROY(chan->clnt->cl_auth); 00581 /* destroy it */ 00582 clnt_destroy(chan->clnt); 00583 chan->clnt = NULL; 00584 } 00585 break; 00586 case RPC_CHAN_V41: 00587 /* XXX channel is shared */ 00588 break; 00589 } 00590 00591 chan->clnt = NULL; 00592 chan->last_called = 0; 00593 } 00594 00595 /* 00596 * Call the NFSv4 client's CB_NULL procedure. 00597 */ 00598 enum clnt_stat 00599 rpc_cb_null(rpc_call_channel_t *chan, struct timeval timeout) 00600 { 00601 enum clnt_stat stat = RPC_SUCCESS; 00602 00603 /* XXX TI-RPC does the signal masking */ 00604 pthread_mutex_lock(&chan->mtx); 00605 00606 if (! chan->clnt) { 00607 stat = RPC_INTR; 00608 goto unlock; 00609 } 00610 00611 stat = clnt_call(chan->clnt, CB_NULL, 00612 (xdrproc_t) xdr_void, NULL, 00613 (xdrproc_t) xdr_void, NULL, timeout); 00614 00615 /* If a call fails, we have to assume path down, or equally fatal 00616 * error. We may need back-off. */ 00617 if (stat != RPC_SUCCESS) { 00618 if (chan->clnt) { 00619 clnt_destroy(chan->clnt); 00620 chan->clnt = NULL; 00621 } 00622 } 00623 00624 unlock: 00625 pthread_mutex_unlock(&chan->mtx); 00626 00627 return (stat); 00628 } 00629 00630 static inline void free_argop(nfs_cb_argop4 *op) 00631 { 00632 gsh_free(op); 00633 } 00634 00635 static inline void free_resop(nfs_cb_resop4 *op) 00636 { 00637 gsh_free(op); 00638 } 00639 00640 rpc_call_t *alloc_rpc_call() 00641 { 00642 rpc_call_t *call; 00643 00644 call = pool_alloc(rpc_call_pool, NULL); 00645 00646 return (call); 00647 } 00648 00649 void free_rpc_call(rpc_call_t *call) 00650 { 00651 free_argop(call->cbt.v_u.v4.args.argarray.argarray_val); 00652 free_resop(call->cbt.v_u.v4.res.resarray.resarray_val); 00653 pool_free(rpc_call_pool, call); 00654 } 00655 00656 static inline void RPC_CALL_HOOK(rpc_call_t *call, rpc_call_hook hook, 00657 void* arg, uint32_t flags) 00658 { 00659 if (call) 00660 (void) call->call_hook(call, hook, arg, flags); 00661 } 00662 00663 int32_t 00664 nfs_rpc_submit_call(rpc_call_t *call, uint32_t flags) 00665 { 00666 int32_t code = 0; 00667 request_data_t *pnfsreq = NULL; 00668 rpc_call_channel_t *chan = call->chan; 00669 00670 assert(chan); 00671 00672 if (flags & NFS_RPC_CALL_INLINE) { 00673 code = nfs_rpc_dispatch_call(call, NFS_RPC_CALL_NONE); 00674 } 00675 else { 00676 /* select a thread from the general thread pool */ 00677 int32_t thrd_ix; 00678 nfs_worker_data_t *worker; 00679 00680 thrd_ix = nfs_core_select_worker_queue( WORKER_INDEX_ANY ); 00681 worker = &workers_data[thrd_ix]; 00682 00683 LogFullDebug(COMPONENT_NFS_CB, 00684 "Use request from Worker Thread #%u's pool, thread has %d " 00685 "pending requests", 00686 thrd_ix, 00687 worker->pending_request_len); 00688 00689 pnfsreq = nfs_rpc_get_nfsreq(worker, 0 /* flags */); 00690 pthread_mutex_lock(&call->we.mtx); 00691 call->states = NFS_CB_CALL_QUEUED; 00692 pnfsreq->rtype = NFS_CALL; 00693 pnfsreq->r_u.call = call; 00694 DispatchWorkNFS(pnfsreq, thrd_ix); 00695 pthread_mutex_unlock(&call->we.mtx); 00696 } 00697 00698 return (code); 00699 } 00700 00701 int32_t 00702 nfs_rpc_dispatch_call(rpc_call_t *call, uint32_t flags) 00703 { 00704 int code = 0; 00705 struct timeval CB_TIMEOUT = {15, 0}; /* XXX */ 00706 00707 /* send the call, set states, wake waiters, etc */ 00708 pthread_mutex_lock(&call->we.mtx); 00709 00710 switch (call->states) { 00711 case NFS_CB_CALL_DISPATCH: 00712 case NFS_CB_CALL_FINISHED: 00713 /* XXX invalid entry states for nfs_rpc_dispatch_call */ 00714 abort(); 00715 } 00716 00717 call->states = NFS_CB_CALL_DISPATCH; 00718 pthread_mutex_unlock(&call->we.mtx); 00719 00720 /* XXX TI-RPC does the signal masking */ 00721 pthread_mutex_lock(&call->chan->mtx); 00722 00723 if (! call->chan->clnt) { 00724 call->stat = RPC_INTR; 00725 goto unlock; 00726 } 00727 00728 call->stat = clnt_call(call->chan->clnt, 00729 CB_COMPOUND, 00730 (xdrproc_t) xdr_CB_COMPOUND4args, 00731 &call->cbt.v_u.v4.args, 00732 (xdrproc_t) xdr_CB_COMPOUND4res, 00733 &call->cbt.v_u.v4.res, 00734 CB_TIMEOUT); 00735 00736 /* If a call fails, we have to assume path down, or equally fatal 00737 * error. We may need back-off. */ 00738 if (call->stat != RPC_SUCCESS) { 00739 if (call->chan->clnt) { 00740 clnt_destroy(call->chan->clnt); 00741 call->chan->clnt = NULL; 00742 } 00743 } 00744 00745 unlock: 00746 pthread_mutex_unlock(&call->chan->mtx); 00747 00748 /* signal waiter(s) */ 00749 pthread_mutex_lock(&call->we.mtx); 00750 call->states |= NFS_CB_CALL_FINISHED; 00751 00752 /* broadcast will generally be inexpensive */ 00753 if (call->flags & NFS_RPC_CALL_BROADCAST) 00754 pthread_cond_broadcast(&call->we.cv); 00755 pthread_mutex_unlock(&call->we.mtx); 00756 00757 /* call completion hook */ 00758 RPC_CALL_HOOK(call, RPC_CALL_COMPLETE, NULL, NFS_RPC_CALL_NONE); 00759 00760 return (code); 00761 } 00762 00763 int32_t 00764 nfs_rpc_abort_call(rpc_call_t *call) 00765 { 00766 return (0); 00767 } 00768