xref: /openbmc/linux/fs/9p/v9fs.c (revision 1dac06b2)
19e82cf6aSEric Van Hensbergen /*
29e82cf6aSEric Van Hensbergen  *  linux/fs/9p/v9fs.c
39e82cf6aSEric Van Hensbergen  *
49e82cf6aSEric Van Hensbergen  *  This file contains functions assisting in mapping VFS to 9P2000
59e82cf6aSEric Van Hensbergen  *
69e82cf6aSEric Van Hensbergen  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
79e82cf6aSEric Van Hensbergen  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
89e82cf6aSEric Van Hensbergen  *
99e82cf6aSEric Van Hensbergen  *  This program is free software; you can redistribute it and/or modify
109e82cf6aSEric Van Hensbergen  *  it under the terms of the GNU General Public License as published by
119e82cf6aSEric Van Hensbergen  *  the Free Software Foundation; either version 2 of the License, or
129e82cf6aSEric Van Hensbergen  *  (at your option) any later version.
139e82cf6aSEric Van Hensbergen  *
149e82cf6aSEric Van Hensbergen  *  This program is distributed in the hope that it will be useful,
159e82cf6aSEric Van Hensbergen  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
169e82cf6aSEric Van Hensbergen  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
179e82cf6aSEric Van Hensbergen  *  GNU General Public License for more details.
189e82cf6aSEric Van Hensbergen  *
199e82cf6aSEric Van Hensbergen  *  You should have received a copy of the GNU General Public License
209e82cf6aSEric Van Hensbergen  *  along with this program; if not, write to:
219e82cf6aSEric Van Hensbergen  *  Free Software Foundation
229e82cf6aSEric Van Hensbergen  *  51 Franklin Street, Fifth Floor
239e82cf6aSEric Van Hensbergen  *  Boston, MA  02111-1301  USA
249e82cf6aSEric Van Hensbergen  *
259e82cf6aSEric Van Hensbergen  */
269e82cf6aSEric Van Hensbergen 
279e82cf6aSEric Van Hensbergen #include <linux/config.h>
289e82cf6aSEric Van Hensbergen #include <linux/module.h>
299e82cf6aSEric Van Hensbergen #include <linux/errno.h>
309e82cf6aSEric Van Hensbergen #include <linux/fs.h>
319e82cf6aSEric Van Hensbergen #include <linux/parser.h>
329e82cf6aSEric Van Hensbergen #include <linux/idr.h>
339e82cf6aSEric Van Hensbergen 
349e82cf6aSEric Van Hensbergen #include "debug.h"
359e82cf6aSEric Van Hensbergen #include "v9fs.h"
369e82cf6aSEric Van Hensbergen #include "9p.h"
379e82cf6aSEric Van Hensbergen #include "v9fs_vfs.h"
389e82cf6aSEric Van Hensbergen #include "transport.h"
399e82cf6aSEric Van Hensbergen #include "mux.h"
409e82cf6aSEric Van Hensbergen 
419e82cf6aSEric Van Hensbergen /* TODO: sysfs or debugfs interface */
429e82cf6aSEric Van Hensbergen int v9fs_debug_level = 0;	/* feature-rific global debug level  */
439e82cf6aSEric Van Hensbergen 
449e82cf6aSEric Van Hensbergen /*
459e82cf6aSEric Van Hensbergen   * Option Parsing (code inspired by NFS code)
469e82cf6aSEric Van Hensbergen   *
479e82cf6aSEric Van Hensbergen   */
489e82cf6aSEric Van Hensbergen 
499e82cf6aSEric Van Hensbergen enum {
509e82cf6aSEric Van Hensbergen 	/* Options that take integer arguments */
519e82cf6aSEric Van Hensbergen 	Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, Opt_debug,
529e82cf6aSEric Van Hensbergen 	Opt_rfdno, Opt_wfdno,
539e82cf6aSEric Van Hensbergen 	/* String options */
549e82cf6aSEric Van Hensbergen 	Opt_name, Opt_remotename,
559e82cf6aSEric Van Hensbergen 	/* Options that take no arguments */
569e82cf6aSEric Van Hensbergen 	Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd,
579e82cf6aSEric Van Hensbergen 	/* Error token */
589e82cf6aSEric Van Hensbergen 	Opt_err
599e82cf6aSEric Van Hensbergen };
609e82cf6aSEric Van Hensbergen 
619e82cf6aSEric Van Hensbergen static match_table_t tokens = {
629e82cf6aSEric Van Hensbergen 	{Opt_port, "port=%u"},
639e82cf6aSEric Van Hensbergen 	{Opt_msize, "msize=%u"},
649e82cf6aSEric Van Hensbergen 	{Opt_uid, "uid=%u"},
659e82cf6aSEric Van Hensbergen 	{Opt_gid, "gid=%u"},
669e82cf6aSEric Van Hensbergen 	{Opt_afid, "afid=%u"},
679e82cf6aSEric Van Hensbergen 	{Opt_rfdno, "rfdno=%u"},
689e82cf6aSEric Van Hensbergen 	{Opt_wfdno, "wfdno=%u"},
699e82cf6aSEric Van Hensbergen 	{Opt_debug, "debug=%u"},
709e82cf6aSEric Van Hensbergen 	{Opt_name, "name=%s"},
719e82cf6aSEric Van Hensbergen 	{Opt_remotename, "aname=%s"},
729e82cf6aSEric Van Hensbergen 	{Opt_unix, "proto=unix"},
739e82cf6aSEric Van Hensbergen 	{Opt_tcp, "proto=tcp"},
749e82cf6aSEric Van Hensbergen 	{Opt_fd, "proto=fd"},
759e82cf6aSEric Van Hensbergen 	{Opt_tcp, "tcp"},
769e82cf6aSEric Van Hensbergen 	{Opt_unix, "unix"},
779e82cf6aSEric Van Hensbergen 	{Opt_fd, "fd"},
789e82cf6aSEric Van Hensbergen 	{Opt_legacy, "noextend"},
799e82cf6aSEric Van Hensbergen 	{Opt_nodevmap, "nodevmap"},
809e82cf6aSEric Van Hensbergen 	{Opt_err, NULL}
819e82cf6aSEric Van Hensbergen };
829e82cf6aSEric Van Hensbergen 
839e82cf6aSEric Van Hensbergen /*
849e82cf6aSEric Van Hensbergen  *  Parse option string.
859e82cf6aSEric Van Hensbergen  */
869e82cf6aSEric Van Hensbergen 
879e82cf6aSEric Van Hensbergen /**
889e82cf6aSEric Van Hensbergen  * v9fs_parse_options - parse mount options into session structure
899e82cf6aSEric Van Hensbergen  * @options: options string passed from mount
909e82cf6aSEric Van Hensbergen  * @v9ses: existing v9fs session information
919e82cf6aSEric Van Hensbergen  *
929e82cf6aSEric Van Hensbergen  */
939e82cf6aSEric Van Hensbergen 
949e82cf6aSEric Van Hensbergen static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses)
959e82cf6aSEric Van Hensbergen {
969e82cf6aSEric Van Hensbergen 	char *p;
979e82cf6aSEric Van Hensbergen 	substring_t args[MAX_OPT_ARGS];
989e82cf6aSEric Van Hensbergen 	int option;
999e82cf6aSEric Van Hensbergen 	int ret;
1009e82cf6aSEric Van Hensbergen 
1019e82cf6aSEric Van Hensbergen 	/* setup defaults */
1029e82cf6aSEric Van Hensbergen 	v9ses->port = V9FS_PORT;
1039e82cf6aSEric Van Hensbergen 	v9ses->maxdata = 9000;
1049e82cf6aSEric Van Hensbergen 	v9ses->proto = PROTO_TCP;
1059e82cf6aSEric Van Hensbergen 	v9ses->extended = 1;
1069e82cf6aSEric Van Hensbergen 	v9ses->afid = ~0;
1079e82cf6aSEric Van Hensbergen 	v9ses->debug = 0;
1089e82cf6aSEric Van Hensbergen 	v9ses->rfdno = ~0;
1099e82cf6aSEric Van Hensbergen 	v9ses->wfdno = ~0;
1109e82cf6aSEric Van Hensbergen 
1119e82cf6aSEric Van Hensbergen 	if (!options)
1129e82cf6aSEric Van Hensbergen 		return;
1139e82cf6aSEric Van Hensbergen 
1149e82cf6aSEric Van Hensbergen 	while ((p = strsep(&options, ",")) != NULL) {
1159e82cf6aSEric Van Hensbergen 		int token;
1169e82cf6aSEric Van Hensbergen 		if (!*p)
1179e82cf6aSEric Van Hensbergen 			continue;
1189e82cf6aSEric Van Hensbergen 		token = match_token(p, tokens, args);
1199e82cf6aSEric Van Hensbergen 		if (token < Opt_name) {
1209e82cf6aSEric Van Hensbergen 			if ((ret = match_int(&args[0], &option)) < 0) {
1219e82cf6aSEric Van Hensbergen 				dprintk(DEBUG_ERROR,
1229e82cf6aSEric Van Hensbergen 					"integer field, but no integer?\n");
1239e82cf6aSEric Van Hensbergen 				continue;
1249e82cf6aSEric Van Hensbergen 			}
1259e82cf6aSEric Van Hensbergen 
1269e82cf6aSEric Van Hensbergen 		}
1279e82cf6aSEric Van Hensbergen 		switch (token) {
1289e82cf6aSEric Van Hensbergen 		case Opt_port:
1299e82cf6aSEric Van Hensbergen 			v9ses->port = option;
1309e82cf6aSEric Van Hensbergen 			break;
1319e82cf6aSEric Van Hensbergen 		case Opt_msize:
1329e82cf6aSEric Van Hensbergen 			v9ses->maxdata = option;
1339e82cf6aSEric Van Hensbergen 			break;
1349e82cf6aSEric Van Hensbergen 		case Opt_uid:
1359e82cf6aSEric Van Hensbergen 			v9ses->uid = option;
1369e82cf6aSEric Van Hensbergen 			break;
1379e82cf6aSEric Van Hensbergen 		case Opt_gid:
1389e82cf6aSEric Van Hensbergen 			v9ses->gid = option;
1399e82cf6aSEric Van Hensbergen 			break;
1409e82cf6aSEric Van Hensbergen 		case Opt_afid:
1419e82cf6aSEric Van Hensbergen 			v9ses->afid = option;
1429e82cf6aSEric Van Hensbergen 			break;
1439e82cf6aSEric Van Hensbergen 		case Opt_rfdno:
1449e82cf6aSEric Van Hensbergen 			v9ses->rfdno = option;
1459e82cf6aSEric Van Hensbergen 			break;
1469e82cf6aSEric Van Hensbergen 		case Opt_wfdno:
1479e82cf6aSEric Van Hensbergen 			v9ses->wfdno = option;
1489e82cf6aSEric Van Hensbergen 			break;
1499e82cf6aSEric Van Hensbergen 		case Opt_debug:
1509e82cf6aSEric Van Hensbergen 			v9ses->debug = option;
1519e82cf6aSEric Van Hensbergen 			break;
1529e82cf6aSEric Van Hensbergen 		case Opt_tcp:
1539e82cf6aSEric Van Hensbergen 			v9ses->proto = PROTO_TCP;
1549e82cf6aSEric Van Hensbergen 			break;
1559e82cf6aSEric Van Hensbergen 		case Opt_unix:
1569e82cf6aSEric Van Hensbergen 			v9ses->proto = PROTO_UNIX;
1579e82cf6aSEric Van Hensbergen 			break;
1589e82cf6aSEric Van Hensbergen 		case Opt_fd:
1599e82cf6aSEric Van Hensbergen 			v9ses->proto = PROTO_FD;
1609e82cf6aSEric Van Hensbergen 			break;
1619e82cf6aSEric Van Hensbergen 		case Opt_name:
1629e82cf6aSEric Van Hensbergen 			match_strcpy(v9ses->name, &args[0]);
1639e82cf6aSEric Van Hensbergen 			break;
1649e82cf6aSEric Van Hensbergen 		case Opt_remotename:
1659e82cf6aSEric Van Hensbergen 			match_strcpy(v9ses->remotename, &args[0]);
1669e82cf6aSEric Van Hensbergen 			break;
1679e82cf6aSEric Van Hensbergen 		case Opt_legacy:
1689e82cf6aSEric Van Hensbergen 			v9ses->extended = 0;
1699e82cf6aSEric Van Hensbergen 			break;
1709e82cf6aSEric Van Hensbergen 		case Opt_nodevmap:
1719e82cf6aSEric Van Hensbergen 			v9ses->nodev = 1;
1729e82cf6aSEric Van Hensbergen 			break;
1739e82cf6aSEric Van Hensbergen 		default:
1749e82cf6aSEric Van Hensbergen 			continue;
1759e82cf6aSEric Van Hensbergen 		}
1769e82cf6aSEric Van Hensbergen 	}
1779e82cf6aSEric Van Hensbergen }
1789e82cf6aSEric Van Hensbergen 
1799e82cf6aSEric Van Hensbergen /**
1809e82cf6aSEric Van Hensbergen  * v9fs_inode2v9ses - safely extract v9fs session info from super block
1819e82cf6aSEric Van Hensbergen  * @inode: inode to extract information from
1829e82cf6aSEric Van Hensbergen  *
1839e82cf6aSEric Van Hensbergen  * Paranoid function to extract v9ses information from superblock,
1849e82cf6aSEric Van Hensbergen  * if anything is missing it will report an error.
1859e82cf6aSEric Van Hensbergen  *
1869e82cf6aSEric Van Hensbergen  */
1879e82cf6aSEric Van Hensbergen 
1889e82cf6aSEric Van Hensbergen struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
1899e82cf6aSEric Van Hensbergen {
1909e82cf6aSEric Van Hensbergen 	return (inode->i_sb->s_fs_info);
1919e82cf6aSEric Van Hensbergen }
1929e82cf6aSEric Van Hensbergen 
1939e82cf6aSEric Van Hensbergen /**
1949e82cf6aSEric Van Hensbergen  * v9fs_get_idpool - allocate numeric id from pool
1959e82cf6aSEric Van Hensbergen  * @p - pool to allocate from
1969e82cf6aSEric Van Hensbergen  *
1979e82cf6aSEric Van Hensbergen  * XXX - This seems to be an awful generic function, should it be in idr.c with
1989e82cf6aSEric Van Hensbergen  *            the lock included in struct idr?
1999e82cf6aSEric Van Hensbergen  */
2009e82cf6aSEric Van Hensbergen 
2019e82cf6aSEric Van Hensbergen int v9fs_get_idpool(struct v9fs_idpool *p)
2029e82cf6aSEric Van Hensbergen {
2039e82cf6aSEric Van Hensbergen 	int i = 0;
2049e82cf6aSEric Van Hensbergen 	int error;
2059e82cf6aSEric Van Hensbergen 
2069e82cf6aSEric Van Hensbergen retry:
2079e82cf6aSEric Van Hensbergen 	if (idr_pre_get(&p->pool, GFP_KERNEL) == 0)
2089e82cf6aSEric Van Hensbergen 		return 0;
2099e82cf6aSEric Van Hensbergen 
2109e82cf6aSEric Van Hensbergen 	if (down_interruptible(&p->lock) == -EINTR) {
2119e82cf6aSEric Van Hensbergen 		eprintk(KERN_WARNING, "Interrupted while locking\n");
2129e82cf6aSEric Van Hensbergen 		return -1;
2139e82cf6aSEric Van Hensbergen 	}
2149e82cf6aSEric Van Hensbergen 
2153cf6429aSLatchesar Ionkov 	/* no need to store exactly p, we just need something non-null */
2163cf6429aSLatchesar Ionkov 	error = idr_get_new(&p->pool, p, &i);
2179e82cf6aSEric Van Hensbergen 	up(&p->lock);
2189e82cf6aSEric Van Hensbergen 
2199e82cf6aSEric Van Hensbergen 	if (error == -EAGAIN)
2209e82cf6aSEric Van Hensbergen 		goto retry;
2219e82cf6aSEric Van Hensbergen 	else if (error)
2229e82cf6aSEric Van Hensbergen 		return -1;
2239e82cf6aSEric Van Hensbergen 
2249e82cf6aSEric Van Hensbergen 	return i;
2259e82cf6aSEric Van Hensbergen }
2269e82cf6aSEric Van Hensbergen 
2279e82cf6aSEric Van Hensbergen /**
2289e82cf6aSEric Van Hensbergen  * v9fs_put_idpool - release numeric id from pool
2299e82cf6aSEric Van Hensbergen  * @p - pool to allocate from
2309e82cf6aSEric Van Hensbergen  *
2319e82cf6aSEric Van Hensbergen  * XXX - This seems to be an awful generic function, should it be in idr.c with
2329e82cf6aSEric Van Hensbergen  *            the lock included in struct idr?
2339e82cf6aSEric Van Hensbergen  */
2349e82cf6aSEric Van Hensbergen 
2359e82cf6aSEric Van Hensbergen void v9fs_put_idpool(int id, struct v9fs_idpool *p)
2369e82cf6aSEric Van Hensbergen {
2379e82cf6aSEric Van Hensbergen 	if (down_interruptible(&p->lock) == -EINTR) {
2389e82cf6aSEric Van Hensbergen 		eprintk(KERN_WARNING, "Interrupted while locking\n");
2399e82cf6aSEric Van Hensbergen 		return;
2409e82cf6aSEric Van Hensbergen 	}
2419e82cf6aSEric Van Hensbergen 	idr_remove(&p->pool, id);
2429e82cf6aSEric Van Hensbergen 	up(&p->lock);
2439e82cf6aSEric Van Hensbergen }
2449e82cf6aSEric Van Hensbergen 
2459e82cf6aSEric Van Hensbergen /**
2463cf6429aSLatchesar Ionkov  * v9fs_check_idpool - check if the specified id is available
2473cf6429aSLatchesar Ionkov  * @id - id to check
2483cf6429aSLatchesar Ionkov  * @p - pool
2493cf6429aSLatchesar Ionkov  */
2503cf6429aSLatchesar Ionkov int v9fs_check_idpool(int id, struct v9fs_idpool *p)
2513cf6429aSLatchesar Ionkov {
2523cf6429aSLatchesar Ionkov 	return idr_find(&p->pool, id) != NULL;
2533cf6429aSLatchesar Ionkov }
2543cf6429aSLatchesar Ionkov 
2553cf6429aSLatchesar Ionkov /**
2569e82cf6aSEric Van Hensbergen  * v9fs_session_init - initialize session
2579e82cf6aSEric Van Hensbergen  * @v9ses: session information structure
2589e82cf6aSEric Van Hensbergen  * @dev_name: device being mounted
2599e82cf6aSEric Van Hensbergen  * @data: options
2609e82cf6aSEric Van Hensbergen  *
2619e82cf6aSEric Van Hensbergen  */
2629e82cf6aSEric Van Hensbergen 
2639e82cf6aSEric Van Hensbergen int
2649e82cf6aSEric Van Hensbergen v9fs_session_init(struct v9fs_session_info *v9ses,
2659e82cf6aSEric Van Hensbergen 		  const char *dev_name, char *data)
2669e82cf6aSEric Van Hensbergen {
2679e82cf6aSEric Van Hensbergen 	struct v9fs_fcall *fcall = NULL;
2689e82cf6aSEric Van Hensbergen 	struct v9fs_transport *trans_proto;
2699e82cf6aSEric Van Hensbergen 	int n = 0;
2709e82cf6aSEric Van Hensbergen 	int newfid = -1;
2719e82cf6aSEric Van Hensbergen 	int retval = -EINVAL;
2721dac06b2SLatchesar Ionkov 	struct v9fs_str *version;
2739e82cf6aSEric Van Hensbergen 
2749e82cf6aSEric Van Hensbergen 	v9ses->name = __getname();
2759e82cf6aSEric Van Hensbergen 	if (!v9ses->name)
2769e82cf6aSEric Van Hensbergen 		return -ENOMEM;
2779e82cf6aSEric Van Hensbergen 
2789e82cf6aSEric Van Hensbergen 	v9ses->remotename = __getname();
2799e82cf6aSEric Van Hensbergen 	if (!v9ses->remotename) {
280ce44eeb6SDavi Arnaut 		__putname(v9ses->name);
2819e82cf6aSEric Van Hensbergen 		return -ENOMEM;
2829e82cf6aSEric Van Hensbergen 	}
2839e82cf6aSEric Van Hensbergen 
2849e82cf6aSEric Van Hensbergen 	strcpy(v9ses->name, V9FS_DEFUSER);
2859e82cf6aSEric Van Hensbergen 	strcpy(v9ses->remotename, V9FS_DEFANAME);
2869e82cf6aSEric Van Hensbergen 
2879e82cf6aSEric Van Hensbergen 	v9fs_parse_options(data, v9ses);
2889e82cf6aSEric Van Hensbergen 
2899e82cf6aSEric Van Hensbergen 	/* set global debug level */
2909e82cf6aSEric Van Hensbergen 	v9fs_debug_level = v9ses->debug;
2919e82cf6aSEric Van Hensbergen 
2929e82cf6aSEric Van Hensbergen 	/* id pools that are session-dependent: FIDs and TIDs */
2939e82cf6aSEric Van Hensbergen 	idr_init(&v9ses->fidpool.pool);
2949e82cf6aSEric Van Hensbergen 	init_MUTEX(&v9ses->fidpool.lock);
2959e82cf6aSEric Van Hensbergen 
2969e82cf6aSEric Van Hensbergen 	switch (v9ses->proto) {
2979e82cf6aSEric Van Hensbergen 	case PROTO_TCP:
2989e82cf6aSEric Van Hensbergen 		trans_proto = &v9fs_trans_tcp;
2999e82cf6aSEric Van Hensbergen 		break;
3009e82cf6aSEric Van Hensbergen 	case PROTO_UNIX:
3019e82cf6aSEric Van Hensbergen 		trans_proto = &v9fs_trans_unix;
3029e82cf6aSEric Van Hensbergen 		*v9ses->remotename = 0;
3039e82cf6aSEric Van Hensbergen 		break;
3049e82cf6aSEric Van Hensbergen 	case PROTO_FD:
3059e82cf6aSEric Van Hensbergen 		trans_proto = &v9fs_trans_fd;
3069e82cf6aSEric Van Hensbergen 		*v9ses->remotename = 0;
3079e82cf6aSEric Van Hensbergen 		break;
3089e82cf6aSEric Van Hensbergen 	default:
3099e82cf6aSEric Van Hensbergen 		printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto);
3109e82cf6aSEric Van Hensbergen 		retval = -ENOPROTOOPT;
3119e82cf6aSEric Van Hensbergen 		goto SessCleanUp;
3129e82cf6aSEric Van Hensbergen 	};
3139e82cf6aSEric Van Hensbergen 
314a8e63bffSLatchesar Ionkov 	v9ses->transport = kmalloc(sizeof(*v9ses->transport), GFP_KERNEL);
315a8e63bffSLatchesar Ionkov 	if (!v9ses->transport) {
316a8e63bffSLatchesar Ionkov 		retval = -ENOMEM;
317a8e63bffSLatchesar Ionkov 		goto SessCleanUp;
318a8e63bffSLatchesar Ionkov 	}
319a8e63bffSLatchesar Ionkov 
320a8e63bffSLatchesar Ionkov 	memmove(v9ses->transport, trans_proto, sizeof(*v9ses->transport));
3219e82cf6aSEric Van Hensbergen 
3229e82cf6aSEric Van Hensbergen 	if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) {
3239e82cf6aSEric Van Hensbergen 		eprintk(KERN_ERR, "problem initializing transport\n");
3249e82cf6aSEric Van Hensbergen 		goto SessCleanUp;
3259e82cf6aSEric Van Hensbergen 	}
3269e82cf6aSEric Van Hensbergen 
3279e82cf6aSEric Van Hensbergen 	v9ses->inprogress = 0;
3289e82cf6aSEric Van Hensbergen 	v9ses->shutdown = 0;
3299e82cf6aSEric Van Hensbergen 	v9ses->session_hung = 0;
3309e82cf6aSEric Van Hensbergen 
3313cf6429aSLatchesar Ionkov 	v9ses->mux = v9fs_mux_init(v9ses->transport, v9ses->maxdata + V9FS_IOHDRSZ,
3323cf6429aSLatchesar Ionkov 		&v9ses->extended);
3333cf6429aSLatchesar Ionkov 
3343cf6429aSLatchesar Ionkov 	if (IS_ERR(v9ses->mux)) {
3353cf6429aSLatchesar Ionkov 		retval = PTR_ERR(v9ses->mux);
3363cf6429aSLatchesar Ionkov 		v9ses->mux = NULL;
3379e82cf6aSEric Van Hensbergen 		dprintk(DEBUG_ERROR, "problem initializing mux\n");
3389e82cf6aSEric Van Hensbergen 		goto SessCleanUp;
3399e82cf6aSEric Van Hensbergen 	}
3409e82cf6aSEric Van Hensbergen 
3419e82cf6aSEric Van Hensbergen 	if (v9ses->afid == ~0) {
3429e82cf6aSEric Van Hensbergen 		if (v9ses->extended)
3439e82cf6aSEric Van Hensbergen 			retval =
3449e82cf6aSEric Van Hensbergen 			    v9fs_t_version(v9ses, v9ses->maxdata, "9P2000.u",
3459e82cf6aSEric Van Hensbergen 					   &fcall);
3469e82cf6aSEric Van Hensbergen 		else
3479e82cf6aSEric Van Hensbergen 			retval = v9fs_t_version(v9ses, v9ses->maxdata, "9P2000",
3489e82cf6aSEric Van Hensbergen 						&fcall);
3499e82cf6aSEric Van Hensbergen 
3509e82cf6aSEric Van Hensbergen 		if (retval < 0) {
3519e82cf6aSEric Van Hensbergen 			dprintk(DEBUG_ERROR, "v9fs_t_version failed\n");
3529e82cf6aSEric Van Hensbergen 			goto FreeFcall;
3539e82cf6aSEric Van Hensbergen 		}
3549e82cf6aSEric Van Hensbergen 
3551dac06b2SLatchesar Ionkov 		version = &fcall->params.rversion.version;
3561dac06b2SLatchesar Ionkov 		if (version->len==8 && !memcmp(version->str, "9P2000.u", 8)) {
3579e82cf6aSEric Van Hensbergen 			dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n");
3589e82cf6aSEric Van Hensbergen 			v9ses->extended = 1;
3591dac06b2SLatchesar Ionkov 		} else if (version->len==6 && !memcmp(version->str, "9P2000", 6)) {
3609e82cf6aSEric Van Hensbergen 			dprintk(DEBUG_9P, "9P2000 legacy mode enabled\n");
3619e82cf6aSEric Van Hensbergen 			v9ses->extended = 0;
3621dac06b2SLatchesar Ionkov 		} else {
3631dac06b2SLatchesar Ionkov 			retval = -EREMOTEIO;
3641dac06b2SLatchesar Ionkov 			goto FreeFcall;
3659e82cf6aSEric Van Hensbergen 		}
3669e82cf6aSEric Van Hensbergen 
3679e82cf6aSEric Van Hensbergen 		n = fcall->params.rversion.msize;
3689e82cf6aSEric Van Hensbergen 		kfree(fcall);
3699e82cf6aSEric Van Hensbergen 
3709e82cf6aSEric Van Hensbergen 		if (n < v9ses->maxdata)
3719e82cf6aSEric Van Hensbergen 			v9ses->maxdata = n;
3729e82cf6aSEric Van Hensbergen 	}
3739e82cf6aSEric Van Hensbergen 
3749e82cf6aSEric Van Hensbergen 	newfid = v9fs_get_idpool(&v9ses->fidpool);
3759e82cf6aSEric Van Hensbergen 	if (newfid < 0) {
3769e82cf6aSEric Van Hensbergen 		eprintk(KERN_WARNING, "couldn't allocate FID\n");
3779e82cf6aSEric Van Hensbergen 		retval = -ENOMEM;
3789e82cf6aSEric Van Hensbergen 		goto SessCleanUp;
3799e82cf6aSEric Van Hensbergen 	}
3809e82cf6aSEric Van Hensbergen 	/* it is a little bit ugly, but we have to prevent newfid */
3819e82cf6aSEric Van Hensbergen 	/* being the same as afid, so if it is, get a new fid     */
3829e82cf6aSEric Van Hensbergen 	if (v9ses->afid != ~0 && newfid == v9ses->afid) {
3839e82cf6aSEric Van Hensbergen 		newfid = v9fs_get_idpool(&v9ses->fidpool);
3849e82cf6aSEric Van Hensbergen 		if (newfid < 0) {
3859e82cf6aSEric Van Hensbergen 			eprintk(KERN_WARNING, "couldn't allocate FID\n");
3869e82cf6aSEric Van Hensbergen 			retval = -ENOMEM;
3879e82cf6aSEric Van Hensbergen 			goto SessCleanUp;
3889e82cf6aSEric Van Hensbergen 		}
3899e82cf6aSEric Van Hensbergen 	}
3909e82cf6aSEric Van Hensbergen 
3919e82cf6aSEric Van Hensbergen 	if ((retval =
3929e82cf6aSEric Van Hensbergen 	     v9fs_t_attach(v9ses, v9ses->name, v9ses->remotename, newfid,
3939e82cf6aSEric Van Hensbergen 			   v9ses->afid, NULL))
3949e82cf6aSEric Van Hensbergen 	    < 0) {
3959e82cf6aSEric Van Hensbergen 		dprintk(DEBUG_ERROR, "cannot attach\n");
3969e82cf6aSEric Van Hensbergen 		goto SessCleanUp;
3979e82cf6aSEric Van Hensbergen 	}
3989e82cf6aSEric Van Hensbergen 
3999e82cf6aSEric Van Hensbergen 	if (v9ses->afid != ~0) {
4003cf6429aSLatchesar Ionkov 		if (v9fs_t_clunk(v9ses, v9ses->afid))
4019e82cf6aSEric Van Hensbergen 			dprintk(DEBUG_ERROR, "clunk failed\n");
4029e82cf6aSEric Van Hensbergen 	}
4039e82cf6aSEric Van Hensbergen 
4049e82cf6aSEric Van Hensbergen 	return newfid;
4059e82cf6aSEric Van Hensbergen 
4069e82cf6aSEric Van Hensbergen       FreeFcall:
4079e82cf6aSEric Van Hensbergen 	kfree(fcall);
4089e82cf6aSEric Van Hensbergen 
4099e82cf6aSEric Van Hensbergen       SessCleanUp:
4109e82cf6aSEric Van Hensbergen 	v9fs_session_close(v9ses);
4119e82cf6aSEric Van Hensbergen 	return retval;
4129e82cf6aSEric Van Hensbergen }
4139e82cf6aSEric Van Hensbergen 
4149e82cf6aSEric Van Hensbergen /**
4159e82cf6aSEric Van Hensbergen  * v9fs_session_close - shutdown a session
4169e82cf6aSEric Van Hensbergen  * @v9ses: session information structure
4179e82cf6aSEric Van Hensbergen  *
4189e82cf6aSEric Van Hensbergen  */
4199e82cf6aSEric Van Hensbergen 
4209e82cf6aSEric Van Hensbergen void v9fs_session_close(struct v9fs_session_info *v9ses)
4219e82cf6aSEric Van Hensbergen {
4223cf6429aSLatchesar Ionkov 	if (v9ses->mux) {
4233cf6429aSLatchesar Ionkov 		v9fs_mux_destroy(v9ses->mux);
4243cf6429aSLatchesar Ionkov 		v9ses->mux = NULL;
4259e82cf6aSEric Van Hensbergen 	}
4269e82cf6aSEric Van Hensbergen 
4273cf6429aSLatchesar Ionkov 	if (v9ses->transport) {
4289e82cf6aSEric Van Hensbergen 		v9ses->transport->close(v9ses->transport);
4293cf6429aSLatchesar Ionkov 		kfree(v9ses->transport);
4303cf6429aSLatchesar Ionkov 		v9ses->transport = NULL;
4313cf6429aSLatchesar Ionkov 	}
4329e82cf6aSEric Van Hensbergen 
433ce44eeb6SDavi Arnaut 	__putname(v9ses->name);
434ce44eeb6SDavi Arnaut 	__putname(v9ses->remotename);
4359e82cf6aSEric Van Hensbergen }
4369e82cf6aSEric Van Hensbergen 
437322b329aSEric Van Hensbergen /**
438322b329aSEric Van Hensbergen  * v9fs_session_cancel - mark transport as disconnected
439322b329aSEric Van Hensbergen  * 	and cancel all pending requests.
440322b329aSEric Van Hensbergen  */
441322b329aSEric Van Hensbergen void v9fs_session_cancel(struct v9fs_session_info *v9ses) {
4423cf6429aSLatchesar Ionkov 	dprintk(DEBUG_ERROR, "cancel session %p\n", v9ses);
443322b329aSEric Van Hensbergen 	v9ses->transport->status = Disconnected;
4443cf6429aSLatchesar Ionkov 	v9fs_mux_cancel(v9ses->mux, -EIO);
445322b329aSEric Van Hensbergen }
446322b329aSEric Van Hensbergen 
4479e82cf6aSEric Van Hensbergen extern int v9fs_error_init(void);
4489e82cf6aSEric Van Hensbergen 
4499e82cf6aSEric Van Hensbergen /**
4509e82cf6aSEric Van Hensbergen  * v9fs_init - Initialize module
4519e82cf6aSEric Van Hensbergen  *
4529e82cf6aSEric Van Hensbergen  */
4539e82cf6aSEric Van Hensbergen 
4549e82cf6aSEric Van Hensbergen static int __init init_v9fs(void)
4559e82cf6aSEric Van Hensbergen {
4561dac06b2SLatchesar Ionkov 	int ret;
4571dac06b2SLatchesar Ionkov 
4589e82cf6aSEric Van Hensbergen 	v9fs_error_init();
4599e82cf6aSEric Van Hensbergen 
4609e82cf6aSEric Van Hensbergen 	printk(KERN_INFO "Installing v9fs 9P2000 file system support\n");
4619e82cf6aSEric Van Hensbergen 
4621dac06b2SLatchesar Ionkov 	ret = v9fs_mux_global_init();
4631dac06b2SLatchesar Ionkov 	if (!ret)
4641dac06b2SLatchesar Ionkov 		ret = register_filesystem(&v9fs_fs_type);
4651dac06b2SLatchesar Ionkov 
4661dac06b2SLatchesar Ionkov 	return ret;
4679e82cf6aSEric Van Hensbergen }
4689e82cf6aSEric Van Hensbergen 
4699e82cf6aSEric Van Hensbergen /**
4709e82cf6aSEric Van Hensbergen  * v9fs_init - shutdown module
4719e82cf6aSEric Van Hensbergen  *
4729e82cf6aSEric Van Hensbergen  */
4739e82cf6aSEric Van Hensbergen 
4749e82cf6aSEric Van Hensbergen static void __exit exit_v9fs(void)
4759e82cf6aSEric Van Hensbergen {
4763cf6429aSLatchesar Ionkov 	v9fs_mux_global_exit();
4779e82cf6aSEric Van Hensbergen 	unregister_filesystem(&v9fs_fs_type);
4789e82cf6aSEric Van Hensbergen }
4799e82cf6aSEric Van Hensbergen 
4809e82cf6aSEric Van Hensbergen module_init(init_v9fs)
4819e82cf6aSEric Van Hensbergen module_exit(exit_v9fs)
4829e82cf6aSEric Van Hensbergen 
4839e82cf6aSEric Van Hensbergen MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
4849e82cf6aSEric Van Hensbergen MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
4859e82cf6aSEric Van Hensbergen MODULE_LICENSE("GPL");
486