[PATCH] v9fs: handle kthread_create failure, minor bugfixes

- remove unnecessary -ENOMEM assignments
- return correct value when buf_check_size for second time in a buffer
- handle failures when create_workqueue and kthread_create are called
- use kzalloc instead of kmalloc/memset 0
- v9fs_str_copy and v9fs_str_compare were buggy, were used only in one
  place, correct the logic and move it to the place it is used.

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>
diff --git a/fs/9p/9p.c b/fs/9p/9p.c
index dc3ce44..1a6d087 100644
--- a/fs/9p/9p.c
+++ b/fs/9p/9p.c
@@ -86,7 +86,6 @@
 	dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname,
 		aname, fid, afid);
 
-	ret = -ENOMEM;
 	tc = v9fs_create_tattach(fid, afid, uname, aname);
 	if (!IS_ERR(tc)) {
 		ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
@@ -136,7 +135,6 @@
 
 	dprintk(DEBUG_9P, "fid %d\n", fid);
 
-	ret = -ENOMEM;
 	rc = NULL;
 	tc = v9fs_create_tclunk(fid);
 	if (!IS_ERR(tc))
@@ -165,7 +163,6 @@
 
 	dprintk(DEBUG_9P, "oldtag %d\n", oldtag);
 
-	ret = -ENOMEM;
 	tc = v9fs_create_tflush(oldtag);
 	if (!IS_ERR(tc)) {
 		ret = v9fs_mux_rpc(v9ses->mux, tc, NULL);
@@ -221,7 +218,6 @@
 
 	dprintk(DEBUG_9P, "fid %d\n", fid);
 
-	ret = -ENOMEM;
 	tc = v9fs_create_twstat(fid, wstat, v9ses->extended);
 	if (!IS_ERR(tc)) {
 		ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
@@ -259,7 +255,6 @@
 	else
 		nwname = 0;
 
-	ret = -ENOMEM;
 	tc = v9fs_create_twalk(fid, newfid, nwname, &name);
 	if (!IS_ERR(tc)) {
 		ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
@@ -289,7 +284,6 @@
 
 	dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode);
 
-	ret = -ENOMEM;
 	tc = v9fs_create_topen(fid, mode);
 	if (!IS_ERR(tc)) {
 		ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
@@ -317,7 +311,6 @@
 
 	dprintk(DEBUG_9P, "fid %d\n", fid);
 
-	ret = -ENOMEM;
 	tc = v9fs_create_tremove(fid);
 	if (!IS_ERR(tc)) {
 		ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
@@ -349,7 +342,6 @@
 	dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n",
 		fid, name, perm, mode);
 
-	ret = -ENOMEM;
 	tc = v9fs_create_tcreate(fid, name, perm, mode);
 	if (!IS_ERR(tc)) {
 		ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
@@ -380,7 +372,6 @@
 	dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
 		(long long unsigned) offset, count);
 
-	ret = -ENOMEM;
 	tc = v9fs_create_tread(fid, offset, count);
 	if (!IS_ERR(tc)) {
 		ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
@@ -418,7 +409,6 @@
 	dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
 		(long long unsigned) offset, count);
 
-	ret = -ENOMEM;
 	tc = v9fs_create_twrite(fid, offset, count, data);
 	if (!IS_ERR(tc)) {
 		ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
diff --git a/fs/9p/9p.h b/fs/9p/9p.h
index 007ff63..0cd374d 100644
--- a/fs/9p/9p.h
+++ b/fs/9p/9p.h
@@ -340,9 +340,6 @@
 	fcall?fcall->params.rerror.error.len:0, \
 	fcall?fcall->params.rerror.error.str:"");
 
-char *v9fs_str_copy(char *buf, int buflen, struct v9fs_str *str);
-int v9fs_str_compare(char *buf, struct v9fs_str *str);
-
 int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
 		   char *version, struct v9fs_fcall **rcall);
 
diff --git a/fs/9p/conv.c b/fs/9p/conv.c
index f62434d..55ccfa1 100644
--- a/fs/9p/conv.c
+++ b/fs/9p/conv.c
@@ -45,37 +45,6 @@
 	unsigned char *ep;
 };
 
-char *v9fs_str_copy(char *buf, int buflen, struct v9fs_str *str)
-{
-	int n;
-
-	if (buflen < str->len)
-		n = buflen;
-	else
-		n = str->len;
-
-	memmove(buf, str->str, n - 1);
-
-	return buf;
-}
-
-int v9fs_str_compare(char *buf, struct v9fs_str *str)
-{
-	int n, ret;
-
-	ret = strncmp(buf, str->str, str->len);
-
-	if (!ret) {
-		n = strlen(buf);
-		if (n < str->len)
-			ret = -1;
-		else if (n > str->len)
-			ret = 1;
-	}
-
-	return ret;
-}
-
 static inline void buf_init(struct cbuf *buf, void *data, int datalen)
 {
 	buf->sp = buf->p = data;
@@ -89,11 +58,14 @@
 
 static inline int buf_check_size(struct cbuf *buf, int len)
 {
-	if (buf->p + len > buf->ep && buf->p < buf->ep) {
-		eprintk(KERN_ERR, "buffer overflow: want %d has %d\n",
-			len, (int)(buf->ep - buf->p));
-		dump_stack();
-		buf->p = buf->ep + 1;
+	if (buf->p + len > buf->ep) {
+		if (buf->p < buf->ep) {
+			eprintk(KERN_ERR, "buffer overflow: want %d has %d\n",
+				len, (int)(buf->ep - buf->p));
+			dump_stack();
+			buf->p = buf->ep + 1;
+		}
+
 		return 0;
 	}
 
@@ -527,6 +499,7 @@
 
 void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag)
 {
+	fc->tag = tag;
 	*(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
 }
 
diff --git a/fs/9p/error.h b/fs/9p/error.h
index 8b3176b..a9794e8 100644
--- a/fs/9p/error.h
+++ b/fs/9p/error.h
@@ -176,4 +176,3 @@
 };
 
 extern int v9fs_error_init(void);
-extern int v9fs_errstr2errno(char *errstr, int len);
diff --git a/fs/9p/mux.c b/fs/9p/mux.c
index f21cf50..945cb36 100644
--- a/fs/9p/mux.c
+++ b/fs/9p/mux.c
@@ -102,8 +102,6 @@
 	wait_queue_head_t wqueue;
 };
 
-extern int v9fs_errstr2errno(char *str, int len);
-
 static int v9fs_poll_proc(void *);
 static void v9fs_read_work(void *);
 static void v9fs_write_work(void *);
@@ -119,7 +117,7 @@
 static int v9fs_mux_poll_task_num;
 static struct v9fs_mux_poll_task v9fs_mux_poll_tasks[100];
 
-void v9fs_mux_global_init(void)
+int v9fs_mux_global_init(void)
 {
 	int i;
 
@@ -127,6 +125,10 @@
 		v9fs_mux_poll_tasks[i].task = NULL;
 
 	v9fs_mux_wq = create_workqueue("v9fs");
+	if (!v9fs_mux_wq)
+		return -ENOMEM;
+
+	return 0;
 }
 
 void v9fs_mux_global_exit(void)
@@ -156,10 +158,11 @@
 	return n;
 }
 
-static void v9fs_mux_poll_start(struct v9fs_mux_data *m)
+static int v9fs_mux_poll_start(struct v9fs_mux_data *m)
 {
 	int i, n;
 	struct v9fs_mux_poll_task *vpt, *vptlast;
+	struct task_struct *pproc;
 
 	dprintk(DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, v9fs_mux_num,
 		v9fs_mux_poll_task_num);
@@ -171,13 +174,16 @@
 			if (v9fs_mux_poll_tasks[i].task == NULL) {
 				vpt = &v9fs_mux_poll_tasks[i];
 				dprintk(DEBUG_MUX, "create proc %p\n", vpt);
-				vpt->task =
-				    kthread_create(v9fs_poll_proc, vpt,
+				pproc = kthread_create(v9fs_poll_proc, vpt,
 						   "v9fs-poll");
-				INIT_LIST_HEAD(&vpt->mux_list);
-				vpt->muxnum = 0;
-				v9fs_mux_poll_task_num++;
-				wake_up_process(vpt->task);
+
+				if (!IS_ERR(pproc)) {
+					vpt->task = pproc;
+					INIT_LIST_HEAD(&vpt->mux_list);
+					vpt->muxnum = 0;
+					v9fs_mux_poll_task_num++;
+					wake_up_process(vpt->task);
+				}
 				break;
 			}
 		}
@@ -207,16 +213,21 @@
 	}
 
 	if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks)) {
+		if (vptlast == NULL)
+			return -ENOMEM;
+
 		dprintk(DEBUG_MUX, "put in proc %d\n", i);
 		list_add(&m->mux_list, &vptlast->mux_list);
 		vptlast->muxnum++;
-		m->poll_task = vpt;
+		m->poll_task = vptlast;
 		memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
 		init_poll_funcptr(&m->pt, v9fs_pollwait);
 	}
 
 	v9fs_mux_num++;
 	down(&v9fs_mux_task_lock);
+
+	return 0;
 }
 
 static void v9fs_mux_poll_stop(struct v9fs_mux_data *m)
@@ -283,7 +294,10 @@
 	INIT_WORK(&m->wq, v9fs_write_work, m);
 	m->wsched = 0;
 	memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
-	v9fs_mux_poll_start(m);
+	m->poll_task = NULL;
+	n = v9fs_mux_poll_start(m);
+	if (n)
+		return ERR_PTR(n);
 
 	n = trans->poll(trans, &m->pt);
 	if (n & POLLIN) {
diff --git a/fs/9p/mux.h b/fs/9p/mux.h
index 02b13b1..9473b84 100644
--- a/fs/9p/mux.h
+++ b/fs/9p/mux.h
@@ -40,7 +40,7 @@
 typedef void (*v9fs_mux_req_callback)(void *a, struct v9fs_fcall *tc,
 	struct v9fs_fcall *rc, int err);
 
-void v9fs_mux_global_init(void);
+int v9fs_mux_global_init(void);
 void v9fs_mux_global_exit(void);
 
 struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
@@ -55,3 +55,4 @@
 
 void v9fs_mux_flush(struct v9fs_mux_data *m, int sendflush);
 void v9fs_mux_cancel(struct v9fs_mux_data *m, int err);
+int v9fs_errstr2errno(char *errstr, int len);
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 519b21d..5250c42 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -269,6 +269,7 @@
 	int n = 0;
 	int newfid = -1;
 	int retval = -EINVAL;
+	struct v9fs_str *version;
 
 	v9ses->name = __getname();
 	if (!v9ses->name)
@@ -351,13 +352,16 @@
 			goto FreeFcall;
 		}
 
-		/* Really should check for 9P1 and report error */
-		if (!v9fs_str_compare("9P2000.u", &fcall->params.rversion.version)) {
+		version = &fcall->params.rversion.version;
+		if (version->len==8 && !memcmp(version->str, "9P2000.u", 8)) {
 			dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n");
 			v9ses->extended = 1;
-		} else {
+		} else if (version->len==6 && !memcmp(version->str, "9P2000", 6)) {
 			dprintk(DEBUG_9P, "9P2000 legacy mode enabled\n");
 			v9ses->extended = 0;
+		} else {
+			retval = -EREMOTEIO;
+			goto FreeFcall;
 		}
 
 		n = fcall->params.rversion.msize;
@@ -449,12 +453,17 @@
 
 static int __init init_v9fs(void)
 {
+	int ret;
+
 	v9fs_error_init();
 
 	printk(KERN_INFO "Installing v9fs 9P2000 file system support\n");
 
-	v9fs_mux_global_init();
-	return register_filesystem(&v9fs_fs_type);
+	ret = v9fs_mux_global_init();
+	if (!ret)
+		ret = register_filesystem(&v9fs_fs_type);
+
+	return ret;
 }
 
 /**
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 742bcd0..d933ef1 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -768,6 +768,7 @@
 v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode,
 	struct super_block *sb)
 {
+	int n;
 	char ext[32];
 	struct v9fs_session_info *v9ses = sb->s_fs_info;
 
@@ -791,7 +792,11 @@
 		int major = -1;
 		int minor = -1;
 
-		v9fs_str_copy(ext, sizeof(ext), &stat->extension);
+		n = stat->extension.len;
+		if (n > sizeof(ext)-1)
+			n = sizeof(ext)-1;
+		memmove(ext, stat->extension.str, n);
+		ext[n] = 0;
 		sscanf(ext, "%c %u %u", &type, &major, &minor);
 		switch (type) {
 		case 'c':
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index d4d71a9..ae0f06b 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -122,11 +122,10 @@
 
 	dprintk(DEBUG_VFS, " \n");
 
-	v9ses = kmalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
+	v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
 	if (!v9ses)
 		return ERR_PTR(-ENOMEM);
 
-	memset(v9ses, 0, sizeof(struct v9fs_session_info));
 	if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) {
 		dprintk(DEBUG_ERROR, "problem initiating session\n");
 		kfree(v9ses);