mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-11-07 04:36:52 -10:00
gss_impl.c: Fix a nfsd hang when the kgssapi.ko is loaded, but no gssd
After the conversion to using netlink, the kgssapi had no way of knowing if the gssd daemon was running. As such, a boot where the kgssapi is loaded, but the gssd is not enabled would hang the nfsd for a very long time. (Many timeouts at 300sec each.) This patch adds a Null RPC upcall with a 200msec timeout to check to see if the gssd is running. If the gssd is not running, the nfsd starts up (without Kerberos support) with only a 200msec delay.) Also, move the svc_svc_nl_create() and svc_reg() calls in gssd.c to before the daemon() call, so they are guaranteed to have been done before the nfsd(8) daemon is started by the rc scripts. PR: 295714 Reviewed by: glebius MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D57455
This commit is contained in:
1 parent
b3249ed3a6
commit
455c354dd4
2 files changed
+45
-19
No files matched your search
+40
-2
@@ -57,6 +57,7 @@ static int
|
||||
kgss_load(void)
|
||||
{
|
||||
CLIENT *cl;
|
||||
struct timeval nulltimo = {.tv_sec = 0, .tv_usec = 200000};
|
||||
|
||||
LIST_INIT(&kgss_mechs);
|
||||
|
||||
@@ -65,13 +66,16 @@ kgss_load(void)
|
||||
|
||||
/*
|
||||
* The transport default is no retries at all, since there could
|
||||
* be no userland listener to our messages. We will retry for 5
|
||||
* be no userland listener to our messages. Initially, a short timeout
|
||||
* is set, so that a Null RPC upcall will fail quickly if the daemon
|
||||
* is not running. After the Null RPC succeeds, we will retry for 5
|
||||
* minutes with 10 second interval. This will potentially cure hosts
|
||||
* with misconfigured startup, where kernel starts sending GSS queries
|
||||
* before userland had started up the gssd(8) daemon.
|
||||
* The initial timeout of 200usec is for the Null RPC.
|
||||
*/
|
||||
clnt_control(cl, CLSET_RETRIES, &(int){30});
|
||||
clnt_control(cl, CLSET_TIMEOUT, &(struct timeval){.tv_sec = 300});
|
||||
clnt_control(cl, CLSET_TIMEOUT, &nulltimo);
|
||||
|
||||
/*
|
||||
* We literally wait on gssd(8), let's see that in top(1).
|
||||
@@ -237,9 +241,43 @@ CLIENT *
|
||||
kgss_gssd_client(void)
|
||||
{
|
||||
CLIENT *cl;
|
||||
struct rpc_callextra ext;
|
||||
enum clnt_stat stat;
|
||||
struct timeval rpctimo = {.tv_sec = 300, .tv_usec = 0};
|
||||
static time_t nextrpc = 0;
|
||||
static bool done_upcall = false;
|
||||
|
||||
mtx_lock(&kgss_gssd_lock);
|
||||
cl = kgss_gssd_handle;
|
||||
if (!done_upcall) {
|
||||
mtx_unlock(&kgss_gssd_lock);
|
||||
/*
|
||||
* Can only be NULL if client_nl_create() called from
|
||||
* kgss_load() returns NULL.
|
||||
*/
|
||||
if (cl == NULL)
|
||||
return (cl);
|
||||
if (time_uptime < nextrpc)
|
||||
return (NULL);
|
||||
/*
|
||||
* Do a Null RPC with a short timeout. If the RPC succeeds,
|
||||
* the gssd daemon is running. If the Null RPC fails, don't
|
||||
* again for 5sec.
|
||||
*/
|
||||
memset(&ext, 0, sizeof(ext));
|
||||
ext.rc_auth = authnone_create();
|
||||
stat = clnt_call_private(cl, &ext, NULLPROC,
|
||||
(xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_void, NULL,
|
||||
rpctimo); /* rpctimo is ignored by clnt_nl_call(). */
|
||||
AUTH_DESTROY(ext.rc_auth);
|
||||
if (stat != RPC_SUCCESS) {
|
||||
nextrpc = time_uptime + 5;
|
||||
return (NULL);
|
||||
}
|
||||
CLNT_CONTROL(cl, CLSET_TIMEOUT, &rpctimo);
|
||||
mtx_lock(&kgss_gssd_lock);
|
||||
done_upcall = true;
|
||||
}
|
||||
if (cl != NULL)
|
||||
CLNT_ACQUIRE(cl);
|
||||
mtx_unlock(&kgss_gssd_lock);
|
||||
|
||||
+5
-17
@@ -167,6 +167,11 @@ main(int argc, char **argv)
|
||||
|
||||
gssd_load_mech();
|
||||
|
||||
if ((xprt = svc_nl_create("kgss")) == NULL)
|
||||
errx(1, "Can't create transport for local gssd socket");
|
||||
if (!svc_reg(xprt, GSSD, GSSDVERS, gssd_1, NULL))
|
||||
errx(1, "Can't register service for local gssd socket");
|
||||
|
||||
if (!debug_level) {
|
||||
if (daemon(0, 0) != 0)
|
||||
err(1, "Can't daemonize");
|
||||
@@ -177,23 +182,6 @@ main(int argc, char **argv)
|
||||
signal(SIGTERM, gssd_terminate);
|
||||
signal(SIGPIPE, gssd_terminate);
|
||||
|
||||
if ((xprt = svc_nl_create("kgss")) == NULL) {
|
||||
if (debug_level == 0) {
|
||||
syslog(LOG_ERR,
|
||||
"Can't create transport for local gssd socket");
|
||||
exit(1);
|
||||
}
|
||||
err(1, "Can't create transport for local gssd socket");
|
||||
}
|
||||
if (!svc_reg(xprt, GSSD, GSSDVERS, gssd_1, NULL)) {
|
||||
if (debug_level == 0) {
|
||||
syslog(LOG_ERR,
|
||||
"Can't register service for local gssd socket");
|
||||
exit(1);
|
||||
}
|
||||
err(1, "Can't register service for local gssd socket");
|
||||
}
|
||||
|
||||
LIST_INIT(&gss_resources);
|
||||
gss_next_id = 1;
|
||||
gss_start_time = time(0);
|
||||
|
||||
Reference in new issue
Block a user