summary refs log tree commit diff
path: root/fs/9p
diff options
context:
space:
mode:
authorLatchesar Ionkov <lucho@ionkov.net>2006-02-03 03:04:20 -0800
committerLinus Torvalds <torvalds@g5.osdl.org>2006-02-03 08:32:06 -0800
commit034b91a3b66cf9d2983ac45f73162395c0936c36 (patch)
treed8d731e5ef3dbe3cea129c48d5c1bc245414f189 /fs/9p
parent05818a004a84951fd383694f3b35d89eb49fa308 (diff)
downloadlinux-034b91a3b66cf9d2983ac45f73162395c0936c36.tar.gz
[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')
-rw-r--r--fs/9p/mux.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/fs/9p/mux.c b/fs/9p/mux.c
index 945cb368d451..ea1134eb47c8 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;
 	}