diff options
Diffstat (limited to 'usr/src/uts/common/klm')
-rw-r--r-- | usr/src/uts/common/klm/nlm_impl.h | 8 | ||||
-rw-r--r-- | usr/src/uts/common/klm/nlm_rpc_handle.c | 21 | ||||
-rw-r--r-- | usr/src/uts/common/klm/nlm_rpc_svc.c | 80 | ||||
-rw-r--r-- | usr/src/uts/common/klm/nlm_service.c | 120 |
4 files changed, 162 insertions, 67 deletions
diff --git a/usr/src/uts/common/klm/nlm_impl.h b/usr/src/uts/common/klm/nlm_impl.h index 68604309a2..9caae1a8c7 100644 --- a/usr/src/uts/common/klm/nlm_impl.h +++ b/usr/src/uts/common/klm/nlm_impl.h @@ -28,7 +28,7 @@ */ /* - * Copyright 2012 Nexenta Systems, Inc. All rights reserved. + * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. * Copyright 2016 Joyent, Inc. */ @@ -112,7 +112,7 @@ struct _kthread; * We pass three callback functions to nlm_do_lock: * nlm_reply_cb: send a normal RPC reply * nlm_res_cb: do a _res (message style) RPC (call) - * nlm_testargs_cb: do a "granted" RPC call (after blocking) + * nlm_granted_cb: do a "granted" RPC call (after blocking) * Only one of the 1st or 2nd is used. * The 3rd is used only for blocking * @@ -123,7 +123,7 @@ struct _kthread; */ typedef bool_t (*nlm_reply_cb)(SVCXPRT *, nlm4_res *); typedef enum clnt_stat (*nlm_res_cb)(nlm4_res *, void *, CLIENT *); -typedef enum clnt_stat (*nlm_testargs_cb)(nlm4_testargs *, void *, CLIENT *); +typedef enum clnt_stat (*nlm_granted_cb)(nlm4_testargs *, nlm4_res *, CLIENT *); typedef enum clnt_stat (*nlm_testres_cb)(nlm4_testres *, void *, CLIENT *); /* @@ -624,7 +624,7 @@ void nlm_do_notify2(nlm_sm_status *, void *, struct svc_req *); void nlm_do_test(nlm4_testargs *, nlm4_testres *, struct svc_req *, nlm_testres_cb); void nlm_do_lock(nlm4_lockargs *, nlm4_res *, struct svc_req *, - nlm_reply_cb, nlm_res_cb, nlm_testargs_cb); + nlm_reply_cb, nlm_res_cb, nlm_granted_cb); void nlm_do_cancel(nlm4_cancargs *, nlm4_res *, struct svc_req *, nlm_res_cb); void nlm_do_unlock(nlm4_unlockargs *, nlm4_res *, diff --git a/usr/src/uts/common/klm/nlm_rpc_handle.c b/usr/src/uts/common/klm/nlm_rpc_handle.c index 9ddf56856c..b022acc380 100644 --- a/usr/src/uts/common/klm/nlm_rpc_handle.c +++ b/usr/src/uts/common/klm/nlm_rpc_handle.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. */ @@ -130,6 +130,7 @@ update_host_rpcbinding(struct nlm_host *hostp, int vers) static int refresh_nlm_rpc(struct nlm_host *hostp, nlm_rpc_t *rpcp) { + uint32_t zero = 0; int ret; if (rpcp->nr_handle == NULL) { @@ -175,6 +176,12 @@ refresh_nlm_rpc(struct nlm_host *hostp, nlm_rpc_t *rpcp) if (NLM_STALE_CLNT(stat)) { ret = ESTALE; } + /* + * Need to reset the XID after the null call above, + * otherwise we'll reuse the XID from that call. + */ + (void) CLNT_CONTROL(rpcp->nr_handle, CLSET_XID, + (char *)&zero); } } @@ -209,7 +216,8 @@ again: rc = cv_wait_sig(&hostp->nh_rpcb_cv, &hostp->nh_lock); if (rc == 0) { mutex_exit(&hostp->nh_lock); - return (EINTR); + rc = EINTR; + goto errout; } } @@ -229,7 +237,8 @@ again: */ if (hostp->nh_rpcb_ustat != RPC_SUCCESS) { mutex_exit(&hostp->nh_lock); - return (ENOENT); + rc = ENOENT; + goto errout; } } @@ -263,7 +272,7 @@ again: } destroy_rpch(rpcp); - return (rc); + goto errout; } DTRACE_PROBE2(end, struct nlm_host *, hostp, @@ -271,6 +280,10 @@ again: *rpcpp = rpcp; return (0); + +errout: + NLM_ERR("Can't get RPC client handle for: %s", hostp->nh_name); + return (rc); } void diff --git a/usr/src/uts/common/klm/nlm_rpc_svc.c b/usr/src/uts/common/klm/nlm_rpc_svc.c index 2911b31877..1f04e3f036 100644 --- a/usr/src/uts/common/klm/nlm_rpc_svc.c +++ b/usr/src/uts/common/klm/nlm_rpc_svc.c @@ -26,7 +26,7 @@ */ /* - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. */ @@ -63,7 +63,7 @@ * 32-bit lock ranges. */ static void -nlm_convert_to_nlm_lock(struct nlm_lock *dst, struct nlm4_lock *src) +nlm_convert_to_nlm_lock(struct nlm_lock *dst, const struct nlm4_lock *src) { dst->caller_name = src->caller_name; dst->fh = src->fh; @@ -76,12 +76,22 @@ nlm_convert_to_nlm_lock(struct nlm_lock *dst, struct nlm4_lock *src) } /* + * Up-convert for v1 granted response + */ +static void +nlm_convert_to_nlm4_res(struct nlm4_res *dst, const struct nlm_res *src) +{ + dst->cookie = src->cookie; + dst->stat.stat = (nlm4_stats) src->stat.stat; +} + +/* * Up-convert for v1 svc functions with a 32-bit lock range arg. * Note that lock range checks (like overflow) are done later, * in nlm_init_flock(). */ static void -nlm_convert_to_nlm4_lock(struct nlm4_lock *dst, struct nlm_lock *src) +nlm_convert_to_nlm4_lock(struct nlm4_lock *dst, const struct nlm_lock *src) { dst->caller_name = src->caller_name; @@ -93,7 +103,7 @@ nlm_convert_to_nlm4_lock(struct nlm4_lock *dst, struct nlm_lock *src) } static void -nlm_convert_to_nlm4_share(struct nlm4_share *dst, struct nlm_share *src) +nlm_convert_to_nlm4_share(struct nlm4_share *dst, const struct nlm_share *src) { dst->caller_name = src->caller_name; @@ -113,7 +123,7 @@ nlm_convert_to_nlm4_share(struct nlm4_share *dst, struct nlm_share *src) * valid 32-bit lock range. */ static void -nlm_convert_to_nlm_holder(struct nlm_holder *dst, struct nlm4_holder *src) +nlm_convert_to_nlm_holder(struct nlm_holder *dst, const struct nlm4_holder *src) { dst->exclusive = src->exclusive; dst->svid = src->svid; @@ -133,7 +143,7 @@ nlm_convert_to_nlm_stats(enum nlm4_stats src) } static void -nlm_convert_to_nlm_res(struct nlm_res *dst, struct nlm4_res *src) +nlm_convert_to_nlm_res(struct nlm_res *dst, const struct nlm4_res *src) { dst->cookie = src->cookie; dst->stat.stat = nlm_convert_to_nlm_stats(src->stat.stat); @@ -175,7 +185,7 @@ nlm_test_1_svc(struct nlm_testargs *argp, nlm_testres *resp, * Callback functions for nlm_lock_1_svc */ static bool_t nlm_lock_1_reply(SVCXPRT *, nlm4_res *); -static enum clnt_stat nlm_granted_1_cb(nlm4_testargs *, void *, CLIENT *); +static enum clnt_stat nlm_granted_1_cb(nlm4_testargs *, nlm4_res *, CLIENT *); bool_t nlm_lock_1_svc(nlm_lockargs *argp, nlm_res *resp, @@ -215,7 +225,7 @@ nlm_lock_1_reply(SVCXPRT *transp, nlm4_res *resp) } static enum clnt_stat -nlm_granted_1_cb(nlm4_testargs *argp, void *resp, CLIENT *clnt) +nlm_granted_1_cb(nlm4_testargs *argp, nlm4_res *resp, CLIENT *clnt) { nlm_testargs args1; nlm_res res1; @@ -229,9 +239,7 @@ nlm_granted_1_cb(nlm4_testargs *argp, void *resp, CLIENT *clnt) rv = nlm_granted_1(&args1, &res1, clnt); - /* NB: We have a result our caller will not free. */ - xdr_free((xdrproc_t)xdr_nlm_res, (void *)&res1); - (void) resp; + nlm_convert_to_nlm4_res(resp, &res1); return (rv); } @@ -355,7 +363,8 @@ nlm_test_res_1_cb(nlm4_testres *res4, void *null, CLIENT *clnt) * Callback functions for nlm_lock_msg_1_svc */ static enum clnt_stat nlm_lock_res_1_cb(nlm4_res *, void *, CLIENT *); -static enum clnt_stat nlm_granted_msg_1_cb(nlm4_testargs *, void *, CLIENT *); +static enum clnt_stat nlm_granted_msg_1_cb(nlm4_testargs *, nlm4_res *, + CLIENT *); bool_t nlm_lock_msg_1_svc(nlm_lockargs *argp, void *resp, @@ -396,16 +405,22 @@ nlm_lock_res_1_cb(nlm4_res *resp, void *null, CLIENT *clnt) } static enum clnt_stat -nlm_granted_msg_1_cb(nlm4_testargs *argp, void *null, CLIENT *clnt) +nlm_granted_msg_1_cb(nlm4_testargs *argp, nlm4_res *resp, CLIENT *clnt) { nlm_testargs args1; + int rv; args1.cookie = argp->cookie; args1.exclusive = argp->exclusive; nlm_convert_to_nlm_lock(&args1.alock, &argp->alock); - return (nlm_granted_msg_1(&args1, null, clnt)); + rv = nlm_granted_msg_1(&args1, NULL, clnt); + + /* MSG call doesn't fill in *resp, so do it here. */ + if (rv != RPC_SUCCESS) + resp->stat.stat = nlm4_failed; + return (rv); } @@ -693,7 +708,6 @@ nlm4_test_4_svc(nlm4_testargs *argp, nlm4_testres *resp, struct svc_req *sr) * Callback functions for nlm4_lock_4_svc */ static bool_t nlm4_lock_4_reply(SVCXPRT *, nlm4_res *); -static enum clnt_stat nlm4_granted_4_cb(nlm4_testargs *, void *, CLIENT *); bool_t nlm4_lock_4_svc(nlm4_lockargs *argp, nlm4_res *resp, @@ -703,7 +717,7 @@ nlm4_lock_4_svc(nlm4_lockargs *argp, nlm4_res *resp, /* NLM4_LOCK */ nlm_do_lock(argp, resp, sr, nlm4_lock_4_reply, NULL, - nlm4_granted_4_cb); + nlm4_granted_4); /* above does its own reply */ return (FALSE); @@ -715,22 +729,6 @@ nlm4_lock_4_reply(SVCXPRT *transp, nlm4_res *resp) return (svc_sendreply(transp, xdr_nlm4_res, (char *)resp)); } -static enum clnt_stat -nlm4_granted_4_cb(nlm4_testargs *argp, void *resp, CLIENT *clnt) -{ - nlm4_res res4; - int rv; - - bzero(&res4, sizeof (res4)); - rv = nlm4_granted_4(argp, &res4, clnt); - - /* NB: We have a result our caller will not free. */ - xdr_free((xdrproc_t)xdr_nlm4_res, (void *)&res4); - (void) resp; - - return (rv); -} - bool_t nlm4_cancel_4_svc(nlm4_cancargs *argp, nlm4_res *resp, struct svc_req *sr) { @@ -773,6 +771,8 @@ nlm4_test_msg_4_svc(nlm4_testargs *argp, void *resp, struct svc_req *sr) * Callback functions for nlm4_lock_msg_4_svc * (using the RPC client stubs directly) */ +static enum clnt_stat nlm4_granted_msg_4_cb(nlm4_testargs *, nlm4_res *, + CLIENT *); bool_t nlm4_lock_msg_4_svc(nlm4_lockargs *argp, void *resp, @@ -784,7 +784,7 @@ nlm4_lock_msg_4_svc(nlm4_lockargs *argp, void *resp, bzero(&res4, sizeof (res4)); nlm_do_lock(argp, &res4, sr, NULL, nlm4_lock_res_4, - nlm4_granted_msg_4); + nlm4_granted_msg_4_cb); /* NB: We have a result our caller will not free. */ xdr_free((xdrproc_t)xdr_nlm4_res, (void *)&res4); @@ -794,6 +794,20 @@ nlm4_lock_msg_4_svc(nlm4_lockargs *argp, void *resp, return (FALSE); } +static enum clnt_stat +nlm4_granted_msg_4_cb(nlm4_testargs *argp, nlm4_res *resp, CLIENT *clnt) +{ + int rv; + + rv = nlm4_granted_msg_4(argp, NULL, clnt); + + /* MSG call doesn't fill in *resp, so do it here. */ + if (rv != RPC_SUCCESS) + resp->stat.stat = nlm4_failed; + + return (rv); +} + bool_t nlm4_cancel_msg_4_svc(nlm4_cancargs *argp, void *resp, struct svc_req *sr) { diff --git a/usr/src/uts/common/klm/nlm_service.c b/usr/src/uts/common/klm/nlm_service.c index dceabaf53f..f4f733443e 100644 --- a/usr/src/uts/common/klm/nlm_service.c +++ b/usr/src/uts/common/klm/nlm_service.c @@ -27,7 +27,7 @@ /* * Copyright (c) 2012, 2016 by Delphix. All rights reserved. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. * Copyright 2014 Joyent, Inc. All rights reserved. */ @@ -81,6 +81,7 @@ struct nlm_block_cb_data { struct nlm_host *hostp; struct nlm_vhold *nvp; struct flock64 *flp; + bool_t registered; }; /* @@ -107,9 +108,9 @@ static void nlm_block( nlm4_lockargs *lockargs, struct nlm_host *host, struct nlm_vhold *nvp, - nlm_rpc_t *rpcp, struct flock64 *fl, - nlm_testargs_cb grant_cb); + nlm_granted_cb grant_cb, + rpcvers_t); static vnode_t *nlm_fh_to_vp(struct netobj *); static struct nlm_vhold *nlm_fh_to_vhold(struct nlm_host *, struct netobj *); @@ -314,6 +315,11 @@ nlm_do_notify2(nlm_sm_status *argp, void *res, struct svc_req *sr) * NLM_TEST, NLM_TEST_MSG, * NLM4_TEST, NLM4_TEST_MSG, * Client inquiry about locks, non-blocking. + * + * Arg cb is NULL for NLM_TEST, NLM4_TEST, and + * non-NULL for NLM_TEST_MSG, NLM4_TEST_MSG + * The MSG forms use the cb to send the reply, + * and don't return a reply for this call. */ void nlm_do_test(nlm4_testargs *argp, nlm4_testres *resp, @@ -455,10 +461,19 @@ out: * We also have to keep a list of locks (pending + granted) * both to handle retransmitted requests, and to keep the * vnodes for those locks active. + * + * Callback arguments: + * reply_cb Used to send a normal RPC reply just as if + * we had filled in a response for our caller. + * Needed because we do work after the reply. + * res_cb Used for the MSG calls, where there's no + * regular RPC response. + * grant_cb Used to CALL the client informing them of a + * granted lock after a "blocked" reply. */ void nlm_do_lock(nlm4_lockargs *argp, nlm4_res *resp, struct svc_req *sr, - nlm_reply_cb reply_cb, nlm_res_cb res_cb, nlm_testargs_cb grant_cb) + nlm_reply_cb reply_cb, nlm_res_cb res_cb, nlm_granted_cb grant_cb) { struct nlm_globals *g; struct flock64 fl; @@ -492,20 +507,18 @@ nlm_do_lock(nlm4_lockargs *argp, nlm4_res *resp, struct svc_req *sr, struct nlm_host *, host, nlm4_lockargs *, argp); /* - * If we may need to do _msg_ call needing an RPC - * callback, get the RPC client handle now, - * so we know if we can bind to the NLM service on - * this client. - * - * Note: host object carries transport type. - * One client using multiple transports gets - * separate sysids for each of its transports. + * If this is a MSG call (NLM_LOCK_MSG, NLM4_LOCK_MSG) + * we'll have res_cb != NULL, and we know we'll need an + * RPC client handle _now_ so we can send the response. + * If we can't get an rpc handle (rpcp) then we have + * no way to respond, and the client will time out. */ - if (res_cb != NULL || (grant_cb != NULL && argp->block == TRUE)) { + if (res_cb != NULL) { error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp); if (error != 0) { + ASSERT(rpcp == NULL); status = nlm4_denied_nolocks; - goto doreply; + goto out; } } @@ -584,6 +597,8 @@ nlm_do_lock(nlm4_lockargs *argp, nlm4_res *resp, struct svc_req *sr, /* * OK, can detach this thread, so this call * will block below (after we reply). + * The "blocked" reply tells the client to + * expect a "granted" call-back later. */ status = nlm4_blocked; do_blocking = TRUE; @@ -655,11 +670,12 @@ doreply: * "detach" it from the RPC SVC pool, allowing it * to block indefinitely if needed. */ - ASSERT(rpcp != NULL); + ASSERT(grant_cb != NULL); (void) svc_detach_thread(sr->rq_xprt); - nlm_block(argp, host, nvp, rpcp, &fl, grant_cb); + nlm_block(argp, host, nvp, &fl, grant_cb, sr->rq_vers); } +out: DTRACE_PROBE3(lock__end, struct nlm_globals *, g, struct nlm_host *, host, nlm4_res *, resp); @@ -679,25 +695,26 @@ static void nlm_block(nlm4_lockargs *lockargs, struct nlm_host *host, struct nlm_vhold *nvp, - nlm_rpc_t *rpcp, struct flock64 *flp, - nlm_testargs_cb grant_cb) + nlm_granted_cb grant_cb, + rpcvers_t vers) { nlm4_testargs args; + nlm4_res res; int error; flk_callback_t flk_cb; struct nlm_block_cb_data cb_data; + nlm_rpc_t *rpcp = NULL; + enum clnt_stat status; /* * Keep a list of blocked locks on nh_pending, and use it * to cancel these threads in nlm_destroy_client_pending. * - * Check to see if this lock is already in the list - * and if not, add an entry for it. Allocate first, - * then if we don't insert, free the new one. - * Caller already has vp held. + * Check to see if this lock is already in the list. If so, + * some earlier call is already blocked getting this lock, + * so there's nothing more this call needs to do. */ - error = nlm_slreq_register(host, nvp, flp); if (error != 0) { /* @@ -710,9 +727,22 @@ nlm_block(nlm4_lockargs *lockargs, return; } + /* + * Make sure we can get an RPC client handle we can use to + * deliver the "granted" callback if/when we get the lock. + * If we can't, there's no point blocking to get the lock + * for them because they'll never find out about it. + */ + error = nlm_host_get_rpc(host, vers, &rpcp); + if (error != 0) { + (void) nlm_slreq_unregister(host, nvp, flp); + return; + } + cb_data.hostp = host; cb_data.nvp = nvp; cb_data.flp = flp; + cb_data.registered = TRUE; flk_init_callback(&flk_cb, nlm_block_callback, &cb_data); /* BSD: VOP_ADVLOCK(vp, NULL, F_SETLK, fl, F_REMOTE); */ @@ -720,23 +750,60 @@ nlm_block(nlm4_lockargs *lockargs, F_REMOTELOCK | FREAD | FWRITE, (u_offset_t)0, &flk_cb, CRED(), NULL); + /* + * If the nlm_block_callback didn't already do it... + */ + if (cb_data.registered) + (void) nlm_slreq_unregister(host, nvp, flp); + if (error != 0) { /* * We failed getting the lock, but have no way to * tell the client about that. Let 'em time out. */ - (void) nlm_slreq_unregister(host, nvp, flp); return; } - /* + * ... else we got the lock on behalf of this client. + * + * We MUST either tell the client about this lock + * (via the "granted" callback RPC) or unlock. + * * Do the "granted" call-back to the client. */ + bzero(&args, sizeof (args)); args.cookie = lockargs->cookie; args.exclusive = lockargs->exclusive; args.alock = lockargs->alock; + bzero(&res, sizeof (res)); + + /* + * Not using the NLM_INVOKE_CALLBACK() macro because + * we need to take actions on errors. + */ + status = (*grant_cb)(&args, &res, (rpcp)->nr_handle); + if (status != RPC_SUCCESS) { + struct rpc_err err; + + CLNT_GETERR((rpcp)->nr_handle, &err); + NLM_ERR("NLM: %s callback failed: " + "stat %d, err %d\n", "grant", status, + err.re_errno); + res.stat.stat = nlm4_failed; + } + if (res.stat.stat != nlm4_granted) { + /* + * Failed to deliver the granted callback, so + * the client doesn't know about this lock. + * Unlock the lock. The client will time out. + */ + (void) nlm_vop_frlock(nvp->nv_vp, F_UNLCK, flp, + F_REMOTELOCK | FREAD | FWRITE, + (u_offset_t)0, NULL, CRED(), NULL); + } + xdr_free((xdrproc_t)xdr_nlm4_res, (void *)&res); - NLM_INVOKE_CALLBACK("grant", rpcp, &args, grant_cb); + nlm_host_rele_rpc(host, rpcp); } /* @@ -756,6 +823,7 @@ nlm_block_callback(flk_cb_when_t when, void *data) if (when == FLK_AFTER_SLEEP) { (void) nlm_slreq_unregister(cb_data->hostp, cb_data->nvp, cb_data->flp); + cb_data->registered = FALSE; } return (0); |