mirror of
https://github.com/lkl/linux.git
synced 2025-12-19 16:13:19 +09:00
NFS: Fix up nfs_ctx_key_to_expire()
If the cached credential exists but doesn't have any expiration callback then exit early. Fix up atomicity issues when replacing the credential with a new one since the existing code could lead to refcount leaks. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
@@ -1024,7 +1024,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry,
|
|||||||
ctx->cred = get_cred(filp->f_cred);
|
ctx->cred = get_cred(filp->f_cred);
|
||||||
else
|
else
|
||||||
ctx->cred = get_current_cred();
|
ctx->cred = get_current_cred();
|
||||||
ctx->ll_cred = NULL;
|
rcu_assign_pointer(ctx->ll_cred, NULL);
|
||||||
ctx->state = NULL;
|
ctx->state = NULL;
|
||||||
ctx->mode = f_mode;
|
ctx->mode = f_mode;
|
||||||
ctx->flags = 0;
|
ctx->flags = 0;
|
||||||
@@ -1063,7 +1063,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
|
|||||||
put_cred(ctx->cred);
|
put_cred(ctx->cred);
|
||||||
dput(ctx->dentry);
|
dput(ctx->dentry);
|
||||||
nfs_sb_deactive(sb);
|
nfs_sb_deactive(sb);
|
||||||
put_rpccred(ctx->ll_cred);
|
put_rpccred(rcu_dereference_protected(ctx->ll_cred, 1));
|
||||||
kfree(ctx->mdsthreshold);
|
kfree(ctx->mdsthreshold);
|
||||||
kfree_rcu(ctx, rcu_head);
|
kfree_rcu(ctx, rcu_head);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1246,7 +1246,7 @@ nfs_key_timeout_notify(struct file *filp, struct inode *inode)
|
|||||||
struct nfs_open_context *ctx = nfs_file_open_context(filp);
|
struct nfs_open_context *ctx = nfs_file_open_context(filp);
|
||||||
|
|
||||||
if (nfs_ctx_key_to_expire(ctx, inode) &&
|
if (nfs_ctx_key_to_expire(ctx, inode) &&
|
||||||
!ctx->ll_cred)
|
!rcu_access_pointer(ctx->ll_cred))
|
||||||
/* Already expired! */
|
/* Already expired! */
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1258,23 +1258,38 @@ nfs_key_timeout_notify(struct file *filp, struct inode *inode)
|
|||||||
bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx, struct inode *inode)
|
bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx, struct inode *inode)
|
||||||
{
|
{
|
||||||
struct rpc_auth *auth = NFS_SERVER(inode)->client->cl_auth;
|
struct rpc_auth *auth = NFS_SERVER(inode)->client->cl_auth;
|
||||||
struct rpc_cred *cred = ctx->ll_cred;
|
struct rpc_cred *cred, *new, *old = NULL;
|
||||||
struct auth_cred acred = {
|
struct auth_cred acred = {
|
||||||
.cred = ctx->cred,
|
.cred = ctx->cred,
|
||||||
};
|
};
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
if (cred && !cred->cr_ops->crmatch(&acred, cred, 0)) {
|
rcu_read_lock();
|
||||||
put_rpccred(cred);
|
cred = rcu_dereference(ctx->ll_cred);
|
||||||
ctx->ll_cred = NULL;
|
if (cred && !(cred->cr_ops->crkey_timeout &&
|
||||||
cred = NULL;
|
cred->cr_ops->crkey_timeout(cred)))
|
||||||
}
|
goto out;
|
||||||
if (!cred)
|
rcu_read_unlock();
|
||||||
cred = auth->au_ops->lookup_cred(auth, &acred, 0);
|
|
||||||
if (!cred || IS_ERR(cred))
|
new = auth->au_ops->lookup_cred(auth, &acred, 0);
|
||||||
|
if (new == cred) {
|
||||||
|
put_rpccred(new);
|
||||||
return true;
|
return true;
|
||||||
ctx->ll_cred = cred;
|
}
|
||||||
return !!(cred->cr_ops->crkey_timeout &&
|
if (IS_ERR_OR_NULL(new)) {
|
||||||
cred->cr_ops->crkey_timeout(cred));
|
new = NULL;
|
||||||
|
ret = true;
|
||||||
|
} else if (new->cr_ops->crkey_timeout &&
|
||||||
|
new->cr_ops->crkey_timeout(new))
|
||||||
|
ret = true;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
old = rcu_dereference_protected(xchg(&ctx->ll_cred,
|
||||||
|
RCU_INITIALIZER(new)), 1);
|
||||||
|
out:
|
||||||
|
rcu_read_unlock();
|
||||||
|
put_rpccred(old);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ struct nfs_open_context {
|
|||||||
fl_owner_t flock_owner;
|
fl_owner_t flock_owner;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
const struct cred *cred;
|
const struct cred *cred;
|
||||||
struct rpc_cred *ll_cred; /* low-level cred - use to check for expiry */
|
struct rpc_cred __rcu *ll_cred; /* low-level cred - use to check for expiry */
|
||||||
struct nfs4_state *state;
|
struct nfs4_state *state;
|
||||||
fmode_t mode;
|
fmode_t mode;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user