mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-15 22:31:47 -04:00
Merge tag 'nfs-for-3.14-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust:
"Highlights include stable fixes for the following bugs:
- General performance regression due to NFS_INO_INVALID_LABEL being
set when the server doesn't support labeled NFS
- Hang in the RPC code due to a socket out-of-buffer race
- Infinite loop when trying to establish the NFSv4 lease
- Use-after-free bug in the RPCSEC gss code.
- nfs4_select_rw_stateid is returning with a non-zero error value on
success
Other bug fixes:
- Potential memory scribble in the RPC bi-directional RPC code
- Pipe version reference leak
- Use the correct net namespace in the new NFSv4 migration code"
* tag 'nfs-for-3.14-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFS fix error return in nfs4_select_rw_stateid
NFSv4: Use the correct net namespace in nfs4_update_server
SUNRPC: Fix a pipe_version reference leak
SUNRPC: Ensure that gss_auth isn't freed before its upcall messages
SUNRPC: Fix potential memory scribble in xprt_free_bc_request()
SUNRPC: Fix races in xs_nospace()
SUNRPC: Don't create a gss auth cache unless rpc.gssd is running
NFS: Do not set NFS_INO_INVALID_LABEL unless server supports labeled NFS
This commit is contained in:
@@ -108,6 +108,7 @@ struct gss_auth {
|
||||
static DEFINE_SPINLOCK(pipe_version_lock);
|
||||
static struct rpc_wait_queue pipe_version_rpc_waitqueue;
|
||||
static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
|
||||
static void gss_put_auth(struct gss_auth *gss_auth);
|
||||
|
||||
static void gss_free_ctx(struct gss_cl_ctx *);
|
||||
static const struct rpc_pipe_ops gss_upcall_ops_v0;
|
||||
@@ -320,6 +321,7 @@ gss_release_msg(struct gss_upcall_msg *gss_msg)
|
||||
if (gss_msg->ctx != NULL)
|
||||
gss_put_ctx(gss_msg->ctx);
|
||||
rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
|
||||
gss_put_auth(gss_msg->auth);
|
||||
kfree(gss_msg);
|
||||
}
|
||||
|
||||
@@ -498,9 +500,12 @@ gss_alloc_msg(struct gss_auth *gss_auth,
|
||||
default:
|
||||
err = gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name);
|
||||
if (err)
|
||||
goto err_free_msg;
|
||||
goto err_put_pipe_version;
|
||||
};
|
||||
kref_get(&gss_auth->kref);
|
||||
return gss_msg;
|
||||
err_put_pipe_version:
|
||||
put_pipe_version(gss_auth->net);
|
||||
err_free_msg:
|
||||
kfree(gss_msg);
|
||||
err:
|
||||
@@ -991,6 +996,8 @@ gss_create_new(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
|
||||
gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
|
||||
if (gss_auth->service == 0)
|
||||
goto err_put_mech;
|
||||
if (!gssd_running(gss_auth->net))
|
||||
goto err_put_mech;
|
||||
auth = &gss_auth->rpc_auth;
|
||||
auth->au_cslack = GSS_CRED_SLACK >> 2;
|
||||
auth->au_rslack = GSS_VERF_SLACK >> 2;
|
||||
@@ -1061,6 +1068,12 @@ gss_free_callback(struct kref *kref)
|
||||
gss_free(gss_auth);
|
||||
}
|
||||
|
||||
static void
|
||||
gss_put_auth(struct gss_auth *gss_auth)
|
||||
{
|
||||
kref_put(&gss_auth->kref, gss_free_callback);
|
||||
}
|
||||
|
||||
static void
|
||||
gss_destroy(struct rpc_auth *auth)
|
||||
{
|
||||
@@ -1082,7 +1095,7 @@ gss_destroy(struct rpc_auth *auth)
|
||||
gss_auth->gss_pipe[1] = NULL;
|
||||
rpcauth_destroy_credcache(auth);
|
||||
|
||||
kref_put(&gss_auth->kref, gss_free_callback);
|
||||
gss_put_auth(gss_auth);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1253,7 +1266,7 @@ gss_destroy_nullcred(struct rpc_cred *cred)
|
||||
call_rcu(&cred->cr_rcu, gss_free_cred_callback);
|
||||
if (ctx)
|
||||
gss_put_ctx(ctx);
|
||||
kref_put(&gss_auth->kref, gss_free_callback);
|
||||
gss_put_auth(gss_auth);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -64,7 +64,6 @@ static void xprt_free_allocation(struct rpc_rqst *req)
|
||||
free_page((unsigned long)xbufp->head[0].iov_base);
|
||||
xbufp = &req->rq_snd_buf;
|
||||
free_page((unsigned long)xbufp->head[0].iov_base);
|
||||
list_del(&req->rq_bc_pa_list);
|
||||
kfree(req);
|
||||
}
|
||||
|
||||
@@ -168,8 +167,10 @@ int xprt_setup_backchannel(struct rpc_xprt *xprt, unsigned int min_reqs)
|
||||
/*
|
||||
* Memory allocation failed, free the temporary list
|
||||
*/
|
||||
list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list)
|
||||
list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list) {
|
||||
list_del(&req->rq_bc_pa_list);
|
||||
xprt_free_allocation(req);
|
||||
}
|
||||
|
||||
dprintk("RPC: setup backchannel transport failed\n");
|
||||
return -ENOMEM;
|
||||
@@ -198,6 +199,7 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs)
|
||||
xprt_dec_alloc_count(xprt, max_reqs);
|
||||
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);
|
||||
xprt_free_allocation(req);
|
||||
if (--max_reqs == 0)
|
||||
break;
|
||||
|
||||
@@ -510,6 +510,7 @@ static int xs_nospace(struct rpc_task *task)
|
||||
struct rpc_rqst *req = task->tk_rqstp;
|
||||
struct rpc_xprt *xprt = req->rq_xprt;
|
||||
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
|
||||
struct sock *sk = transport->inet;
|
||||
int ret = -EAGAIN;
|
||||
|
||||
dprintk("RPC: %5u xmit incomplete (%u left of %u)\n",
|
||||
@@ -527,7 +528,7 @@ static int xs_nospace(struct rpc_task *task)
|
||||
* window size
|
||||
*/
|
||||
set_bit(SOCK_NOSPACE, &transport->sock->flags);
|
||||
transport->inet->sk_write_pending++;
|
||||
sk->sk_write_pending++;
|
||||
/* ...and wait for more buffer space */
|
||||
xprt_wait_for_buffer_space(task, xs_nospace_callback);
|
||||
}
|
||||
@@ -537,6 +538,9 @@ static int xs_nospace(struct rpc_task *task)
|
||||
}
|
||||
|
||||
spin_unlock_bh(&xprt->transport_lock);
|
||||
|
||||
/* Race breaker in case memory is freed before above code is called */
|
||||
sk->sk_write_space(sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user