Commit 2b6e72ed authored by Dominique Martinet's avatar Dominique Martinet Committed by Eric Van Hensbergen

9P: Add memory barriers to protect request fields over cb/rpc threads handoff

We need barriers to guarantee this pattern works as intended:
[w] req->rc, 1		[r] req->status, 1
wmb			rmb
[w] req->status, 1	[r] req->rc

Where the wmb ensures that rc gets written before status,
and the rmb ensures that if you observe status == 1, rc is the new value.
Signed-off-by: default avatarDominique Martinet <dominique.martinet@cea.fr>
Signed-off-by: default avatarEric Van Hensbergen <ericvh@gmail.com>
parent 38dbfb59
...@@ -261,7 +261,7 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, ...@@ -261,7 +261,7 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status); int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status);
int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl); int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl);
struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
void p9_client_cb(struct p9_client *c, struct p9_req_t *req); void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status);
int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int); int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int);
int p9stat_read(struct p9_client *, char *, int, struct p9_wstat *); int p9stat_read(struct p9_client *, char *, int, struct p9_wstat *);
......
...@@ -415,9 +415,17 @@ static void p9_free_req(struct p9_client *c, struct p9_req_t *r) ...@@ -415,9 +415,17 @@ static void p9_free_req(struct p9_client *c, struct p9_req_t *r)
* req: request received * req: request received
* *
*/ */
void p9_client_cb(struct p9_client *c, struct p9_req_t *req) void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status)
{ {
p9_debug(P9_DEBUG_MUX, " tag %d\n", req->tc->tag); p9_debug(P9_DEBUG_MUX, " tag %d\n", req->tc->tag);
/*
* This barrier is needed to make sure any change made to req before
* the other thread wakes up will indeed be seen by the waiting side.
*/
smp_wmb();
req->status = status;
wake_up(req->wq); wake_up(req->wq);
p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag); p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag);
} }
...@@ -751,6 +759,12 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) ...@@ -751,6 +759,12 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
err = wait_event_interruptible(*req->wq, err = wait_event_interruptible(*req->wq,
req->status >= REQ_STATUS_RCVD); req->status >= REQ_STATUS_RCVD);
/*
* Make sure our req is coherent with regard to updates in other
* threads - echoes to wmb() in the callback
*/
smp_rmb();
if ((err == -ERESTARTSYS) && (c->status == Connected) if ((err == -ERESTARTSYS) && (c->status == Connected)
&& (type == P9_TFLUSH)) { && (type == P9_TFLUSH)) {
sigpending = 1; sigpending = 1;
......
...@@ -212,15 +212,9 @@ static void p9_conn_cancel(struct p9_conn *m, int err) ...@@ -212,15 +212,9 @@ static void p9_conn_cancel(struct p9_conn *m, int err)
m->err = err; m->err = err;
list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
req->status = REQ_STATUS_ERROR;
if (!req->t_err)
req->t_err = err;
list_move(&req->req_list, &cancel_list); list_move(&req->req_list, &cancel_list);
} }
list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
req->status = REQ_STATUS_ERROR;
if (!req->t_err)
req->t_err = err;
list_move(&req->req_list, &cancel_list); list_move(&req->req_list, &cancel_list);
} }
spin_unlock_irqrestore(&m->client->lock, flags); spin_unlock_irqrestore(&m->client->lock, flags);
...@@ -228,7 +222,9 @@ static void p9_conn_cancel(struct p9_conn *m, int err) ...@@ -228,7 +222,9 @@ static void p9_conn_cancel(struct p9_conn *m, int err)
list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
p9_debug(P9_DEBUG_ERROR, "call back req %p\n", req); p9_debug(P9_DEBUG_ERROR, "call back req %p\n", req);
list_del(&req->req_list); list_del(&req->req_list);
p9_client_cb(m->client, req); if (!req->t_err)
req->t_err = err;
p9_client_cb(m->client, req, REQ_STATUS_ERROR);
} }
} }
...@@ -302,6 +298,7 @@ static void p9_read_work(struct work_struct *work) ...@@ -302,6 +298,7 @@ static void p9_read_work(struct work_struct *work)
{ {
int n, err; int n, err;
struct p9_conn *m; struct p9_conn *m;
int status = REQ_STATUS_ERROR;
m = container_of(work, struct p9_conn, rq); m = container_of(work, struct p9_conn, rq);
...@@ -375,10 +372,10 @@ static void p9_read_work(struct work_struct *work) ...@@ -375,10 +372,10 @@ static void p9_read_work(struct work_struct *work)
p9_debug(P9_DEBUG_TRANS, "got new packet\n"); p9_debug(P9_DEBUG_TRANS, "got new packet\n");
spin_lock(&m->client->lock); spin_lock(&m->client->lock);
if (m->req->status != REQ_STATUS_ERROR) if (m->req->status != REQ_STATUS_ERROR)
m->req->status = REQ_STATUS_RCVD; status = REQ_STATUS_RCVD;
list_del(&m->req->req_list); list_del(&m->req->req_list);
spin_unlock(&m->client->lock); spin_unlock(&m->client->lock);
p9_client_cb(m->client, m->req); p9_client_cb(m->client, m->req, status);
m->rbuf = NULL; m->rbuf = NULL;
m->rpos = 0; m->rpos = 0;
m->rsize = 0; m->rsize = 0;
......
...@@ -305,8 +305,7 @@ handle_recv(struct p9_client *client, struct p9_trans_rdma *rdma, ...@@ -305,8 +305,7 @@ handle_recv(struct p9_client *client, struct p9_trans_rdma *rdma,
} }
req->rc = c->rc; req->rc = c->rc;
req->status = REQ_STATUS_RCVD; p9_client_cb(client, req, REQ_STATUS_RCVD);
p9_client_cb(client, req);
return; return;
......
...@@ -164,8 +164,7 @@ static void req_done(struct virtqueue *vq) ...@@ -164,8 +164,7 @@ static void req_done(struct virtqueue *vq)
p9_debug(P9_DEBUG_TRANS, ": rc %p\n", rc); p9_debug(P9_DEBUG_TRANS, ": rc %p\n", rc);
p9_debug(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag); p9_debug(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
req = p9_tag_lookup(chan->client, rc->tag); req = p9_tag_lookup(chan->client, rc->tag);
req->status = REQ_STATUS_RCVD; p9_client_cb(chan->client, req, REQ_STATUS_RCVD);
p9_client_cb(chan->client, req);
} }
} }
......
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