1 /* 2 * linux/fs/9p/trans_fd.c 3 * 4 * Fd transport layer. Includes deprecated socket layer. 5 * 6 * Copyright (C) 2006 by Russ Cox <rsc@swtch.com> 7 * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> 8 * Copyright (C) 2004-2007 by Eric Van Hensbergen <ericvh@gmail.com> 9 * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com> 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License version 2 13 * as published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to: 22 * Free Software Foundation 23 * 51 Franklin Street, Fifth Floor 24 * Boston, MA 02111-1301 USA 25 * 26 */ 27 28 #include <linux/in.h> 29 #include <linux/module.h> 30 #include <linux/net.h> 31 #include <linux/ipv6.h> 32 #include <linux/errno.h> 33 #include <linux/kernel.h> 34 #include <linux/un.h> 35 #include <linux/uaccess.h> 36 #include <linux/inet.h> 37 #include <linux/idr.h> 38 #include <linux/file.h> 39 #include <linux/parser.h> 40 #include <net/9p/9p.h> 41 #include <net/9p/transport.h> 42 43 #define P9_PORT 564 44 #define MAX_SOCK_BUF (64*1024) 45 46 47 struct p9_fd_opts { 48 int rfd; 49 int wfd; 50 u16 port; 51 }; 52 53 struct p9_trans_fd { 54 struct file *rd; 55 struct file *wr; 56 }; 57 58 /* 59 * Option Parsing (code inspired by NFS code) 60 * - a little lazy - parse all fd-transport options 61 */ 62 63 enum { 64 /* Options that take integer arguments */ 65 Opt_port, Opt_rfdno, Opt_wfdno, Opt_err, 66 }; 67 68 static match_table_t tokens = { 69 {Opt_port, "port=%u"}, 70 {Opt_rfdno, "rfdno=%u"}, 71 {Opt_wfdno, "wfdno=%u"}, 72 {Opt_err, NULL}, 73 }; 74 75 /** 76 * v9fs_parse_options - parse mount options into session structure 77 * @options: options string passed from mount 78 * @v9ses: existing v9fs session information 79 * 80 */ 81 82 static void parse_opts(char *options, struct p9_fd_opts *opts) 83 { 84 char *p; 85 substring_t args[MAX_OPT_ARGS]; 86 int option; 87 int ret; 88 89 opts->port = P9_PORT; 90 opts->rfd = ~0; 91 opts->wfd = ~0; 92 93 if (!options) 94 return; 95 96 while ((p = strsep(&options, ",")) != NULL) { 97 int token; 98 if (!*p) 99 continue; 100 token = match_token(p, tokens, args); 101 ret = match_int(&args[0], &option); 102 if (ret < 0) { 103 P9_DPRINTK(P9_DEBUG_ERROR, 104 "integer field, but no integer?\n"); 105 continue; 106 } 107 switch (token) { 108 case Opt_port: 109 opts->port = option; 110 break; 111 case Opt_rfdno: 112 opts->rfd = option; 113 break; 114 case Opt_wfdno: 115 opts->wfd = option; 116 break; 117 default: 118 continue; 119 } 120 } 121 } 122 123 static int p9_fd_open(struct p9_trans *trans, int rfd, int wfd) 124 { 125 struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd), 126 GFP_KERNEL); 127 if (!ts) 128 return -ENOMEM; 129 130 ts->rd = fget(rfd); 131 ts->wr = fget(wfd); 132 if (!ts->rd || !ts->wr) { 133 if (ts->rd) 134 fput(ts->rd); 135 if (ts->wr) 136 fput(ts->wr); 137 kfree(ts); 138 return -EIO; 139 } 140 141 trans->priv = ts; 142 trans->status = Connected; 143 144 return 0; 145 } 146 147 static int p9_socket_open(struct p9_trans *trans, struct socket *csocket) 148 { 149 int fd, ret; 150 151 csocket->sk->sk_allocation = GFP_NOIO; 152 fd = sock_map_fd(csocket); 153 if (fd < 0) { 154 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n"); 155 return fd; 156 } 157 158 ret = p9_fd_open(trans, fd, fd); 159 if (ret < 0) { 160 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n"); 161 sockfd_put(csocket); 162 return ret; 163 } 164 165 ((struct p9_trans_fd *)trans->priv)->rd->f_flags |= O_NONBLOCK; 166 167 return 0; 168 } 169 170 /** 171 * p9_fd_read- read from a fd 172 * @v9ses: session information 173 * @v: buffer to receive data into 174 * @len: size of receive buffer 175 * 176 */ 177 static int p9_fd_read(struct p9_trans *trans, void *v, int len) 178 { 179 int ret; 180 struct p9_trans_fd *ts = NULL; 181 182 if (trans && trans->status != Disconnected) 183 ts = trans->priv; 184 185 if (!ts) 186 return -EREMOTEIO; 187 188 if (!(ts->rd->f_flags & O_NONBLOCK)) 189 P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n"); 190 191 ret = kernel_read(ts->rd, ts->rd->f_pos, v, len); 192 if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) 193 trans->status = Disconnected; 194 return ret; 195 } 196 197 /** 198 * p9_fd_write - write to a socket 199 * @v9ses: session information 200 * @v: buffer to send data from 201 * @len: size of send buffer 202 * 203 */ 204 static int p9_fd_write(struct p9_trans *trans, void *v, int len) 205 { 206 int ret; 207 mm_segment_t oldfs; 208 struct p9_trans_fd *ts = NULL; 209 210 if (trans && trans->status != Disconnected) 211 ts = trans->priv; 212 213 if (!ts) 214 return -EREMOTEIO; 215 216 if (!(ts->wr->f_flags & O_NONBLOCK)) 217 P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n"); 218 219 oldfs = get_fs(); 220 set_fs(get_ds()); 221 /* The cast to a user pointer is valid due to the set_fs() */ 222 ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos); 223 set_fs(oldfs); 224 225 if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) 226 trans->status = Disconnected; 227 return ret; 228 } 229 230 static unsigned int 231 p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt) 232 { 233 int ret, n; 234 struct p9_trans_fd *ts = NULL; 235 mm_segment_t oldfs; 236 237 if (trans && trans->status == Connected) 238 ts = trans->priv; 239 240 if (!ts) 241 return -EREMOTEIO; 242 243 if (!ts->rd->f_op || !ts->rd->f_op->poll) 244 return -EIO; 245 246 if (!ts->wr->f_op || !ts->wr->f_op->poll) 247 return -EIO; 248 249 oldfs = get_fs(); 250 set_fs(get_ds()); 251 252 ret = ts->rd->f_op->poll(ts->rd, pt); 253 if (ret < 0) 254 goto end; 255 256 if (ts->rd != ts->wr) { 257 n = ts->wr->f_op->poll(ts->wr, pt); 258 if (n < 0) { 259 ret = n; 260 goto end; 261 } 262 ret = (ret & ~POLLOUT) | (n & ~POLLIN); 263 } 264 265 end: 266 set_fs(oldfs); 267 return ret; 268 } 269 270 /** 271 * p9_sock_close - shutdown socket 272 * @trans: private socket structure 273 * 274 */ 275 static void p9_fd_close(struct p9_trans *trans) 276 { 277 struct p9_trans_fd *ts; 278 279 if (!trans) 280 return; 281 282 ts = xchg(&trans->priv, NULL); 283 284 if (!ts) 285 return; 286 287 trans->status = Disconnected; 288 if (ts->rd) 289 fput(ts->rd); 290 if (ts->wr) 291 fput(ts->wr); 292 kfree(ts); 293 } 294 295 static struct p9_trans *p9_trans_create_tcp(const char *addr, char *args) 296 { 297 int err; 298 struct p9_trans *trans; 299 struct socket *csocket; 300 struct sockaddr_in sin_server; 301 struct p9_fd_opts opts; 302 303 parse_opts(args, &opts); 304 305 csocket = NULL; 306 trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); 307 if (!trans) 308 return ERR_PTR(-ENOMEM); 309 310 trans->write = p9_fd_write; 311 trans->read = p9_fd_read; 312 trans->close = p9_fd_close; 313 trans->poll = p9_fd_poll; 314 315 sin_server.sin_family = AF_INET; 316 sin_server.sin_addr.s_addr = in_aton(addr); 317 sin_server.sin_port = htons(opts.port); 318 sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket); 319 320 if (!csocket) { 321 P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n"); 322 err = -EIO; 323 goto error; 324 } 325 326 err = csocket->ops->connect(csocket, 327 (struct sockaddr *)&sin_server, 328 sizeof(struct sockaddr_in), 0); 329 if (err < 0) { 330 P9_EPRINTK(KERN_ERR, 331 "p9_trans_tcp: problem connecting socket to %s\n", 332 addr); 333 goto error; 334 } 335 336 err = p9_socket_open(trans, csocket); 337 if (err < 0) 338 goto error; 339 340 return trans; 341 342 error: 343 if (csocket) 344 sock_release(csocket); 345 346 kfree(trans); 347 return ERR_PTR(err); 348 } 349 350 static struct p9_trans *p9_trans_create_unix(const char *addr, char *args) 351 { 352 int err; 353 struct socket *csocket; 354 struct sockaddr_un sun_server; 355 struct p9_trans *trans; 356 357 csocket = NULL; 358 trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); 359 if (!trans) 360 return ERR_PTR(-ENOMEM); 361 362 trans->write = p9_fd_write; 363 trans->read = p9_fd_read; 364 trans->close = p9_fd_close; 365 trans->poll = p9_fd_poll; 366 367 if (strlen(addr) > UNIX_PATH_MAX) { 368 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", 369 addr); 370 err = -ENAMETOOLONG; 371 goto error; 372 } 373 374 sun_server.sun_family = PF_UNIX; 375 strcpy(sun_server.sun_path, addr); 376 sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); 377 err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, 378 sizeof(struct sockaddr_un) - 1, 0); 379 if (err < 0) { 380 P9_EPRINTK(KERN_ERR, 381 "p9_trans_unix: problem connecting socket: %s: %d\n", 382 addr, err); 383 goto error; 384 } 385 386 err = p9_socket_open(trans, csocket); 387 if (err < 0) 388 goto error; 389 390 return trans; 391 392 error: 393 if (csocket) 394 sock_release(csocket); 395 396 kfree(trans); 397 return ERR_PTR(err); 398 } 399 400 static struct p9_trans *p9_trans_create_fd(const char *name, char *args) 401 { 402 int err; 403 struct p9_trans *trans; 404 struct p9_fd_opts opts; 405 406 parse_opts(args, &opts); 407 408 if (opts.rfd == ~0 || opts.wfd == ~0) { 409 printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); 410 return ERR_PTR(-ENOPROTOOPT); 411 } 412 413 trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); 414 if (!trans) 415 return ERR_PTR(-ENOMEM); 416 417 trans->write = p9_fd_write; 418 trans->read = p9_fd_read; 419 trans->close = p9_fd_close; 420 trans->poll = p9_fd_poll; 421 422 err = p9_fd_open(trans, opts.rfd, opts.wfd); 423 if (err < 0) 424 goto error; 425 426 return trans; 427 428 error: 429 kfree(trans); 430 return ERR_PTR(err); 431 } 432 433 static struct p9_trans_module p9_tcp_trans = { 434 .name = "tcp", 435 .maxsize = MAX_SOCK_BUF, 436 .def = 1, 437 .create = p9_trans_create_tcp, 438 }; 439 440 static struct p9_trans_module p9_unix_trans = { 441 .name = "unix", 442 .maxsize = MAX_SOCK_BUF, 443 .def = 0, 444 .create = p9_trans_create_unix, 445 }; 446 447 static struct p9_trans_module p9_fd_trans = { 448 .name = "fd", 449 .maxsize = MAX_SOCK_BUF, 450 .def = 0, 451 .create = p9_trans_create_fd, 452 }; 453 454 static int __init p9_trans_fd_init(void) 455 { 456 v9fs_register_trans(&p9_tcp_trans); 457 v9fs_register_trans(&p9_unix_trans); 458 v9fs_register_trans(&p9_fd_trans); 459 460 return 1; 461 } 462 463 static void __exit p9_trans_fd_exit(void) { 464 printk(KERN_ERR "Removal of 9p transports not implemented\n"); 465 BUG(); 466 } 467 468 module_init(p9_trans_fd_init); 469 module_exit(p9_trans_fd_exit); 470 471 MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>"); 472 MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>"); 473 MODULE_LICENSE("GPL"); 474