2005-04-17 02:20:36 +04:00
/*
* linux / fs / nfs / nfs2xdr . c
*
* XDR functions to encode / decode NFS RPC arguments and results .
*
* Copyright ( C ) 1992 , 1993 , 1994 Rick Sladkey
* Copyright ( C ) 1996 Olaf Kirch
* 04 Aug 1998 Ion Badulescu < ionut @ cs . columbia . edu >
* FIFO ' s need special handling in NFSv2
*/
# include <linux/param.h>
# include <linux/time.h>
# include <linux/mm.h>
# include <linux/errno.h>
# include <linux/string.h>
# include <linux/in.h>
# include <linux/pagemap.h>
# include <linux/proc_fs.h>
# include <linux/sunrpc/clnt.h>
# include <linux/nfs.h>
# include <linux/nfs2.h>
# include <linux/nfs_fs.h>
2006-06-24 16:41:41 +04:00
# include "internal.h"
2005-04-17 02:20:36 +04:00
# define NFSDBG_FACILITY NFSDBG_XDR
/* Mapping from NFS error code to "errno" error code. */
# define errno_NFSERR_IO EIO
/*
* Declare the space requirements for NFS arguments and replies as
* number of 32 bit - words
*/
# define NFS_fhandle_sz (8)
# define NFS_sattr_sz (8)
# define NFS_filename_sz (1+(NFS2_MAXNAMLEN>>2))
# define NFS_path_sz (1+(NFS2_MAXPATHLEN>>2))
# define NFS_fattr_sz (17)
# define NFS_info_sz (5)
# define NFS_entry_sz (NFS_filename_sz+3)
# define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz)
2007-07-14 23:39:57 +04:00
# define NFS_removeargs_sz (NFS_fhandle_sz+NFS_filename_sz)
2005-04-17 02:20:36 +04:00
# define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz)
# define NFS_readlinkargs_sz (NFS_fhandle_sz)
# define NFS_readargs_sz (NFS_fhandle_sz+3)
# define NFS_writeargs_sz (NFS_fhandle_sz+4)
# define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz)
# define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz)
# define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz)
2006-08-23 04:06:23 +04:00
# define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz)
2005-04-17 02:20:36 +04:00
# define NFS_readdirargs_sz (NFS_fhandle_sz+2)
# define NFS_attrstat_sz (1+NFS_fattr_sz)
# define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz)
# define NFS_readlinkres_sz (2)
# define NFS_readres_sz (1+NFS_fattr_sz+1)
# define NFS_writeres_sz (NFS_attrstat_sz)
# define NFS_stat_sz (1)
# define NFS_readdirres_sz (1)
# define NFS_statfsres_sz (1+NFS_info_sz)
2012-05-11 00:47:18 +04:00
static int nfs_stat_to_errno ( enum nfs_stat ) ;
2010-12-14 17:54:30 +03:00
/*
* While encoding arguments , set up the reply buffer in advance to
* receive reply data directly into the page cache .
*/
static void prepare_reply_buffer ( struct rpc_rqst * req , struct page * * pages ,
unsigned int base , unsigned int len ,
unsigned int bufsize )
{
struct rpc_auth * auth = req - > rq_cred - > cr_auth ;
unsigned int replen ;
replen = RPC_REPHDRSIZE + auth - > au_rslack + bufsize ;
xdr_inline_pages ( & req - > rq_rcv_buf , replen < < 2 , pages , base , len ) ;
}
2010-12-14 17:55:10 +03:00
/*
* Handle decode buffer overflows out - of - line .
*/
static void print_overflow_msg ( const char * func , const struct xdr_stream * xdr )
{
dprintk ( " NFS: %s prematurely hit the end of our receive buffer. "
" Remaining buffer length is %tu words. \n " ,
func , xdr - > end - xdr - > p ) ;
}
2010-12-14 17:54:30 +03:00
/*
* Encode / decode NFSv2 basic data types
*
* Basic NFSv2 data types are defined in section 2.3 of RFC 1094 :
* " NFS: Network File System Protocol Specification " .
*
* Not all basic data types have their own encoding and decoding
* functions . For run - time efficiency , some data types are encoded
* or decoded inline .
*/
2010-12-14 17:55:10 +03:00
/*
* typedef opaque nfsdata < > ;
*/
2014-05-06 17:12:25 +04:00
static int decode_nfsdata ( struct xdr_stream * xdr , struct nfs_pgio_res * result )
2010-12-14 17:55:10 +03:00
{
u32 recvd , count ;
__be32 * p ;
p = xdr_inline_decode ( xdr , 4 ) ;
if ( unlikely ( p = = NULL ) )
goto out_overflow ;
count = be32_to_cpup ( p ) ;
2012-06-21 06:35:05 +04:00
recvd = xdr_read_pages ( xdr , count ) ;
2010-12-14 17:55:10 +03:00
if ( unlikely ( count > recvd ) )
goto out_cheating ;
out :
result - > eof = 0 ; /* NFSv2 does not pass EOF flag on the wire. */
result - > count = count ;
return count ;
out_cheating :
dprintk ( " NFS: server cheating in read result: "
" count %u > recvd %u \n " , count , recvd ) ;
count = recvd ;
goto out ;
out_overflow :
print_overflow_msg ( __func__ , xdr ) ;
return - EIO ;
}
/*
* enum stat {
* NFS_OK = 0 ,
* NFSERR_PERM = 1 ,
* NFSERR_NOENT = 2 ,
* NFSERR_IO = 5 ,
* NFSERR_NXIO = 6 ,
* NFSERR_ACCES = 13 ,
* NFSERR_EXIST = 17 ,
* NFSERR_NODEV = 19 ,
* NFSERR_NOTDIR = 20 ,
* NFSERR_ISDIR = 21 ,
* NFSERR_FBIG = 27 ,
* NFSERR_NOSPC = 28 ,
* NFSERR_ROFS = 30 ,
* NFSERR_NAMETOOLONG = 63 ,
* NFSERR_NOTEMPTY = 66 ,
* NFSERR_DQUOT = 69 ,
* NFSERR_STALE = 70 ,
* NFSERR_WFLUSH = 99
* } ;
*/
static int decode_stat ( struct xdr_stream * xdr , enum nfs_stat * status )
{
__be32 * p ;
p = xdr_inline_decode ( xdr , 4 ) ;
if ( unlikely ( p = = NULL ) )
goto out_overflow ;
* status = be32_to_cpup ( p ) ;
return 0 ;
out_overflow :
print_overflow_msg ( __func__ , xdr ) ;
return - EIO ;
}
2010-12-14 17:55:30 +03:00
/*
* 2.3 .2 . ftype
*
* enum ftype {
* NFNON = 0 ,
* NFREG = 1 ,
* NFDIR = 2 ,
* NFBLK = 3 ,
* NFCHR = 4 ,
* NFLNK = 5
* } ;
*
*/
static __be32 * xdr_decode_ftype ( __be32 * p , u32 * type )
{
* type = be32_to_cpup ( p + + ) ;
if ( unlikely ( * type > NF2FIFO ) )
* type = NFBAD ;
return p ;
}
2010-12-14 17:54:30 +03:00
/*
* 2.3 .3 . fhandle
*
* typedef opaque fhandle [ FHSIZE ] ;
*/
static void encode_fhandle ( struct xdr_stream * xdr , const struct nfs_fh * fh )
{
__be32 * p ;
p = xdr_reserve_space ( xdr , NFS2_FHSIZE ) ;
memcpy ( p , fh - > data , NFS2_FHSIZE ) ;
}
2010-12-14 17:55:10 +03:00
static int decode_fhandle ( struct xdr_stream * xdr , struct nfs_fh * fh )
{
__be32 * p ;
p = xdr_inline_decode ( xdr , NFS2_FHSIZE ) ;
if ( unlikely ( p = = NULL ) )
goto out_overflow ;
fh - > size = NFS2_FHSIZE ;
memcpy ( fh - > data , p , NFS2_FHSIZE ) ;
return 0 ;
out_overflow :
print_overflow_msg ( __func__ , xdr ) ;
return - EIO ;
}
2010-12-14 17:54:50 +03:00
/*
* 2.3 .4 . timeval
*
* struct timeval {
* unsigned int seconds ;
* unsigned int useconds ;
* } ;
*/
static __be32 * xdr_encode_time ( __be32 * p , const struct timespec * timep )
{
* p + + = cpu_to_be32 ( timep - > tv_sec ) ;
if ( timep - > tv_nsec ! = 0 )
* p + + = cpu_to_be32 ( timep - > tv_nsec / NSEC_PER_USEC ) ;
else
* p + + = cpu_to_be32 ( 0 ) ;
return p ;
}
/*
* Passing the invalid value useconds = 1000000 is a Sun convention for
* " set to current server time " . It ' s needed to make permissions checks
* for the " touch " program across v2 mounts to Solaris and Irix servers
* work correctly . See description of sattr in section 6.1 of " NFS
* Illustrated " by Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5.
*/
static __be32 * xdr_encode_current_server_time ( __be32 * p ,
const struct timespec * timep )
{
* p + + = cpu_to_be32 ( timep - > tv_sec ) ;
* p + + = cpu_to_be32 ( 1000000 ) ;
return p ;
}
2010-12-14 17:55:30 +03:00
static __be32 * xdr_decode_time ( __be32 * p , struct timespec * timep )
{
timep - > tv_sec = be32_to_cpup ( p + + ) ;
timep - > tv_nsec = be32_to_cpup ( p + + ) * NSEC_PER_USEC ;
return p ;
}
2010-12-14 17:55:10 +03:00
/*
* 2.3 .5 . fattr
*
* struct fattr {
* ftype type ;
* unsigned int mode ;
* unsigned int nlink ;
* unsigned int uid ;
* unsigned int gid ;
* unsigned int size ;
* unsigned int blocksize ;
* unsigned int rdev ;
* unsigned int blocks ;
* unsigned int fsid ;
* unsigned int fileid ;
* timeval atime ;
* timeval mtime ;
* timeval ctime ;
* } ;
*
*/
static int decode_fattr ( struct xdr_stream * xdr , struct nfs_fattr * fattr )
{
2010-12-14 17:55:30 +03:00
u32 rdev , type ;
2010-12-14 17:55:10 +03:00
__be32 * p ;
p = xdr_inline_decode ( xdr , NFS_fattr_sz < < 2 ) ;
if ( unlikely ( p = = NULL ) )
goto out_overflow ;
2010-12-14 17:55:30 +03:00
fattr - > valid | = NFS_ATTR_FATTR_V2 ;
p = xdr_decode_ftype ( p , & type ) ;
fattr - > mode = be32_to_cpup ( p + + ) ;
fattr - > nlink = be32_to_cpup ( p + + ) ;
2013-02-01 15:45:54 +04:00
fattr - > uid = make_kuid ( & init_user_ns , be32_to_cpup ( p + + ) ) ;
if ( ! uid_valid ( fattr - > uid ) )
goto out_uid ;
fattr - > gid = make_kgid ( & init_user_ns , be32_to_cpup ( p + + ) ) ;
if ( ! gid_valid ( fattr - > gid ) )
goto out_gid ;
2010-12-14 17:55:30 +03:00
fattr - > size = be32_to_cpup ( p + + ) ;
fattr - > du . nfs2 . blocksize = be32_to_cpup ( p + + ) ;
rdev = be32_to_cpup ( p + + ) ;
fattr - > rdev = new_decode_dev ( rdev ) ;
if ( type = = ( u32 ) NFCHR & & rdev = = ( u32 ) NFS2_FIFO_DEV ) {
fattr - > mode = ( fattr - > mode & ~ S_IFMT ) | S_IFIFO ;
fattr - > rdev = 0 ;
}
fattr - > du . nfs2 . blocks = be32_to_cpup ( p + + ) ;
fattr - > fsid . major = be32_to_cpup ( p + + ) ;
fattr - > fsid . minor = 0 ;
fattr - > fileid = be32_to_cpup ( p + + ) ;
p = xdr_decode_time ( p , & fattr - > atime ) ;
p = xdr_decode_time ( p , & fattr - > mtime ) ;
xdr_decode_time ( p , & fattr - > ctime ) ;
2012-04-27 21:48:18 +04:00
fattr - > change_attr = nfs_timespec_to_change_attr ( & fattr - > ctime ) ;
2010-12-14 17:55:10 +03:00
return 0 ;
2013-02-01 15:45:54 +04:00
out_uid :
dprintk ( " NFS: returned invalid uid \n " ) ;
return - EINVAL ;
out_gid :
dprintk ( " NFS: returned invalid gid \n " ) ;
return - EINVAL ;
2010-12-14 17:55:10 +03:00
out_overflow :
print_overflow_msg ( __func__ , xdr ) ;
return - EIO ;
}
2010-12-14 17:54:30 +03:00
/*
* 2.3 .6 . sattr
*
* struct sattr {
* unsigned int mode ;
* unsigned int uid ;
* unsigned int gid ;
* unsigned int size ;
* timeval atime ;
* timeval mtime ;
* } ;
*/
# define NFS2_SATTR_NOT_SET (0xffffffff)
static __be32 * xdr_time_not_set ( __be32 * p )
{
* p + + = cpu_to_be32 ( NFS2_SATTR_NOT_SET ) ;
* p + + = cpu_to_be32 ( NFS2_SATTR_NOT_SET ) ;
return p ;
}
static void encode_sattr ( struct xdr_stream * xdr , const struct iattr * attr )
{
__be32 * p ;
p = xdr_reserve_space ( xdr , NFS_sattr_sz < < 2 ) ;
if ( attr - > ia_valid & ATTR_MODE )
* p + + = cpu_to_be32 ( attr - > ia_mode ) ;
else
* p + + = cpu_to_be32 ( NFS2_SATTR_NOT_SET ) ;
if ( attr - > ia_valid & ATTR_UID )
2013-02-01 15:45:54 +04:00
* p + + = cpu_to_be32 ( from_kuid ( & init_user_ns , attr - > ia_uid ) ) ;
2010-12-14 17:54:30 +03:00
else
* p + + = cpu_to_be32 ( NFS2_SATTR_NOT_SET ) ;
if ( attr - > ia_valid & ATTR_GID )
2013-02-01 15:45:54 +04:00
* p + + = cpu_to_be32 ( from_kgid ( & init_user_ns , attr - > ia_gid ) ) ;
2010-12-14 17:54:30 +03:00
else
* p + + = cpu_to_be32 ( NFS2_SATTR_NOT_SET ) ;
if ( attr - > ia_valid & ATTR_SIZE )
* p + + = cpu_to_be32 ( ( u32 ) attr - > ia_size ) ;
else
* p + + = cpu_to_be32 ( NFS2_SATTR_NOT_SET ) ;
if ( attr - > ia_valid & ATTR_ATIME_SET )
p = xdr_encode_time ( p , & attr - > ia_atime ) ;
else if ( attr - > ia_valid & ATTR_ATIME )
p = xdr_encode_current_server_time ( p , & attr - > ia_atime ) ;
else
p = xdr_time_not_set ( p ) ;
if ( attr - > ia_valid & ATTR_MTIME_SET )
xdr_encode_time ( p , & attr - > ia_mtime ) ;
else if ( attr - > ia_valid & ATTR_MTIME )
xdr_encode_current_server_time ( p , & attr - > ia_mtime ) ;
else
xdr_time_not_set ( p ) ;
}
/*
* 2.3 .7 . filename
*
* typedef string filename < MAXNAMLEN > ;
*/
static void encode_filename ( struct xdr_stream * xdr ,
const char * name , u32 length )
{
__be32 * p ;
2012-10-15 19:51:21 +04:00
WARN_ON_ONCE ( length > NFS2_MAXNAMLEN ) ;
2010-12-14 17:54:30 +03:00
p = xdr_reserve_space ( xdr , 4 + length ) ;
xdr_encode_opaque ( p , name , length ) ;
}
2010-12-14 17:55:10 +03:00
static int decode_filename_inline ( struct xdr_stream * xdr ,
const char * * name , u32 * length )
{
__be32 * p ;
u32 count ;
p = xdr_inline_decode ( xdr , 4 ) ;
if ( unlikely ( p = = NULL ) )
goto out_overflow ;
count = be32_to_cpup ( p ) ;
if ( count > NFS3_MAXNAMLEN )
goto out_nametoolong ;
p = xdr_inline_decode ( xdr , count ) ;
if ( unlikely ( p = = NULL ) )
goto out_overflow ;
* name = ( const char * ) p ;
* length = count ;
return 0 ;
out_nametoolong :
dprintk ( " NFS: returned filename too long: %u \n " , count ) ;
return - ENAMETOOLONG ;
out_overflow :
print_overflow_msg ( __func__ , xdr ) ;
return - EIO ;
}
2010-12-14 17:54:30 +03:00
/*
* 2.3 .8 . path
*
* typedef string path < MAXPATHLEN > ;
*/
static void encode_path ( struct xdr_stream * xdr , struct page * * pages , u32 length )
{
__be32 * p ;
p = xdr_reserve_space ( xdr , 4 ) ;
* p = cpu_to_be32 ( length ) ;
xdr_write_pages ( xdr , pages , 0 , length ) ;
}
2010-12-14 17:55:10 +03:00
static int decode_path ( struct xdr_stream * xdr )
{
u32 length , recvd ;
__be32 * p ;
p = xdr_inline_decode ( xdr , 4 ) ;
if ( unlikely ( p = = NULL ) )
goto out_overflow ;
length = be32_to_cpup ( p ) ;
if ( unlikely ( length > = xdr - > buf - > page_len | | length > NFS_MAXPATHLEN ) )
goto out_size ;
2012-06-21 06:35:05 +04:00
recvd = xdr_read_pages ( xdr , length ) ;
2010-12-14 17:55:10 +03:00
if ( unlikely ( length > recvd ) )
goto out_cheating ;
xdr_terminate_string ( xdr - > buf , length ) ;
return 0 ;
out_size :
dprintk ( " NFS: returned pathname too long: %u \n " , length ) ;
return - ENAMETOOLONG ;
out_cheating :
dprintk ( " NFS: server cheating in pathname result: "
" length %u > received %u \n " , length , recvd ) ;
return - EIO ;
out_overflow :
print_overflow_msg ( __func__ , xdr ) ;
return - EIO ;
}
/*
* 2.3 .9 . attrstat
*
* union attrstat switch ( stat status ) {
* case NFS_OK :
* fattr attributes ;
* default :
* void ;
* } ;
*/
static int decode_attrstat ( struct xdr_stream * xdr , struct nfs_fattr * result )
{
enum nfs_stat status ;
int error ;
error = decode_stat ( xdr , & status ) ;
if ( unlikely ( error ) )
goto out ;
if ( status ! = NFS_OK )
goto out_default ;
error = decode_fattr ( xdr , result ) ;
out :
return error ;
out_default :
return nfs_stat_to_errno ( status ) ;
}
2010-12-14 17:54:30 +03:00
/*
* 2.3 .10 . diropargs
*
* struct diropargs {
* fhandle dir ;
* filename name ;
* } ;
*/
static void encode_diropargs ( struct xdr_stream * xdr , const struct nfs_fh * fh ,
const char * name , u32 length )
{
encode_fhandle ( xdr , fh ) ;
encode_filename ( xdr , name , length ) ;
}
2010-12-14 17:55:10 +03:00
/*
* 2.3 .11 . diropres
*
* union diropres switch ( stat status ) {
* case NFS_OK :
* struct {
* fhandle file ;
* fattr attributes ;
* } diropok ;
* default :
* void ;
* } ;
*/
static int decode_diropok ( struct xdr_stream * xdr , struct nfs_diropok * result )
{
int error ;
error = decode_fhandle ( xdr , result - > fh ) ;
if ( unlikely ( error ) )
goto out ;
error = decode_fattr ( xdr , result - > fattr ) ;
out :
return error ;
}
static int decode_diropres ( struct xdr_stream * xdr , struct nfs_diropok * result )
{
enum nfs_stat status ;
int error ;
error = decode_stat ( xdr , & status ) ;
if ( unlikely ( error ) )
goto out ;
if ( status ! = NFS_OK )
goto out_default ;
error = decode_diropok ( xdr , result ) ;
out :
return error ;
out_default :
return nfs_stat_to_errno ( status ) ;
}
2010-12-14 17:54:30 +03:00
2005-04-17 02:20:36 +04:00
/*
2010-12-14 17:54:40 +03:00
* NFSv2 XDR encode functions
*
* NFSv2 argument types are defined in section 2.2 of RFC 1094 :
* " NFS: Network File System Protocol Specification " .
2005-04-17 02:20:36 +04:00
*/
2010-12-14 17:59:18 +03:00
static void nfs2_xdr_enc_fhandle ( struct rpc_rqst * req ,
struct xdr_stream * xdr ,
const struct nfs_fh * fh )
2010-12-14 17:54:30 +03:00
{
2010-12-14 17:59:18 +03:00
encode_fhandle ( xdr , fh ) ;
2010-12-14 17:54:30 +03:00
}
/*
* 2.2 .3 . sattrargs
*
* struct sattrargs {
* fhandle file ;
* sattr attributes ;
* } ;
*/
2010-12-14 17:59:18 +03:00
static void nfs2_xdr_enc_sattrargs ( struct rpc_rqst * req ,
struct xdr_stream * xdr ,
const struct nfs_sattrargs * args )
2010-12-14 17:54:30 +03:00
{
2010-12-14 17:59:18 +03:00
encode_fhandle ( xdr , args - > fh ) ;
encode_sattr ( xdr , args - > sattr ) ;
2010-12-14 17:54:30 +03:00
}
2010-12-14 17:59:18 +03:00
static void nfs2_xdr_enc_diropargs ( struct rpc_rqst * req ,
struct xdr_stream * xdr ,
const struct nfs_diropargs * args )
2010-12-14 17:54:30 +03:00
{
2010-12-14 17:59:18 +03:00
encode_diropargs ( xdr , args - > fh , args - > name , args - > len ) ;
2010-12-14 17:54:30 +03:00
}
2010-12-14 17:59:18 +03:00
static void nfs2_xdr_enc_readlinkargs ( struct rpc_rqst * req ,
struct xdr_stream * xdr ,
const struct nfs_readlinkargs * args )
2010-12-14 17:54:30 +03:00
{
2010-12-14 17:59:18 +03:00
encode_fhandle ( xdr , args - > fh ) ;
2010-12-14 17:54:30 +03:00
prepare_reply_buffer ( req , args - > pages , args - > pgbase ,
args - > pglen , NFS_readlinkres_sz ) ;
}
/*
* 2.2 .7 . readargs
*
* struct readargs {
* fhandle file ;
* unsigned offset ;
* unsigned count ;
* unsigned totalcount ;
* } ;
*/
static void encode_readargs ( struct xdr_stream * xdr ,
2014-05-06 17:12:24 +04:00
const struct nfs_pgio_args * args )
2010-12-14 17:54:30 +03:00
{
u32 offset = args - > offset ;
u32 count = args - > count ;
__be32 * p ;
encode_fhandle ( xdr , args - > fh ) ;
p = xdr_reserve_space ( xdr , 4 + 4 + 4 ) ;
* p + + = cpu_to_be32 ( offset ) ;
* p + + = cpu_to_be32 ( count ) ;
* p = cpu_to_be32 ( count ) ;
}
2010-12-14 17:59:18 +03:00
static void nfs2_xdr_enc_readargs ( struct rpc_rqst * req ,
struct xdr_stream * xdr ,
2014-05-06 17:12:24 +04:00
const struct nfs_pgio_args * args )
2010-12-14 17:54:30 +03:00
{
2010-12-14 17:59:18 +03:00
encode_readargs ( xdr , args ) ;
2010-12-14 17:54:30 +03:00
prepare_reply_buffer ( req , args - > pages , args - > pgbase ,
args - > count , NFS_readres_sz ) ;
req - > rq_rcv_buf . flags | = XDRBUF_READ ;
}
/*
* 2.2 .9 . writeargs
*
* struct writeargs {
* fhandle file ;
* unsigned beginoffset ;
* unsigned offset ;
* unsigned totalcount ;
* nfsdata data ;
* } ;
*/
static void encode_writeargs ( struct xdr_stream * xdr ,
2014-05-06 17:12:24 +04:00
const struct nfs_pgio_args * args )
2010-12-14 17:54:30 +03:00
{
u32 offset = args - > offset ;
u32 count = args - > count ;
__be32 * p ;
encode_fhandle ( xdr , args - > fh ) ;
p = xdr_reserve_space ( xdr , 4 + 4 + 4 + 4 ) ;
* p + + = cpu_to_be32 ( offset ) ;
* p + + = cpu_to_be32 ( offset ) ;
* p + + = cpu_to_be32 ( count ) ;
/* nfsdata */
* p = cpu_to_be32 ( count ) ;
xdr_write_pages ( xdr , args - > pages , args - > pgbase , count ) ;
}
2010-12-14 17:59:18 +03:00
static void nfs2_xdr_enc_writeargs ( struct rpc_rqst * req ,
struct xdr_stream * xdr ,
2014-05-06 17:12:24 +04:00
const struct nfs_pgio_args * args )
2010-12-14 17:54:30 +03:00
{
2010-12-14 17:59:18 +03:00
encode_writeargs ( xdr , args ) ;
xdr - > buf - > flags | = XDRBUF_WRITE ;
2010-12-14 17:54:30 +03:00
}
/*
* 2.2 .10 . createargs
*
* struct createargs {
* diropargs where ;
* sattr attributes ;
* } ;
*/
2010-12-14 17:59:18 +03:00
static void nfs2_xdr_enc_createargs ( struct rpc_rqst * req ,
struct xdr_stream * xdr ,
const struct nfs_createargs * args )
2010-12-14 17:54:30 +03:00
{
2010-12-14 17:59:18 +03:00
encode_diropargs ( xdr , args - > fh , args - > name , args - > len ) ;
encode_sattr ( xdr , args - > sattr ) ;
2010-12-14 17:54:30 +03:00
}
2010-12-14 17:59:18 +03:00
static void nfs2_xdr_enc_removeargs ( struct rpc_rqst * req ,
struct xdr_stream * xdr ,
const struct nfs_removeargs * args )
2010-12-14 17:54:30 +03:00
{
2010-12-14 17:59:18 +03:00
encode_diropargs ( xdr , args - > fh , args - > name . name , args - > name . len ) ;
2010-12-14 17:54:30 +03:00
}
/*
* 2.2 .12 . renameargs
*
* struct renameargs {
* diropargs from ;
* diropargs to ;
* } ;
*/
2010-12-14 17:59:18 +03:00
static void nfs2_xdr_enc_renameargs ( struct rpc_rqst * req ,
struct xdr_stream * xdr ,
const struct nfs_renameargs * args )
2010-12-14 17:54:30 +03:00
{
const struct qstr * old = args - > old_name ;
const struct qstr * new = args - > new_name ;
2010-12-14 17:59:18 +03:00
encode_diropargs ( xdr , args - > old_dir , old - > name , old - > len ) ;
encode_diropargs ( xdr , args - > new_dir , new - > name , new - > len ) ;
2010-12-14 17:54:30 +03:00
}
/*
* 2.2 .13 . linkargs
*
* struct linkargs {
* fhandle from ;
* diropargs to ;
* } ;
*/
2010-12-14 17:59:18 +03:00
static void nfs2_xdr_enc_linkargs ( struct rpc_rqst * req ,
struct xdr_stream * xdr ,
const struct nfs_linkargs * args )
2010-12-14 17:54:30 +03:00
{
2010-12-14 17:59:18 +03:00
encode_fhandle ( xdr , args - > fromfh ) ;
encode_diropargs ( xdr , args - > tofh , args - > toname , args - > tolen ) ;
2010-12-14 17:54:30 +03:00
}
/*
* 2.2 .14 . symlinkargs
*
* struct symlinkargs {
* diropargs from ;
* path to ;
* sattr attributes ;
* } ;
*/
2010-12-14 17:59:18 +03:00
static void nfs2_xdr_enc_symlinkargs ( struct rpc_rqst * req ,
struct xdr_stream * xdr ,
const struct nfs_symlinkargs * args )
2010-12-14 17:54:30 +03:00
{
2010-12-14 17:59:18 +03:00
encode_diropargs ( xdr , args - > fromfh , args - > fromname , args - > fromlen ) ;
encode_path ( xdr , args - > pages , args - > pathlen ) ;
encode_sattr ( xdr , args - > sattr ) ;
2010-12-14 17:54:30 +03:00
}
/*
* 2.2 .17 . readdirargs
*
* struct readdirargs {
* fhandle dir ;
* nfscookie cookie ;
* unsigned count ;
* } ;
*/
static void encode_readdirargs ( struct xdr_stream * xdr ,
const struct nfs_readdirargs * args )
{
__be32 * p ;
encode_fhandle ( xdr , args - > fh ) ;
p = xdr_reserve_space ( xdr , 4 + 4 ) ;
* p + + = cpu_to_be32 ( args - > cookie ) ;
* p = cpu_to_be32 ( args - > count ) ;
}
2010-12-14 17:59:18 +03:00
static void nfs2_xdr_enc_readdirargs ( struct rpc_rqst * req ,
struct xdr_stream * xdr ,
const struct nfs_readdirargs * args )
2010-12-14 17:54:30 +03:00
{
2010-12-14 17:59:18 +03:00
encode_readdirargs ( xdr , args ) ;
2010-12-14 17:54:30 +03:00
prepare_reply_buffer ( req , args - > pages , 0 ,
args - > count , NFS_readdirres_sz ) ;
}
2005-04-17 02:20:36 +04:00
/*
2010-12-14 17:55:20 +03:00
* NFSv2 XDR decode functions
*
* NFSv2 result types are defined in section 2.2 of RFC 1094 :
* " NFS: Network File System Protocol Specification " .
2005-04-17 02:20:36 +04:00
*/
2010-12-14 17:59:29 +03:00
static int nfs2_xdr_dec_stat ( struct rpc_rqst * req , struct xdr_stream * xdr ,
2010-12-14 17:55:10 +03:00
void * __unused )
{
enum nfs_stat status ;
int error ;
2010-12-14 17:59:29 +03:00
error = decode_stat ( xdr , & status ) ;
2010-12-14 17:55:10 +03:00
if ( unlikely ( error ) )
goto out ;
if ( status ! = NFS_OK )
goto out_default ;
out :
return error ;
out_default :
return nfs_stat_to_errno ( status ) ;
}
2010-12-14 17:59:29 +03:00
static int nfs2_xdr_dec_attrstat ( struct rpc_rqst * req , struct xdr_stream * xdr ,
2010-12-14 17:55:10 +03:00
struct nfs_fattr * result )
{
2010-12-14 17:59:29 +03:00
return decode_attrstat ( xdr , result ) ;
2010-12-14 17:55:10 +03:00
}
2010-12-14 17:59:29 +03:00
static int nfs2_xdr_dec_diropres ( struct rpc_rqst * req , struct xdr_stream * xdr ,
2010-12-14 17:55:10 +03:00
struct nfs_diropok * result )
{
2010-12-14 17:59:29 +03:00
return decode_diropres ( xdr , result ) ;
2010-12-14 17:55:10 +03:00
}
/*
* 2.2 .6 . readlinkres
*
* union readlinkres switch ( stat status ) {
* case NFS_OK :
* path data ;
* default :
* void ;
* } ;
*/
2010-12-14 17:59:29 +03:00
static int nfs2_xdr_dec_readlinkres ( struct rpc_rqst * req ,
struct xdr_stream * xdr , void * __unused )
2010-12-14 17:55:10 +03:00
{
enum nfs_stat status ;
int error ;
2010-12-14 17:59:29 +03:00
error = decode_stat ( xdr , & status ) ;
2010-12-14 17:55:10 +03:00
if ( unlikely ( error ) )
goto out ;
if ( status ! = NFS_OK )
goto out_default ;
2010-12-14 17:59:29 +03:00
error = decode_path ( xdr ) ;
2010-12-14 17:55:10 +03:00
out :
return error ;
out_default :
return nfs_stat_to_errno ( status ) ;
}
/*
* 2.2 .7 . readres
*
* union readres switch ( stat status ) {
* case NFS_OK :
* fattr attributes ;
* nfsdata data ;
* default :
* void ;
* } ;
*/
2010-12-14 17:59:29 +03:00
static int nfs2_xdr_dec_readres ( struct rpc_rqst * req , struct xdr_stream * xdr ,
2014-05-06 17:12:25 +04:00
struct nfs_pgio_res * result )
2010-12-14 17:55:10 +03:00
{
enum nfs_stat status ;
int error ;
2010-12-14 17:59:29 +03:00
error = decode_stat ( xdr , & status ) ;
2010-12-14 17:55:10 +03:00
if ( unlikely ( error ) )
goto out ;
if ( status ! = NFS_OK )
goto out_default ;
2010-12-14 17:59:29 +03:00
error = decode_fattr ( xdr , result - > fattr ) ;
2010-12-14 17:55:10 +03:00
if ( unlikely ( error ) )
goto out ;
2010-12-14 17:59:29 +03:00
error = decode_nfsdata ( xdr , result ) ;
2010-12-14 17:55:10 +03:00
out :
return error ;
out_default :
return nfs_stat_to_errno ( status ) ;
}
2010-12-14 17:59:29 +03:00
static int nfs2_xdr_dec_writeres ( struct rpc_rqst * req , struct xdr_stream * xdr ,
2014-05-06 17:12:25 +04:00
struct nfs_pgio_res * result )
2010-12-14 17:55:10 +03:00
{
/* All NFSv2 writes are "file sync" writes */
result - > verf - > committed = NFS_FILE_SYNC ;
2010-12-14 17:59:29 +03:00
return decode_attrstat ( xdr , result - > fattr ) ;
2010-12-14 17:55:10 +03:00
}
/**
* nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in
* the local page cache .
* @ xdr : XDR stream where entry resides
* @ entry : buffer to fill in with entry data
* @ plus : boolean indicating whether this should be a readdirplus entry
*
2010-12-14 17:58:11 +03:00
* Returns zero if successful , otherwise a negative errno value is
* returned .
2010-12-14 17:55:10 +03:00
*
* This function is not invoked during READDIR reply decoding , but
* rather whenever an application invokes the getdents ( 2 ) system call
* on a directory already in our cache .
*
* 2.2 .17 . entry
*
* struct entry {
* unsigned fileid ;
* filename name ;
* nfscookie cookie ;
* entry * nextentry ;
* } ;
*/
2010-12-14 17:58:11 +03:00
int nfs2_decode_dirent ( struct xdr_stream * xdr , struct nfs_entry * entry ,
int plus )
2010-12-14 17:55:10 +03:00
{
__be32 * p ;
int error ;
p = xdr_inline_decode ( xdr , 4 ) ;
if ( unlikely ( p = = NULL ) )
goto out_overflow ;
if ( * p + + = = xdr_zero ) {
p = xdr_inline_decode ( xdr , 4 ) ;
if ( unlikely ( p = = NULL ) )
goto out_overflow ;
if ( * p + + = = xdr_zero )
2010-12-14 17:58:11 +03:00
return - EAGAIN ;
2010-12-14 17:55:10 +03:00
entry - > eof = 1 ;
2010-12-14 17:58:11 +03:00
return - EBADCOOKIE ;
2010-12-14 17:55:10 +03:00
}
p = xdr_inline_decode ( xdr , 4 ) ;
if ( unlikely ( p = = NULL ) )
goto out_overflow ;
entry - > ino = be32_to_cpup ( p ) ;
error = decode_filename_inline ( xdr , & entry - > name , & entry - > len ) ;
if ( unlikely ( error ) )
2010-12-14 17:58:11 +03:00
return error ;
2010-12-14 17:55:10 +03:00
/*
* The type ( size and byte order ) of nfscookie isn ' t defined in
* RFC 1094. This implementation assumes that it ' s an XDR uint32 .
*/
entry - > prev_cookie = entry - > cookie ;
p = xdr_inline_decode ( xdr , 4 ) ;
if ( unlikely ( p = = NULL ) )
goto out_overflow ;
entry - > cookie = be32_to_cpup ( p ) ;
entry - > d_type = DT_UNKNOWN ;
2010-12-14 17:58:11 +03:00
return 0 ;
2010-12-14 17:55:10 +03:00
out_overflow :
print_overflow_msg ( __func__ , xdr ) ;
2010-12-14 17:58:11 +03:00
return - EAGAIN ;
2010-12-14 17:55:10 +03:00
}
/*
* 2.2 .17 . readdirres
*
* union readdirres switch ( stat status ) {
* case NFS_OK :
* struct {
* entry * entries ;
* bool eof ;
* } readdirok ;
* default :
* void ;
* } ;
*
* Read the directory contents into the page cache , but don ' t
* touch them . The actual decoding is done by nfs2_decode_dirent ( )
* during subsequent nfs_readdir ( ) calls .
*/
static int decode_readdirok ( struct xdr_stream * xdr )
{
2012-06-21 06:35:05 +04:00
return xdr_read_pages ( xdr , xdr - > buf - > page_len ) ;
2010-12-14 17:55:10 +03:00
}
2010-12-14 17:59:29 +03:00
static int nfs2_xdr_dec_readdirres ( struct rpc_rqst * req ,
struct xdr_stream * xdr , void * __unused )
2010-12-14 17:55:10 +03:00
{
enum nfs_stat status ;
int error ;
2010-12-14 17:59:29 +03:00
error = decode_stat ( xdr , & status ) ;
2010-12-14 17:55:10 +03:00
if ( unlikely ( error ) )
goto out ;
if ( status ! = NFS_OK )
goto out_default ;
2010-12-14 17:59:29 +03:00
error = decode_readdirok ( xdr ) ;
2010-12-14 17:55:10 +03:00
out :
return error ;
out_default :
return nfs_stat_to_errno ( status ) ;
}
/*
* 2.2 .18 . statfsres
*
* union statfsres ( stat status ) {
* case NFS_OK :
* struct {
* unsigned tsize ;
* unsigned bsize ;
* unsigned blocks ;
* unsigned bfree ;
* unsigned bavail ;
* } info ;
* default :
* void ;
* } ;
*/
static int decode_info ( struct xdr_stream * xdr , struct nfs2_fsstat * result )
{
__be32 * p ;
p = xdr_inline_decode ( xdr , NFS_info_sz < < 2 ) ;
if ( unlikely ( p = = NULL ) )
goto out_overflow ;
result - > tsize = be32_to_cpup ( p + + ) ;
result - > bsize = be32_to_cpup ( p + + ) ;
result - > blocks = be32_to_cpup ( p + + ) ;
result - > bfree = be32_to_cpup ( p + + ) ;
result - > bavail = be32_to_cpup ( p ) ;
return 0 ;
out_overflow :
print_overflow_msg ( __func__ , xdr ) ;
return - EIO ;
}
2010-12-14 17:59:29 +03:00
static int nfs2_xdr_dec_statfsres ( struct rpc_rqst * req , struct xdr_stream * xdr ,
2010-12-14 17:55:10 +03:00
struct nfs2_fsstat * result )
{
enum nfs_stat status ;
int error ;
2010-12-14 17:59:29 +03:00
error = decode_stat ( xdr , & status ) ;
2010-12-14 17:55:10 +03:00
if ( unlikely ( error ) )
goto out ;
if ( status ! = NFS_OK )
goto out_default ;
2010-12-14 17:59:29 +03:00
error = decode_info ( xdr , result ) ;
2010-12-14 17:55:10 +03:00
out :
return error ;
out_default :
return nfs_stat_to_errno ( status ) ;
}
2005-04-17 02:20:36 +04:00
/*
* We need to translate between nfs status return values and
* the local errno values which may not be the same .
*/
2010-12-14 17:55:00 +03:00
static const struct {
2005-04-17 02:20:36 +04:00
int stat ;
int errno ;
} nfs_errtbl [ ] = {
{ NFS_OK , 0 } ,
2008-03-31 18:39:06 +04:00
{ NFSERR_PERM , - EPERM } ,
{ NFSERR_NOENT , - ENOENT } ,
{ NFSERR_IO , - errno_NFSERR_IO } ,
{ NFSERR_NXIO , - ENXIO } ,
/* { NFSERR_EAGAIN, -EAGAIN }, */
{ NFSERR_ACCES , - EACCES } ,
{ NFSERR_EXIST , - EEXIST } ,
{ NFSERR_XDEV , - EXDEV } ,
{ NFSERR_NODEV , - ENODEV } ,
{ NFSERR_NOTDIR , - ENOTDIR } ,
{ NFSERR_ISDIR , - EISDIR } ,
{ NFSERR_INVAL , - EINVAL } ,
{ NFSERR_FBIG , - EFBIG } ,
{ NFSERR_NOSPC , - ENOSPC } ,
{ NFSERR_ROFS , - EROFS } ,
{ NFSERR_MLINK , - EMLINK } ,
{ NFSERR_NAMETOOLONG , - ENAMETOOLONG } ,
{ NFSERR_NOTEMPTY , - ENOTEMPTY } ,
{ NFSERR_DQUOT , - EDQUOT } ,
{ NFSERR_STALE , - ESTALE } ,
{ NFSERR_REMOTE , - EREMOTE } ,
2005-04-17 02:20:36 +04:00
# ifdef EWFLUSH
2008-03-31 18:39:06 +04:00
{ NFSERR_WFLUSH , - EWFLUSH } ,
2005-04-17 02:20:36 +04:00
# endif
2008-03-31 18:39:06 +04:00
{ NFSERR_BADHANDLE , - EBADHANDLE } ,
{ NFSERR_NOT_SYNC , - ENOTSYNC } ,
{ NFSERR_BAD_COOKIE , - EBADCOOKIE } ,
{ NFSERR_NOTSUPP , - ENOTSUPP } ,
{ NFSERR_TOOSMALL , - ETOOSMALL } ,
2010-02-08 17:32:40 +03:00
{ NFSERR_SERVERFAULT , - EREMOTEIO } ,
2008-03-31 18:39:06 +04:00
{ NFSERR_BADTYPE , - EBADTYPE } ,
{ NFSERR_JUKEBOX , - EJUKEBOX } ,
{ - 1 , - EIO }
2005-04-17 02:20:36 +04:00
} ;
2010-12-14 17:55:00 +03:00
/**
* nfs_stat_to_errno - convert an NFS status code to a local errno
* @ status : NFS status code to convert
*
* Returns a local errno value , or - EIO if the NFS status code is
* not recognized . This function is used jointly by NFSv2 and NFSv3 .
2005-04-17 02:20:36 +04:00
*/
2012-05-11 00:47:18 +04:00
static int nfs_stat_to_errno ( enum nfs_stat status )
2005-04-17 02:20:36 +04:00
{
int i ;
for ( i = 0 ; nfs_errtbl [ i ] . stat ! = - 1 ; i + + ) {
2010-12-14 17:55:00 +03:00
if ( nfs_errtbl [ i ] . stat = = ( int ) status )
2005-04-17 02:20:36 +04:00
return nfs_errtbl [ i ] . errno ;
}
2010-12-14 17:55:00 +03:00
dprintk ( " NFS: Unrecognized nfs status value: %u \n " , status ) ;
2005-04-17 02:20:36 +04:00
return nfs_errtbl [ i ] . errno ;
}
# define PROC(proc, argtype, restype, timer) \
[ NFSPROC_ # # proc ] = { \
. p_proc = NFSPROC_ # # proc , \
2010-12-14 17:59:18 +03:00
. p_encode = ( kxdreproc_t ) nfs2_xdr_enc_ # # argtype , \
2010-12-14 17:59:29 +03:00
. p_decode = ( kxdrdproc_t ) nfs2_xdr_dec_ # # restype , \
2007-03-30 00:47:53 +04:00
. p_arglen = NFS_ # # argtype # # _sz , \
. p_replen = NFS_ # # restype # # _sz , \
2006-03-20 21:44:22 +03:00
. p_timer = timer , \
. p_statidx = NFSPROC_ # # proc , \
. p_name = # proc , \
2005-04-17 02:20:36 +04:00
}
struct rpc_procinfo nfs_procedures [ ] = {
2010-12-14 17:57:42 +03:00
PROC ( GETATTR , fhandle , attrstat , 1 ) ,
PROC ( SETATTR , sattrargs , attrstat , 0 ) ,
PROC ( LOOKUP , diropargs , diropres , 2 ) ,
PROC ( READLINK , readlinkargs , readlinkres , 3 ) ,
PROC ( READ , readargs , readres , 3 ) ,
PROC ( WRITE , writeargs , writeres , 4 ) ,
PROC ( CREATE , createargs , diropres , 0 ) ,
PROC ( REMOVE , removeargs , stat , 0 ) ,
PROC ( RENAME , renameargs , stat , 0 ) ,
PROC ( LINK , linkargs , stat , 0 ) ,
PROC ( SYMLINK , symlinkargs , stat , 0 ) ,
PROC ( MKDIR , createargs , diropres , 0 ) ,
PROC ( RMDIR , diropargs , stat , 0 ) ,
PROC ( READDIR , readdirargs , readdirres , 3 ) ,
PROC ( STATFS , fhandle , statfsres , 0 ) ,
2005-04-17 02:20:36 +04:00
} ;
2012-01-20 22:53:56 +04:00
const struct rpc_version nfs_version2 = {
2005-04-17 02:20:36 +04:00
. number = 2 ,
2006-03-24 14:15:34 +03:00
. nrprocs = ARRAY_SIZE ( nfs_procedures ) ,
2005-04-17 02:20:36 +04:00
. procs = nfs_procedures
} ;