2005-09-09 13:04:20 -07:00
/*
* linux / fs / 9 p / v9fs . c
*
* This file contains functions assisting in mapping VFS to 9 P2000
*
* Copyright ( C ) 2004 by Eric Van Hensbergen < ericvh @ gmail . com >
* Copyright ( C ) 2002 by Ron Minnich < rminnich @ lanl . gov >
*
* This program is free software ; you can redistribute it and / or modify
2006-03-25 03:07:28 -08:00
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation .
2005-09-09 13:04:20 -07:00
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to :
* Free Software Foundation
* 51 Franklin Street , Fifth Floor
* Boston , MA 02111 - 1301 USA
*
*/
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/fs.h>
2006-10-18 13:55:46 -04:00
# include <linux/sched.h>
2005-09-09 13:04:20 -07:00
# include <linux/parser.h>
# include <linux/idr.h>
2007-07-10 17:57:28 -05:00
# include <net/9p/9p.h>
# include <net/9p/transport.h>
# include <net/9p/conn.h>
# include <net/9p/client.h>
2005-09-09 13:04:20 -07:00
# include "v9fs.h"
# include "v9fs_vfs.h"
/*
* Option Parsing ( code inspired by NFS code )
*
*/
enum {
/* Options that take integer arguments */
2007-07-13 13:05:21 -05:00
Opt_debug , Opt_port , Opt_msize , Opt_uid , Opt_gid , Opt_afid ,
2005-09-09 13:04:20 -07:00
Opt_rfdno , Opt_wfdno ,
/* String options */
2006-03-25 03:07:29 -08:00
Opt_uname , Opt_remotename ,
2005-09-09 13:04:20 -07:00
/* Options that take no arguments */
2007-07-10 17:57:28 -05:00
Opt_legacy , Opt_nodevmap , Opt_unix , Opt_tcp , Opt_fd , Opt_pci ,
2007-02-11 13:21:39 -06:00
/* Cache options */
Opt_cache_loose ,
2005-09-09 13:04:20 -07:00
/* Error token */
Opt_err
} ;
static match_table_t tokens = {
2007-07-13 13:05:21 -05:00
{ Opt_debug , " debug=%x " } ,
2005-09-09 13:04:20 -07:00
{ Opt_port , " port=%u " } ,
{ Opt_msize , " msize=%u " } ,
{ Opt_uid , " uid=%u " } ,
{ Opt_gid , " gid=%u " } ,
{ Opt_afid , " afid=%u " } ,
{ Opt_rfdno , " rfdno=%u " } ,
{ Opt_wfdno , " wfdno=%u " } ,
2006-03-25 03:07:29 -08:00
{ Opt_uname , " uname=%s " } ,
2005-09-09 13:04:20 -07:00
{ Opt_remotename , " aname=%s " } ,
{ Opt_unix , " proto=unix " } ,
{ Opt_tcp , " proto=tcp " } ,
{ Opt_fd , " proto=fd " } ,
2007-07-10 17:57:28 -05:00
# ifdef CONFIG_PCI_9P
{ Opt_pci , " proto=pci " } ,
# endif
2005-09-09 13:04:20 -07:00
{ Opt_tcp , " tcp " } ,
{ Opt_unix , " unix " } ,
{ Opt_fd , " fd " } ,
{ Opt_legacy , " noextend " } ,
{ Opt_nodevmap , " nodevmap " } ,
2007-02-11 13:21:39 -06:00
{ Opt_cache_loose , " cache=loose " } ,
{ Opt_cache_loose , " loose " } ,
2005-09-09 13:04:20 -07:00
{ Opt_err , NULL }
} ;
2007-07-10 17:57:28 -05:00
extern struct p9_transport * p9pci_trans_create ( void ) ;
2005-09-09 13:04:20 -07:00
/*
* Parse option string .
*/
/**
* v9fs_parse_options - parse mount options into session structure
* @ options : options string passed from mount
* @ v9ses : existing v9fs session information
*
*/
static void v9fs_parse_options ( char * options , struct v9fs_session_info * v9ses )
{
char * p ;
substring_t args [ MAX_OPT_ARGS ] ;
int option ;
int ret ;
/* setup defaults */
v9ses - > port = V9FS_PORT ;
v9ses - > maxdata = 9000 ;
v9ses - > proto = PROTO_TCP ;
v9ses - > extended = 1 ;
v9ses - > afid = ~ 0 ;
v9ses - > debug = 0 ;
v9ses - > rfdno = ~ 0 ;
v9ses - > wfdno = ~ 0 ;
2007-02-11 13:21:39 -06:00
v9ses - > cache = 0 ;
2005-09-09 13:04:20 -07:00
if ( ! options )
return ;
while ( ( p = strsep ( & options , " , " ) ) ! = NULL ) {
int token ;
if ( ! * p )
continue ;
token = match_token ( p , tokens , args ) ;
2006-03-25 03:07:29 -08:00
if ( token < Opt_uname ) {
2005-09-09 13:04:20 -07:00
if ( ( ret = match_int ( & args [ 0 ] , & option ) ) < 0 ) {
2007-07-10 17:57:28 -05:00
P9_DPRINTK ( P9_DEBUG_ERROR ,
2005-09-09 13:04:20 -07:00
" integer field, but no integer? \n " ) ;
continue ;
}
}
switch ( token ) {
2007-07-13 13:05:21 -05:00
case Opt_debug :
v9ses - > debug = option ;
2007-07-16 16:02:49 -05:00
# ifdef CONFIG_NET_9P_DEBUG
2007-07-13 13:05:21 -05:00
p9_debug_level = option ;
2007-07-16 16:02:49 -05:00
# endif
2007-07-13 13:05:21 -05:00
break ;
2005-09-09 13:04:20 -07:00
case Opt_port :
v9ses - > port = option ;
break ;
case Opt_msize :
v9ses - > maxdata = option ;
break ;
case Opt_uid :
v9ses - > uid = option ;
break ;
case Opt_gid :
v9ses - > gid = option ;
break ;
case Opt_afid :
v9ses - > afid = option ;
break ;
case Opt_rfdno :
v9ses - > rfdno = option ;
break ;
case Opt_wfdno :
v9ses - > wfdno = option ;
break ;
case Opt_tcp :
v9ses - > proto = PROTO_TCP ;
break ;
case Opt_unix :
v9ses - > proto = PROTO_UNIX ;
break ;
2007-07-10 17:57:28 -05:00
case Opt_pci :
v9ses - > proto = PROTO_PCI ;
break ;
2005-09-09 13:04:20 -07:00
case Opt_fd :
v9ses - > proto = PROTO_FD ;
break ;
2006-03-25 03:07:29 -08:00
case Opt_uname :
2005-09-09 13:04:20 -07:00
match_strcpy ( v9ses - > name , & args [ 0 ] ) ;
break ;
case Opt_remotename :
match_strcpy ( v9ses - > remotename , & args [ 0 ] ) ;
break ;
case Opt_legacy :
v9ses - > extended = 0 ;
break ;
case Opt_nodevmap :
v9ses - > nodev = 1 ;
break ;
2007-02-11 13:21:39 -06:00
case Opt_cache_loose :
v9ses - > cache = CACHE_LOOSE ;
break ;
2005-09-09 13:04:20 -07:00
default :
continue ;
}
}
}
/**
* v9fs_session_init - initialize session
* @ v9ses : session information structure
* @ dev_name : device being mounted
* @ data : options
*
*/
2007-07-10 17:57:28 -05:00
struct p9_fid * v9fs_session_init ( struct v9fs_session_info * v9ses ,
2005-09-09 13:04:20 -07:00
const char * dev_name , char * data )
{
int retval = - EINVAL ;
2007-07-10 17:57:28 -05:00
struct p9_transport * trans ;
struct p9_fid * fid ;
2005-09-09 13:04:20 -07:00
v9ses - > name = __getname ( ) ;
if ( ! v9ses - > name )
2007-07-10 17:57:28 -05:00
return ERR_PTR ( - ENOMEM ) ;
2005-09-09 13:04:20 -07:00
v9ses - > remotename = __getname ( ) ;
if ( ! v9ses - > remotename ) {
2005-11-07 00:59:36 -08:00
__putname ( v9ses - > name ) ;
2007-07-10 17:57:28 -05:00
return ERR_PTR ( - ENOMEM ) ;
2005-09-09 13:04:20 -07:00
}
strcpy ( v9ses - > name , V9FS_DEFUSER ) ;
strcpy ( v9ses - > remotename , V9FS_DEFANAME ) ;
v9fs_parse_options ( data , v9ses ) ;
switch ( v9ses - > proto ) {
case PROTO_TCP :
2007-07-10 17:57:28 -05:00
trans = p9_trans_create_tcp ( dev_name , v9ses - > port ) ;
2005-09-09 13:04:20 -07:00
break ;
case PROTO_UNIX :
2007-07-10 17:57:28 -05:00
trans = p9_trans_create_unix ( dev_name ) ;
2005-09-09 13:04:20 -07:00
* v9ses - > remotename = 0 ;
break ;
case PROTO_FD :
2007-07-10 17:57:28 -05:00
trans = p9_trans_create_fd ( v9ses - > rfdno , v9ses - > wfdno ) ;
* v9ses - > remotename = 0 ;
break ;
# ifdef CONFIG_PCI_9P
case PROTO_PCI :
trans = p9pci_trans_create ( ) ;
2005-09-09 13:04:20 -07:00
* v9ses - > remotename = 0 ;
break ;
2007-07-10 17:57:28 -05:00
# endif
2005-09-09 13:04:20 -07:00
default :
printk ( KERN_ERR " v9fs: Bad mount protocol %d \n " , v9ses - > proto ) ;
retval = - ENOPROTOOPT ;
2007-07-10 17:57:28 -05:00
goto error ;
2005-09-09 13:04:20 -07:00
} ;
2007-07-10 17:57:28 -05:00
if ( IS_ERR ( trans ) ) {
retval = PTR_ERR ( trans ) ;
trans = NULL ;
goto error ;
2005-09-22 21:43:51 -07:00
}
2007-07-10 17:57:28 -05:00
v9ses - > clnt = p9_client_create ( trans , v9ses - > maxdata + P9_IOHDRSZ ,
v9ses - > extended ) ;
2005-09-09 13:04:20 -07:00
2007-07-10 17:57:28 -05:00
if ( IS_ERR ( v9ses - > clnt ) ) {
retval = PTR_ERR ( v9ses - > clnt ) ;
v9ses - > clnt = NULL ;
P9_DPRINTK ( P9_DEBUG_ERROR , " problem initializing 9p client \n " ) ;
goto error ;
2005-09-09 13:04:20 -07:00
}
2007-07-10 17:57:28 -05:00
fid = p9_client_attach ( v9ses - > clnt , NULL , v9ses - > name ,
v9ses - > remotename ) ;
if ( IS_ERR ( fid ) ) {
retval = PTR_ERR ( fid ) ;
fid = NULL ;
P9_DPRINTK ( P9_DEBUG_ERROR , " cannot attach \n " ) ;
goto error ;
2005-09-09 13:04:20 -07:00
}
2007-07-10 17:57:28 -05:00
return fid ;
2005-09-09 13:04:20 -07:00
2007-07-10 17:57:28 -05:00
error :
2005-09-09 13:04:20 -07:00
v9fs_session_close ( v9ses ) ;
2007-07-10 17:57:28 -05:00
return ERR_PTR ( retval ) ;
2005-09-09 13:04:20 -07:00
}
/**
* v9fs_session_close - shutdown a session
* @ v9ses : session information structure
*
*/
void v9fs_session_close ( struct v9fs_session_info * v9ses )
{
2007-07-10 17:57:28 -05:00
if ( v9ses - > clnt ) {
p9_client_destroy ( v9ses - > clnt ) ;
v9ses - > clnt = NULL ;
2006-01-08 01:04:58 -08:00
}
2005-09-09 13:04:20 -07:00
2005-11-07 00:59:36 -08:00
__putname ( v9ses - > name ) ;
__putname ( v9ses - > remotename ) ;
2005-09-09 13:04:20 -07:00
}
2005-09-09 13:04:23 -07:00
/**
* v9fs_session_cancel - mark transport as disconnected
* and cancel all pending requests .
*/
void v9fs_session_cancel ( struct v9fs_session_info * v9ses ) {
2007-07-10 17:57:28 -05:00
P9_DPRINTK ( P9_DEBUG_ERROR , " cancel session %p \n " , v9ses ) ;
p9_client_disconnect ( v9ses - > clnt ) ;
2005-09-09 13:04:23 -07:00
}
2005-09-09 13:04:20 -07:00
extern int v9fs_error_init ( void ) ;
/**
* v9fs_init - Initialize module
*
*/
static int __init init_v9fs ( void )
{
2007-01-26 00:57:04 -08:00
printk ( KERN_INFO " Installing v9fs 9p2000 file system support \n " ) ;
2005-09-09 13:04:20 -07:00
2007-07-10 17:57:28 -05:00
return register_filesystem ( & v9fs_fs_type ) ;
2005-09-09 13:04:20 -07:00
}
/**
* v9fs_init - shutdown module
*
*/
static void __exit exit_v9fs ( void )
{
unregister_filesystem ( & v9fs_fs_type ) ;
}
module_init ( init_v9fs )
module_exit ( exit_v9fs )
2007-07-10 17:57:28 -05:00
MODULE_AUTHOR ( " Latchesar Ionkov <lucho@ionkov.net> " ) ;
2005-09-09 13:04:20 -07:00
MODULE_AUTHOR ( " Eric Van Hensbergen <ericvh@gmail.com> " ) ;
MODULE_AUTHOR ( " Ron Minnich <rminnich@lanl.gov> " ) ;
MODULE_LICENSE ( " GPL " ) ;