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