2005-09-10 00:04:20 +04: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 14:07:28 +03:00
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation .
2005-09-10 00:04:20 +04: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 21:55:46 +04:00
# include <linux/sched.h>
2005-09-10 00:04:20 +04:00
# include <linux/parser.h>
# include <linux/idr.h>
2007-07-11 02:57:28 +04:00
# include <net/9p/9p.h>
# include <net/9p/transport.h>
# include <net/9p/conn.h>
# include <net/9p/client.h>
2005-09-10 00:04:20 +04:00
# include "v9fs.h"
# include "v9fs_vfs.h"
/*
* Option Parsing ( code inspired by NFS code )
2007-10-17 23:31:07 +04:00
* NOTE : each transport will parse its own options
2005-09-10 00:04:20 +04:00
*/
enum {
/* Options that take integer arguments */
2007-10-17 23:31:07 +04:00
Opt_debug , Opt_msize , Opt_dfltuid , Opt_dfltgid , Opt_afid ,
2005-09-10 00:04:20 +04:00
/* String options */
2007-10-17 23:31:07 +04:00
Opt_uname , Opt_remotename , Opt_trans ,
2005-09-10 00:04:20 +04:00
/* Options that take no arguments */
2007-10-17 23:31:07 +04:00
Opt_legacy , Opt_nodevmap ,
2007-02-11 22:21:39 +03:00
/* Cache options */
Opt_cache_loose ,
2007-10-17 23:31:07 +04:00
/* Access options */
Opt_access ,
2005-09-10 00:04:20 +04:00
/* Error token */
Opt_err
} ;
static match_table_t tokens = {
2007-07-13 22:05:21 +04:00
{ Opt_debug , " debug=%x " } ,
2005-09-10 00:04:20 +04:00
{ Opt_msize , " msize=%u " } ,
2007-10-17 23:31:07 +04:00
{ Opt_dfltuid , " dfltuid=%u " } ,
{ Opt_dfltgid , " dfltgid=%u " } ,
2005-09-10 00:04:20 +04:00
{ Opt_afid , " afid=%u " } ,
2006-03-25 14:07:29 +03:00
{ Opt_uname , " uname=%s " } ,
2005-09-10 00:04:20 +04:00
{ Opt_remotename , " aname=%s " } ,
2007-10-17 23:31:07 +04:00
{ Opt_trans , " trans=%s " } ,
2005-09-10 00:04:20 +04:00
{ Opt_legacy , " noextend " } ,
{ Opt_nodevmap , " nodevmap " } ,
2007-02-11 22:21:39 +03:00
{ Opt_cache_loose , " cache=loose " } ,
{ Opt_cache_loose , " loose " } ,
2007-10-17 23:31:07 +04:00
{ Opt_access , " access=%s " } ,
2005-09-10 00:04:20 +04:00
{ Opt_err , NULL }
} ;
/**
* v9fs_parse_options - parse mount options into session structure
* @ options : options string passed from mount
* @ v9ses : existing v9fs session information
*
*/
2007-10-17 23:31:07 +04:00
static void v9fs_parse_options ( struct v9fs_session_info * v9ses )
2005-09-10 00:04:20 +04:00
{
2007-11-06 17:02:53 +03:00
char * options ;
2005-09-10 00:04:20 +04:00
substring_t args [ MAX_OPT_ARGS ] ;
2007-10-17 23:31:07 +04:00
char * p ;
2005-09-10 00:04:20 +04:00
int option ;
int ret ;
2007-10-17 23:31:07 +04:00
char * s , * e ;
2005-09-10 00:04:20 +04:00
/* setup defaults */
2007-10-17 23:31:07 +04:00
v9ses - > maxdata = 8192 ;
2005-09-10 00:04:20 +04:00
v9ses - > afid = ~ 0 ;
v9ses - > debug = 0 ;
2007-02-11 22:21:39 +03:00
v9ses - > cache = 0 ;
2007-10-17 23:31:07 +04:00
v9ses - > trans = v9fs_default_trans ( ) ;
2005-09-10 00:04:20 +04:00
2007-11-06 17:02:53 +03:00
if ( ! v9ses - > options )
2005-09-10 00:04:20 +04:00
return ;
2007-11-06 17:02:53 +03:00
options = kstrdup ( v9ses - > options , GFP_KERNEL ) ;
2005-09-10 00:04:20 +04:00
while ( ( p = strsep ( & options , " , " ) ) ! = NULL ) {
int token ;
if ( ! * p )
continue ;
token = match_token ( p , tokens , args ) ;
2006-03-25 14:07:29 +03:00
if ( token < Opt_uname ) {
2005-09-10 00:04:20 +04:00
if ( ( ret = match_int ( & args [ 0 ] , & option ) ) < 0 ) {
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_ERROR ,
2005-09-10 00:04:20 +04:00
" integer field, but no integer? \n " ) ;
continue ;
}
}
switch ( token ) {
2007-07-13 22:05:21 +04:00
case Opt_debug :
v9ses - > debug = option ;
2007-07-17 01:02:49 +04:00
# ifdef CONFIG_NET_9P_DEBUG
2007-07-13 22:05:21 +04:00
p9_debug_level = option ;
2007-07-17 01:02:49 +04:00
# endif
2007-07-13 22:05:21 +04:00
break ;
2005-09-10 00:04:20 +04:00
case Opt_msize :
v9ses - > maxdata = option ;
break ;
2007-10-17 23:31:07 +04:00
case Opt_dfltuid :
v9ses - > dfltuid = option ;
2005-09-10 00:04:20 +04:00
break ;
2007-10-17 23:31:07 +04:00
case Opt_dfltgid :
v9ses - > dfltgid = option ;
2005-09-10 00:04:20 +04:00
break ;
case Opt_afid :
v9ses - > afid = option ;
break ;
2007-10-17 23:31:07 +04:00
case Opt_trans :
v9ses - > trans = v9fs_match_trans ( & args [ 0 ] ) ;
2005-09-10 00:04:20 +04:00
break ;
2006-03-25 14:07:29 +03:00
case Opt_uname :
2007-10-17 23:31:07 +04:00
match_strcpy ( v9ses - > uname , & args [ 0 ] ) ;
2005-09-10 00:04:20 +04:00
break ;
case Opt_remotename :
2007-10-17 23:31:07 +04:00
match_strcpy ( v9ses - > aname , & args [ 0 ] ) ;
2005-09-10 00:04:20 +04:00
break ;
case Opt_legacy :
2007-10-17 23:31:07 +04:00
v9ses - > flags & = ~ V9FS_EXTENDED ;
2005-09-10 00:04:20 +04:00
break ;
case Opt_nodevmap :
v9ses - > nodev = 1 ;
break ;
2007-02-11 22:21:39 +03:00
case Opt_cache_loose :
v9ses - > cache = CACHE_LOOSE ;
break ;
2007-10-17 23:31:07 +04:00
case Opt_access :
s = match_strdup ( & args [ 0 ] ) ;
v9ses - > flags & = ~ V9FS_ACCESS_MASK ;
if ( strcmp ( s , " user " ) = = 0 )
v9ses - > flags | = V9FS_ACCESS_USER ;
else if ( strcmp ( s , " any " ) = = 0 )
v9ses - > flags | = V9FS_ACCESS_ANY ;
else {
v9ses - > flags | = V9FS_ACCESS_SINGLE ;
v9ses - > uid = simple_strtol ( s , & e , 10 ) ;
if ( * e ! = ' \0 ' )
v9ses - > uid = ~ 0 ;
}
2007-10-23 22:48:50 +04:00
kfree ( s ) ;
2007-10-17 23:31:07 +04:00
break ;
2005-09-10 00:04:20 +04:00
default :
continue ;
}
}
2007-11-06 17:02:53 +03:00
kfree ( options ) ;
2005-09-10 00:04:20 +04:00
}
/**
* v9fs_session_init - initialize session
* @ v9ses : session information structure
* @ dev_name : device being mounted
* @ data : options
*
*/
2007-07-11 02:57:28 +04:00
struct p9_fid * v9fs_session_init ( struct v9fs_session_info * v9ses ,
2005-09-10 00:04:20 +04:00
const char * dev_name , char * data )
{
int retval = - EINVAL ;
2007-10-17 23:31:07 +04:00
struct p9_trans * trans = NULL ;
2007-07-11 02:57:28 +04:00
struct p9_fid * fid ;
2005-09-10 00:04:20 +04:00
2007-10-17 23:31:07 +04:00
v9ses - > uname = __getname ( ) ;
if ( ! v9ses - > uname )
2007-07-11 02:57:28 +04:00
return ERR_PTR ( - ENOMEM ) ;
2005-09-10 00:04:20 +04:00
2007-10-17 23:31:07 +04:00
v9ses - > aname = __getname ( ) ;
if ( ! v9ses - > aname ) {
__putname ( v9ses - > uname ) ;
2007-07-11 02:57:28 +04:00
return ERR_PTR ( - ENOMEM ) ;
2005-09-10 00:04:20 +04:00
}
2007-10-17 23:31:07 +04:00
v9ses - > flags = V9FS_EXTENDED | V9FS_ACCESS_USER ;
strcpy ( v9ses - > uname , V9FS_DEFUSER ) ;
strcpy ( v9ses - > aname , V9FS_DEFANAME ) ;
v9ses - > uid = ~ 0 ;
2007-10-17 23:31:07 +04:00
v9ses - > dfltuid = V9FS_DEFUID ;
v9ses - > dfltgid = V9FS_DEFGID ;
2007-10-17 23:31:07 +04:00
v9ses - > options = kstrdup ( data , GFP_KERNEL ) ;
v9fs_parse_options ( v9ses ) ;
if ( v9ses - > trans = = NULL ) {
retval = - EPROTONOSUPPORT ;
P9_DPRINTK ( P9_DEBUG_ERROR ,
" No transport defined or default transport \n " ) ;
2007-07-11 02:57:28 +04:00
goto error ;
2007-10-17 23:31:07 +04:00
}
2005-09-10 00:04:20 +04:00
2007-10-17 23:31:07 +04:00
trans = v9ses - > trans - > create ( dev_name , v9ses - > options ) ;
2007-07-11 02:57:28 +04:00
if ( IS_ERR ( trans ) ) {
retval = PTR_ERR ( trans ) ;
trans = NULL ;
goto error ;
2005-09-23 08:43:51 +04:00
}
2007-10-17 23:31:07 +04:00
if ( ( v9ses - > maxdata + P9_IOHDRSZ ) > v9ses - > trans - > maxsize )
v9ses - > maxdata = v9ses - > trans - > maxsize - P9_IOHDRSZ ;
2005-09-23 08:43:51 +04:00
2007-10-17 23:31:07 +04:00
v9ses - > clnt = p9_client_create ( trans , v9ses - > maxdata + P9_IOHDRSZ ,
2007-10-17 23:31:07 +04:00
v9fs_extended ( v9ses ) ) ;
2005-09-10 00:04:20 +04:00
2007-07-11 02:57:28 +04: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-10 00:04:20 +04:00
}
2007-10-17 23:31:07 +04:00
if ( ! v9ses - > clnt - > dotu )
v9ses - > flags & = ~ V9FS_EXTENDED ;
/* for legacy mode, fall back to V9FS_ACCESS_ANY */
if ( ! v9fs_extended ( v9ses ) & &
( ( v9ses - > flags & V9FS_ACCESS_MASK ) = = V9FS_ACCESS_USER ) ) {
v9ses - > flags & = ~ V9FS_ACCESS_MASK ;
v9ses - > flags | = V9FS_ACCESS_ANY ;
v9ses - > uid = ~ 0 ;
}
fid = p9_client_attach ( v9ses - > clnt , NULL , v9ses - > uname , ~ 0 ,
v9ses - > aname ) ;
2007-07-11 02:57:28 +04:00
if ( IS_ERR ( fid ) ) {
retval = PTR_ERR ( fid ) ;
fid = NULL ;
P9_DPRINTK ( P9_DEBUG_ERROR , " cannot attach \n " ) ;
goto error ;
2005-09-10 00:04:20 +04:00
}
2007-10-17 23:31:07 +04:00
if ( ( v9ses - > flags & V9FS_ACCESS_MASK ) = = V9FS_ACCESS_SINGLE )
fid - > uid = v9ses - > uid ;
else
fid - > uid = ~ 0 ;
2007-07-11 02:57:28 +04:00
return fid ;
2005-09-10 00:04:20 +04:00
2007-07-11 02:57:28 +04:00
error :
2005-09-10 00:04:20 +04:00
v9fs_session_close ( v9ses ) ;
2007-07-11 02:57:28 +04:00
return ERR_PTR ( retval ) ;
2005-09-10 00:04:20 +04:00
}
/**
* v9fs_session_close - shutdown a session
* @ v9ses : session information structure
*
*/
void v9fs_session_close ( struct v9fs_session_info * v9ses )
{
2007-07-11 02:57:28 +04:00
if ( v9ses - > clnt ) {
p9_client_destroy ( v9ses - > clnt ) ;
v9ses - > clnt = NULL ;
2006-01-08 12:04:58 +03:00
}
2005-09-10 00:04:20 +04:00
2007-10-17 23:31:07 +04:00
__putname ( v9ses - > uname ) ;
__putname ( v9ses - > aname ) ;
2007-10-17 23:31:07 +04:00
kfree ( v9ses - > options ) ;
2005-09-10 00:04:20 +04:00
}
2005-09-10 00:04:23 +04:00
/**
* v9fs_session_cancel - mark transport as disconnected
* and cancel all pending requests .
*/
void v9fs_session_cancel ( struct v9fs_session_info * v9ses ) {
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_ERROR , " cancel session %p \n " , v9ses ) ;
p9_client_disconnect ( v9ses - > clnt ) ;
2005-09-10 00:04:23 +04:00
}
2005-09-10 00:04:20 +04:00
extern int v9fs_error_init ( void ) ;
/**
* v9fs_init - Initialize module
*
*/
static int __init init_v9fs ( void )
{
2007-01-26 11:57:04 +03:00
printk ( KERN_INFO " Installing v9fs 9p2000 file system support \n " ) ;
2007-10-17 23:31:07 +04:00
/* TODO: Setup list of registered trasnport modules */
2007-07-11 02:57:28 +04:00
return register_filesystem ( & v9fs_fs_type ) ;
2005-09-10 00:04:20 +04: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-11 02:57:28 +04:00
MODULE_AUTHOR ( " Latchesar Ionkov <lucho@ionkov.net> " ) ;
2005-09-10 00:04:20 +04:00
MODULE_AUTHOR ( " Eric Van Hensbergen <ericvh@gmail.com> " ) ;
MODULE_AUTHOR ( " Ron Minnich <rminnich@lanl.gov> " ) ;
MODULE_LICENSE ( " GPL " ) ;