From 034b91a3b66cf9d2983ac45f73162395c0936c36 Mon Sep 17 00:00:00 2001 From: Latchesar Ionkov Date: Fri, 3 Feb 2006 03:04:20 -0800 Subject: [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 Cc: Eric Van Hensbergen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/9p/mux.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/9p/mux.c b/fs/9p/mux.c index 945cb368d45..ea1134eb47c 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; } -- cgit v1.2.3