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: Dominique Martinet <dominique.martinet@cea.fr> Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
This commit is contained in:
Родитель
38dbfb59d1
Коммит
2b6e72ed74
|
@ -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_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl);
|
||||
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 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)
|
|||
* 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag);
|
||||
}
|
||||
|
@ -751,6 +759,12 @@ again:
|
|||
err = wait_event_interruptible(*req->wq,
|
||||
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)
|
||||
&& (type == P9_TFLUSH)) {
|
||||
sigpending = 1;
|
||||
|
|
|
@ -212,15 +212,9 @@ static void p9_conn_cancel(struct p9_conn *m, int err)
|
|||
m->err = err;
|
||||
|
||||
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_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);
|
||||
}
|
||||
spin_unlock_irqrestore(&m->client->lock, flags);
|
||||
|
@ -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) {
|
||||
p9_debug(P9_DEBUG_ERROR, "call back req %p\n", req);
|
||||
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)
|
|||
{
|
||||
int n, err;
|
||||
struct p9_conn *m;
|
||||
int status = REQ_STATUS_ERROR;
|
||||
|
||||
m = container_of(work, struct p9_conn, rq);
|
||||
|
||||
|
@ -375,10 +372,10 @@ static void p9_read_work(struct work_struct *work)
|
|||
p9_debug(P9_DEBUG_TRANS, "got new packet\n");
|
||||
spin_lock(&m->client->lock);
|
||||
if (m->req->status != REQ_STATUS_ERROR)
|
||||
m->req->status = REQ_STATUS_RCVD;
|
||||
status = REQ_STATUS_RCVD;
|
||||
list_del(&m->req->req_list);
|
||||
spin_unlock(&m->client->lock);
|
||||
p9_client_cb(m->client, m->req);
|
||||
p9_client_cb(m->client, m->req, status);
|
||||
m->rbuf = NULL;
|
||||
m->rpos = 0;
|
||||
m->rsize = 0;
|
||||
|
|
|
@ -305,8 +305,7 @@ handle_recv(struct p9_client *client, struct p9_trans_rdma *rdma,
|
|||
}
|
||||
|
||||
req->rc = c->rc;
|
||||
req->status = REQ_STATUS_RCVD;
|
||||
p9_client_cb(client, req);
|
||||
p9_client_cb(client, req, REQ_STATUS_RCVD);
|
||||
|
||||
return;
|
||||
|
||||
|
|
|
@ -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, ": lookup tag %d\n", rc->tag);
|
||||
req = p9_tag_lookup(chan->client, rc->tag);
|
||||
req->status = REQ_STATUS_RCVD;
|
||||
p9_client_cb(chan->client, req);
|
||||
p9_client_cb(chan->client, req, REQ_STATUS_RCVD);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче