Commit 126e216a authored by Trond Myklebust's avatar Trond Myklebust

SUNRPC: Don't spam gssd with upcall requests when the kerberos key expired

Now that the rpc.gssd daemon can explicitly tell us that the key expired,
we should cache that information to avoid spamming gssd.
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 9bb0b813
...@@ -54,6 +54,7 @@ struct rpc_cred { ...@@ -54,6 +54,7 @@ struct rpc_cred {
#define RPCAUTH_CRED_NEW 0 #define RPCAUTH_CRED_NEW 0
#define RPCAUTH_CRED_UPTODATE 1 #define RPCAUTH_CRED_UPTODATE 1
#define RPCAUTH_CRED_HASHED 2 #define RPCAUTH_CRED_HASHED 2
#define RPCAUTH_CRED_NEGATIVE 3
#define RPCAUTH_CRED_MAGIC 0x0f4aa4f0 #define RPCAUTH_CRED_MAGIC 0x0f4aa4f0
......
...@@ -82,6 +82,7 @@ struct gss_cred { ...@@ -82,6 +82,7 @@ struct gss_cred {
enum rpc_gss_svc gc_service; enum rpc_gss_svc gc_service;
struct gss_cl_ctx *gc_ctx; struct gss_cl_ctx *gc_ctx;
struct gss_upcall_msg *gc_upcall; struct gss_upcall_msg *gc_upcall;
unsigned long gc_upcall_timestamp;
unsigned char gc_machine_cred : 1; unsigned char gc_machine_cred : 1;
}; };
......
...@@ -57,6 +57,9 @@ static const struct rpc_authops authgss_ops; ...@@ -57,6 +57,9 @@ static const struct rpc_authops authgss_ops;
static const struct rpc_credops gss_credops; static const struct rpc_credops gss_credops;
static const struct rpc_credops gss_nullops; static const struct rpc_credops gss_nullops;
#define GSS_RETRY_EXPIRED 5
static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED;
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH # define RPCDBG_FACILITY RPCDBG_AUTH
#endif #endif
...@@ -349,6 +352,24 @@ gss_unhash_msg(struct gss_upcall_msg *gss_msg) ...@@ -349,6 +352,24 @@ gss_unhash_msg(struct gss_upcall_msg *gss_msg)
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
static void
gss_handle_downcall_result(struct gss_cred *gss_cred, struct gss_upcall_msg *gss_msg)
{
switch (gss_msg->msg.errno) {
case 0:
if (gss_msg->ctx == NULL)
break;
clear_bit(RPCAUTH_CRED_NEGATIVE, &gss_cred->gc_base.cr_flags);
gss_cred_set_ctx(&gss_cred->gc_base, gss_msg->ctx);
break;
case -EKEYEXPIRED:
set_bit(RPCAUTH_CRED_NEGATIVE, &gss_cred->gc_base.cr_flags);
}
gss_cred->gc_upcall_timestamp = jiffies;
gss_cred->gc_upcall = NULL;
rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
}
static void static void
gss_upcall_callback(struct rpc_task *task) gss_upcall_callback(struct rpc_task *task)
{ {
...@@ -358,13 +379,9 @@ gss_upcall_callback(struct rpc_task *task) ...@@ -358,13 +379,9 @@ gss_upcall_callback(struct rpc_task *task)
struct inode *inode = &gss_msg->inode->vfs_inode; struct inode *inode = &gss_msg->inode->vfs_inode;
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (gss_msg->ctx) gss_handle_downcall_result(gss_cred, gss_msg);
gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
else
task->tk_status = gss_msg->msg.errno;
gss_cred->gc_upcall = NULL;
rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
task->tk_status = gss_msg->msg.errno;
gss_release_msg(gss_msg); gss_release_msg(gss_msg);
} }
...@@ -513,18 +530,16 @@ gss_refresh_upcall(struct rpc_task *task) ...@@ -513,18 +530,16 @@ gss_refresh_upcall(struct rpc_task *task)
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (gss_cred->gc_upcall != NULL) if (gss_cred->gc_upcall != NULL)
rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
else if (gss_msg->ctx != NULL) { else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
gss_cred->gc_upcall = NULL;
rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
} else if (gss_msg->msg.errno >= 0) {
task->tk_timeout = 0; task->tk_timeout = 0;
gss_cred->gc_upcall = gss_msg; gss_cred->gc_upcall = gss_msg;
/* gss_upcall_callback will release the reference to gss_upcall_msg */ /* gss_upcall_callback will release the reference to gss_upcall_msg */
atomic_inc(&gss_msg->count); atomic_inc(&gss_msg->count);
rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback); rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback);
} else } else {
gss_handle_downcall_result(gss_cred, gss_msg);
err = gss_msg->msg.errno; err = gss_msg->msg.errno;
}
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
gss_release_msg(gss_msg); gss_release_msg(gss_msg);
out: out:
...@@ -1123,6 +1138,23 @@ static int gss_renew_cred(struct rpc_task *task) ...@@ -1123,6 +1138,23 @@ static int gss_renew_cred(struct rpc_task *task)
return 0; return 0;
} }
static int gss_cred_is_negative_entry(struct rpc_cred *cred)
{
if (test_bit(RPCAUTH_CRED_NEGATIVE, &cred->cr_flags)) {
unsigned long now = jiffies;
unsigned long begin, expire;
struct gss_cred *gss_cred;
gss_cred = container_of(cred, struct gss_cred, gc_base);
begin = gss_cred->gc_upcall_timestamp;
expire = begin + gss_expired_cred_retry_delay * HZ;
if (time_in_range_open(now, begin, expire))
return 1;
}
return 0;
}
/* /*
* Refresh credentials. XXX - finish * Refresh credentials. XXX - finish
*/ */
...@@ -1132,6 +1164,9 @@ gss_refresh(struct rpc_task *task) ...@@ -1132,6 +1164,9 @@ gss_refresh(struct rpc_task *task)
struct rpc_cred *cred = task->tk_msg.rpc_cred; struct rpc_cred *cred = task->tk_msg.rpc_cred;
int ret = 0; int ret = 0;
if (gss_cred_is_negative_entry(cred))
return -EKEYEXPIRED;
if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
!test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) { !test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) {
ret = gss_renew_cred(task); ret = gss_renew_cred(task);
...@@ -1585,5 +1620,11 @@ static void __exit exit_rpcsec_gss(void) ...@@ -1585,5 +1620,11 @@ static void __exit exit_rpcsec_gss(void)
} }
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_param_named(expired_cred_retry_delay,
gss_expired_cred_retry_delay,
uint, 0644);
MODULE_PARM_DESC(expired_cred_retry_delay, "Timeout (in seconds) until "
"the RPC engine retries an expired credential");
module_init(init_rpcsec_gss) module_init(init_rpcsec_gss)
module_exit(exit_rpcsec_gss) module_exit(exit_rpcsec_gss)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment