1 /* 2 * linux/fs/9p/v9fs.c 3 * 4 * This file contains functions assisting in mapping VFS to 9P2000 5 * 6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> 7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 11 * as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to: 20 * Free Software Foundation 21 * 51 Franklin Street, Fifth Floor 22 * Boston, MA 02111-1301 USA 23 * 24 */ 25 26 #include <linux/module.h> 27 #include <linux/errno.h> 28 #include <linux/fs.h> 29 #include <linux/sched.h> 30 #include <linux/parser.h> 31 #include <linux/idr.h> 32 #include <net/9p/9p.h> 33 #include <net/9p/transport.h> 34 #include <net/9p/conn.h> 35 #include <net/9p/client.h> 36 #include "v9fs.h" 37 #include "v9fs_vfs.h" 38 39 /* 40 * Option Parsing (code inspired by NFS code) 41 * 42 */ 43 44 enum { 45 /* Options that take integer arguments */ 46 Opt_debug, Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, 47 Opt_rfdno, Opt_wfdno, 48 /* String options */ 49 Opt_uname, Opt_remotename, 50 /* Options that take no arguments */ 51 Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, Opt_pci, 52 /* Cache options */ 53 Opt_cache_loose, 54 /* Error token */ 55 Opt_err 56 }; 57 58 static match_table_t tokens = { 59 {Opt_debug, "debug=%x"}, 60 {Opt_port, "port=%u"}, 61 {Opt_msize, "msize=%u"}, 62 {Opt_uid, "uid=%u"}, 63 {Opt_gid, "gid=%u"}, 64 {Opt_afid, "afid=%u"}, 65 {Opt_rfdno, "rfdno=%u"}, 66 {Opt_wfdno, "wfdno=%u"}, 67 {Opt_uname, "uname=%s"}, 68 {Opt_remotename, "aname=%s"}, 69 {Opt_unix, "proto=unix"}, 70 {Opt_tcp, "proto=tcp"}, 71 {Opt_fd, "proto=fd"}, 72 #ifdef CONFIG_PCI_9P 73 {Opt_pci, "proto=pci"}, 74 #endif 75 {Opt_tcp, "tcp"}, 76 {Opt_unix, "unix"}, 77 {Opt_fd, "fd"}, 78 {Opt_legacy, "noextend"}, 79 {Opt_nodevmap, "nodevmap"}, 80 {Opt_cache_loose, "cache=loose"}, 81 {Opt_cache_loose, "loose"}, 82 {Opt_err, NULL} 83 }; 84 85 extern struct p9_transport *p9pci_trans_create(void); 86 87 /* 88 * Parse option string. 89 */ 90 91 /** 92 * v9fs_parse_options - parse mount options into session structure 93 * @options: options string passed from mount 94 * @v9ses: existing v9fs session information 95 * 96 */ 97 98 static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) 99 { 100 char *p; 101 substring_t args[MAX_OPT_ARGS]; 102 int option; 103 int ret; 104 105 /* setup defaults */ 106 v9ses->port = V9FS_PORT; 107 v9ses->maxdata = 9000; 108 v9ses->proto = PROTO_TCP; 109 v9ses->extended = 1; 110 v9ses->afid = ~0; 111 v9ses->debug = 0; 112 v9ses->rfdno = ~0; 113 v9ses->wfdno = ~0; 114 v9ses->cache = 0; 115 116 if (!options) 117 return; 118 119 while ((p = strsep(&options, ",")) != NULL) { 120 int token; 121 if (!*p) 122 continue; 123 token = match_token(p, tokens, args); 124 if (token < Opt_uname) { 125 if ((ret = match_int(&args[0], &option)) < 0) { 126 P9_DPRINTK(P9_DEBUG_ERROR, 127 "integer field, but no integer?\n"); 128 continue; 129 } 130 } 131 switch (token) { 132 case Opt_debug: 133 v9ses->debug = option; 134 #ifdef CONFIG_NET_9P_DEBUG 135 p9_debug_level = option; 136 #endif 137 break; 138 case Opt_port: 139 v9ses->port = option; 140 break; 141 case Opt_msize: 142 v9ses->maxdata = option; 143 break; 144 case Opt_uid: 145 v9ses->uid = option; 146 break; 147 case Opt_gid: 148 v9ses->gid = option; 149 break; 150 case Opt_afid: 151 v9ses->afid = option; 152 break; 153 case Opt_rfdno: 154 v9ses->rfdno = option; 155 break; 156 case Opt_wfdno: 157 v9ses->wfdno = option; 158 break; 159 case Opt_tcp: 160 v9ses->proto = PROTO_TCP; 161 break; 162 case Opt_unix: 163 v9ses->proto = PROTO_UNIX; 164 break; 165 case Opt_pci: 166 v9ses->proto = PROTO_PCI; 167 break; 168 case Opt_fd: 169 v9ses->proto = PROTO_FD; 170 break; 171 case Opt_uname: 172 match_strcpy(v9ses->name, &args[0]); 173 break; 174 case Opt_remotename: 175 match_strcpy(v9ses->remotename, &args[0]); 176 break; 177 case Opt_legacy: 178 v9ses->extended = 0; 179 break; 180 case Opt_nodevmap: 181 v9ses->nodev = 1; 182 break; 183 case Opt_cache_loose: 184 v9ses->cache = CACHE_LOOSE; 185 break; 186 default: 187 continue; 188 } 189 } 190 } 191 192 /** 193 * v9fs_session_init - initialize session 194 * @v9ses: session information structure 195 * @dev_name: device being mounted 196 * @data: options 197 * 198 */ 199 200 struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, 201 const char *dev_name, char *data) 202 { 203 int retval = -EINVAL; 204 struct p9_transport *trans; 205 struct p9_fid *fid; 206 207 v9ses->name = __getname(); 208 if (!v9ses->name) 209 return ERR_PTR(-ENOMEM); 210 211 v9ses->remotename = __getname(); 212 if (!v9ses->remotename) { 213 __putname(v9ses->name); 214 return ERR_PTR(-ENOMEM); 215 } 216 217 strcpy(v9ses->name, V9FS_DEFUSER); 218 strcpy(v9ses->remotename, V9FS_DEFANAME); 219 220 v9fs_parse_options(data, v9ses); 221 222 switch (v9ses->proto) { 223 case PROTO_TCP: 224 trans = p9_trans_create_tcp(dev_name, v9ses->port); 225 break; 226 case PROTO_UNIX: 227 trans = p9_trans_create_unix(dev_name); 228 *v9ses->remotename = 0; 229 break; 230 case PROTO_FD: 231 trans = p9_trans_create_fd(v9ses->rfdno, v9ses->wfdno); 232 *v9ses->remotename = 0; 233 break; 234 #ifdef CONFIG_PCI_9P 235 case PROTO_PCI: 236 trans = p9pci_trans_create(); 237 *v9ses->remotename = 0; 238 break; 239 #endif 240 default: 241 printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto); 242 retval = -ENOPROTOOPT; 243 goto error; 244 }; 245 246 if (IS_ERR(trans)) { 247 retval = PTR_ERR(trans); 248 trans = NULL; 249 goto error; 250 } 251 252 v9ses->clnt = p9_client_create(trans, v9ses->maxdata + P9_IOHDRSZ, 253 v9ses->extended); 254 255 if (IS_ERR(v9ses->clnt)) { 256 retval = PTR_ERR(v9ses->clnt); 257 v9ses->clnt = NULL; 258 P9_DPRINTK(P9_DEBUG_ERROR, "problem initializing 9p client\n"); 259 goto error; 260 } 261 262 fid = p9_client_attach(v9ses->clnt, NULL, v9ses->name, 263 v9ses->remotename); 264 if (IS_ERR(fid)) { 265 retval = PTR_ERR(fid); 266 fid = NULL; 267 P9_DPRINTK(P9_DEBUG_ERROR, "cannot attach\n"); 268 goto error; 269 } 270 271 return fid; 272 273 error: 274 v9fs_session_close(v9ses); 275 return ERR_PTR(retval); 276 } 277 278 /** 279 * v9fs_session_close - shutdown a session 280 * @v9ses: session information structure 281 * 282 */ 283 284 void v9fs_session_close(struct v9fs_session_info *v9ses) 285 { 286 if (v9ses->clnt) { 287 p9_client_destroy(v9ses->clnt); 288 v9ses->clnt = NULL; 289 } 290 291 __putname(v9ses->name); 292 __putname(v9ses->remotename); 293 } 294 295 /** 296 * v9fs_session_cancel - mark transport as disconnected 297 * and cancel all pending requests. 298 */ 299 void v9fs_session_cancel(struct v9fs_session_info *v9ses) { 300 P9_DPRINTK(P9_DEBUG_ERROR, "cancel session %p\n", v9ses); 301 p9_client_disconnect(v9ses->clnt); 302 } 303 304 extern int v9fs_error_init(void); 305 306 /** 307 * v9fs_init - Initialize module 308 * 309 */ 310 311 static int __init init_v9fs(void) 312 { 313 printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); 314 315 return register_filesystem(&v9fs_fs_type); 316 } 317 318 /** 319 * v9fs_init - shutdown module 320 * 321 */ 322 323 static void __exit exit_v9fs(void) 324 { 325 unregister_filesystem(&v9fs_fs_type); 326 } 327 328 module_init(init_v9fs) 329 module_exit(exit_v9fs) 330 331 MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>"); 332 MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>"); 333 MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>"); 334 MODULE_LICENSE("GPL"); 335