diff options
author | Latchesar Ionkov <lucho@ionkov.net> | 2006-02-03 11:04:20 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-02-03 16:32:06 (GMT) |
commit | 034b91a3b66cf9d2983ac45f73162395c0936c36 (patch) | |
tree | d8d731e5ef3dbe3cea129c48d5c1bc245414f189 /fs/9p/mux.c | |
parent | 05818a004a84951fd383694f3b35d89eb49fa308 (diff) | |
download | linux-fsl-qoriq-034b91a3b66cf9d2983ac45f73162395c0936c36.tar.xz |
[PATCH] v9fs: fix corner cases when flushing request
When v9fs_mux_rpc sends a 9P message, it may be put in the queue of unsent
request. If the user process receives a signal, v9fs_mux_rpc sets the
request error to ERREQFLUSH and assigns NULL to request's send message. If
the message was still in the unsent queue, v9fs_write_work would produce an
oops while processing it.
The patch makes sure that requests that are being flushed are moved to the
pending requests queue safely.
If a request is being flushed, don't remove it from the list of pending
requests even if it receives a reply before the flush is acknoledged. The
request will be removed during from the Rflush handler (v9fs_mux_flush_cb).
Signed-off-by: Latchesar Ionkov <lucho@ionkov.net>
Cc: Eric Van Hensbergen <ericvh@ericvh.myip.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/9p/mux.c')
-rw-r--r-- | fs/9p/mux.c | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/fs/9p/mux.c b/fs/9p/mux.c index 945cb36..ea1134e 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c @@ -471,10 +471,13 @@ static void v9fs_write_work(void *a) } spin_lock(&m->lock); - req = - list_entry(m->unsent_req_list.next, struct v9fs_req, +again: + req = list_entry(m->unsent_req_list.next, struct v9fs_req, req_list); list_move_tail(&req->req_list, &m->req_list); + if (req->err == ERREQFLUSH) + goto again; + m->wbuf = req->tcall->sdata; m->wsize = req->tcall->size; m->wpos = 0; @@ -525,7 +528,7 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) struct v9fs_str *ename; tag = req->tag; - if (req->rcall->id == RERROR && !req->err) { + if (!req->err && req->rcall->id == RERROR) { ecode = req->rcall->params.rerror.errno; ename = &req->rcall->params.rerror.error; @@ -551,7 +554,10 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) req->err = -EIO; } - if (req->cb && req->err != ERREQFLUSH) { + if (req->err == ERREQFLUSH) + return; + + if (req->cb) { dprintk(DEBUG_MUX, "calling callback tcall %p rcall %p\n", req->tcall, req->rcall); @@ -812,6 +818,7 @@ v9fs_mux_rpc_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc, int err) struct v9fs_mux_rpc *r; if (err == ERREQFLUSH) { + kfree(rc); dprintk(DEBUG_MUX, "err req flush\n"); return; } |