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: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
9bb0b8136a
commit
126e216a87
@ -54,6 +54,7 @@ struct rpc_cred {
|
||||
#define RPCAUTH_CRED_NEW 0
|
||||
#define RPCAUTH_CRED_UPTODATE 1
|
||||
#define RPCAUTH_CRED_HASHED 2
|
||||
#define RPCAUTH_CRED_NEGATIVE 3
|
||||
|
||||
#define RPCAUTH_CRED_MAGIC 0x0f4aa4f0
|
||||
|
||||
|
@ -82,6 +82,7 @@ struct gss_cred {
|
||||
enum rpc_gss_svc gc_service;
|
||||
struct gss_cl_ctx *gc_ctx;
|
||||
struct gss_upcall_msg *gc_upcall;
|
||||
unsigned long gc_upcall_timestamp;
|
||||
unsigned char gc_machine_cred : 1;
|
||||
};
|
||||
|
||||
|
@ -57,6 +57,9 @@ static const struct rpc_authops authgss_ops;
|
||||
static const struct rpc_credops gss_credops;
|
||||
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
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
@ -349,6 +352,24 @@ gss_unhash_msg(struct gss_upcall_msg *gss_msg)
|
||||
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
|
||||
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;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
if (gss_msg->ctx)
|
||||
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);
|
||||
gss_handle_downcall_result(gss_cred, gss_msg);
|
||||
spin_unlock(&inode->i_lock);
|
||||
task->tk_status = gss_msg->msg.errno;
|
||||
gss_release_msg(gss_msg);
|
||||
}
|
||||
|
||||
@ -513,18 +530,16 @@ gss_refresh_upcall(struct rpc_task *task)
|
||||
spin_lock(&inode->i_lock);
|
||||
if (gss_cred->gc_upcall != NULL)
|
||||
rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
|
||||
else if (gss_msg->ctx != NULL) {
|
||||
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) {
|
||||
else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
|
||||
task->tk_timeout = 0;
|
||||
gss_cred->gc_upcall = gss_msg;
|
||||
/* gss_upcall_callback will release the reference to gss_upcall_msg */
|
||||
atomic_inc(&gss_msg->count);
|
||||
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;
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
gss_release_msg(gss_msg);
|
||||
out:
|
||||
@ -1123,6 +1138,23 @@ static int gss_renew_cred(struct rpc_task *task)
|
||||
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
|
||||
*/
|
||||
@ -1132,6 +1164,9 @@ gss_refresh(struct rpc_task *task)
|
||||
struct rpc_cred *cred = task->tk_msg.rpc_cred;
|
||||
int ret = 0;
|
||||
|
||||
if (gss_cred_is_negative_entry(cred))
|
||||
return -EKEYEXPIRED;
|
||||
|
||||
if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
|
||||
!test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) {
|
||||
ret = gss_renew_cred(task);
|
||||
@ -1585,5 +1620,11 @@ static void __exit exit_rpcsec_gss(void)
|
||||
}
|
||||
|
||||
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_exit(exit_rpcsec_gss)
|
||||
|
Loading…
Reference in New Issue
Block a user