From: Eric Van Hensbergen Date: Fri, 9 Sep 2005 20:04:28 +0000 (-0700) Subject: [PATCH] v9fs: fix handling of malformed 9P messages X-Git-Tag: v2.6.14-rc1~330 X-Git-Url: http://pilppa.com/gitweb/?a=commitdiff_plain;h=cb2e87a65d6cd735eb06fa595bf90497af28c37b;p=linux-2.6-omap-h63xx.git [PATCH] v9fs: fix handling of malformed 9P messages This patch attempts to do a better job of cleaning up after detecting errors on the transport. This should also improve error reporting on broken connections to servers. Signed-off-by: Latchesar Ionkov Signed-off-by: Eric Van Hensbergen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- diff --git a/fs/9p/error.h b/fs/9p/error.h index 2eb5927d589..78f89acf7c9 100644 --- a/fs/9p/error.h +++ b/fs/9p/error.h @@ -47,6 +47,7 @@ static struct errormap errmap[] = { {"Operation not permitted", EPERM}, {"wstat prohibited", EPERM}, {"No such file or directory", ENOENT}, + {"directory entry not found", ENOENT}, {"file not found", ENOENT}, {"Interrupted system call", EINTR}, {"Input/output error", EIO}, diff --git a/fs/9p/mux.c b/fs/9p/mux.c index 0854bef58c1..8835b576f74 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c @@ -162,18 +162,21 @@ static int v9fs_recv(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req) dprintk(DEBUG_MUX, "waiting for response: %d\n", req->tcall->tag); ret = wait_event_interruptible(v9ses->read_wait, ((v9ses->transport->status != Connected) || - (req->rcall != 0) || dprintcond(v9ses, req))); + (req->rcall != 0) || (req->err < 0) || + dprintcond(v9ses, req))); dprintk(DEBUG_MUX, "got it: rcall %p\n", req->rcall); + + spin_lock(&v9ses->muxlock); + list_del(&req->next); + spin_unlock(&v9ses->muxlock); + + if (req->err < 0) + return req->err; + if (v9ses->transport->status == Disconnected) return -ECONNRESET; - if (ret == 0) { - spin_lock(&v9ses->muxlock); - list_del(&req->next); - spin_unlock(&v9ses->muxlock); - } - return ret; } @@ -245,6 +248,9 @@ v9fs_mux_rpc(struct v9fs_session_info *v9ses, struct v9fs_fcall *tcall, if (!v9ses) return -EINVAL; + if (!v9ses->transport || v9ses->transport->status != Connected) + return -EIO; + if (rcall) *rcall = NULL; @@ -257,6 +263,7 @@ v9fs_mux_rpc(struct v9fs_session_info *v9ses, struct v9fs_fcall *tcall, tcall->tag = tid; req.tcall = tcall; + req.err = 0; req.rcall = NULL; ret = v9fs_send(v9ses, &req); @@ -371,16 +378,21 @@ static int v9fs_recvproc(void *data) } err = read_message(v9ses, rcall, v9ses->maxdata + V9FS_IOHDRSZ); - if (err < 0) { - kfree(rcall); - break; - } spin_lock(&v9ses->muxlock); - list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { - if (rreq->tcall->tag == rcall->tag) { - req = rreq; - req->rcall = rcall; - break; + if (err < 0) { + list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { + rreq->err = err; + } + if(err != -ERESTARTSYS) + eprintk(KERN_ERR, + "Transport error while reading message %d\n", err); + } else { + list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { + if (rreq->tcall->tag == rcall->tag) { + req = rreq; + req->rcall = rcall; + break; + } } } @@ -399,9 +411,10 @@ static int v9fs_recvproc(void *data) spin_unlock(&v9ses->muxlock); if (!req) { - dprintk(DEBUG_ERROR, - "unexpected response: id %d tag %d\n", - rcall->id, rcall->tag); + if (err >= 0) + dprintk(DEBUG_ERROR, + "unexpected response: id %d tag %d\n", + rcall->id, rcall->tag); kfree(rcall); } @@ -410,6 +423,8 @@ static int v9fs_recvproc(void *data) set_current_state(TASK_INTERRUPTIBLE); } + v9ses->transport->close(v9ses->transport); + /* Inform all pending processes about the failure */ wake_up_all(&v9ses->read_wait); diff --git a/fs/9p/mux.h b/fs/9p/mux.h index 82ce793af1b..4994cb10bad 100644 --- a/fs/9p/mux.h +++ b/fs/9p/mux.h @@ -28,6 +28,7 @@ struct v9fs_rpcreq { struct v9fs_fcall *tcall; struct v9fs_fcall *rcall; + int err; /* error code if response failed */ /* XXX - could we put scatter/gather buffers here? */ diff --git a/fs/9p/trans_sock.c b/fs/9p/trans_sock.c index 081d1c84780..01e26f0013a 100644 --- a/fs/9p/trans_sock.c +++ b/fs/9p/trans_sock.c @@ -254,7 +254,12 @@ v9fs_unix_init(struct v9fs_session_info *v9ses, const char *dev_name, static void v9fs_sock_close(struct v9fs_transport *trans) { - struct v9fs_trans_sock *ts = trans ? trans->priv : NULL; + struct v9fs_trans_sock *ts; + + if (!trans) + return; + + ts = trans->priv; if ((ts) && (ts->s)) { dprintk(DEBUG_TRANS, "closing the socket %p\n", ts->s); @@ -264,7 +269,10 @@ static void v9fs_sock_close(struct v9fs_transport *trans) dprintk(DEBUG_TRANS, "socket closed\n"); } - kfree(ts); + if (ts) + kfree(ts); + + trans->priv = NULL; } struct v9fs_transport v9fs_trans_tcp = {