mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
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:
committed by
Eric Van Hensbergen
parent
38dbfb59d1
commit
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_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)
|
|||||||
* 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, ...)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user