Re: [PATCH v2 20/34] SUNRPC: Treat the task and request as separate in the xprt_ops->send_request()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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;
>  




[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux