2007-07-11 02:57:28 +04:00
/*
* net / 9 p / clnt . c
*
* 9 P Client
*
* Copyright ( C ) 2007 by Latchesar Ionkov < lucho @ ionkov . net >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation .
*
* 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>
# include <linux/idr.h>
# include <linux/mutex.h>
# include <linux/sched.h>
# include <linux/uaccess.h>
# include <net/9p/9p.h>
2007-10-17 23:31:07 +04:00
# include <linux/parser.h>
2007-07-11 02:57:28 +04:00
# include <net/9p/transport.h>
# include <net/9p/conn.h>
# include <net/9p/client.h>
static struct p9_fid * p9_fid_create ( struct p9_client * clnt ) ;
static void p9_fid_destroy ( struct p9_fid * fid ) ;
static struct p9_stat * p9_clone_stat ( struct p9_stat * st , int dotu ) ;
2007-10-17 23:31:07 +04:00
struct p9_client * p9_client_create ( struct p9_trans * trans , int msize ,
2007-07-11 02:57:28 +04:00
int dotu )
{
int err , n ;
struct p9_client * clnt ;
struct p9_fcall * tc , * rc ;
struct p9_str * version ;
err = 0 ;
tc = NULL ;
rc = NULL ;
clnt = kmalloc ( sizeof ( struct p9_client ) , GFP_KERNEL ) ;
if ( ! clnt )
return ERR_PTR ( - ENOMEM ) ;
P9_DPRINTK ( P9_DEBUG_9P , " clnt %p trans %p msize %d dotu %d \n " ,
clnt , trans , msize , dotu ) ;
spin_lock_init ( & clnt - > lock ) ;
clnt - > trans = trans ;
clnt - > msize = msize ;
clnt - > dotu = dotu ;
INIT_LIST_HEAD ( & clnt - > fidlist ) ;
clnt - > fidpool = p9_idpool_create ( ) ;
if ( ! clnt - > fidpool ) {
err = PTR_ERR ( clnt - > fidpool ) ;
clnt - > fidpool = NULL ;
goto error ;
}
clnt - > conn = p9_conn_create ( clnt - > trans , clnt - > msize , & clnt - > dotu ) ;
if ( IS_ERR ( clnt - > conn ) ) {
err = PTR_ERR ( clnt - > conn ) ;
clnt - > conn = NULL ;
goto error ;
}
tc = p9_create_tversion ( clnt - > msize , clnt - > dotu ? " 9P2000.u " : " 9P2000 " ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto error ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err )
goto error ;
version = & rc - > params . rversion . version ;
if ( version - > len = = 8 & & ! memcmp ( version - > str , " 9P2000.u " , 8 ) )
clnt - > dotu = 1 ;
else if ( version - > len = = 6 & & ! memcmp ( version - > str , " 9P2000 " , 6 ) )
clnt - > dotu = 0 ;
else {
err = - EREMOTEIO ;
goto error ;
}
n = rc - > params . rversion . msize ;
if ( n < clnt - > msize )
clnt - > msize = n ;
kfree ( tc ) ;
kfree ( rc ) ;
return clnt ;
error :
kfree ( tc ) ;
kfree ( rc ) ;
p9_client_destroy ( clnt ) ;
return ERR_PTR ( err ) ;
}
EXPORT_SYMBOL ( p9_client_create ) ;
void p9_client_destroy ( struct p9_client * clnt )
{
struct p9_fid * fid , * fidptr ;
P9_DPRINTK ( P9_DEBUG_9P , " clnt %p \n " , clnt ) ;
if ( clnt - > conn ) {
p9_conn_destroy ( clnt - > conn ) ;
clnt - > conn = NULL ;
}
if ( clnt - > trans ) {
clnt - > trans - > close ( clnt - > trans ) ;
kfree ( clnt - > trans ) ;
clnt - > trans = NULL ;
}
list_for_each_entry_safe ( fid , fidptr , & clnt - > fidlist , flist )
p9_fid_destroy ( fid ) ;
2007-07-14 01:47:58 +04:00
if ( clnt - > fidpool )
p9_idpool_destroy ( clnt - > fidpool ) ;
2007-07-11 02:57:28 +04:00
kfree ( clnt ) ;
}
EXPORT_SYMBOL ( p9_client_destroy ) ;
void p9_client_disconnect ( struct p9_client * clnt )
{
P9_DPRINTK ( P9_DEBUG_9P , " clnt %p \n " , clnt ) ;
clnt - > trans - > status = Disconnected ;
p9_conn_cancel ( clnt - > conn , - EIO ) ;
}
EXPORT_SYMBOL ( p9_client_disconnect ) ;
struct p9_fid * p9_client_attach ( struct p9_client * clnt , struct p9_fid * afid ,
2007-10-17 23:31:07 +04:00
char * uname , u32 n_uname , char * aname )
2007-07-11 02:57:28 +04:00
{
int err ;
struct p9_fcall * tc , * rc ;
struct p9_fid * fid ;
P9_DPRINTK ( P9_DEBUG_9P , " clnt %p afid %d uname %s aname %s \n " ,
clnt , afid ? afid - > fid : - 1 , uname , aname ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
fid = p9_fid_create ( clnt ) ;
if ( IS_ERR ( fid ) ) {
err = PTR_ERR ( fid ) ;
fid = NULL ;
goto error ;
}
2007-10-17 23:31:07 +04:00
tc = p9_create_tattach ( fid - > fid , afid ? afid - > fid : P9_NOFID , uname , aname ,
n_uname , clnt - > dotu ) ;
2007-07-11 02:57:28 +04:00
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto error ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err )
goto error ;
memmove ( & fid - > qid , & rc - > params . rattach . qid , sizeof ( struct p9_qid ) ) ;
kfree ( tc ) ;
kfree ( rc ) ;
return fid ;
error :
kfree ( tc ) ;
kfree ( rc ) ;
if ( fid )
p9_fid_destroy ( fid ) ;
return ERR_PTR ( err ) ;
}
EXPORT_SYMBOL ( p9_client_attach ) ;
2007-10-17 23:31:07 +04:00
struct p9_fid * p9_client_auth ( struct p9_client * clnt , char * uname ,
u32 n_uname , char * aname )
2007-07-11 02:57:28 +04:00
{
int err ;
struct p9_fcall * tc , * rc ;
struct p9_fid * fid ;
P9_DPRINTK ( P9_DEBUG_9P , " clnt %p uname %s aname %s \n " , clnt , uname ,
aname ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
fid = p9_fid_create ( clnt ) ;
if ( IS_ERR ( fid ) ) {
err = PTR_ERR ( fid ) ;
fid = NULL ;
goto error ;
}
2007-10-17 23:31:07 +04:00
tc = p9_create_tauth ( fid - > fid , uname , aname , n_uname , clnt - > dotu ) ;
2007-07-11 02:57:28 +04:00
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto error ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err )
goto error ;
memmove ( & fid - > qid , & rc - > params . rauth . qid , sizeof ( struct p9_qid ) ) ;
kfree ( tc ) ;
kfree ( rc ) ;
return fid ;
error :
kfree ( tc ) ;
kfree ( rc ) ;
if ( fid )
p9_fid_destroy ( fid ) ;
return ERR_PTR ( err ) ;
}
EXPORT_SYMBOL ( p9_client_auth ) ;
struct p9_fid * p9_client_walk ( struct p9_fid * oldfid , int nwname , char * * wnames ,
int clone )
{
int err ;
struct p9_fcall * tc , * rc ;
struct p9_client * clnt ;
struct p9_fid * fid ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d nwname %d wname[0] %s \n " ,
oldfid - > fid , nwname , wnames ? wnames [ 0 ] : NULL ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
clnt = oldfid - > clnt ;
if ( clone ) {
fid = p9_fid_create ( clnt ) ;
if ( IS_ERR ( fid ) ) {
err = PTR_ERR ( fid ) ;
fid = NULL ;
goto error ;
}
fid - > uid = oldfid - > uid ;
} else
fid = oldfid ;
tc = p9_create_twalk ( oldfid - > fid , fid - > fid , nwname , wnames ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto error ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err ) {
if ( rc & & rc - > id = = P9_RWALK )
goto clunk_fid ;
else
goto error ;
}
if ( rc - > params . rwalk . nwqid ! = nwname ) {
err = - ENOENT ;
goto clunk_fid ;
}
if ( nwname )
memmove ( & fid - > qid ,
& rc - > params . rwalk . wqids [ rc - > params . rwalk . nwqid - 1 ] ,
sizeof ( struct p9_qid ) ) ;
else
fid - > qid = oldfid - > qid ;
kfree ( tc ) ;
kfree ( rc ) ;
return fid ;
clunk_fid :
kfree ( tc ) ;
kfree ( rc ) ;
rc = NULL ;
tc = p9_create_tclunk ( fid - > fid ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto error ;
}
p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
error :
kfree ( tc ) ;
kfree ( rc ) ;
if ( fid & & ( fid ! = oldfid ) )
p9_fid_destroy ( fid ) ;
return ERR_PTR ( err ) ;
}
EXPORT_SYMBOL ( p9_client_walk ) ;
int p9_client_open ( struct p9_fid * fid , int mode )
{
int err ;
struct p9_fcall * tc , * rc ;
struct p9_client * clnt ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d mode %d \n " , fid - > fid , mode ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
clnt = fid - > clnt ;
if ( fid - > mode ! = - 1 )
return - EINVAL ;
tc = p9_create_topen ( fid - > fid , mode ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto done ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err )
goto done ;
fid - > mode = mode ;
fid - > iounit = rc - > params . ropen . iounit ;
done :
kfree ( tc ) ;
kfree ( rc ) ;
return err ;
}
EXPORT_SYMBOL ( p9_client_open ) ;
int p9_client_fcreate ( struct p9_fid * fid , char * name , u32 perm , int mode ,
char * extension )
{
int err ;
struct p9_fcall * tc , * rc ;
struct p9_client * clnt ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d name %s perm %d mode %d \n " , fid - > fid ,
name , perm , mode ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
clnt = fid - > clnt ;
if ( fid - > mode ! = - 1 )
return - EINVAL ;
tc = p9_create_tcreate ( fid - > fid , name , perm , mode , extension ,
clnt - > dotu ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto done ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err )
goto done ;
fid - > mode = mode ;
fid - > iounit = rc - > params . ropen . iounit ;
done :
kfree ( tc ) ;
kfree ( rc ) ;
return err ;
}
EXPORT_SYMBOL ( p9_client_fcreate ) ;
int p9_client_clunk ( struct p9_fid * fid )
{
int err ;
struct p9_fcall * tc , * rc ;
struct p9_client * clnt ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d \n " , fid - > fid ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
clnt = fid - > clnt ;
tc = p9_create_tclunk ( fid - > fid ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto done ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err )
goto done ;
p9_fid_destroy ( fid ) ;
done :
kfree ( tc ) ;
kfree ( rc ) ;
return err ;
}
EXPORT_SYMBOL ( p9_client_clunk ) ;
int p9_client_remove ( struct p9_fid * fid )
{
int err ;
struct p9_fcall * tc , * rc ;
struct p9_client * clnt ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d \n " , fid - > fid ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
clnt = fid - > clnt ;
tc = p9_create_tremove ( fid - > fid ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto done ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err )
goto done ;
p9_fid_destroy ( fid ) ;
done :
kfree ( tc ) ;
kfree ( rc ) ;
return err ;
}
EXPORT_SYMBOL ( p9_client_remove ) ;
int p9_client_read ( struct p9_fid * fid , char * data , u64 offset , u32 count )
{
int err , n , rsize , total ;
struct p9_fcall * tc , * rc ;
struct p9_client * clnt ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d offset %llu %d \n " , fid - > fid ,
( long long unsigned ) offset , count ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
clnt = fid - > clnt ;
total = 0 ;
rsize = fid - > iounit ;
if ( ! rsize | | rsize > clnt - > msize - P9_IOHDRSZ )
rsize = clnt - > msize - P9_IOHDRSZ ;
do {
if ( count < rsize )
rsize = count ;
tc = p9_create_tread ( fid - > fid , offset , rsize ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto error ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err )
goto error ;
n = rc - > params . rread . count ;
if ( n > count )
n = count ;
memmove ( data , rc - > params . rread . data , n ) ;
count - = n ;
data + = n ;
offset + = n ;
total + = n ;
kfree ( tc ) ;
tc = NULL ;
kfree ( rc ) ;
rc = NULL ;
} while ( count > 0 & & n = = rsize ) ;
return total ;
error :
kfree ( tc ) ;
kfree ( rc ) ;
return err ;
}
EXPORT_SYMBOL ( p9_client_read ) ;
int p9_client_write ( struct p9_fid * fid , char * data , u64 offset , u32 count )
{
int err , n , rsize , total ;
struct p9_fcall * tc , * rc ;
struct p9_client * clnt ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d offset %llu count %d \n " , fid - > fid ,
( long long unsigned ) offset , count ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
clnt = fid - > clnt ;
total = 0 ;
rsize = fid - > iounit ;
if ( ! rsize | | rsize > clnt - > msize - P9_IOHDRSZ )
rsize = clnt - > msize - P9_IOHDRSZ ;
do {
if ( count < rsize )
rsize = count ;
tc = p9_create_twrite ( fid - > fid , offset , rsize , data ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto error ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err )
goto error ;
n = rc - > params . rread . count ;
count - = n ;
data + = n ;
offset + = n ;
total + = n ;
kfree ( tc ) ;
tc = NULL ;
kfree ( rc ) ;
rc = NULL ;
} while ( count > 0 ) ;
return total ;
error :
kfree ( tc ) ;
kfree ( rc ) ;
return err ;
}
EXPORT_SYMBOL ( p9_client_write ) ;
int
p9_client_uread ( struct p9_fid * fid , char __user * data , u64 offset , u32 count )
{
int err , n , rsize , total ;
struct p9_fcall * tc , * rc ;
struct p9_client * clnt ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d offset %llu count %d \n " , fid - > fid ,
( long long unsigned ) offset , count ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
clnt = fid - > clnt ;
total = 0 ;
rsize = fid - > iounit ;
if ( ! rsize | | rsize > clnt - > msize - P9_IOHDRSZ )
rsize = clnt - > msize - P9_IOHDRSZ ;
do {
if ( count < rsize )
rsize = count ;
tc = p9_create_tread ( fid - > fid , offset , rsize ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto error ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err )
goto error ;
n = rc - > params . rread . count ;
if ( n > count )
n = count ;
err = copy_to_user ( data , rc - > params . rread . data , n ) ;
if ( err ) {
err = - EFAULT ;
goto error ;
}
count - = n ;
data + = n ;
offset + = n ;
total + = n ;
kfree ( tc ) ;
tc = NULL ;
kfree ( rc ) ;
rc = NULL ;
} while ( count > 0 & & n = = rsize ) ;
return total ;
error :
kfree ( tc ) ;
kfree ( rc ) ;
return err ;
}
EXPORT_SYMBOL ( p9_client_uread ) ;
int
p9_client_uwrite ( struct p9_fid * fid , const char __user * data , u64 offset ,
u32 count )
{
int err , n , rsize , total ;
struct p9_fcall * tc , * rc ;
struct p9_client * clnt ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d offset %llu count %d \n " , fid - > fid ,
( long long unsigned ) offset , count ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
clnt = fid - > clnt ;
total = 0 ;
rsize = fid - > iounit ;
if ( ! rsize | | rsize > clnt - > msize - P9_IOHDRSZ )
rsize = clnt - > msize - P9_IOHDRSZ ;
do {
if ( count < rsize )
rsize = count ;
tc = p9_create_twrite_u ( fid - > fid , offset , rsize , data ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto error ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err )
goto error ;
n = rc - > params . rread . count ;
count - = n ;
data + = n ;
offset + = n ;
total + = n ;
kfree ( tc ) ;
tc = NULL ;
kfree ( rc ) ;
rc = NULL ;
} while ( count > 0 ) ;
return total ;
error :
kfree ( tc ) ;
kfree ( rc ) ;
return err ;
}
EXPORT_SYMBOL ( p9_client_uwrite ) ;
int p9_client_readn ( struct p9_fid * fid , char * data , u64 offset , u32 count )
{
int n , total ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d offset %llu count %d \n " , fid - > fid ,
( long long unsigned ) offset , count ) ;
n = 0 ;
total = 0 ;
while ( count ) {
n = p9_client_read ( fid , data , offset , count ) ;
if ( n < = 0 )
break ;
data + = n ;
offset + = n ;
count - = n ;
total + = n ;
}
if ( n < 0 )
total = n ;
return total ;
}
EXPORT_SYMBOL ( p9_client_readn ) ;
struct p9_stat * p9_client_stat ( struct p9_fid * fid )
{
int err ;
struct p9_fcall * tc , * rc ;
struct p9_client * clnt ;
struct p9_stat * ret ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d \n " , fid - > fid ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
ret = NULL ;
clnt = fid - > clnt ;
tc = p9_create_tstat ( fid - > fid ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto error ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err )
goto error ;
ret = p9_clone_stat ( & rc - > params . rstat . stat , clnt - > dotu ) ;
if ( IS_ERR ( ret ) ) {
err = PTR_ERR ( ret ) ;
ret = NULL ;
goto error ;
}
kfree ( tc ) ;
kfree ( rc ) ;
return ret ;
error :
kfree ( tc ) ;
kfree ( rc ) ;
kfree ( ret ) ;
return ERR_PTR ( err ) ;
}
EXPORT_SYMBOL ( p9_client_stat ) ;
int p9_client_wstat ( struct p9_fid * fid , struct p9_wstat * wst )
{
int err ;
struct p9_fcall * tc , * rc ;
struct p9_client * clnt ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d \n " , fid - > fid ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
clnt = fid - > clnt ;
tc = p9_create_twstat ( fid - > fid , wst , clnt - > dotu ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto done ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
done :
kfree ( tc ) ;
kfree ( rc ) ;
return err ;
}
EXPORT_SYMBOL ( p9_client_wstat ) ;
struct p9_stat * p9_client_dirread ( struct p9_fid * fid , u64 offset )
{
int err , n , m ;
struct p9_fcall * tc , * rc ;
struct p9_client * clnt ;
struct p9_stat st , * ret ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d offset %llu \n " , fid - > fid ,
( long long unsigned ) offset ) ;
err = 0 ;
tc = NULL ;
rc = NULL ;
ret = NULL ;
clnt = fid - > clnt ;
/* if the offset is below or above the current response, free it */
if ( offset < fid - > rdir_fpos | | ( fid - > rdir_fcall & &
offset > = fid - > rdir_fpos + fid - > rdir_fcall - > params . rread . count ) ) {
fid - > rdir_pos = 0 ;
if ( fid - > rdir_fcall )
fid - > rdir_fpos + = fid - > rdir_fcall - > params . rread . count ;
kfree ( fid - > rdir_fcall ) ;
fid - > rdir_fcall = NULL ;
if ( offset < fid - > rdir_fpos )
fid - > rdir_fpos = 0 ;
}
if ( ! fid - > rdir_fcall ) {
n = fid - > iounit ;
if ( ! n | | n > clnt - > msize - P9_IOHDRSZ )
n = clnt - > msize - P9_IOHDRSZ ;
while ( 1 ) {
if ( fid - > rdir_fcall ) {
fid - > rdir_fpos + =
fid - > rdir_fcall - > params . rread . count ;
kfree ( fid - > rdir_fcall ) ;
fid - > rdir_fcall = NULL ;
}
tc = p9_create_tread ( fid - > fid , fid - > rdir_fpos , n ) ;
if ( IS_ERR ( tc ) ) {
err = PTR_ERR ( tc ) ;
tc = NULL ;
goto error ;
}
err = p9_conn_rpc ( clnt - > conn , tc , & rc ) ;
if ( err )
goto error ;
n = rc - > params . rread . count ;
if ( n = = 0 )
goto done ;
fid - > rdir_fcall = rc ;
rc = NULL ;
if ( offset > = fid - > rdir_fpos & &
offset < fid - > rdir_fpos + n )
break ;
}
fid - > rdir_pos = 0 ;
}
m = offset - fid - > rdir_fpos ;
if ( m < 0 )
goto done ;
n = p9_deserialize_stat ( fid - > rdir_fcall - > params . rread . data + m ,
fid - > rdir_fcall - > params . rread . count - m , & st , clnt - > dotu ) ;
if ( ! n ) {
err = - EIO ;
goto error ;
}
fid - > rdir_pos + = n ;
st . size = n ;
ret = p9_clone_stat ( & st , clnt - > dotu ) ;
if ( IS_ERR ( ret ) ) {
err = PTR_ERR ( ret ) ;
ret = NULL ;
goto error ;
}
done :
kfree ( tc ) ;
kfree ( rc ) ;
return ret ;
error :
kfree ( tc ) ;
kfree ( rc ) ;
kfree ( ret ) ;
return ERR_PTR ( err ) ;
}
EXPORT_SYMBOL ( p9_client_dirread ) ;
static struct p9_stat * p9_clone_stat ( struct p9_stat * st , int dotu )
{
int n ;
char * p ;
struct p9_stat * ret ;
n = sizeof ( struct p9_stat ) + st - > name . len + st - > uid . len + st - > gid . len +
st - > muid . len ;
if ( dotu )
n + = st - > extension . len ;
ret = kmalloc ( n , GFP_KERNEL ) ;
if ( ! ret )
return ERR_PTR ( - ENOMEM ) ;
memmove ( ret , st , sizeof ( struct p9_stat ) ) ;
p = ( ( char * ) ret ) + sizeof ( struct p9_stat ) ;
memmove ( p , st - > name . str , st - > name . len ) ;
2008-02-05 18:27:09 +03:00
ret - > name . str = p ;
2007-07-11 02:57:28 +04:00
p + = st - > name . len ;
memmove ( p , st - > uid . str , st - > uid . len ) ;
2008-02-05 18:27:09 +03:00
ret - > uid . str = p ;
2007-07-11 02:57:28 +04:00
p + = st - > uid . len ;
memmove ( p , st - > gid . str , st - > gid . len ) ;
2008-02-05 18:27:09 +03:00
ret - > gid . str = p ;
2007-07-11 02:57:28 +04:00
p + = st - > gid . len ;
memmove ( p , st - > muid . str , st - > muid . len ) ;
2008-02-05 18:27:09 +03:00
ret - > muid . str = p ;
2007-07-11 02:57:28 +04:00
p + = st - > muid . len ;
if ( dotu ) {
memmove ( p , st - > extension . str , st - > extension . len ) ;
2008-02-05 18:27:09 +03:00
ret - > extension . str = p ;
2007-07-11 02:57:28 +04:00
p + = st - > extension . len ;
}
return ret ;
}
static struct p9_fid * p9_fid_create ( struct p9_client * clnt )
{
int err ;
struct p9_fid * fid ;
P9_DPRINTK ( P9_DEBUG_9P , " clnt %p \n " , clnt ) ;
fid = kmalloc ( sizeof ( struct p9_fid ) , GFP_KERNEL ) ;
if ( ! fid )
return ERR_PTR ( - ENOMEM ) ;
fid - > fid = p9_idpool_get ( clnt - > fidpool ) ;
if ( fid - > fid < 0 ) {
err = - ENOSPC ;
goto error ;
}
memset ( & fid - > qid , 0 , sizeof ( struct p9_qid ) ) ;
fid - > mode = - 1 ;
fid - > rdir_fpos = 0 ;
fid - > rdir_pos = 0 ;
fid - > rdir_fcall = NULL ;
fid - > uid = current - > fsuid ;
fid - > clnt = clnt ;
fid - > aux = NULL ;
spin_lock ( & clnt - > lock ) ;
list_add ( & fid - > flist , & clnt - > fidlist ) ;
spin_unlock ( & clnt - > lock ) ;
return fid ;
error :
kfree ( fid ) ;
return ERR_PTR ( err ) ;
}
static void p9_fid_destroy ( struct p9_fid * fid )
{
struct p9_client * clnt ;
P9_DPRINTK ( P9_DEBUG_9P , " fid %d \n " , fid - > fid ) ;
clnt = fid - > clnt ;
p9_idpool_put ( fid - > fid , clnt - > fidpool ) ;
spin_lock ( & clnt - > lock ) ;
list_del ( & fid - > flist ) ;
spin_unlock ( & clnt - > lock ) ;
kfree ( fid - > rdir_fcall ) ;
kfree ( fid ) ;
}