2005-09-10 00:04:21 +04:00
/*
2006-03-25 14:07:29 +03:00
* linux / fs / 9 p / fcall . c
2005-09-10 00:04:21 +04:00
*
2006-01-08 12:05:00 +03:00
* This file contains functions to perform synchronous 9 P calls
2005-09-10 00:04:21 +04:00
*
2006-01-08 12:05:00 +03:00
* Copyright ( C ) 2004 by Latchesar Ionkov < lucho @ ionkov . net >
2005-09-10 00:04:21 +04:00
* 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:21 +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:21 +04:00
# include <linux/idr.h>
# include "debug.h"
# include "v9fs.h"
# include "9p.h"
2006-01-08 12:05:00 +03:00
# include "conv.h"
2005-09-10 00:04:21 +04:00
# include "mux.h"
/**
* v9fs_t_version - negotiate protocol parameters with sever
* @ v9ses : 9 P2000 session information
* @ msize : requested max size packet
* @ version : requested version . extension string
* @ fcall : pointer to response fcall pointer
*
*/
int
v9fs_t_version ( struct v9fs_session_info * v9ses , u32 msize ,
2006-01-08 12:05:00 +03:00
char * version , struct v9fs_fcall * * rcp )
2005-09-10 00:04:21 +04:00
{
2006-01-08 12:05:00 +03:00
int ret ;
struct v9fs_fcall * tc ;
2005-09-10 00:04:21 +04:00
dprintk ( DEBUG_9P , " msize: %d version: %s \n " , msize , version ) ;
2006-01-08 12:05:00 +03:00
tc = v9fs_create_tversion ( msize , version ) ;
2005-09-10 00:04:21 +04:00
2006-01-08 12:05:00 +03:00
if ( ! IS_ERR ( tc ) ) {
ret = v9fs_mux_rpc ( v9ses - > mux , tc , rcp ) ;
kfree ( tc ) ;
} else
ret = PTR_ERR ( tc ) ;
return ret ;
2005-09-10 00:04:21 +04:00
}
/**
* v9fs_t_attach - mount the server
* @ v9ses : 9 P2000 session information
* @ uname : user name doing the attach
* @ aname : remote name being attached to
* @ fid : mount fid to attatch to root node
* @ afid : authentication fid ( in this case result key )
* @ fcall : pointer to response fcall pointer
*
*/
int
v9fs_t_attach ( struct v9fs_session_info * v9ses , char * uname , char * aname ,
2006-01-08 12:05:00 +03:00
u32 fid , u32 afid , struct v9fs_fcall * * rcp )
2005-09-10 00:04:21 +04:00
{
2006-01-08 12:05:00 +03:00
int ret ;
struct v9fs_fcall * tc ;
2005-09-10 00:04:21 +04:00
dprintk ( DEBUG_9P , " uname '%s' aname '%s' fid %d afid %d \n " , uname ,
aname , fid , afid ) ;
2006-01-08 12:05:00 +03:00
tc = v9fs_create_tattach ( fid , afid , uname , aname ) ;
if ( ! IS_ERR ( tc ) ) {
ret = v9fs_mux_rpc ( v9ses - > mux , tc , rcp ) ;
kfree ( tc ) ;
} else
ret = PTR_ERR ( tc ) ;
return ret ;
2006-01-08 12:04:58 +03:00
}
static void v9fs_t_clunk_cb ( void * a , struct v9fs_fcall * tc ,
struct v9fs_fcall * rc , int err )
{
2006-05-15 20:44:18 +04:00
int fid , id ;
2006-01-08 12:04:58 +03:00
struct v9fs_session_info * v9ses ;
2006-05-15 20:44:18 +04:00
id = 0 ;
2006-01-08 12:04:58 +03:00
fid = tc - > params . tclunk . fid ;
2006-05-15 20:44:18 +04:00
if ( rc )
id = rc - > id ;
2006-01-08 12:04:58 +03:00
2006-05-15 20:44:18 +04:00
kfree ( tc ) ;
2006-01-08 12:04:58 +03:00
kfree ( rc ) ;
2006-05-15 20:44:18 +04:00
if ( id = = RCLUNK ) {
v9ses = a ;
v9fs_put_idpool ( fid , & v9ses - > fidpool ) ;
}
2005-09-10 00:04:21 +04:00
}
/**
* v9fs_t_clunk - release a fid ( finish a transaction )
* @ v9ses : 9 P2000 session information
* @ fid : fid to release
* @ fcall : pointer to response fcall pointer
*
*/
2006-01-08 12:05:00 +03:00
2005-09-10 00:04:21 +04:00
int
2006-01-08 12:04:58 +03:00
v9fs_t_clunk ( struct v9fs_session_info * v9ses , u32 fid )
2005-09-10 00:04:21 +04:00
{
2006-01-08 12:05:00 +03:00
int ret ;
2006-01-08 12:04:58 +03:00
struct v9fs_fcall * tc , * rc ;
2005-09-10 00:04:21 +04:00
dprintk ( DEBUG_9P , " fid %d \n " , fid ) ;
2006-01-08 12:05:00 +03:00
rc = NULL ;
tc = v9fs_create_tclunk ( fid ) ;
if ( ! IS_ERR ( tc ) )
ret = v9fs_mux_rpc ( v9ses - > mux , tc , & rc ) ;
else
ret = PTR_ERR ( tc ) ;
if ( ret )
dprintk ( DEBUG_ERROR , " failed fid %d err %d \n " , fid , ret ) ;
2006-01-08 12:04:58 +03:00
2006-01-08 12:05:00 +03:00
v9fs_t_clunk_cb ( v9ses , tc , rc , ret ) ;
return ret ;
2005-09-10 00:04:21 +04:00
}
2006-03-24 14:15:52 +03:00
#if 0
2005-09-10 00:04:21 +04:00
/**
* v9fs_v9fs_t_flush - flush a pending transaction
* @ v9ses : 9 P2000 session information
2006-03-25 14:07:24 +03:00
* @ tag : tag to release
2005-09-10 00:04:21 +04:00
*
*/
2006-01-08 12:05:00 +03:00
int v9fs_t_flush ( struct v9fs_session_info * v9ses , u16 oldtag )
2005-09-10 00:04:21 +04:00
{
2006-01-08 12:05:00 +03:00
int ret ;
struct v9fs_fcall * tc ;
2005-09-10 00:04:21 +04:00
2006-01-08 12:05:00 +03:00
dprintk ( DEBUG_9P , " oldtag %d \n " , oldtag ) ;
tc = v9fs_create_tflush ( oldtag ) ;
if ( ! IS_ERR ( tc ) ) {
ret = v9fs_mux_rpc ( v9ses - > mux , tc , NULL ) ;
kfree ( tc ) ;
} else
ret = PTR_ERR ( tc ) ;
return ret ;
2005-09-10 00:04:21 +04:00
}
2006-03-25 14:07:29 +03:00
# endif
2005-09-10 00:04:21 +04:00
/**
* v9fs_t_stat - read a file ' s meta - data
* @ v9ses : 9 P2000 session information
* @ fid : fid pointing to file or directory to get info about
* @ fcall : pointer to response fcall
*
*/
int
2006-01-08 12:05:00 +03:00
v9fs_t_stat ( struct v9fs_session_info * v9ses , u32 fid , struct v9fs_fcall * * rcp )
2005-09-10 00:04:21 +04:00
{
2006-01-08 12:05:00 +03:00
int ret ;
struct v9fs_fcall * tc ;
2005-09-10 00:04:21 +04:00
dprintk ( DEBUG_9P , " fid %d \n " , fid ) ;
2006-01-08 12:05:00 +03:00
ret = - ENOMEM ;
tc = v9fs_create_tstat ( fid ) ;
if ( ! IS_ERR ( tc ) ) {
ret = v9fs_mux_rpc ( v9ses - > mux , tc , rcp ) ;
kfree ( tc ) ;
} else
ret = PTR_ERR ( tc ) ;
return ret ;
2005-09-10 00:04:21 +04:00
}
/**
* v9fs_t_wstat - write a file ' s meta - data
* @ v9ses : 9 P2000 session information
* @ fid : fid pointing to file or directory to write info about
* @ stat : metadata
* @ fcall : pointer to response fcall
*
*/
int
v9fs_t_wstat ( struct v9fs_session_info * v9ses , u32 fid ,
2006-01-08 12:05:00 +03:00
struct v9fs_wstat * wstat , struct v9fs_fcall * * rcp )
2005-09-10 00:04:21 +04:00
{
2006-01-08 12:05:00 +03:00
int ret ;
struct v9fs_fcall * tc ;
2005-09-10 00:04:21 +04:00
2006-01-08 12:05:00 +03:00
dprintk ( DEBUG_9P , " fid %d \n " , fid ) ;
tc = v9fs_create_twstat ( fid , wstat , v9ses - > extended ) ;
if ( ! IS_ERR ( tc ) ) {
ret = v9fs_mux_rpc ( v9ses - > mux , tc , rcp ) ;
kfree ( tc ) ;
} else
ret = PTR_ERR ( tc ) ;
2005-09-10 00:04:21 +04:00
2006-01-08 12:05:00 +03:00
return ret ;
2005-09-10 00:04:21 +04:00
}
/**
* v9fs_t_walk - walk a fid to a new file or directory
* @ v9ses : 9 P2000 session information
* @ fid : fid to walk
* @ newfid : new fid ( for clone operations )
* @ name : path to walk fid to
* @ fcall : pointer to response fcall
*
*/
/* TODO: support multiple walk */
int
v9fs_t_walk ( struct v9fs_session_info * v9ses , u32 fid , u32 newfid ,
2006-01-08 12:05:00 +03:00
char * name , struct v9fs_fcall * * rcp )
2005-09-10 00:04:21 +04:00
{
2006-01-08 12:05:00 +03:00
int ret ;
struct v9fs_fcall * tc ;
int nwname ;
2005-09-10 00:04:21 +04:00
dprintk ( DEBUG_9P , " fid %d newfid %d wname '%s' \n " , fid , newfid , name ) ;
2006-01-08 12:05:00 +03:00
if ( name )
nwname = 1 ;
else
nwname = 0 ;
tc = v9fs_create_twalk ( fid , newfid , nwname , & name ) ;
if ( ! IS_ERR ( tc ) ) {
ret = v9fs_mux_rpc ( v9ses - > mux , tc , rcp ) ;
kfree ( tc ) ;
} else
ret = PTR_ERR ( tc ) ;
return ret ;
2005-09-10 00:04:21 +04:00
}
/**
* v9fs_t_open - open a file
*
* @ v9ses - 9 P2000 session information
* @ fid - fid to open
* @ mode - mode to open file ( R , RW , etc )
* @ fcall - pointer to response fcall
*
*/
int
v9fs_t_open ( struct v9fs_session_info * v9ses , u32 fid , u8 mode ,
2006-01-08 12:05:00 +03:00
struct v9fs_fcall * * rcp )
2005-09-10 00:04:21 +04:00
{
2006-01-08 12:05:00 +03:00
int ret ;
struct v9fs_fcall * tc ;
2005-09-10 00:04:21 +04:00
dprintk ( DEBUG_9P , " fid %d mode %d \n " , fid , mode ) ;
2006-01-08 12:05:00 +03:00
tc = v9fs_create_topen ( fid , mode ) ;
if ( ! IS_ERR ( tc ) ) {
ret = v9fs_mux_rpc ( v9ses - > mux , tc , rcp ) ;
kfree ( tc ) ;
} else
ret = PTR_ERR ( tc ) ;
2005-09-10 00:04:21 +04:00
2006-01-08 12:05:00 +03:00
return ret ;
2005-09-10 00:04:21 +04:00
}
/**
* v9fs_t_remove - remove a file or directory
* @ v9ses : 9 P2000 session information
* @ fid : fid to remove
* @ fcall : pointer to response fcall
*
*/
int
v9fs_t_remove ( struct v9fs_session_info * v9ses , u32 fid ,
2006-01-08 12:05:00 +03:00
struct v9fs_fcall * * rcp )
2005-09-10 00:04:21 +04:00
{
2006-01-08 12:05:00 +03:00
int ret ;
struct v9fs_fcall * tc ;
2005-09-10 00:04:21 +04:00
dprintk ( DEBUG_9P , " fid %d \n " , fid ) ;
2006-01-08 12:05:00 +03:00
tc = v9fs_create_tremove ( fid ) ;
if ( ! IS_ERR ( tc ) ) {
ret = v9fs_mux_rpc ( v9ses - > mux , tc , rcp ) ;
kfree ( tc ) ;
} else
ret = PTR_ERR ( tc ) ;
return ret ;
2005-09-10 00:04:21 +04:00
}
/**
* v9fs_t_create - create a file or directory
* @ v9ses : 9 P2000 session information
* @ fid : fid to create
* @ name : name of the file or directory to create
* @ perm : permissions to create with
* @ mode : mode to open file ( R , RW , etc )
* @ fcall : pointer to response fcall
*
*/
int
2006-03-25 14:07:26 +03:00
v9fs_t_create ( struct v9fs_session_info * v9ses , u32 fid , char * name , u32 perm ,
u8 mode , char * extension , struct v9fs_fcall * * rcp )
2005-09-10 00:04:21 +04:00
{
2006-01-08 12:05:00 +03:00
int ret ;
struct v9fs_fcall * tc ;
2005-09-10 00:04:21 +04:00
dprintk ( DEBUG_9P , " fid %d name '%s' perm %x mode %d \n " ,
fid , name , perm , mode ) ;
2006-03-25 14:07:26 +03:00
tc = v9fs_create_tcreate ( fid , name , perm , mode , extension ,
v9ses - > extended ) ;
2006-01-08 12:05:00 +03:00
if ( ! IS_ERR ( tc ) ) {
ret = v9fs_mux_rpc ( v9ses - > mux , tc , rcp ) ;
kfree ( tc ) ;
} else
ret = PTR_ERR ( tc ) ;
2005-09-10 00:04:21 +04:00
2006-01-08 12:05:00 +03:00
return ret ;
2005-09-10 00:04:21 +04:00
}
/**
* v9fs_t_read - read data
* @ v9ses : 9 P2000 session information
* @ fid : fid to read from
* @ offset : offset to start read at
* @ count : how many bytes to read
* @ fcall : pointer to response fcall ( with data )
*
*/
int
v9fs_t_read ( struct v9fs_session_info * v9ses , u32 fid , u64 offset ,
2006-01-08 12:05:00 +03:00
u32 count , struct v9fs_fcall * * rcp )
2005-09-10 00:04:21 +04:00
{
2006-01-08 12:05:00 +03:00
int ret ;
struct v9fs_fcall * tc , * rc ;
2005-09-10 00:04:21 +04:00
2006-01-08 12:05:00 +03:00
dprintk ( DEBUG_9P , " fid %d offset 0x%llux count 0x%x \n " , fid ,
( long long unsigned ) offset , count ) ;
tc = v9fs_create_tread ( fid , offset , count ) ;
if ( ! IS_ERR ( tc ) ) {
ret = v9fs_mux_rpc ( v9ses - > mux , tc , & rc ) ;
if ( ! ret )
ret = rc - > params . rread . count ;
if ( rcp )
* rcp = rc ;
else
kfree ( rc ) ;
kfree ( tc ) ;
} else
ret = PTR_ERR ( tc ) ;
return ret ;
2005-09-10 00:04:21 +04:00
}
/**
* v9fs_t_write - write data
* @ v9ses : 9 P2000 session information
* @ fid : fid to write to
* @ offset : offset to start write at
* @ count : how many bytes to write
* @ fcall : pointer to response fcall
*
*/
int
2006-01-08 12:05:00 +03:00
v9fs_t_write ( struct v9fs_session_info * v9ses , u32 fid , u64 offset , u32 count ,
const char __user * data , struct v9fs_fcall * * rcp )
2005-09-10 00:04:21 +04:00
{
2006-01-08 12:05:00 +03:00
int ret ;
struct v9fs_fcall * tc , * rc ;
2005-09-10 00:04:21 +04:00
2006-01-08 12:05:00 +03:00
dprintk ( DEBUG_9P , " fid %d offset 0x%llux count 0x%x \n " , fid ,
( long long unsigned ) offset , count ) ;
2005-09-10 00:04:21 +04:00
2006-01-08 12:05:00 +03:00
tc = v9fs_create_twrite ( fid , offset , count , data ) ;
if ( ! IS_ERR ( tc ) ) {
ret = v9fs_mux_rpc ( v9ses - > mux , tc , & rc ) ;
2005-09-10 00:04:21 +04:00
2006-01-08 12:05:00 +03:00
if ( ! ret )
ret = rc - > params . rwrite . count ;
if ( rcp )
* rcp = rc ;
else
kfree ( rc ) ;
2005-09-10 00:04:21 +04:00
2006-01-08 12:05:00 +03:00
kfree ( tc ) ;
} else
ret = PTR_ERR ( tc ) ;
2005-09-10 00:04:21 +04:00
2006-01-08 12:05:00 +03:00
return ret ;
2005-09-10 00:04:21 +04:00
}
2006-01-08 12:05:00 +03:00