aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominique Martinet <dominique.martinet@cea.fr>2014-01-17 12:31:00 -0500
committerEric Van Hensbergen <ericvh@gmail.com>2014-03-25 17:37:59 -0400
commit2b6e72ed747f68a038df616efd86744b3644d694 (patch)
treed781427484432608a74ccc44fd4a7a3296751f23
parent38dbfb59d1175ef458d006556061adeaa8751b72 (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.h2
-rw-r--r--net/9p/client.c16
-rw-r--r--net/9p/trans_fd.c15
-rw-r--r--net/9p/trans_rdma.c3
-rw-r--r--net/9p/trans_virtio.c3
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,
261int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status); 261int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status);
262int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl); 262int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl);
263struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); 263struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
264void p9_client_cb(struct p9_client *c, struct p9_req_t *req); 264void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status);
265 265
266int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int); 266int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int);
267int p9stat_read(struct p9_client *, char *, int, struct p9_wstat *); 267int 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 */
418void p9_client_cb(struct p9_client *c, struct p9_req_t *req) 418void 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