Skip to content

Commit 1a4f69e

Browse files
committed
9p/client: fix data race on req->status
KCSAN reported a race between writing req->status in p9_client_cb and accessing it in p9_client_rpc's wait_event. Accesses to req itself is protected by the data barrier (writing req fields, write barrier, writing status // reading status, read barrier, reading other req fields), but status accesses themselves apparently also must be annotated properly with WRITE_ONCE/READ_ONCE when we access it without locks. Follows: - error paths writing status in various threads all can notify p9_client_rpc, so these all also need WRITE_ONCE - there's a similar read loop in trans_virtio for zc case that also needs READ_ONCE - other reads in trans_fd should be protected by the trans_fd lock and lists state machine, as corresponding writers all are within trans_fd and should be under the same lock. If KCSAN complains on them we likely will have something else to fix as well, so it's better to leave them unmarked and look again if required. Link: https://lkml.kernel.org/r/[email protected] Reported-by: Naresh Kamboju <[email protected]> Suggested-by: Marco Elver <[email protected]> Acked-by: Marco Elver <[email protected]> Reviewed-by: Christian Schoenebeck <[email protected]> Signed-off-by: Dominique Martinet <[email protected]>
1 parent a31b3cf commit 1a4f69e

File tree

5 files changed

+23
-21
lines changed

5 files changed

+23
-21
lines changed

net/9p/client.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status)
443443
* the status change is visible to another thread
444444
*/
445445
smp_wmb();
446-
req->status = status;
446+
WRITE_ONCE(req->status, status);
447447

448448
wake_up(&req->wq);
449449
p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc.tag);
@@ -604,7 +604,7 @@ static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
604604
/* if we haven't received a response for oldreq,
605605
* remove it from the list
606606
*/
607-
if (oldreq->status == REQ_STATUS_SENT) {
607+
if (READ_ONCE(oldreq->status) == REQ_STATUS_SENT) {
608608
if (c->trans_mod->cancelled)
609609
c->trans_mod->cancelled(c, oldreq);
610610
}
@@ -704,7 +704,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
704704
}
705705
again:
706706
/* Wait for the response */
707-
err = wait_event_killable(req->wq, req->status >= REQ_STATUS_RCVD);
707+
err = wait_event_killable(req->wq,
708+
READ_ONCE(req->status) >= REQ_STATUS_RCVD);
708709

709710
/* Make sure our req is coherent with regard to updates in other
710711
* threads - echoes to wmb() in the callback
@@ -718,7 +719,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
718719
goto again;
719720
}
720721

721-
if (req->status == REQ_STATUS_ERROR) {
722+
if (READ_ONCE(req->status) == REQ_STATUS_ERROR) {
722723
p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
723724
err = req->t_err;
724725
}
@@ -731,7 +732,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
731732
p9_client_flush(c, req);
732733

733734
/* if we received the response anyway, don't signal error */
734-
if (req->status == REQ_STATUS_RCVD)
735+
if (READ_ONCE(req->status) == REQ_STATUS_RCVD)
735736
err = 0;
736737
}
737738
recalc_sigpending:
@@ -803,7 +804,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
803804
if (err != -ERESTARTSYS)
804805
goto recalc_sigpending;
805806
}
806-
if (req->status == REQ_STATUS_ERROR) {
807+
if (READ_ONCE(req->status) == REQ_STATUS_ERROR) {
807808
p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
808809
err = req->t_err;
809810
}
@@ -816,7 +817,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
816817
p9_client_flush(c, req);
817818

818819
/* if we received the response anyway, don't signal error */
819-
if (req->status == REQ_STATUS_RCVD)
820+
if (READ_ONCE(req->status) == REQ_STATUS_RCVD)
820821
err = 0;
821822
}
822823
recalc_sigpending:

net/9p/trans_fd.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,11 @@ static void p9_conn_cancel(struct p9_conn *m, int err)
201201

202202
list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
203203
list_move(&req->req_list, &cancel_list);
204-
req->status = REQ_STATUS_ERROR;
204+
WRITE_ONCE(req->status, REQ_STATUS_ERROR);
205205
}
206206
list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
207207
list_move(&req->req_list, &cancel_list);
208-
req->status = REQ_STATUS_ERROR;
208+
WRITE_ONCE(req->status, REQ_STATUS_ERROR);
209209
}
210210

211211
spin_unlock(&m->req_lock);
@@ -466,7 +466,7 @@ static void p9_write_work(struct work_struct *work)
466466

467467
req = list_entry(m->unsent_req_list.next, struct p9_req_t,
468468
req_list);
469-
req->status = REQ_STATUS_SENT;
469+
WRITE_ONCE(req->status, REQ_STATUS_SENT);
470470
p9_debug(P9_DEBUG_TRANS, "move req %p\n", req);
471471
list_move_tail(&req->req_list, &m->req_list);
472472

@@ -675,7 +675,7 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req)
675675
return m->err;
676676

677677
spin_lock(&m->req_lock);
678-
req->status = REQ_STATUS_UNSENT;
678+
WRITE_ONCE(req->status, REQ_STATUS_UNSENT);
679679
list_add_tail(&req->req_list, &m->unsent_req_list);
680680
spin_unlock(&m->req_lock);
681681

@@ -702,7 +702,7 @@ static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req)
702702

703703
if (req->status == REQ_STATUS_UNSENT) {
704704
list_del(&req->req_list);
705-
req->status = REQ_STATUS_FLSHD;
705+
WRITE_ONCE(req->status, REQ_STATUS_FLSHD);
706706
p9_req_put(client, req);
707707
ret = 0;
708708
}
@@ -731,7 +731,7 @@ static int p9_fd_cancelled(struct p9_client *client, struct p9_req_t *req)
731731
* remove it from the list.
732732
*/
733733
list_del(&req->req_list);
734-
req->status = REQ_STATUS_FLSHD;
734+
WRITE_ONCE(req->status, REQ_STATUS_FLSHD);
735735
spin_unlock(&m->req_lock);
736736

737737
p9_req_put(client, req);

net/9p/trans_rdma.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
506506
* because doing if after could erase the REQ_STATUS_RCVD
507507
* status in case of a very fast reply.
508508
*/
509-
req->status = REQ_STATUS_SENT;
509+
WRITE_ONCE(req->status, REQ_STATUS_SENT);
510510
err = ib_post_send(rdma->qp, &wr, NULL);
511511
if (err)
512512
goto send_error;
@@ -516,7 +516,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
516516

517517
/* Handle errors that happened during or while preparing the send: */
518518
send_error:
519-
req->status = REQ_STATUS_ERROR;
519+
WRITE_ONCE(req->status, REQ_STATUS_ERROR);
520520
kfree(c);
521521
p9_debug(P9_DEBUG_ERROR, "Error %d in rdma_request()\n", err);
522522

net/9p/trans_virtio.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
262262

263263
p9_debug(P9_DEBUG_TRANS, "9p debug: virtio request\n");
264264

265-
req->status = REQ_STATUS_SENT;
265+
WRITE_ONCE(req->status, REQ_STATUS_SENT);
266266
req_retry:
267267
spin_lock_irqsave(&chan->lock, flags);
268268

@@ -468,7 +468,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
468468
inlen = n;
469469
}
470470
}
471-
req->status = REQ_STATUS_SENT;
471+
WRITE_ONCE(req->status, REQ_STATUS_SENT);
472472
req_retry_pinned:
473473
spin_lock_irqsave(&chan->lock, flags);
474474

@@ -531,9 +531,10 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
531531
spin_unlock_irqrestore(&chan->lock, flags);
532532
kicked = 1;
533533
p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n");
534-
err = wait_event_killable(req->wq, req->status >= REQ_STATUS_RCVD);
534+
err = wait_event_killable(req->wq,
535+
READ_ONCE(req->status) >= REQ_STATUS_RCVD);
535536
// RERROR needs reply (== error string) in static data
536-
if (req->status == REQ_STATUS_RCVD &&
537+
if (READ_ONCE(req->status) == REQ_STATUS_RCVD &&
537538
unlikely(req->rc.sdata[4] == P9_RERROR))
538539
handle_rerror(req, in_hdr_len, offs, in_pages);
539540

net/9p/trans_xen.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req)
157157
&masked_prod, masked_cons,
158158
XEN_9PFS_RING_SIZE(ring));
159159

160-
p9_req->status = REQ_STATUS_SENT;
160+
WRITE_ONCE(p9_req->status, REQ_STATUS_SENT);
161161
virt_wmb(); /* write ring before updating pointer */
162162
prod += size;
163163
ring->intf->out_prod = prod;
@@ -212,7 +212,7 @@ static void p9_xen_response(struct work_struct *work)
212212
dev_warn(&priv->dev->dev,
213213
"requested packet size too big: %d for tag %d with capacity %zd\n",
214214
h.size, h.tag, req->rc.capacity);
215-
req->status = REQ_STATUS_ERROR;
215+
WRITE_ONCE(req->status, REQ_STATUS_ERROR);
216216
goto recv_error;
217217
}
218218

0 commit comments

Comments
 (0)