xref: /openbmc/linux/fs/9p/v9fs.c (revision f94b3470)
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
1042e8c509SEric Van Hensbergen  *  it under the terms of the GNU General Public License version 2
1142e8c509SEric Van Hensbergen  *  as published by the Free Software Foundation.
129e82cf6aSEric Van Hensbergen  *
139e82cf6aSEric Van Hensbergen  *  This program is distributed in the hope that it will be useful,
149e82cf6aSEric Van Hensbergen  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
159e82cf6aSEric Van Hensbergen  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
169e82cf6aSEric Van Hensbergen  *  GNU General Public License for more details.
179e82cf6aSEric Van Hensbergen  *
189e82cf6aSEric Van Hensbergen  *  You should have received a copy of the GNU General Public License
199e82cf6aSEric Van Hensbergen  *  along with this program; if not, write to:
209e82cf6aSEric Van Hensbergen  *  Free Software Foundation
219e82cf6aSEric Van Hensbergen  *  51 Franklin Street, Fifth Floor
229e82cf6aSEric Van Hensbergen  *  Boston, MA  02111-1301  USA
239e82cf6aSEric Van Hensbergen  *
249e82cf6aSEric Van Hensbergen  */
259e82cf6aSEric Van Hensbergen 
269e82cf6aSEric Van Hensbergen #include <linux/module.h>
279e82cf6aSEric Van Hensbergen #include <linux/errno.h>
289e82cf6aSEric Van Hensbergen #include <linux/fs.h>
29914e2637SAl Viro #include <linux/sched.h>
309e82cf6aSEric Van Hensbergen #include <linux/parser.h>
319e82cf6aSEric Van Hensbergen #include <linux/idr.h>
329e82cf6aSEric Van Hensbergen 
339e82cf6aSEric Van Hensbergen #include "debug.h"
349e82cf6aSEric Van Hensbergen #include "v9fs.h"
359e82cf6aSEric Van Hensbergen #include "9p.h"
369e82cf6aSEric Van Hensbergen #include "v9fs_vfs.h"
379e82cf6aSEric Van Hensbergen #include "transport.h"
389e82cf6aSEric Van Hensbergen #include "mux.h"
399e82cf6aSEric Van Hensbergen 
409e82cf6aSEric Van Hensbergen /* TODO: sysfs or debugfs interface */
419e82cf6aSEric Van Hensbergen int v9fs_debug_level = 0;	/* feature-rific global debug level  */
429e82cf6aSEric Van Hensbergen 
439e82cf6aSEric Van Hensbergen /*
449e82cf6aSEric Van Hensbergen   * Option Parsing (code inspired by NFS code)
459e82cf6aSEric Van Hensbergen   *
469e82cf6aSEric Van Hensbergen   */
479e82cf6aSEric Van Hensbergen 
489e82cf6aSEric Van Hensbergen enum {
499e82cf6aSEric Van Hensbergen 	/* Options that take integer arguments */
509e82cf6aSEric Van Hensbergen 	Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, Opt_debug,
519e82cf6aSEric Van Hensbergen 	Opt_rfdno, Opt_wfdno,
529e82cf6aSEric Van Hensbergen 	/* String options */
5367543e50SEric Van Hensbergen 	Opt_uname, Opt_remotename,
549e82cf6aSEric Van Hensbergen 	/* Options that take no arguments */
559e82cf6aSEric Van Hensbergen 	Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd,
569e82cf6aSEric Van Hensbergen 	/* Error token */
579e82cf6aSEric Van Hensbergen 	Opt_err
589e82cf6aSEric Van Hensbergen };
599e82cf6aSEric Van Hensbergen 
609e82cf6aSEric Van Hensbergen static match_table_t tokens = {
619e82cf6aSEric Van Hensbergen 	{Opt_port, "port=%u"},
629e82cf6aSEric Van Hensbergen 	{Opt_msize, "msize=%u"},
639e82cf6aSEric Van Hensbergen 	{Opt_uid, "uid=%u"},
649e82cf6aSEric Van Hensbergen 	{Opt_gid, "gid=%u"},
659e82cf6aSEric Van Hensbergen 	{Opt_afid, "afid=%u"},
669e82cf6aSEric Van Hensbergen 	{Opt_rfdno, "rfdno=%u"},
679e82cf6aSEric Van Hensbergen 	{Opt_wfdno, "wfdno=%u"},
68e1c92117SEric Van Hensbergen 	{Opt_debug, "debug=%x"},
6967543e50SEric Van Hensbergen 	{Opt_uname, "uname=%s"},
709e82cf6aSEric Van Hensbergen 	{Opt_remotename, "aname=%s"},
719e82cf6aSEric Van Hensbergen 	{Opt_unix, "proto=unix"},
729e82cf6aSEric Van Hensbergen 	{Opt_tcp, "proto=tcp"},
739e82cf6aSEric Van Hensbergen 	{Opt_fd, "proto=fd"},
749e82cf6aSEric Van Hensbergen 	{Opt_tcp, "tcp"},
759e82cf6aSEric Van Hensbergen 	{Opt_unix, "unix"},
769e82cf6aSEric Van Hensbergen 	{Opt_fd, "fd"},
779e82cf6aSEric Van Hensbergen 	{Opt_legacy, "noextend"},
789e82cf6aSEric Van Hensbergen 	{Opt_nodevmap, "nodevmap"},
799e82cf6aSEric Van Hensbergen 	{Opt_err, NULL}
809e82cf6aSEric Van Hensbergen };
819e82cf6aSEric Van Hensbergen 
829e82cf6aSEric Van Hensbergen /*
839e82cf6aSEric Van Hensbergen  *  Parse option string.
849e82cf6aSEric Van Hensbergen  */
859e82cf6aSEric Van Hensbergen 
869e82cf6aSEric Van Hensbergen /**
879e82cf6aSEric Van Hensbergen  * v9fs_parse_options - parse mount options into session structure
889e82cf6aSEric Van Hensbergen  * @options: options string passed from mount
899e82cf6aSEric Van Hensbergen  * @v9ses: existing v9fs session information
909e82cf6aSEric Van Hensbergen  *
919e82cf6aSEric Van Hensbergen  */
929e82cf6aSEric Van Hensbergen 
939e82cf6aSEric Van Hensbergen static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses)
949e82cf6aSEric Van Hensbergen {
959e82cf6aSEric Van Hensbergen 	char *p;
969e82cf6aSEric Van Hensbergen 	substring_t args[MAX_OPT_ARGS];
979e82cf6aSEric Van Hensbergen 	int option;
989e82cf6aSEric Van Hensbergen 	int ret;
999e82cf6aSEric Van Hensbergen 
1009e82cf6aSEric Van Hensbergen 	/* setup defaults */
1019e82cf6aSEric Van Hensbergen 	v9ses->port = V9FS_PORT;
1029e82cf6aSEric Van Hensbergen 	v9ses->maxdata = 9000;
1039e82cf6aSEric Van Hensbergen 	v9ses->proto = PROTO_TCP;
1049e82cf6aSEric Van Hensbergen 	v9ses->extended = 1;
1059e82cf6aSEric Van Hensbergen 	v9ses->afid = ~0;
1069e82cf6aSEric Van Hensbergen 	v9ses->debug = 0;
1079e82cf6aSEric Van Hensbergen 	v9ses->rfdno = ~0;
1089e82cf6aSEric Van Hensbergen 	v9ses->wfdno = ~0;
1099e82cf6aSEric Van Hensbergen 
1109e82cf6aSEric Van Hensbergen 	if (!options)
1119e82cf6aSEric Van Hensbergen 		return;
1129e82cf6aSEric Van Hensbergen 
1139e82cf6aSEric Van Hensbergen 	while ((p = strsep(&options, ",")) != NULL) {
1149e82cf6aSEric Van Hensbergen 		int token;
1159e82cf6aSEric Van Hensbergen 		if (!*p)
1169e82cf6aSEric Van Hensbergen 			continue;
1179e82cf6aSEric Van Hensbergen 		token = match_token(p, tokens, args);
11867543e50SEric Van Hensbergen 		if (token < Opt_uname) {
1199e82cf6aSEric Van Hensbergen 			if ((ret = match_int(&args[0], &option)) < 0) {
1209e82cf6aSEric Van Hensbergen 				dprintk(DEBUG_ERROR,
1219e82cf6aSEric Van Hensbergen 					"integer field, but no integer?\n");
1229e82cf6aSEric Van Hensbergen 				continue;
1239e82cf6aSEric Van Hensbergen 			}
1249e82cf6aSEric Van Hensbergen 
1259e82cf6aSEric Van Hensbergen 		}
1269e82cf6aSEric Van Hensbergen 		switch (token) {
1279e82cf6aSEric Van Hensbergen 		case Opt_port:
1289e82cf6aSEric Van Hensbergen 			v9ses->port = option;
1299e82cf6aSEric Van Hensbergen 			break;
1309e82cf6aSEric Van Hensbergen 		case Opt_msize:
1319e82cf6aSEric Van Hensbergen 			v9ses->maxdata = option;
1329e82cf6aSEric Van Hensbergen 			break;
1339e82cf6aSEric Van Hensbergen 		case Opt_uid:
1349e82cf6aSEric Van Hensbergen 			v9ses->uid = option;
1359e82cf6aSEric Van Hensbergen 			break;
1369e82cf6aSEric Van Hensbergen 		case Opt_gid:
1379e82cf6aSEric Van Hensbergen 			v9ses->gid = option;
1389e82cf6aSEric Van Hensbergen 			break;
1399e82cf6aSEric Van Hensbergen 		case Opt_afid:
1409e82cf6aSEric Van Hensbergen 			v9ses->afid = option;
1419e82cf6aSEric Van Hensbergen 			break;
1429e82cf6aSEric Van Hensbergen 		case Opt_rfdno:
1439e82cf6aSEric Van Hensbergen 			v9ses->rfdno = option;
1449e82cf6aSEric Van Hensbergen 			break;
1459e82cf6aSEric Van Hensbergen 		case Opt_wfdno:
1469e82cf6aSEric Van Hensbergen 			v9ses->wfdno = option;
1479e82cf6aSEric Van Hensbergen 			break;
1489e82cf6aSEric Van Hensbergen 		case Opt_debug:
1499e82cf6aSEric Van Hensbergen 			v9ses->debug = option;
1509e82cf6aSEric Van Hensbergen 			break;
1519e82cf6aSEric Van Hensbergen 		case Opt_tcp:
1529e82cf6aSEric Van Hensbergen 			v9ses->proto = PROTO_TCP;
1539e82cf6aSEric Van Hensbergen 			break;
1549e82cf6aSEric Van Hensbergen 		case Opt_unix:
1559e82cf6aSEric Van Hensbergen 			v9ses->proto = PROTO_UNIX;
1569e82cf6aSEric Van Hensbergen 			break;
1579e82cf6aSEric Van Hensbergen 		case Opt_fd:
1589e82cf6aSEric Van Hensbergen 			v9ses->proto = PROTO_FD;
1599e82cf6aSEric Van Hensbergen 			break;
16067543e50SEric Van Hensbergen 		case Opt_uname:
1619e82cf6aSEric Van Hensbergen 			match_strcpy(v9ses->name, &args[0]);
1629e82cf6aSEric Van Hensbergen 			break;
1639e82cf6aSEric Van Hensbergen 		case Opt_remotename:
1649e82cf6aSEric Van Hensbergen 			match_strcpy(v9ses->remotename, &args[0]);
1659e82cf6aSEric Van Hensbergen 			break;
1669e82cf6aSEric Van Hensbergen 		case Opt_legacy:
1679e82cf6aSEric Van Hensbergen 			v9ses->extended = 0;
1689e82cf6aSEric Van Hensbergen 			break;
1699e82cf6aSEric Van Hensbergen 		case Opt_nodevmap:
1709e82cf6aSEric Van Hensbergen 			v9ses->nodev = 1;
1719e82cf6aSEric Van Hensbergen 			break;
1729e82cf6aSEric Van Hensbergen 		default:
1739e82cf6aSEric Van Hensbergen 			continue;
1749e82cf6aSEric Van Hensbergen 		}
1759e82cf6aSEric Van Hensbergen 	}
1769e82cf6aSEric Van Hensbergen }
1779e82cf6aSEric Van Hensbergen 
1789e82cf6aSEric Van Hensbergen /**
1799e82cf6aSEric Van Hensbergen  * v9fs_inode2v9ses - safely extract v9fs session info from super block
1809e82cf6aSEric Van Hensbergen  * @inode: inode to extract information from
1819e82cf6aSEric Van Hensbergen  *
1829e82cf6aSEric Van Hensbergen  * Paranoid function to extract v9ses information from superblock,
1839e82cf6aSEric Van Hensbergen  * if anything is missing it will report an error.
1849e82cf6aSEric Van Hensbergen  *
1859e82cf6aSEric Van Hensbergen  */
1869e82cf6aSEric Van Hensbergen 
1879e82cf6aSEric Van Hensbergen struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
1889e82cf6aSEric Van Hensbergen {
1899e82cf6aSEric Van Hensbergen 	return (inode->i_sb->s_fs_info);
1909e82cf6aSEric Van Hensbergen }
1919e82cf6aSEric Van Hensbergen 
1929e82cf6aSEric Van Hensbergen /**
1939e82cf6aSEric Van Hensbergen  * v9fs_get_idpool - allocate numeric id from pool
1949e82cf6aSEric Van Hensbergen  * @p - pool to allocate from
1959e82cf6aSEric Van Hensbergen  *
1969e82cf6aSEric Van Hensbergen  * XXX - This seems to be an awful generic function, should it be in idr.c with
1979e82cf6aSEric Van Hensbergen  *            the lock included in struct idr?
1989e82cf6aSEric Van Hensbergen  */
1999e82cf6aSEric Van Hensbergen 
2009e82cf6aSEric Van Hensbergen int v9fs_get_idpool(struct v9fs_idpool *p)
2019e82cf6aSEric Van Hensbergen {
2029e82cf6aSEric Van Hensbergen 	int i = 0;
2039e82cf6aSEric Van Hensbergen 	int error;
2049e82cf6aSEric Van Hensbergen 
2059e82cf6aSEric Van Hensbergen retry:
2069e82cf6aSEric Van Hensbergen 	if (idr_pre_get(&p->pool, GFP_KERNEL) == 0)
2079e82cf6aSEric Van Hensbergen 		return 0;
2089e82cf6aSEric Van Hensbergen 
2099e82cf6aSEric Van Hensbergen 	if (down_interruptible(&p->lock) == -EINTR) {
2109e82cf6aSEric Van Hensbergen 		eprintk(KERN_WARNING, "Interrupted while locking\n");
2119e82cf6aSEric Van Hensbergen 		return -1;
2129e82cf6aSEric Van Hensbergen 	}
2139e82cf6aSEric Van Hensbergen 
2143cf6429aSLatchesar Ionkov 	/* no need to store exactly p, we just need something non-null */
2153cf6429aSLatchesar Ionkov 	error = idr_get_new(&p->pool, p, &i);
2169e82cf6aSEric Van Hensbergen 	up(&p->lock);
2179e82cf6aSEric Van Hensbergen 
2189e82cf6aSEric Van Hensbergen 	if (error == -EAGAIN)
2199e82cf6aSEric Van Hensbergen 		goto retry;
2209e82cf6aSEric Van Hensbergen 	else if (error)
2219e82cf6aSEric Van Hensbergen 		return -1;
2229e82cf6aSEric Van Hensbergen 
2239e82cf6aSEric Van Hensbergen 	return i;
2249e82cf6aSEric Van Hensbergen }
2259e82cf6aSEric Van Hensbergen 
2269e82cf6aSEric Van Hensbergen /**
2279e82cf6aSEric Van Hensbergen  * v9fs_put_idpool - release numeric id from pool
2289e82cf6aSEric Van Hensbergen  * @p - pool to allocate from
2299e82cf6aSEric Van Hensbergen  *
2309e82cf6aSEric Van Hensbergen  * XXX - This seems to be an awful generic function, should it be in idr.c with
2319e82cf6aSEric Van Hensbergen  *            the lock included in struct idr?
2329e82cf6aSEric Van Hensbergen  */
2339e82cf6aSEric Van Hensbergen 
2349e82cf6aSEric Van Hensbergen void v9fs_put_idpool(int id, struct v9fs_idpool *p)
2359e82cf6aSEric Van Hensbergen {
2369e82cf6aSEric Van Hensbergen 	if (down_interruptible(&p->lock) == -EINTR) {
2379e82cf6aSEric Van Hensbergen 		eprintk(KERN_WARNING, "Interrupted while locking\n");
2389e82cf6aSEric Van Hensbergen 		return;
2399e82cf6aSEric Van Hensbergen 	}
2409e82cf6aSEric Van Hensbergen 	idr_remove(&p->pool, id);
2419e82cf6aSEric Van Hensbergen 	up(&p->lock);
2429e82cf6aSEric Van Hensbergen }
2439e82cf6aSEric Van Hensbergen 
2449e82cf6aSEric Van Hensbergen /**
2453cf6429aSLatchesar Ionkov  * v9fs_check_idpool - check if the specified id is available
2463cf6429aSLatchesar Ionkov  * @id - id to check
2473cf6429aSLatchesar Ionkov  * @p - pool
2483cf6429aSLatchesar Ionkov  */
2493cf6429aSLatchesar Ionkov int v9fs_check_idpool(int id, struct v9fs_idpool *p)
2503cf6429aSLatchesar Ionkov {
2513cf6429aSLatchesar Ionkov 	return idr_find(&p->pool, id) != NULL;
2523cf6429aSLatchesar Ionkov }
2533cf6429aSLatchesar Ionkov 
2543cf6429aSLatchesar Ionkov /**
2559e82cf6aSEric Van Hensbergen  * v9fs_session_init - initialize session
2569e82cf6aSEric Van Hensbergen  * @v9ses: session information structure
2579e82cf6aSEric Van Hensbergen  * @dev_name: device being mounted
2589e82cf6aSEric Van Hensbergen  * @data: options
2599e82cf6aSEric Van Hensbergen  *
2609e82cf6aSEric Van Hensbergen  */
2619e82cf6aSEric Van Hensbergen 
2629e82cf6aSEric Van Hensbergen int
2639e82cf6aSEric Van Hensbergen v9fs_session_init(struct v9fs_session_info *v9ses,
2649e82cf6aSEric Van Hensbergen 		  const char *dev_name, char *data)
2659e82cf6aSEric Van Hensbergen {
2669e82cf6aSEric Van Hensbergen 	struct v9fs_fcall *fcall = NULL;
2679e82cf6aSEric Van Hensbergen 	struct v9fs_transport *trans_proto;
2689e82cf6aSEric Van Hensbergen 	int n = 0;
2699e82cf6aSEric Van Hensbergen 	int newfid = -1;
2709e82cf6aSEric Van Hensbergen 	int retval = -EINVAL;
2711dac06b2SLatchesar Ionkov 	struct v9fs_str *version;
2729e82cf6aSEric Van Hensbergen 
2739e82cf6aSEric Van Hensbergen 	v9ses->name = __getname();
2749e82cf6aSEric Van Hensbergen 	if (!v9ses->name)
2759e82cf6aSEric Van Hensbergen 		return -ENOMEM;
2769e82cf6aSEric Van Hensbergen 
2779e82cf6aSEric Van Hensbergen 	v9ses->remotename = __getname();
2789e82cf6aSEric Van Hensbergen 	if (!v9ses->remotename) {
279ce44eeb6SDavi Arnaut 		__putname(v9ses->name);
2809e82cf6aSEric Van Hensbergen 		return -ENOMEM;
2819e82cf6aSEric Van Hensbergen 	}
2829e82cf6aSEric Van Hensbergen 
2839e82cf6aSEric Van Hensbergen 	strcpy(v9ses->name, V9FS_DEFUSER);
2849e82cf6aSEric Van Hensbergen 	strcpy(v9ses->remotename, V9FS_DEFANAME);
2859e82cf6aSEric Van Hensbergen 
2869e82cf6aSEric Van Hensbergen 	v9fs_parse_options(data, v9ses);
2879e82cf6aSEric Van Hensbergen 
2889e82cf6aSEric Van Hensbergen 	/* set global debug level */
2899e82cf6aSEric Van Hensbergen 	v9fs_debug_level = v9ses->debug;
2909e82cf6aSEric Van Hensbergen 
2914a26c242SRuss Cox 	/* id pools that are session-dependent: fids and tags */
2929e82cf6aSEric Van Hensbergen 	idr_init(&v9ses->fidpool.pool);
2939e82cf6aSEric Van Hensbergen 	init_MUTEX(&v9ses->fidpool.lock);
2949e82cf6aSEric Van Hensbergen 
2959e82cf6aSEric Van Hensbergen 	switch (v9ses->proto) {
2969e82cf6aSEric Van Hensbergen 	case PROTO_TCP:
2979e82cf6aSEric Van Hensbergen 		trans_proto = &v9fs_trans_tcp;
2989e82cf6aSEric Van Hensbergen 		break;
2999e82cf6aSEric Van Hensbergen 	case PROTO_UNIX:
3009e82cf6aSEric Van Hensbergen 		trans_proto = &v9fs_trans_unix;
3019e82cf6aSEric Van Hensbergen 		*v9ses->remotename = 0;
3029e82cf6aSEric Van Hensbergen 		break;
3039e82cf6aSEric Van Hensbergen 	case PROTO_FD:
3049e82cf6aSEric Van Hensbergen 		trans_proto = &v9fs_trans_fd;
3059e82cf6aSEric Van Hensbergen 		*v9ses->remotename = 0;
3069e82cf6aSEric Van Hensbergen 		break;
3079e82cf6aSEric Van Hensbergen 	default:
3089e82cf6aSEric Van Hensbergen 		printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto);
3099e82cf6aSEric Van Hensbergen 		retval = -ENOPROTOOPT;
3109e82cf6aSEric Van Hensbergen 		goto SessCleanUp;
3119e82cf6aSEric Van Hensbergen 	};
3129e82cf6aSEric Van Hensbergen 
313a8e63bffSLatchesar Ionkov 	v9ses->transport = kmalloc(sizeof(*v9ses->transport), GFP_KERNEL);
314a8e63bffSLatchesar Ionkov 	if (!v9ses->transport) {
315a8e63bffSLatchesar Ionkov 		retval = -ENOMEM;
316a8e63bffSLatchesar Ionkov 		goto SessCleanUp;
317a8e63bffSLatchesar Ionkov 	}
318a8e63bffSLatchesar Ionkov 
319a8e63bffSLatchesar Ionkov 	memmove(v9ses->transport, trans_proto, sizeof(*v9ses->transport));
3209e82cf6aSEric Van Hensbergen 
3219e82cf6aSEric Van Hensbergen 	if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) {
3229e82cf6aSEric Van Hensbergen 		eprintk(KERN_ERR, "problem initializing transport\n");
3239e82cf6aSEric Van Hensbergen 		goto SessCleanUp;
3249e82cf6aSEric Van Hensbergen 	}
3259e82cf6aSEric Van Hensbergen 
3269e82cf6aSEric Van Hensbergen 	v9ses->inprogress = 0;
3279e82cf6aSEric Van Hensbergen 	v9ses->shutdown = 0;
3289e82cf6aSEric Van Hensbergen 	v9ses->session_hung = 0;
3299e82cf6aSEric Van Hensbergen 
3303cf6429aSLatchesar Ionkov 	v9ses->mux = v9fs_mux_init(v9ses->transport, v9ses->maxdata + V9FS_IOHDRSZ,
3313cf6429aSLatchesar Ionkov 		&v9ses->extended);
3323cf6429aSLatchesar Ionkov 
3333cf6429aSLatchesar Ionkov 	if (IS_ERR(v9ses->mux)) {
3343cf6429aSLatchesar Ionkov 		retval = PTR_ERR(v9ses->mux);
3353cf6429aSLatchesar Ionkov 		v9ses->mux = NULL;
3369e82cf6aSEric Van Hensbergen 		dprintk(DEBUG_ERROR, "problem initializing mux\n");
3379e82cf6aSEric Van Hensbergen 		goto SessCleanUp;
3389e82cf6aSEric Van Hensbergen 	}
3399e82cf6aSEric Van Hensbergen 
3409e82cf6aSEric Van Hensbergen 	if (v9ses->afid == ~0) {
3419e82cf6aSEric Van Hensbergen 		if (v9ses->extended)
3429e82cf6aSEric Van Hensbergen 			retval =
3439e82cf6aSEric Van Hensbergen 			    v9fs_t_version(v9ses, v9ses->maxdata, "9P2000.u",
3449e82cf6aSEric Van Hensbergen 					   &fcall);
3459e82cf6aSEric Van Hensbergen 		else
3469e82cf6aSEric Van Hensbergen 			retval = v9fs_t_version(v9ses, v9ses->maxdata, "9P2000",
3479e82cf6aSEric Van Hensbergen 						&fcall);
3489e82cf6aSEric Van Hensbergen 
3499e82cf6aSEric Van Hensbergen 		if (retval < 0) {
3509e82cf6aSEric Van Hensbergen 			dprintk(DEBUG_ERROR, "v9fs_t_version failed\n");
3519e82cf6aSEric Van Hensbergen 			goto FreeFcall;
3529e82cf6aSEric Van Hensbergen 		}
3539e82cf6aSEric Van Hensbergen 
3541dac06b2SLatchesar Ionkov 		version = &fcall->params.rversion.version;
3551dac06b2SLatchesar Ionkov 		if (version->len==8 && !memcmp(version->str, "9P2000.u", 8)) {
3569e82cf6aSEric Van Hensbergen 			dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n");
3579e82cf6aSEric Van Hensbergen 			v9ses->extended = 1;
3581dac06b2SLatchesar Ionkov 		} else if (version->len==6 && !memcmp(version->str, "9P2000", 6)) {
3599e82cf6aSEric Van Hensbergen 			dprintk(DEBUG_9P, "9P2000 legacy mode enabled\n");
3609e82cf6aSEric Van Hensbergen 			v9ses->extended = 0;
3611dac06b2SLatchesar Ionkov 		} else {
3621dac06b2SLatchesar Ionkov 			retval = -EREMOTEIO;
3631dac06b2SLatchesar Ionkov 			goto FreeFcall;
3649e82cf6aSEric Van Hensbergen 		}
3659e82cf6aSEric Van Hensbergen 
3669e82cf6aSEric Van Hensbergen 		n = fcall->params.rversion.msize;
3679e82cf6aSEric Van Hensbergen 		kfree(fcall);
3689e82cf6aSEric Van Hensbergen 
3699e82cf6aSEric Van Hensbergen 		if (n < v9ses->maxdata)
3709e82cf6aSEric Van Hensbergen 			v9ses->maxdata = n;
3719e82cf6aSEric Van Hensbergen 	}
3729e82cf6aSEric Van Hensbergen 
3739e82cf6aSEric Van Hensbergen 	newfid = v9fs_get_idpool(&v9ses->fidpool);
3749e82cf6aSEric Van Hensbergen 	if (newfid < 0) {
3759e82cf6aSEric Van Hensbergen 		eprintk(KERN_WARNING, "couldn't allocate FID\n");
3769e82cf6aSEric Van Hensbergen 		retval = -ENOMEM;
3779e82cf6aSEric Van Hensbergen 		goto SessCleanUp;
3789e82cf6aSEric Van Hensbergen 	}
3799e82cf6aSEric Van Hensbergen 	/* it is a little bit ugly, but we have to prevent newfid */
3809e82cf6aSEric Van Hensbergen 	/* being the same as afid, so if it is, get a new fid     */
3819e82cf6aSEric Van Hensbergen 	if (v9ses->afid != ~0 && newfid == v9ses->afid) {
3829e82cf6aSEric Van Hensbergen 		newfid = v9fs_get_idpool(&v9ses->fidpool);
3839e82cf6aSEric Van Hensbergen 		if (newfid < 0) {
3849e82cf6aSEric Van Hensbergen 			eprintk(KERN_WARNING, "couldn't allocate FID\n");
3859e82cf6aSEric Van Hensbergen 			retval = -ENOMEM;
3869e82cf6aSEric Van Hensbergen 			goto SessCleanUp;
3879e82cf6aSEric Van Hensbergen 		}
3889e82cf6aSEric Van Hensbergen 	}
3899e82cf6aSEric Van Hensbergen 
3909e82cf6aSEric Van Hensbergen 	if ((retval =
3919e82cf6aSEric Van Hensbergen 	     v9fs_t_attach(v9ses, v9ses->name, v9ses->remotename, newfid,
3929e82cf6aSEric Van Hensbergen 			   v9ses->afid, NULL))
3939e82cf6aSEric Van Hensbergen 	    < 0) {
3949e82cf6aSEric Van Hensbergen 		dprintk(DEBUG_ERROR, "cannot attach\n");
3959e82cf6aSEric Van Hensbergen 		goto SessCleanUp;
3969e82cf6aSEric Van Hensbergen 	}
3979e82cf6aSEric Van Hensbergen 
3989e82cf6aSEric Van Hensbergen 	if (v9ses->afid != ~0) {
39946f6dac2SEric Van Hensbergen 		dprintk(DEBUG_ERROR, "afid not equal to ~0\n");
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 
460f94b3470SEric Van Hensbergen 	printk(KERN_INFO "Installing v9fs 9p2000 file system support\n");
4619e82cf6aSEric Van Hensbergen 
4621dac06b2SLatchesar Ionkov 	ret = v9fs_mux_global_init();
463f94b3470SEric Van Hensbergen 	if (ret) {
464f94b3470SEric Van Hensbergen 		printk(KERN_WARNING "v9fs: starting mux failed\n");
465d826380bSAlexey Dobriyan 		return ret;
466f94b3470SEric Van Hensbergen 	}
4671dac06b2SLatchesar Ionkov 	ret = register_filesystem(&v9fs_fs_type);
468f94b3470SEric Van Hensbergen 	if (ret) {
469f94b3470SEric Van Hensbergen 		printk(KERN_WARNING "v9fs: registering file system failed\n");
470d826380bSAlexey Dobriyan 		v9fs_mux_global_exit();
471f94b3470SEric Van Hensbergen 	}
472f94b3470SEric Van Hensbergen 
4731dac06b2SLatchesar Ionkov 	return ret;
4749e82cf6aSEric Van Hensbergen }
4759e82cf6aSEric Van Hensbergen 
4769e82cf6aSEric Van Hensbergen /**
4779e82cf6aSEric Van Hensbergen  * v9fs_init - shutdown module
4789e82cf6aSEric Van Hensbergen  *
4799e82cf6aSEric Van Hensbergen  */
4809e82cf6aSEric Van Hensbergen 
4819e82cf6aSEric Van Hensbergen static void __exit exit_v9fs(void)
4829e82cf6aSEric Van Hensbergen {
4833cf6429aSLatchesar Ionkov 	v9fs_mux_global_exit();
4849e82cf6aSEric Van Hensbergen 	unregister_filesystem(&v9fs_fs_type);
4859e82cf6aSEric Van Hensbergen }
4869e82cf6aSEric Van Hensbergen 
4879e82cf6aSEric Van Hensbergen module_init(init_v9fs)
4889e82cf6aSEric Van Hensbergen module_exit(exit_v9fs)
4899e82cf6aSEric Van Hensbergen 
4909e82cf6aSEric Van Hensbergen MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
4919e82cf6aSEric Van Hensbergen MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
4929e82cf6aSEric Van Hensbergen MODULE_LICENSE("GPL");
493