2005-04-17 02:20:36 +04:00
/*
* XDR support for nfsd
*
* Copyright ( C ) 1995 , 1996 Olaf Kirch < okir @ monad . swb . de >
*/
2013-01-24 11:18:08 +04:00
# include "vfs.h"
2009-12-03 21:30:56 +03:00
# include "xdr.h"
2007-11-16 01:05:43 +03:00
# include "auth.h"
2005-04-17 02:20:36 +04:00
# define NFSDDBG_FACILITY NFSDDBG_XDR
/*
* Mapping of S_IF * types to NFS file types
*/
static u32 nfs_ftypes [ ] = {
NFNON , NFCHR , NFCHR , NFBAD ,
NFDIR , NFBAD , NFBLK , NFBAD ,
NFREG , NFBAD , NFLNK , NFBAD ,
NFSOCK , NFBAD , NFLNK , NFBAD ,
} ;
/*
* XDR functions for basic NFS types
*/
2006-10-20 10:28:56 +04:00
static __be32 *
decode_fh ( __be32 * p , struct svc_fh * fhp )
2005-04-17 02:20:36 +04:00
{
fh_init ( fhp , NFS_FHSIZE ) ;
memcpy ( & fhp - > fh_handle . fh_base , p , NFS_FHSIZE ) ;
fhp - > fh_handle . fh_size = NFS_FHSIZE ;
/* FIXME: Look up export pointer here and verify
* Sun Secure RPC if requested */
return p + ( NFS_FHSIZE > > 2 ) ;
}
2005-06-22 21:16:26 +04:00
/* Helper function for NFSv2 ACL code */
2006-10-20 10:28:56 +04:00
__be32 * nfs2svc_decode_fh ( __be32 * p , struct svc_fh * fhp )
2005-06-22 21:16:26 +04:00
{
return decode_fh ( p , fhp ) ;
}
2006-12-07 07:40:23 +03:00
static __be32 *
2006-10-20 10:28:56 +04:00
encode_fh ( __be32 * p , struct svc_fh * fhp )
2005-04-17 02:20:36 +04:00
{
memcpy ( p , & fhp - > fh_handle . fh_base , NFS_FHSIZE ) ;
return p + ( NFS_FHSIZE > > 2 ) ;
}
/*
* Decode a file name and make sure that the path contains
* no slashes or null bytes .
*/
2006-12-07 07:40:23 +03:00
static __be32 *
2007-11-01 23:56:58 +03:00
decode_filename ( __be32 * p , char * * namp , unsigned int * lenp )
2005-04-17 02:20:36 +04:00
{
char * name ;
2007-11-01 23:56:58 +03:00
unsigned int i ;
2005-04-17 02:20:36 +04:00
if ( ( p = xdr_decode_string_inplace ( p , namp , lenp , NFS_MAXNAMLEN ) ) ! = NULL ) {
for ( i = 0 , name = * namp ; i < * lenp ; i + + , name + + ) {
if ( * name = = ' \0 ' | | * name = = ' / ' )
return NULL ;
}
}
return p ;
}
2006-12-07 07:40:23 +03:00
static __be32 *
2007-11-01 23:57:14 +03:00
decode_pathname ( __be32 * p , char * * namp , unsigned int * lenp )
2005-04-17 02:20:36 +04:00
{
char * name ;
2007-11-01 23:57:14 +03:00
unsigned int i ;
2005-04-17 02:20:36 +04:00
if ( ( p = xdr_decode_string_inplace ( p , namp , lenp , NFS_MAXPATHLEN ) ) ! = NULL ) {
for ( i = 0 , name = * namp ; i < * lenp ; i + + , name + + ) {
if ( * name = = ' \0 ' )
return NULL ;
}
}
return p ;
}
2006-12-07 07:40:23 +03:00
static __be32 *
2006-10-20 10:28:56 +04:00
decode_sattr ( __be32 * p , struct iattr * iap )
2005-04-17 02:20:36 +04:00
{
u32 tmp , tmp1 ;
iap - > ia_valid = 0 ;
/* Sun client bug compatibility check: some sun clients seem to
* put 0xffff in the mode field when they mean 0xffffffff .
* Quoting the 4.4 BSD nfs server code : Nah nah nah nah na nah .
*/
if ( ( tmp = ntohl ( * p + + ) ) ! = ( u32 ) - 1 & & tmp ! = 0xffff ) {
iap - > ia_valid | = ATTR_MODE ;
iap - > ia_mode = tmp ;
}
if ( ( tmp = ntohl ( * p + + ) ) ! = ( u32 ) - 1 ) {
2013-02-02 16:32:35 +04:00
iap - > ia_uid = make_kuid ( & init_user_ns , tmp ) ;
if ( uid_valid ( iap - > ia_uid ) )
iap - > ia_valid | = ATTR_UID ;
2005-04-17 02:20:36 +04:00
}
if ( ( tmp = ntohl ( * p + + ) ) ! = ( u32 ) - 1 ) {
2013-02-02 16:32:35 +04:00
iap - > ia_gid = make_kgid ( & init_user_ns , tmp ) ;
if ( gid_valid ( iap - > ia_gid ) )
iap - > ia_valid | = ATTR_GID ;
2005-04-17 02:20:36 +04:00
}
if ( ( tmp = ntohl ( * p + + ) ) ! = ( u32 ) - 1 ) {
iap - > ia_valid | = ATTR_SIZE ;
iap - > ia_size = tmp ;
}
tmp = ntohl ( * p + + ) ; tmp1 = ntohl ( * p + + ) ;
if ( tmp ! = ( u32 ) - 1 & & tmp1 ! = ( u32 ) - 1 ) {
iap - > ia_valid | = ATTR_ATIME | ATTR_ATIME_SET ;
iap - > ia_atime . tv_sec = tmp ;
iap - > ia_atime . tv_nsec = tmp1 * 1000 ;
}
tmp = ntohl ( * p + + ) ; tmp1 = ntohl ( * p + + ) ;
if ( tmp ! = ( u32 ) - 1 & & tmp1 ! = ( u32 ) - 1 ) {
iap - > ia_valid | = ATTR_MTIME | ATTR_MTIME_SET ;
iap - > ia_mtime . tv_sec = tmp ;
iap - > ia_mtime . tv_nsec = tmp1 * 1000 ;
/*
* Passing the invalid value useconds = 1000000 for mtime
* is a Sun convention for " set both mtime and atime to
* current server time " . It's needed to make permissions
* checks for the " touch " program across v2 mounts to
* Solaris and Irix boxes work correctly . See description of
* sattr in section 6.1 of " NFS Illustrated " by
* Brent Callaghan , Addison - Wesley , ISBN 0 - 201 - 32750 - 5
*/
if ( tmp1 = = 1000000 )
iap - > ia_valid & = ~ ( ATTR_ATIME_SET | ATTR_MTIME_SET ) ;
}
return p ;
}
2006-10-20 10:28:56 +04:00
static __be32 *
encode_fattr ( struct svc_rqst * rqstp , __be32 * p , struct svc_fh * fhp ,
2006-01-06 11:19:58 +03:00
struct kstat * stat )
2005-04-17 02:20:36 +04:00
{
struct dentry * dentry = fhp - > fh_dentry ;
int type ;
struct timespec time ;
2007-02-14 11:33:12 +03:00
u32 f ;
2005-04-17 02:20:36 +04:00
2006-01-06 11:19:58 +03:00
type = ( stat - > mode & S_IFMT ) ;
2005-04-17 02:20:36 +04:00
* p + + = htonl ( nfs_ftypes [ type > > 12 ] ) ;
2014-04-03 23:10:35 +04:00
* p + + = htonl ( ( u32 ) stat - > mode ) ;
2006-01-06 11:19:58 +03:00
* p + + = htonl ( ( u32 ) stat - > nlink ) ;
2013-02-02 16:32:35 +04:00
* p + + = htonl ( ( u32 ) from_kuid ( & init_user_ns , stat - > uid ) ) ;
* p + + = htonl ( ( u32 ) from_kgid ( & init_user_ns , stat - > gid ) ) ;
2005-04-17 02:20:36 +04:00
2006-01-06 11:19:58 +03:00
if ( S_ISLNK ( type ) & & stat - > size > NFS_MAXPATHLEN ) {
2005-04-17 02:20:36 +04:00
* p + + = htonl ( NFS_MAXPATHLEN ) ;
} else {
2006-01-06 11:19:58 +03:00
* p + + = htonl ( ( u32 ) stat - > size ) ;
2005-04-17 02:20:36 +04:00
}
2006-01-06 11:19:58 +03:00
* p + + = htonl ( ( u32 ) stat - > blksize ) ;
2005-04-17 02:20:36 +04:00
if ( S_ISCHR ( type ) | | S_ISBLK ( type ) )
2006-01-06 11:19:58 +03:00
* p + + = htonl ( new_encode_dev ( stat - > rdev ) ) ;
2005-04-17 02:20:36 +04:00
else
* p + + = htonl ( 0xffffffff ) ;
2006-01-06 11:19:58 +03:00
* p + + = htonl ( ( u32 ) stat - > blocks ) ;
2007-02-14 11:33:12 +03:00
switch ( fsid_source ( fhp ) ) {
default :
case FSIDSOURCE_DEV :
2006-01-06 11:19:58 +03:00
* p + + = htonl ( new_encode_dev ( stat - > dev ) ) ;
2007-02-14 11:33:12 +03:00
break ;
case FSIDSOURCE_FSID :
* p + + = htonl ( ( u32 ) fhp - > fh_export - > ex_fsid ) ;
break ;
case FSIDSOURCE_UUID :
f = ( ( u32 * ) fhp - > fh_export - > ex_uuid ) [ 0 ] ;
f ^ = ( ( u32 * ) fhp - > fh_export - > ex_uuid ) [ 1 ] ;
f ^ = ( ( u32 * ) fhp - > fh_export - > ex_uuid ) [ 2 ] ;
f ^ = ( ( u32 * ) fhp - > fh_export - > ex_uuid ) [ 3 ] ;
* p + + = htonl ( f ) ;
break ;
}
2006-01-06 11:19:58 +03:00
* p + + = htonl ( ( u32 ) stat - > ino ) ;
* p + + = htonl ( ( u32 ) stat - > atime . tv_sec ) ;
* p + + = htonl ( stat - > atime . tv_nsec ? stat - > atime . tv_nsec / 1000 : 0 ) ;
2005-04-17 02:20:36 +04:00
lease_get_mtime ( dentry - > d_inode , & time ) ;
* p + + = htonl ( ( u32 ) time . tv_sec ) ;
* p + + = htonl ( time . tv_nsec ? time . tv_nsec / 1000 : 0 ) ;
2006-01-06 11:19:58 +03:00
* p + + = htonl ( ( u32 ) stat - > ctime . tv_sec ) ;
* p + + = htonl ( stat - > ctime . tv_nsec ? stat - > ctime . tv_nsec / 1000 : 0 ) ;
2005-04-17 02:20:36 +04:00
return p ;
}
2005-06-22 21:16:26 +04:00
/* Helper function for NFSv2 ACL code */
2013-02-02 00:13:04 +04:00
__be32 * nfs2svc_encode_fattr ( struct svc_rqst * rqstp , __be32 * p , struct svc_fh * fhp , struct kstat * stat )
2005-06-22 21:16:26 +04:00
{
2013-02-02 00:13:04 +04:00
return encode_fattr ( rqstp , p , fhp , stat ) ;
2005-06-22 21:16:26 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* XDR decode functions
*/
int
2006-10-20 10:28:56 +04:00
nfssvc_decode_void ( struct svc_rqst * rqstp , __be32 * p , void * dummy )
2005-04-17 02:20:36 +04:00
{
return xdr_argsize_check ( rqstp , p ) ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_decode_fhandle ( struct svc_rqst * rqstp , __be32 * p , struct nfsd_fhandle * args )
2005-04-17 02:20:36 +04:00
{
2014-05-22 18:32:30 +04:00
p = decode_fh ( p , & args - > fh ) ;
if ( ! p )
2005-04-17 02:20:36 +04:00
return 0 ;
return xdr_argsize_check ( rqstp , p ) ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_decode_sattrargs ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_sattrargs * args )
{
2007-05-09 13:34:57 +04:00
p = decode_fh ( p , & args - > fh ) ;
if ( ! p )
2005-04-17 02:20:36 +04:00
return 0 ;
2007-05-09 13:34:57 +04:00
p = decode_sattr ( p , & args - > attrs ) ;
2005-04-17 02:20:36 +04:00
return xdr_argsize_check ( rqstp , p ) ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_decode_diropargs ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_diropargs * args )
{
if ( ! ( p = decode_fh ( p , & args - > fh ) )
| | ! ( p = decode_filename ( p , & args - > name , & args - > len ) ) )
return 0 ;
return xdr_argsize_check ( rqstp , p ) ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_decode_readargs ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_readargs * args )
{
unsigned int len ;
2012-12-11 03:01:37 +04:00
int v ;
2014-05-22 18:32:30 +04:00
p = decode_fh ( p , & args - > fh ) ;
if ( ! p )
2005-04-17 02:20:36 +04:00
return 0 ;
args - > offset = ntohl ( * p + + ) ;
len = args - > count = ntohl ( * p + + ) ;
p + + ; /* totalcount - unused */
2014-06-10 14:08:19 +04:00
len = min_t ( unsigned int , len , NFSSVC_MAXBLKSIZE_V2 ) ;
2005-04-17 02:20:36 +04:00
/* set up somewhere to store response.
* We take pages , put them on reslist and include in iovec
*/
v = 0 ;
while ( len > 0 ) {
2012-12-11 03:01:37 +04:00
struct page * p = * ( rqstp - > rq_next_page + + ) ;
rqstp - > rq_vec [ v ] . iov_base = page_address ( p ) ;
2014-06-10 14:08:19 +04:00
rqstp - > rq_vec [ v ] . iov_len = min_t ( unsigned int , len , PAGE_SIZE ) ;
2006-10-04 13:15:47 +04:00
len - = rqstp - > rq_vec [ v ] . iov_len ;
2005-04-17 02:20:36 +04:00
v + + ;
}
args - > vlen = v ;
return xdr_argsize_check ( rqstp , p ) ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_decode_writeargs ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_writeargs * args )
{
2007-05-09 13:34:48 +04:00
unsigned int len , hdr , dlen ;
2005-04-17 02:20:36 +04:00
int v ;
2007-05-09 13:34:48 +04:00
2014-05-22 18:32:30 +04:00
p = decode_fh ( p , & args - > fh ) ;
if ( ! p )
2005-04-17 02:20:36 +04:00
return 0 ;
p + + ; /* beginoffset */
args - > offset = ntohl ( * p + + ) ; /* offset */
p + + ; /* totalcount */
len = args - > len = ntohl ( * p + + ) ;
2007-05-09 13:34:48 +04:00
/*
* The protocol specifies a maximum of 8192 bytes .
*/
2006-10-04 13:15:47 +04:00
if ( len > NFSSVC_MAXBLKSIZE_V2 )
2007-05-09 13:34:48 +04:00
return 0 ;
/*
* Check to make sure that we got the right number of
* bytes .
*/
hdr = ( void * ) p - rqstp - > rq_arg . head [ 0 ] . iov_base ;
2007-05-09 13:34:57 +04:00
dlen = rqstp - > rq_arg . head [ 0 ] . iov_len + rqstp - > rq_arg . page_len
- hdr ;
2007-05-09 13:34:48 +04:00
/*
* Round the length of the data which was specified up to
* the next multiple of XDR units and then compare that
* against the length which was actually received .
2008-01-12 01:06:52 +03:00
* Note that when RPCSEC / GSS ( for example ) is used , the
* data buffer can be padded so dlen might be larger
* than required . It must never be smaller .
2007-05-09 13:34:48 +04:00
*/
2008-01-12 01:06:52 +03:00
if ( dlen < XDR_QUADLEN ( len ) * 4 )
2007-05-09 13:34:48 +04:00
return 0 ;
rqstp - > rq_vec [ 0 ] . iov_base = ( void * ) p ;
rqstp - > rq_vec [ 0 ] . iov_len = rqstp - > rq_arg . head [ 0 ] . iov_len - hdr ;
2005-04-17 02:20:36 +04:00
v = 0 ;
2006-10-04 13:15:47 +04:00
while ( len > rqstp - > rq_vec [ v ] . iov_len ) {
len - = rqstp - > rq_vec [ v ] . iov_len ;
2005-04-17 02:20:36 +04:00
v + + ;
2006-10-04 13:15:47 +04:00
rqstp - > rq_vec [ v ] . iov_base = page_address ( rqstp - > rq_pages [ v ] ) ;
rqstp - > rq_vec [ v ] . iov_len = PAGE_SIZE ;
2005-04-17 02:20:36 +04:00
}
2006-10-04 13:15:47 +04:00
rqstp - > rq_vec [ v ] . iov_len = len ;
2007-05-09 13:34:48 +04:00
args - > vlen = v + 1 ;
return 1 ;
2005-04-17 02:20:36 +04:00
}
int
2006-10-20 10:28:56 +04:00
nfssvc_decode_createargs ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_createargs * args )
{
2007-05-09 13:34:57 +04:00
if ( ! ( p = decode_fh ( p , & args - > fh ) )
| | ! ( p = decode_filename ( p , & args - > name , & args - > len ) ) )
2005-04-17 02:20:36 +04:00
return 0 ;
2007-05-09 13:34:57 +04:00
p = decode_sattr ( p , & args - > attrs ) ;
2005-04-17 02:20:36 +04:00
return xdr_argsize_check ( rqstp , p ) ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_decode_renameargs ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_renameargs * args )
{
if ( ! ( p = decode_fh ( p , & args - > ffh ) )
| | ! ( p = decode_filename ( p , & args - > fname , & args - > flen ) )
| | ! ( p = decode_fh ( p , & args - > tfh ) )
| | ! ( p = decode_filename ( p , & args - > tname , & args - > tlen ) ) )
return 0 ;
return xdr_argsize_check ( rqstp , p ) ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_decode_readlinkargs ( struct svc_rqst * rqstp , __be32 * p , struct nfsd_readlinkargs * args )
2005-04-17 02:20:36 +04:00
{
2014-05-22 18:32:30 +04:00
p = decode_fh ( p , & args - > fh ) ;
if ( ! p )
2005-04-17 02:20:36 +04:00
return 0 ;
2012-12-11 03:01:37 +04:00
args - > buffer = page_address ( * ( rqstp - > rq_next_page + + ) ) ;
2005-04-17 02:20:36 +04:00
return xdr_argsize_check ( rqstp , p ) ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_decode_linkargs ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_linkargs * args )
{
if ( ! ( p = decode_fh ( p , & args - > ffh ) )
| | ! ( p = decode_fh ( p , & args - > tfh ) )
| | ! ( p = decode_filename ( p , & args - > tname , & args - > tlen ) ) )
return 0 ;
return xdr_argsize_check ( rqstp , p ) ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_decode_symlinkargs ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_symlinkargs * args )
{
2007-05-09 13:34:57 +04:00
if ( ! ( p = decode_fh ( p , & args - > ffh ) )
| | ! ( p = decode_filename ( p , & args - > fname , & args - > flen ) )
| | ! ( p = decode_pathname ( p , & args - > tname , & args - > tlen ) ) )
2005-04-17 02:20:36 +04:00
return 0 ;
2007-05-09 13:34:57 +04:00
p = decode_sattr ( p , & args - > attrs ) ;
2005-04-17 02:20:36 +04:00
return xdr_argsize_check ( rqstp , p ) ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_decode_readdirargs ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_readdirargs * args )
{
2014-05-22 18:32:30 +04:00
p = decode_fh ( p , & args - > fh ) ;
if ( ! p )
2005-04-17 02:20:36 +04:00
return 0 ;
args - > cookie = ntohl ( * p + + ) ;
args - > count = ntohl ( * p + + ) ;
2014-06-10 14:08:19 +04:00
args - > count = min_t ( u32 , args - > count , PAGE_SIZE ) ;
2012-12-11 03:01:37 +04:00
args - > buffer = page_address ( * ( rqstp - > rq_next_page + + ) ) ;
2005-04-17 02:20:36 +04:00
return xdr_argsize_check ( rqstp , p ) ;
}
/*
* XDR encode functions
*/
int
2006-10-20 10:28:56 +04:00
nfssvc_encode_void ( struct svc_rqst * rqstp , __be32 * p , void * dummy )
2005-04-17 02:20:36 +04:00
{
return xdr_ressize_check ( rqstp , p ) ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_encode_attrstat ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_attrstat * resp )
{
2006-01-06 11:19:58 +03:00
p = encode_fattr ( rqstp , p , & resp - > fh , & resp - > stat ) ;
2005-04-17 02:20:36 +04:00
return xdr_ressize_check ( rqstp , p ) ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_encode_diropres ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_diropres * resp )
{
p = encode_fh ( p , & resp - > fh ) ;
2006-01-06 11:19:58 +03:00
p = encode_fattr ( rqstp , p , & resp - > fh , & resp - > stat ) ;
2005-04-17 02:20:36 +04:00
return xdr_ressize_check ( rqstp , p ) ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_encode_readlinkres ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_readlinkres * resp )
{
* p + + = htonl ( resp - > len ) ;
xdr_ressize_check ( rqstp , p ) ;
rqstp - > rq_res . page_len = resp - > len ;
if ( resp - > len & 3 ) {
/* need to pad the tail */
rqstp - > rq_res . tail [ 0 ] . iov_base = p ;
* p = 0 ;
rqstp - > rq_res . tail [ 0 ] . iov_len = 4 - ( resp - > len & 3 ) ;
}
return 1 ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_encode_readres ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_readres * resp )
{
2006-01-06 11:19:58 +03:00
p = encode_fattr ( rqstp , p , & resp - > fh , & resp - > stat ) ;
2005-04-17 02:20:36 +04:00
* p + + = htonl ( resp - > count ) ;
xdr_ressize_check ( rqstp , p ) ;
2011-03-31 05:57:33 +04:00
/* now update rqstp->rq_res to reflect data as well */
2005-04-17 02:20:36 +04:00
rqstp - > rq_res . page_len = resp - > count ;
if ( resp - > count & 3 ) {
/* need to pad the tail */
rqstp - > rq_res . tail [ 0 ] . iov_base = p ;
* p = 0 ;
rqstp - > rq_res . tail [ 0 ] . iov_len = 4 - ( resp - > count & 3 ) ;
}
return 1 ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_encode_readdirres ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_readdirres * resp )
{
xdr_ressize_check ( rqstp , p ) ;
p = resp - > buffer ;
* p + + = 0 ; /* no more entries */
* p + + = htonl ( ( resp - > common . err = = nfserr_eof ) ) ;
rqstp - > rq_res . page_len = ( ( ( unsigned long ) p - 1 ) & ~ PAGE_MASK ) + 1 ;
return 1 ;
}
int
2006-10-20 10:28:56 +04:00
nfssvc_encode_statfsres ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_statfsres * resp )
{
struct kstatfs * stat = & resp - > stats ;
2006-10-04 13:15:47 +04:00
* p + + = htonl ( NFSSVC_MAXBLKSIZE_V2 ) ; /* max transfer size */
2005-04-17 02:20:36 +04:00
* p + + = htonl ( stat - > f_bsize ) ;
* p + + = htonl ( stat - > f_blocks ) ;
* p + + = htonl ( stat - > f_bfree ) ;
* p + + = htonl ( stat - > f_bavail ) ;
return xdr_ressize_check ( rqstp , p ) ;
}
int
2007-01-26 11:57:10 +03:00
nfssvc_encode_entry ( void * ccdv , const char * name ,
int namlen , loff_t offset , u64 ino , unsigned int d_type )
2005-04-17 02:20:36 +04:00
{
2007-01-26 11:57:10 +03:00
struct readdir_cd * ccd = ccdv ;
2005-04-17 02:20:36 +04:00
struct nfsd_readdirres * cd = container_of ( ccd , struct nfsd_readdirres , common ) ;
2006-10-20 10:28:56 +04:00
__be32 * p = cd - > buffer ;
2005-04-17 02:20:36 +04:00
int buflen , slen ;
/*
dprintk ( " nfsd: entry(%.*s off %ld ino %ld) \n " ,
namlen , name , offset , ino ) ;
*/
if ( offset > ~ ( ( u32 ) 0 ) ) {
cd - > common . err = nfserr_fbig ;
return - EINVAL ;
}
if ( cd - > offset )
* cd - > offset = htonl ( offset ) ;
2014-06-10 14:08:19 +04:00
/* truncate filename */
namlen = min ( namlen , NFS2_MAXNAMLEN ) ;
2005-04-17 02:20:36 +04:00
slen = XDR_QUADLEN ( namlen ) ;
2014-06-10 14:08:19 +04:00
2005-04-17 02:20:36 +04:00
if ( ( buflen = cd - > buflen - slen - 4 ) < 0 ) {
cd - > common . err = nfserr_toosmall ;
return - EINVAL ;
}
2007-08-16 20:10:07 +04:00
if ( ino > ~ ( ( u32 ) 0 ) ) {
cd - > common . err = nfserr_fbig ;
return - EINVAL ;
}
2005-04-17 02:20:36 +04:00
* p + + = xdr_one ; /* mark entry present */
* p + + = htonl ( ( u32 ) ino ) ; /* file id */
p = xdr_encode_array ( p , name , namlen ) ; /* name length & name */
cd - > offset = p ; /* remember pointer */
2006-10-20 10:28:56 +04:00
* p + + = htonl ( ~ 0U ) ; /* offset of next entry */
2005-04-17 02:20:36 +04:00
cd - > buflen = buflen ;
cd - > buffer = p ;
cd - > common . err = nfs_ok ;
return 0 ;
}
/*
* XDR release functions
*/
int
2006-10-20 10:28:56 +04:00
nfssvc_release_fhandle ( struct svc_rqst * rqstp , __be32 * p ,
2005-04-17 02:20:36 +04:00
struct nfsd_fhandle * resp )
{
fh_put ( & resp - > fh ) ;
return 1 ;
}