diff options
author | Dominique Martinet <dominique.martinet@cea.fr> | 2014-01-17 12:31:00 -0500 |
---|---|---|
committer | Eric Van Hensbergen <ericvh@gmail.com> | 2014-03-25 17:37:59 -0400 |
commit | 2b6e72ed747f68a038df616efd86744b3644d694 (patch) | |
tree | d781427484432608a74ccc44fd4a7a3296751f23 | |
parent | 38dbfb59d1175ef458d006556061adeaa8751b72 (diff) |
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>
-rw-r--r-- | include/net/9p/client.h | 2 | ||||
-rw-r--r-- | net/9p/client.c | 16 | ||||
-rw-r--r-- | net/9p/trans_fd.c | 15 | ||||
-rw-r--r-- | net/9p/trans_rdma.c | 3 | ||||
-rw-r--r-- | net/9p/trans_virtio.c | 3 |
5 files changed, 24 insertions, 15 deletions
diff --git a/include/net/9p/client.h b/include/net/9p/client.h index c38a005bd0cf..115aeac401b1 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h | |||
@@ -261,7 +261,7 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, | |||
261 | int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status); | 261 | int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status); |
262 | int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl); | 262 | int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl); |
263 | struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); | 263 | struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); |
264 | void p9_client_cb(struct p9_client *c, struct p9_req_t *req); | 264 | void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status); |
265 | 265 | ||
266 | int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int); | 266 | int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int); |
267 | int p9stat_read(struct p9_client *, char *, int, struct p9_wstat *); | 267 | int p9stat_read(struct p9_client *, char *, int, struct p9_wstat *); |
diff --git a/net/9p/client.c b/net/9p/client.c index a5e4d2dcb03e..95b1836173e1 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -415,9 +415,17 @@ static void p9_free_req(struct p9_client *c, struct p9_req_t *r) | |||
415 | * req: request received | 415 | * req: request received |
416 | * | 416 | * |
417 | */ | 417 | */ |
418 | void p9_client_cb(struct p9_client *c, struct p9_req_t *req) | 418 | void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status) |
419 | { | 419 | { |
420 | p9_debug(P9_DEBUG_MUX, " tag %d\n", req->tc->tag); | 420 | p9_debug(P9_DEBUG_MUX, " tag %d\n", req->tc->tag); |
421 | |||
422 | /* | ||
423 | * This barrier is needed to make sure any change made to req before | ||
424 | * the other thread wakes up will indeed be seen by the waiting side. | ||
425 | */ | ||
426 | smp_wmb(); | ||
427 | req->status = status; | ||
428 | |||
421 | wake_up(req->wq); | 429 | wake_up(req->wq); |
422 | p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag); | 430 | p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag); |
423 | } | 431 | } |
@@ -751,6 +759,12 @@ again: | |||
751 | err = wait_event_interruptible(*req->wq, | 759 | err = wait_event_interruptible(*req->wq, |
752 | req->status >= REQ_STATUS_RCVD); | 760 | req->status >= REQ_STATUS_RCVD); |
753 | 761 | ||
762 | /* | ||
763 | * Make sure our req is coherent with regard to updates in other | ||
764 | * threads - echoes to wmb() in the callback | ||
765 | */ | ||
766 | smp_rmb(); | ||
767 | |||
754 | if ((err == -ERESTARTSYS) && (c->status == Connected) | 768 | if ((err == -ERESTARTSYS) && (c->status == Connected) |
755 | && (type == P9_TFLUSH)) { | 769 | && (type == P9_TFLUSH)) { |
756 | sigpending = 1; | 770 | sigpending = 1; |
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index b7bd7f2961bf..193efd562466 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c | |||
@@ -212,15 +212,9 @@ static void p9_conn_cancel(struct p9_conn *m, int err) | |||
212 | m->err = err; | 212 | m->err = err; |
213 | 213 | ||
214 | list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { | 214 | list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { |
215 | req->status = REQ_STATUS_ERROR; | ||
216 | if (!req->t_err) | ||
217 | req->t_err = err; | ||
218 | list_move(&req->req_list, &cancel_list); | 215 | list_move(&req->req_list, &cancel_list); |
219 | } | 216 | } |
220 | list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { | 217 | list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { |
221 | req->status = REQ_STATUS_ERROR; | ||
222 | if (!req->t_err) | ||
223 | req->t_err = err; | ||
224 | list_move(&req->req_list, &cancel_list); | 218 | list_move(&req->req_list, &cancel_list); |
225 | } | 219 | } |
226 | spin_unlock_irqrestore(&m->client->lock, flags); | 220 | spin_unlock_irqrestore(&m->client->lock, flags); |
@@ -228,7 +222,9 @@ static void p9_conn_cancel(struct p9_conn *m, int err) | |||
228 | list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { | 222 | list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { |
229 | p9_debug(P9_DEBUG_ERROR, "call back req %p\n", req); | 223 | p9_debug(P9_DEBUG_ERROR, "call back req %p\n", req); |
230 | list_del(&req->req_list); | 224 | list_del(&req->req_list); |
231 | p9_client_cb(m->client, req); | 225 | if (!req->t_err) |
226 | req->t_err = err; | ||
227 | p9_client_cb(m->client, req, REQ_STATUS_ERROR); | ||
232 | } | 228 | } |
233 | } | 229 | } |
234 | 230 | ||
@@ -302,6 +298,7 @@ static void p9_read_work(struct work_struct *work) | |||
302 | { | 298 | { |
303 | int n, err; | 299 | int n, err; |
304 | struct p9_conn *m; | 300 | struct p9_conn *m; |
301 | int status = REQ_STATUS_ERROR; | ||
305 | 302 | ||
306 | m = container_of(work, struct p9_conn, rq); | 303 | m = container_of(work, struct p9_conn, rq); |
307 | 304 | ||
@@ -375,10 +372,10 @@ static void p9_read_work(struct work_struct *work) | |||
375 | p9_debug(P9_DEBUG_TRANS, "got new packet\n"); | 372 | p9_debug(P9_DEBUG_TRANS, "got new packet\n"); |
376 | spin_lock(&m->client->lock); | 373 | spin_lock(&m->client->lock); |
377 | if (m->req->status != REQ_STATUS_ERROR) | 374 | if (m->req->status != REQ_STATUS_ERROR) |
378 | m->req->status = REQ_STATUS_RCVD; | 375 | status = REQ_STATUS_RCVD; |
379 | list_del(&m->req->req_list); | 376 | list_del(&m->req->req_list); |
380 | spin_unlock(&m->client->lock); | 377 | spin_unlock(&m->client->lock); |
381 | p9_client_cb(m->client, m->req); | 378 | p9_client_cb(m->client, m->req, status); |
382 | m->rbuf = NULL; | 379 | m->rbuf = NULL; |
383 | m->rpos = 0; | 380 | m->rpos = 0; |
384 | m->rsize = 0; | 381 | m->rsize = 0; |
diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c index 8f68df5d2973..f127ae504911 100644 --- a/net/9p/trans_rdma.c +++ b/net/9p/trans_rdma.c | |||
@@ -305,8 +305,7 @@ handle_recv(struct p9_client *client, struct p9_trans_rdma *rdma, | |||
305 | } | 305 | } |
306 | 306 | ||
307 | req->rc = c->rc; | 307 | req->rc = c->rc; |
308 | req->status = REQ_STATUS_RCVD; | 308 | p9_client_cb(client, req, REQ_STATUS_RCVD); |
309 | p9_client_cb(client, req); | ||
310 | 309 | ||
311 | return; | 310 | return; |
312 | 311 | ||
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index cd1e1ede73a4..a8c67e2be3f8 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c | |||
@@ -164,8 +164,7 @@ static void req_done(struct virtqueue *vq) | |||
164 | p9_debug(P9_DEBUG_TRANS, ": rc %p\n", rc); | 164 | p9_debug(P9_DEBUG_TRANS, ": rc %p\n", rc); |
165 | p9_debug(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag); | 165 | p9_debug(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag); |
166 | req = p9_tag_lookup(chan->client, rc->tag); | 166 | req = p9_tag_lookup(chan->client, rc->tag); |
167 | req->status = REQ_STATUS_RCVD; | 167 | p9_client_cb(chan->client, req, REQ_STATUS_RCVD); |
168 | p9_client_cb(chan->client, req); | ||
169 | } | 168 | } |
170 | } | 169 | } |
171 | 170 | ||