Commit 105065c3 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfsd-4.13-2' of git://linux-nfs.org/~bfields/linux

Pull nfsd fixes from Bruce Fields:
 "Two nfsd bugfixes, neither 4.13 regressions, but both potentially
  serious"

* tag 'nfsd-4.13-2' of git://linux-nfs.org/~bfields/linux:
  net: sunrpc: svcsock: fix NULL-pointer exception
  nfsd: Limit end of page list when decoding NFSv4 WRITE
parents 8c7932a3 eebe53e8
...@@ -144,7 +144,7 @@ static void next_decode_page(struct nfsd4_compoundargs *argp) ...@@ -144,7 +144,7 @@ static void next_decode_page(struct nfsd4_compoundargs *argp)
argp->p = page_address(argp->pagelist[0]); argp->p = page_address(argp->pagelist[0]);
argp->pagelist++; argp->pagelist++;
if (argp->pagelen < PAGE_SIZE) { if (argp->pagelen < PAGE_SIZE) {
argp->end = argp->p + (argp->pagelen>>2); argp->end = argp->p + XDR_QUADLEN(argp->pagelen);
argp->pagelen = 0; argp->pagelen = 0;
} else { } else {
argp->end = argp->p + (PAGE_SIZE>>2); argp->end = argp->p + (PAGE_SIZE>>2);
...@@ -1279,9 +1279,7 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) ...@@ -1279,9 +1279,7 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
argp->pagelen -= pages * PAGE_SIZE; argp->pagelen -= pages * PAGE_SIZE;
len -= pages * PAGE_SIZE; len -= pages * PAGE_SIZE;
argp->p = (__be32 *)page_address(argp->pagelist[0]); next_decode_page(argp);
argp->pagelist++;
argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE);
} }
argp->p += XDR_QUADLEN(len); argp->p += XDR_QUADLEN(len);
......
...@@ -421,6 +421,9 @@ static void svc_data_ready(struct sock *sk) ...@@ -421,6 +421,9 @@ static void svc_data_ready(struct sock *sk)
dprintk("svc: socket %p(inet %p), busy=%d\n", dprintk("svc: socket %p(inet %p), busy=%d\n",
svsk, sk, svsk, sk,
test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags)); test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
/* Refer to svc_setup_socket() for details. */
rmb();
svsk->sk_odata(sk); svsk->sk_odata(sk);
if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags)) if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags))
svc_xprt_enqueue(&svsk->sk_xprt); svc_xprt_enqueue(&svsk->sk_xprt);
...@@ -437,6 +440,9 @@ static void svc_write_space(struct sock *sk) ...@@ -437,6 +440,9 @@ static void svc_write_space(struct sock *sk)
if (svsk) { if (svsk) {
dprintk("svc: socket %p(inet %p), write_space busy=%d\n", dprintk("svc: socket %p(inet %p), write_space busy=%d\n",
svsk, sk, test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags)); svsk, sk, test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
/* Refer to svc_setup_socket() for details. */
rmb();
svsk->sk_owspace(sk); svsk->sk_owspace(sk);
svc_xprt_enqueue(&svsk->sk_xprt); svc_xprt_enqueue(&svsk->sk_xprt);
} }
...@@ -760,8 +766,12 @@ static void svc_tcp_listen_data_ready(struct sock *sk) ...@@ -760,8 +766,12 @@ static void svc_tcp_listen_data_ready(struct sock *sk)
dprintk("svc: socket %p TCP (listen) state change %d\n", dprintk("svc: socket %p TCP (listen) state change %d\n",
sk, sk->sk_state); sk, sk->sk_state);
if (svsk) if (svsk) {
/* Refer to svc_setup_socket() for details. */
rmb();
svsk->sk_odata(sk); svsk->sk_odata(sk);
}
/* /*
* This callback may called twice when a new connection * This callback may called twice when a new connection
* is established as a child socket inherits everything * is established as a child socket inherits everything
...@@ -794,6 +804,8 @@ static void svc_tcp_state_change(struct sock *sk) ...@@ -794,6 +804,8 @@ static void svc_tcp_state_change(struct sock *sk)
if (!svsk) if (!svsk)
printk("svc: socket %p: no user data\n", sk); printk("svc: socket %p: no user data\n", sk);
else { else {
/* Refer to svc_setup_socket() for details. */
rmb();
svsk->sk_ostate(sk); svsk->sk_ostate(sk);
if (sk->sk_state != TCP_ESTABLISHED) { if (sk->sk_state != TCP_ESTABLISHED) {
set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
...@@ -1381,12 +1393,18 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, ...@@ -1381,12 +1393,18 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
return ERR_PTR(err); return ERR_PTR(err);
} }
inet->sk_user_data = svsk;
svsk->sk_sock = sock; svsk->sk_sock = sock;
svsk->sk_sk = inet; svsk->sk_sk = inet;
svsk->sk_ostate = inet->sk_state_change; svsk->sk_ostate = inet->sk_state_change;
svsk->sk_odata = inet->sk_data_ready; svsk->sk_odata = inet->sk_data_ready;
svsk->sk_owspace = inet->sk_write_space; svsk->sk_owspace = inet->sk_write_space;
/*
* This barrier is necessary in order to prevent race condition
* with svc_data_ready(), svc_listen_data_ready() and others
* when calling callbacks above.
*/
wmb();
inet->sk_user_data = svsk;
/* Initialize the socket */ /* Initialize the socket */
if (sock->type == SOCK_DGRAM) if (sock->type == SOCK_DGRAM)
......
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