forked from Minki/linux
NFS Client Bugfixes for Linux 5.4-rc6
Stable bugfixes: - Fix an RCU lock leak in nfs4_refresh_delegation_stateid() Other fixes: - The TCP back channel mustn't disappear while requests are outstanding - The RDMA back channel mustn't disappear while requests are outstanding - Destroy the back channel when we destroy the host transport - Don't allow a cached open with a revoked delegation -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEnZ5MQTpR7cLU7KEp18tUv7ClQOsFAl28mZ4ACgkQ18tUv7Cl QOvAAxAA5h15NJ8OTOpr/kyWQAHEYWIEWQyTNYT8Gi/TI/YCfauET6kxAKg7ETk+ Bx6+A7Q5OlKSqFZXf2UMMIHPnvH7Ar06uIof6DLjWxA9N/q57SNW0YszQCUhvWjp 4Ry7d9A2yNrCizEk/vTmY5zfFIo2S88AvwkQ6gLCEyfIn5REWQyQnS4SS3vL7MuS E/iWBsXFV2C9/yON+zzZnC0ewMIPbtWA3/CsVI2zDKLsHKvBYOx6n7TbfTtMtc/p mCdgLzdEEZlN0KOCzzMp7ziME8y1qUGX6eo17Jrr0ZBZIM7o5d7sYMA88Apu6dMg MQM5iEEAf//kmHLWzQ6yg8XZEZrXFMOiGKYu0kWt4pVlqi78gemEfE6T8dClsB5m P7jqn/4ntDlJPWPciImsVEzDOHlzlZBIXwZs1JjufeO/hIB570cs80PjeDQP0id8 Cx3yR7Hr1ldKzwSwpWrtIaqEPljJJw0jhxQ7YYlvfbA1Ogd4ek4QU4RuvyW11CRr d/5Oaa7xvjGs63klu8HpZG4NHFby3PPmZT6t4xUcH75MR14S15YCGtaUvPJ7ORck C6tZJAkVtJqSoAjsGuBtTc5qiOdo+hMRghutW4Pd6UpnPYJKwQUtTqp3MbfM4+bA S19tGG6qn+7cl7bW4NJpNy8HfbC7BdS+m7maHpQfGIdMsxKVFoI= =ttcU -----END PGP SIGNATURE----- Merge tag 'nfs-for-5.4-3' of git://git.linux-nfs.org/projects/anna/linux-nfs Pull NFS client bugfixes from Anna Schumaker: "This contains two delegation fixes (with the RCU lock leak fix marked for stable), and three patches to fix destroying the the sunrpc back channel. Stable bugfixes: - Fix an RCU lock leak in nfs4_refresh_delegation_stateid() Other fixes: - The TCP back channel mustn't disappear while requests are outstanding - The RDMA back channel mustn't disappear while requests are outstanding - Destroy the back channel when we destroy the host transport - Don't allow a cached open with a revoked delegation" * tag 'nfs-for-5.4-3' of git://git.linux-nfs.org/projects/anna/linux-nfs: NFS: Fix an RCU lock leak in nfs4_refresh_delegation_stateid() NFSv4: Don't allow a cached open with a revoked delegation SUNRPC: Destroy the back channel when we destroy the host transport SUNRPC: The RDMA back channel mustn't disappear while requests are outstanding SUNRPC: The TCP back channel mustn't disappear while requests are outstanding
This commit is contained in:
commit
372bf6c1c8
@ -53,6 +53,16 @@ nfs4_is_valid_delegation(const struct nfs_delegation *delegation,
|
||||
return false;
|
||||
}
|
||||
|
||||
struct nfs_delegation *nfs4_get_valid_delegation(const struct inode *inode)
|
||||
{
|
||||
struct nfs_delegation *delegation;
|
||||
|
||||
delegation = rcu_dereference(NFS_I(inode)->delegation);
|
||||
if (nfs4_is_valid_delegation(delegation, 0))
|
||||
return delegation;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark)
|
||||
{
|
||||
@ -1181,7 +1191,7 @@ bool nfs4_refresh_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
|
||||
if (delegation != NULL &&
|
||||
nfs4_stateid_match_other(dst, &delegation->stateid)) {
|
||||
dst->seqid = delegation->stateid.seqid;
|
||||
return ret;
|
||||
ret = true;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
out:
|
||||
|
@ -68,6 +68,7 @@ int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state,
|
||||
bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags, nfs4_stateid *dst, const struct cred **cred);
|
||||
bool nfs4_refresh_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
|
||||
|
||||
struct nfs_delegation *nfs4_get_valid_delegation(const struct inode *inode);
|
||||
void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
|
||||
int nfs4_have_delegation(struct inode *inode, fmode_t flags);
|
||||
int nfs4_check_delegation(struct inode *inode, fmode_t flags);
|
||||
|
@ -1440,8 +1440,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode,
|
||||
return 0;
|
||||
if ((delegation->type & fmode) != fmode)
|
||||
return 0;
|
||||
if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
|
||||
return 0;
|
||||
switch (claim) {
|
||||
case NFS4_OPEN_CLAIM_NULL:
|
||||
case NFS4_OPEN_CLAIM_FH:
|
||||
@ -1810,7 +1808,6 @@ static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmo
|
||||
static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
|
||||
{
|
||||
struct nfs4_state *state = opendata->state;
|
||||
struct nfs_inode *nfsi = NFS_I(state->inode);
|
||||
struct nfs_delegation *delegation;
|
||||
int open_mode = opendata->o_arg.open_flags;
|
||||
fmode_t fmode = opendata->o_arg.fmode;
|
||||
@ -1827,7 +1824,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
|
||||
}
|
||||
spin_unlock(&state->owner->so_lock);
|
||||
rcu_read_lock();
|
||||
delegation = rcu_dereference(nfsi->delegation);
|
||||
delegation = nfs4_get_valid_delegation(state->inode);
|
||||
if (!can_open_delegated(delegation, fmode, claim)) {
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
@ -2371,7 +2368,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
|
||||
data->o_arg.open_flags, claim))
|
||||
goto out_no_action;
|
||||
rcu_read_lock();
|
||||
delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
|
||||
delegation = nfs4_get_valid_delegation(data->state->inode);
|
||||
if (can_open_delegated(delegation, data->o_arg.fmode, claim))
|
||||
goto unlock_no_action;
|
||||
rcu_read_unlock();
|
||||
|
@ -64,6 +64,11 @@ static inline int xprt_setup_backchannel(struct rpc_xprt *xprt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void xprt_destroy_backchannel(struct rpc_xprt *xprt,
|
||||
unsigned int max_reqs)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool svc_is_backchannel(const struct svc_rqst *rqstp)
|
||||
{
|
||||
return false;
|
||||
|
@ -220,7 +220,7 @@ void xprt_destroy_bc(struct rpc_xprt *xprt, unsigned int max_reqs)
|
||||
goto out;
|
||||
|
||||
spin_lock_bh(&xprt->bc_pa_lock);
|
||||
xprt->bc_alloc_max -= max_reqs;
|
||||
xprt->bc_alloc_max -= min(max_reqs, xprt->bc_alloc_max);
|
||||
list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) {
|
||||
dprintk("RPC: req=%p\n", req);
|
||||
list_del(&req->rq_bc_pa_list);
|
||||
@ -307,8 +307,8 @@ void xprt_free_bc_rqst(struct rpc_rqst *req)
|
||||
*/
|
||||
dprintk("RPC: Last session removed req=%p\n", req);
|
||||
xprt_free_allocation(req);
|
||||
return;
|
||||
}
|
||||
xprt_put(xprt);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -339,7 +339,7 @@ found:
|
||||
spin_unlock(&xprt->bc_pa_lock);
|
||||
if (new) {
|
||||
if (req != new)
|
||||
xprt_free_bc_rqst(new);
|
||||
xprt_free_allocation(new);
|
||||
break;
|
||||
} else if (req)
|
||||
break;
|
||||
@ -368,6 +368,7 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
|
||||
set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
|
||||
|
||||
dprintk("RPC: add callback request to list\n");
|
||||
xprt_get(xprt);
|
||||
spin_lock(&bc_serv->sv_cb_lock);
|
||||
list_add(&req->rq_bc_list, &bc_serv->sv_cb_list);
|
||||
wake_up(&bc_serv->sv_cb_waitq);
|
||||
|
@ -1942,6 +1942,11 @@ static void xprt_destroy_cb(struct work_struct *work)
|
||||
rpc_destroy_wait_queue(&xprt->sending);
|
||||
rpc_destroy_wait_queue(&xprt->backlog);
|
||||
kfree(xprt->servername);
|
||||
/*
|
||||
* Destroy any existing back channel
|
||||
*/
|
||||
xprt_destroy_backchannel(xprt, UINT_MAX);
|
||||
|
||||
/*
|
||||
* Tear down transport state and free the rpc_xprt
|
||||
*/
|
||||
|
@ -163,6 +163,7 @@ void xprt_rdma_bc_free_rqst(struct rpc_rqst *rqst)
|
||||
spin_lock(&xprt->bc_pa_lock);
|
||||
list_add_tail(&rqst->rq_bc_pa_list, &xprt->bc_pa_list);
|
||||
spin_unlock(&xprt->bc_pa_lock);
|
||||
xprt_put(xprt);
|
||||
}
|
||||
|
||||
static struct rpc_rqst *rpcrdma_bc_rqst_get(struct rpcrdma_xprt *r_xprt)
|
||||
@ -259,6 +260,7 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt,
|
||||
|
||||
/* Queue rqst for ULP's callback service */
|
||||
bc_serv = xprt->bc_serv;
|
||||
xprt_get(xprt);
|
||||
spin_lock(&bc_serv->sv_cb_lock);
|
||||
list_add(&rqst->rq_bc_list, &bc_serv->sv_cb_list);
|
||||
spin_unlock(&bc_serv->sv_cb_lock);
|
||||
|
Loading…
Reference in New Issue
Block a user