Hi Trond, On Tue, 2018-09-04 at 17:05 -0400, Trond Myklebust wrote: > When we shift to using the transmit queue, then the task that holds the > write lock will not necessarily be the same as the one being transmitted. > > Signed-off-by: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx> > --- > include/linux/sunrpc/xprt.h | 2 +- > net/sunrpc/xprt.c | 2 +- > net/sunrpc/xprtrdma/svc_rdma_backchannel.c | 3 +-- > net/sunrpc/xprtrdma/transport.c | 5 ++-- > net/sunrpc/xprtsock.c | 27 +++++++++++----------- > 5 files changed, 18 insertions(+), 21 deletions(-) > > diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h > index 81a6c2c8dfc7..6d91acfe0644 100644 > --- a/include/linux/sunrpc/xprt.h > +++ b/include/linux/sunrpc/xprt.h > @@ -140,7 +140,7 @@ struct rpc_xprt_ops { > void (*connect)(struct rpc_xprt *xprt, struct rpc_task > *task); > int (*buf_alloc)(struct rpc_task *task); > void (*buf_free)(struct rpc_task *task); > - int (*send_request)(struct rpc_task *task); > + int (*send_request)(struct rpc_rqst *req, struct rpc_task > *task); > void (*set_retrans_timeout)(struct rpc_task *task); > void (*timer)(struct rpc_xprt *xprt, struct rpc_task > *task); > void (*release_request)(struct rpc_task *task); > diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c > index 8e8c345eedf7..7c80f93562e5 100644 > --- a/net/sunrpc/xprt.c > +++ b/net/sunrpc/xprt.c > @@ -1170,7 +1170,7 @@ void xprt_transmit(struct rpc_task *task) > } > > connect_cookie = xprt->connect_cookie; > - status = xprt->ops->send_request(task); > + status = xprt->ops->send_request(req, task); > trace_xprt_transmit(xprt, req->rq_xid, status); > if (status != 0) { > task->tk_status = status; > diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c > b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c > index 09b12b7568fe..d1618c70edb4 100644 > --- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c > +++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c > @@ -215,9 +215,8 @@ rpcrdma_bc_send_request(struct svcxprt_rdma *rdma, struct > rpc_rqst *rqst) > * connection. > */ > static int > -xprt_rdma_bc_send_request(struct rpc_task *task) > +xprt_rdma_bc_send_request(struct rpc_rqst *rqst, struct rpc_task *task) > { > - struct rpc_rqst *rqst = task->tk_rqstp; > struct svc_xprt *sxprt = rqst->rq_xprt->bc_xprt; > struct svcxprt_rdma *rdma; > int ret; > diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c > index 143ce2579ba9..fa684bf4d090 100644 > --- a/net/sunrpc/xprtrdma/transport.c > +++ b/net/sunrpc/xprtrdma/transport.c > @@ -706,9 +706,8 @@ xprt_rdma_free(struct rpc_task *task) > * sent. Do not try to send this message again. > */ > static int > -xprt_rdma_send_request(struct rpc_task *task) > +xprt_rdma_send_request(struct rpc_rqst *rqst, struct rpc_task *task) > { > - struct rpc_rqst *rqst = task->tk_rqstp; > struct rpc_xprt *xprt = rqst->rq_xprt; > struct rpcrdma_req *req = rpcr_to_rdmar(rqst); > struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); > @@ -741,7 +740,7 @@ xprt_rdma_send_request(struct rpc_task *task) > /* An RPC with no reply will throw off credit accounting, > * so drop the connection to reset the credit grant. > */ > - if (!rpc_reply_expected(task)) > + if (!rpc_reply_expected(rqst->rq_task)) > goto drop_connection; > return 0; > > diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c > index 8d6404259ff9..b8143eded4af 100644 > --- a/net/sunrpc/xprtsock.c > +++ b/net/sunrpc/xprtsock.c > @@ -449,12 +449,12 @@ static void xs_nospace_callback(struct rpc_task *task) > > /** > * xs_nospace - place task on wait queue if transmit was incomplete > + * @req: pointer to RPC request > * @task: task to put to sleep > * > */ > -static int xs_nospace(struct rpc_task *task) > +static int xs_nospace(struct rpc_rqst *req, 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; > @@ -513,6 +513,7 @@ static inline void xs_encode_stream_record_marker(struct > xdr_buf *buf) > > /** > * xs_local_send_request - write an RPC request to an AF_LOCAL socket > + * @req: pointer to RPC request > * @task: RPC task that manages the state of an RPC request > * > * Return values: > @@ -522,9 +523,8 @@ static inline void xs_encode_stream_record_marker(struct > xdr_buf *buf) > * ENOTCONN: Caller needs to invoke connect logic then call again > * other: Some other error occured, the request was not sent > */ > -static int xs_local_send_request(struct rpc_task *task) > +static int xs_local_send_request(struct rpc_rqst *req, 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); > @@ -569,7 +569,7 @@ static int xs_local_send_request(struct rpc_task *task) > case -ENOBUFS: > break; > case -EAGAIN: > - status = xs_nospace(task); > + status = xs_nospace(req, task); > break; > default: > dprintk("RPC: sendmsg returned unrecognized error %d\n", > @@ -585,6 +585,7 @@ static int xs_local_send_request(struct rpc_task *task) > > /** > * xs_udp_send_request - write an RPC request to a UDP socket > + * @req: pointer to RPC request > * @task: address of RPC task that manages the state of an RPC request > * > * Return values: > @@ -594,9 +595,8 @@ static int xs_local_send_request(struct rpc_task *task) > * ENOTCONN: Caller needs to invoke connect logic then call again > * other: Some other error occurred, the request was not sent > */ > -static int xs_udp_send_request(struct rpc_task *task) > +static int xs_udp_send_request(struct rpc_rqst *req, 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 xdr_buf *xdr = &req->rq_snd_buf; > @@ -638,7 +638,7 @@ static int xs_udp_send_request(struct rpc_task *task) > /* Should we call xs_close() here? */ > break; > case -EAGAIN: > - status = xs_nospace(task); > + status = xs_nospace(req, task); > break; > case -ENETUNREACH: > case -ENOBUFS: > @@ -658,6 +658,7 @@ static int xs_udp_send_request(struct rpc_task *task) > > /** > * xs_tcp_send_request - write an RPC request to a TCP socket > + * @req: pointer to RPC request > * @task: address of RPC task that manages the state of an RPC request > * > * Return values: > @@ -670,9 +671,8 @@ static int xs_udp_send_request(struct rpc_task *task) > * XXX: In the case of soft timeouts, should we eventually give up > * if sendmsg is not able to make progress? > */ > -static int xs_tcp_send_request(struct rpc_task *task) > +static int xs_tcp_send_request(struct rpc_rqst *req, 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 xdr_buf *xdr = &req->rq_snd_buf; > @@ -697,7 +697,7 @@ static int xs_tcp_send_request(struct rpc_task *task) > * completes while the socket holds a reference to the pages, > * then we may end up resending corrupted data. > */ > - if (task->tk_flags & RPC_TASK_SENT) > + if (req->rq_task->tk_flags & RPC_TASK_SENT) Can req or rq_task be null coming into this function? I'm seeing the following null pointer dereference while running connectathon tests on v4.1 after this patch: [ 77.782045] BUG: unable to handle kernel NULL pointer dereference at 00000000000000d4 [ 77.782184] PGD 0 P4D 0 [ 77.782232] Oops: 0000 [#1] PREEMPT SMP PTI [ 77.782286] CPU: 0 PID: 1790 Comm: NFSv4 callback Not tainted 4.19.0-rc2- ANNA+ #1350 [ 77.782382] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ 77.782468] RIP: 0010:xs_tcp_send_request+0x5f/0x250 [sunrpc] [ 77.782531] Code: 74 0e 8b 97 6c 01 00 00 85 d2 0f 84 21 01 00 00 8b 43 40 48 8b 53 08 83 e8 04 0d 00 00 00 80 0f c8 89 02 48 8b 83 88 00 00 00 <0f> b7 a8 d4 00 00 00 49 8b 87 78 05 00 00 66 c1 ed 0b 83 f5 01 83 [ 77.782716] RSP: 0018:ffffc900010a3d18 EFLAGS: 00010282 [ 77.782775] RAX: 0000000000000000 RBX: ffff8800ba452e00 RCX: 0000000000000000 [ 77.782843] RDX: ffff8800b8883000 RSI: ffff8800ba6b7100 RDI: ffff8800ba452e00 [ 77.782911] RBP: ffff8800ba452e00 R08: 000000185e977fc9 R09: ffffffff82229c98 [ 77.782980] R10: ffffffff82229c94 R11: 0000000000000000 R12: ffff8800ba452e08 [ 77.783048] R13: ffff8800ba452e00 R14: ffffffffa03034b0 R15: ffff8800b4c11800 [ 77.783118] FS: 0000000000000000(0000) GS:ffff8800bca00000(0000) knlGS:0000000000000000 [ 77.783217] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 77.783278] CR2: 00000000000000d4 CR3: 000000000200a001 CR4: 00000000001606f0 [ 77.783351] Call Trace: [ 77.783418] ? rpc_wake_up_status+0x70/0x70 [sunrpc] [ 77.783542] ? rpc_clnt_test_and_add_xprt+0xb0/0xb0 [sunrpc] [ 77.783634] xprt_transmit+0x82/0x230 [sunrpc] [ 77.783711] ? rpc_wake_up_status+0x70/0x70 [sunrpc] [ 77.783786] ? rpc_clnt_test_and_add_xprt+0xb0/0xb0 [sunrpc] [ 77.784772] call_bc_transmit+0x50/0xf0 [sunrpc] [ 77.785737] __rpc_execute+0x7a/0x370 [sunrpc] [ 77.786626] ? kvm_clock_read+0x14/0x30 [ 77.787546] ? ktime_get+0x31/0x90 [ 77.788393] rpc_run_bc_task+0x85/0xc0 [sunrpc] [ 77.789260] bc_svc_process+0x275/0x2f0 [sunrpc] [ 77.790216] nfs41_callback_svc+0x120/0x190 [nfsv4] [ 77.790631] ? wait_woken+0x80/0x80 [ 77.790998] ? nfs_map_gid_to_group+0x110/0x110 [nfsv4] [ 77.791356] kthread+0x10d/0x130 [ 77.791708] ? kthread_park+0x80/0x80 [ 77.792047] ret_from_fork+0x35/0x40 [ 77.792272] Modules linked in: nfsv3 rpcsec_gss_krb5 nfsv4 nfs fscache cfg80211 rpcrdma rfkill crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel pcbc joydev mousedev aesni_intel evdev aes_x86_64 crypto_simd input_leds cryptd led_class mac_hid glue_helper psmouse pcspkr intel_agp nfsd intel_gtt i2c_piix4 button auth_rpcgss nfs_acl lockd grace sunrpc sch_fq_codel ip_tables x_tables ata_generic pata_acpi serio_raw atkbd libps2 ata_piix libata i8042 floppy serio uhci_hcd scsi_mod ehci_pci ehci_hcd usbcore usb_common xfs virtio_balloon virtio_net net_failover failover virtio_pci virtio_blk virtio_ring virtio [ 77.794397] CR2: 00000000000000d4 [ 77.794650] ---[ end trace 8d8888b6bde84d33 ]--- Thanks, Anna > zerocopy = false; > > if (test_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state)) > @@ -761,7 +761,7 @@ static int xs_tcp_send_request(struct rpc_task *task) > /* Should we call xs_close() here? */ > break; > case -EAGAIN: > - status = xs_nospace(task); > + status = xs_nospace(req, task); > break; > case -ECONNRESET: > case -ECONNREFUSED: > @@ -2706,9 +2706,8 @@ static int bc_sendto(struct rpc_rqst *req) > /* > * The send routine. Borrows from svc_send > */ > -static int bc_send_request(struct rpc_task *task) > +static int bc_send_request(struct rpc_rqst *req, struct rpc_task *task) > { > - struct rpc_rqst *req = task->tk_rqstp; > struct svc_xprt *xprt; > int len; >