2005-04-17 02:20:36 +04:00
/*
* XDR support for nfsd / protocol version 3.
*
* Copyright ( C ) 1995 , 1996 , 1997 Olaf Kirch < okir @ monad . swb . de >
*
* 2003 - 08 - 09 Jamie Lokier : Use htonl ( ) for nanoseconds , not htons ( ) !
*/
# include <linux/namei.h>
2012-12-06 15:23:19 +04:00
# include <linux/sunrpc/svc_xprt.h>
2009-12-03 21:30:56 +03:00
# include "xdr3.h"
2007-11-16 01:05:43 +03:00
# include "auth.h"
2012-12-06 15:23:19 +04:00
# include "netns.h"
2013-01-24 11:18:08 +04:00
# include "vfs.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 nfs3_ftypes [ ] = {
NF3NON , NF3FIFO , NF3CHR , NF3BAD ,
NF3DIR , NF3BAD , NF3BLK , NF3BAD ,
NF3REG , NF3BAD , NF3LNK , NF3BAD ,
NF3SOCK , NF3BAD , NF3LNK , NF3BAD ,
} ;
/*
* XDR functions for basic NFS types
*/
2006-12-07 07:40:23 +03:00
static __be32 *
2006-10-20 10:28:57 +04:00
encode_time3 ( __be32 * p , struct timespec * time )
2005-04-17 02:20:36 +04:00
{
* p + + = htonl ( ( u32 ) time - > tv_sec ) ; * p + + = htonl ( time - > tv_nsec ) ;
return p ;
}
2006-12-07 07:40:23 +03:00
static __be32 *
2006-10-20 10:28:57 +04:00
decode_time3 ( __be32 * p , struct timespec * time )
2005-04-17 02:20:36 +04:00
{
time - > tv_sec = ntohl ( * p + + ) ;
time - > tv_nsec = ntohl ( * p + + ) ;
return p ;
}
2006-12-07 07:40:23 +03:00
static __be32 *
2006-10-20 10:28:57 +04:00
decode_fh ( __be32 * p , struct svc_fh * fhp )
2005-04-17 02:20:36 +04:00
{
unsigned int size ;
fh_init ( fhp , NFS3_FHSIZE ) ;
size = ntohl ( * p + + ) ;
if ( size > NFS3_FHSIZE )
return NULL ;
memcpy ( & fhp - > fh_handle . fh_base , p , size ) ;
fhp - > fh_handle . fh_size = size ;
return p + XDR_QUADLEN ( size ) ;
}
2005-06-22 21:16:26 +04:00
/* Helper function for NFSv3 ACL code */
2006-10-20 10:28:57 +04:00
__be32 * nfs3svc_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:57 +04:00
encode_fh ( __be32 * p , struct svc_fh * fhp )
2005-04-17 02:20:36 +04:00
{
unsigned int size = fhp - > fh_handle . fh_size ;
* p + + = htonl ( size ) ;
if ( size ) p [ XDR_QUADLEN ( size ) - 1 ] = 0 ;
memcpy ( p , & fhp - > fh_handle . fh_base , size ) ;
return p + XDR_QUADLEN ( size ) ;
}
/*
* 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 , NFS3_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 *
2006-10-20 10:28:57 +04:00
decode_sattr3 ( __be32 * p , struct iattr * iap )
2005-04-17 02:20:36 +04:00
{
u32 tmp ;
iap - > ia_valid = 0 ;
if ( * p + + ) {
iap - > ia_valid | = ATTR_MODE ;
iap - > ia_mode = ntohl ( * p + + ) ;
}
if ( * p + + ) {
2013-02-02 16:16:08 +04:00
iap - > ia_uid = make_kuid ( & init_user_ns , ntohl ( * p + + ) ) ;
if ( uid_valid ( iap - > ia_uid ) )
iap - > ia_valid | = ATTR_UID ;
2005-04-17 02:20:36 +04:00
}
if ( * p + + ) {
2013-02-02 16:16:08 +04:00
iap - > ia_gid = make_kgid ( & init_user_ns , ntohl ( * p + + ) ) ;
if ( gid_valid ( iap - > ia_gid ) )
iap - > ia_valid | = ATTR_GID ;
2005-04-17 02:20:36 +04:00
}
if ( * p + + ) {
u64 newsize ;
iap - > ia_valid | = ATTR_SIZE ;
p = xdr_decode_hyper ( p , & newsize ) ;
2014-06-10 14:08:19 +04:00
iap - > ia_size = min_t ( u64 , newsize , NFS_OFFSET_MAX ) ;
2005-04-17 02:20:36 +04:00
}
if ( ( tmp = ntohl ( * p + + ) ) = = 1 ) { /* set to server time */
iap - > ia_valid | = ATTR_ATIME ;
} else if ( tmp = = 2 ) { /* set to client time */
iap - > ia_valid | = ATTR_ATIME | ATTR_ATIME_SET ;
iap - > ia_atime . tv_sec = ntohl ( * p + + ) ;
iap - > ia_atime . tv_nsec = ntohl ( * p + + ) ;
}
if ( ( tmp = ntohl ( * p + + ) ) = = 1 ) { /* set to server time */
iap - > ia_valid | = ATTR_MTIME ;
} else if ( tmp = = 2 ) { /* set to client time */
iap - > ia_valid | = ATTR_MTIME | ATTR_MTIME_SET ;
iap - > ia_mtime . tv_sec = ntohl ( * p + + ) ;
iap - > ia_mtime . tv_nsec = ntohl ( * p + + ) ;
}
return p ;
}
2007-02-14 11:33:12 +03:00
static __be32 * encode_fsid ( __be32 * p , struct svc_fh * fhp )
{
u64 f ;
switch ( fsid_source ( fhp ) ) {
default :
case FSIDSOURCE_DEV :
p = xdr_encode_hyper ( p , ( u64 ) huge_encode_dev
2016-04-10 08:33:30 +03:00
( fhp - > fh_dentry - > d_sb - > s_dev ) ) ;
2007-02-14 11:33:12 +03:00
break ;
case FSIDSOURCE_FSID :
p = xdr_encode_hyper ( p , ( u64 ) fhp - > fh_export - > ex_fsid ) ;
break ;
case FSIDSOURCE_UUID :
f = ( ( u64 * ) fhp - > fh_export - > ex_uuid ) [ 0 ] ;
f ^ = ( ( u64 * ) fhp - > fh_export - > ex_uuid ) [ 1 ] ;
p = xdr_encode_hyper ( p , f ) ;
break ;
}
return p ;
}
2006-12-07 07:40:23 +03:00
static __be32 *
2006-10-20 10:28:57 +04:00
encode_fattr3 ( 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
{
2006-01-06 11:19:58 +03:00
* p + + = htonl ( nfs3_ftypes [ ( stat - > mode & S_IFMT ) > > 12 ] ) ;
2013-11-18 21:18:01 +04:00
* p + + = htonl ( ( u32 ) ( stat - > mode & S_IALLUGO ) ) ;
2006-01-06 11:19:58 +03:00
* p + + = htonl ( ( u32 ) stat - > nlink ) ;
2013-02-02 16:16:08 +04:00
* p + + = htonl ( ( u32 ) from_kuid ( & init_user_ns , stat - > uid ) ) ;
* p + + = htonl ( ( u32 ) from_kgid ( & init_user_ns , stat - > gid ) ) ;
2006-01-06 11:19:58 +03:00
if ( S_ISLNK ( stat - > mode ) & & stat - > size > NFS3_MAXPATHLEN ) {
2005-04-17 02:20:36 +04:00
p = xdr_encode_hyper ( p , ( u64 ) NFS3_MAXPATHLEN ) ;
} else {
2006-01-06 11:19:58 +03:00
p = xdr_encode_hyper ( p , ( u64 ) stat - > size ) ;
2005-04-17 02:20:36 +04:00
}
2006-01-06 11:19:58 +03:00
p = xdr_encode_hyper ( p , ( ( u64 ) stat - > blocks ) < < 9 ) ;
* p + + = htonl ( ( u32 ) MAJOR ( stat - > rdev ) ) ;
* p + + = htonl ( ( u32 ) MINOR ( stat - > rdev ) ) ;
2007-02-14 11:33:12 +03:00
p = encode_fsid ( p , fhp ) ;
2007-08-16 20:10:07 +04:00
p = xdr_encode_hyper ( p , stat - > ino ) ;
2006-01-06 11:19:58 +03:00
p = encode_time3 ( p , & stat - > atime ) ;
2007-08-16 20:10:07 +04:00
p = encode_time3 ( p , & stat - > mtime ) ;
2006-01-06 11:19:58 +03:00
p = encode_time3 ( p , & stat - > ctime ) ;
2005-04-17 02:20:36 +04:00
return p ;
}
2006-12-07 07:40:23 +03:00
static __be32 *
2006-10-20 10:28:57 +04:00
encode_saved_post_attr ( struct svc_rqst * rqstp , __be32 * p , struct svc_fh * fhp )
2005-04-17 02:20:36 +04:00
{
/* Attributes to follow */
* p + + = xdr_one ;
2007-08-16 20:10:07 +04:00
return encode_fattr3 ( rqstp , p , fhp , & fhp - > fh_post_attr ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Encode post - operation attributes .
* The inode may be NULL if the call failed because of a stale file
* handle . In this case , no attributes are returned .
*/
2006-10-20 10:28:57 +04:00
static __be32 *
encode_post_op_attr ( struct svc_rqst * rqstp , __be32 * p , struct svc_fh * fhp )
2005-04-17 02:20:36 +04:00
{
struct dentry * dentry = fhp - > fh_dentry ;
2015-03-18 01:25:59 +03:00
if ( dentry & & d_really_is_positive ( dentry ) ) {
2013-01-24 11:18:08 +04:00
__be32 err ;
2006-01-06 11:19:58 +03:00
struct kstat stat ;
2013-01-24 11:18:08 +04:00
err = fh_getattr ( fhp , & stat ) ;
2006-01-06 11:19:58 +03:00
if ( ! err ) {
* p + + = xdr_one ; /* attributes follow */
2015-03-18 01:25:59 +03:00
lease_get_mtime ( d_inode ( dentry ) , & stat . mtime ) ;
2006-01-06 11:19:58 +03:00
return encode_fattr3 ( rqstp , p , fhp , & stat ) ;
}
2005-04-17 02:20:36 +04:00
}
* p + + = xdr_zero ;
return p ;
}
2005-06-22 21:16:26 +04:00
/* Helper for NFSv3 ACLs */
2006-10-20 10:28:57 +04:00
__be32 *
nfs3svc_encode_post_op_attr ( struct svc_rqst * rqstp , __be32 * p , struct svc_fh * fhp )
2005-06-22 21:16:26 +04:00
{
return encode_post_op_attr ( rqstp , p , fhp ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Enocde weak cache consistency data
*/
2006-10-20 10:28:57 +04:00
static __be32 *
encode_wcc_data ( struct svc_rqst * rqstp , __be32 * p , struct svc_fh * fhp )
2005-04-17 02:20:36 +04:00
{
struct dentry * dentry = fhp - > fh_dentry ;
2015-03-18 01:25:59 +03:00
if ( dentry & & d_really_is_positive ( dentry ) & & fhp - > fh_post_saved ) {
2005-04-17 02:20:36 +04:00
if ( fhp - > fh_pre_saved ) {
* p + + = xdr_one ;
p = xdr_encode_hyper ( p , ( u64 ) fhp - > fh_pre_size ) ;
p = encode_time3 ( p , & fhp - > fh_pre_mtime ) ;
p = encode_time3 ( p , & fhp - > fh_pre_ctime ) ;
} else {
* p + + = xdr_zero ;
}
return encode_saved_post_attr ( rqstp , p , fhp ) ;
}
/* no pre- or post-attrs */
* p + + = xdr_zero ;
return encode_post_op_attr ( rqstp , p , fhp ) ;
}
2007-08-16 20:10:07 +04:00
/*
* Fill in the post_op attr for the wcc data
*/
void fill_post_wcc ( struct svc_fh * fhp )
{
2013-01-24 11:18:08 +04:00
__be32 err ;
2007-08-16 20:10:07 +04:00
if ( fhp - > fh_post_saved )
printk ( " nfsd: inode locked twice during operation. \n " ) ;
2013-01-24 11:18:08 +04:00
err = fh_getattr ( fhp , & fhp - > fh_post_attr ) ;
2017-05-11 21:45:06 +03:00
fhp - > fh_post_change = nfsd4_change_attribute ( d_inode ( fhp - > fh_dentry ) ) ;
2010-12-02 03:14:30 +03:00
if ( err ) {
2015-09-17 15:28:39 +03:00
fhp - > fh_post_saved = false ;
2010-12-02 03:14:30 +03:00
/* Grab the ctime anyway - set_change_info might use it */
2015-03-18 01:25:59 +03:00
fhp - > fh_post_attr . ctime = d_inode ( fhp - > fh_dentry ) - > i_ctime ;
2010-12-02 03:14:30 +03:00
} else
2015-09-17 15:28:39 +03:00
fhp - > fh_post_saved = true ;
2007-08-16 20:10:07 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* XDR decode functions
*/
int
2017-05-08 20:01:48 +03:00
nfs3svc_decode_fhandle ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd_fhandle * args = rqstp - > rq_argp ;
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
2017-05-08 20:01:48 +03:00
nfs3svc_decode_sattrargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_sattrargs * args = rqstp - > rq_argp ;
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 ;
2007-05-09 13:34:57 +04:00
p = decode_sattr3 ( p , & args - > attrs ) ;
2005-04-17 02:20:36 +04:00
if ( ( args - > check_guard = ntohl ( * p + + ) ) ! = 0 ) {
struct timespec time ;
p = decode_time3 ( p , & time ) ;
args - > guardtime = time . tv_sec ;
}
return xdr_argsize_check ( rqstp , p ) ;
}
int
2017-05-08 20:01:48 +03:00
nfs3svc_decode_diropargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_diropargs * args = rqstp - > rq_argp ;
2005-04-17 02:20:36 +04:00
if ( ! ( p = decode_fh ( p , & args - > fh ) )
| | ! ( p = decode_filename ( p , & args - > name , & args - > len ) ) )
return 0 ;
return xdr_argsize_check ( rqstp , p ) ;
}
int
2017-05-08 20:01:48 +03:00
nfs3svc_decode_accessargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_accessargs * args = rqstp - > rq_argp ;
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 - > access = ntohl ( * p + + ) ;
return xdr_argsize_check ( rqstp , p ) ;
}
int
2017-05-08 20:01:48 +03:00
nfs3svc_decode_readargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_readargs * args = rqstp - > rq_argp ;
2005-04-17 02:20:36 +04:00
unsigned int len ;
2012-12-11 03:01:37 +04:00
int v ;
2006-10-04 13:15:47 +04:00
u32 max_blocksize = svc_max_payload ( rqstp ) ;
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 ;
2007-05-09 13:34:57 +04:00
p = xdr_decode_hyper ( p , & args - > offset ) ;
2017-04-07 05:36:31 +03:00
2017-05-16 22:57:42 +03:00
args - > count = ntohl ( * p + + ) ;
2014-06-10 14:08:19 +04:00
len = min ( args - > count , max_blocksize ) ;
2005-04-17 02:20:36 +04:00
/* set up the kvec */
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 ;
2017-05-16 22:57:42 +03:00
return xdr_argsize_check ( rqstp , p ) ;
2005-04-17 02:20:36 +04:00
}
int
2017-05-08 20:01:48 +03:00
nfs3svc_decode_writeargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_writeargs * args = rqstp - > rq_argp ;
2007-05-09 13:34:48 +04:00
unsigned int len , v , hdr , dlen ;
2006-10-04 13:15:47 +04:00
u32 max_blocksize = svc_max_payload ( rqstp ) ;
2017-04-25 23:21:34 +03:00
struct kvec * head = rqstp - > rq_arg . head ;
struct kvec * tail = rqstp - > rq_arg . tail ;
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 ;
2007-05-09 13:34:57 +04:00
p = xdr_decode_hyper ( p , & args - > offset ) ;
2005-04-17 02:20:36 +04:00
args - > count = ntohl ( * p + + ) ;
args - > stable = ntohl ( * p + + ) ;
len = args - > len = ntohl ( * p + + ) ;
2017-04-21 22:26:30 +03:00
if ( ( void * ) p > head - > iov_base + head - > iov_len )
return 0 ;
2007-05-09 13:34:48 +04:00
/*
* The count must equal the amount of data passed .
*/
if ( args - > count ! = args - > len )
return 0 ;
2005-04-17 02:20:36 +04:00
2007-05-09 13:34:48 +04:00
/*
* Check to make sure that we got the right number of
* bytes .
*/
2017-04-25 23:21:34 +03:00
hdr = ( void * ) p - head - > iov_base ;
dlen = head - > iov_len + rqstp - > rq_arg . page_len + tail - > iov_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 )
2005-04-17 02:20:36 +04:00
return 0 ;
2007-05-09 13:34:48 +04:00
if ( args - > count > max_blocksize ) {
args - > count = max_blocksize ;
len = args - > len = max_blocksize ;
}
2006-10-04 13:15:47 +04:00
rqstp - > rq_vec [ 0 ] . iov_base = ( void * ) p ;
2017-04-25 23:21:34 +03:00
rqstp - > rq_vec [ 0 ] . iov_len = head - > iov_len - hdr ;
2007-05-09 13:34:48 +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
2017-05-08 20:01:48 +03:00
nfs3svc_decode_createargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_createargs * args = rqstp - > rq_argp ;
2005-04-17 02:20:36 +04:00
if ( ! ( p = decode_fh ( p , & args - > fh ) )
| | ! ( p = decode_filename ( p , & args - > name , & args - > len ) ) )
return 0 ;
switch ( args - > createmode = ntohl ( * p + + ) ) {
case NFS3_CREATE_UNCHECKED :
case NFS3_CREATE_GUARDED :
2007-05-09 13:34:57 +04:00
p = decode_sattr3 ( p , & args - > attrs ) ;
2005-04-17 02:20:36 +04:00
break ;
case NFS3_CREATE_EXCLUSIVE :
args - > verf = p ;
p + = 2 ;
break ;
default :
return 0 ;
}
return xdr_argsize_check ( rqstp , p ) ;
}
2017-05-08 20:01:48 +03:00
2005-04-17 02:20:36 +04:00
int
2017-05-08 20:01:48 +03:00
nfs3svc_decode_mkdirargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_createargs * args = rqstp - > rq_argp ;
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_sattr3 ( p , & args - > attrs ) ;
2005-04-17 02:20:36 +04:00
return xdr_argsize_check ( rqstp , p ) ;
}
int
2017-05-08 20:01:48 +03:00
nfs3svc_decode_symlinkargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_symlinkargs * args = rqstp - > rq_argp ;
2007-11-01 23:57:20 +03:00
unsigned int len , avail ;
2005-04-17 02:20:36 +04:00
char * old , * new ;
struct kvec * vec ;
2007-05-09 13:34:57 +04:00
if ( ! ( p = decode_fh ( p , & args - > ffh ) ) | |
! ( p = decode_filename ( p , & args - > fname , & args - > flen ) )
2005-04-17 02:20:36 +04:00
)
return 0 ;
2007-05-09 13:34:57 +04:00
p = decode_sattr3 ( p , & args - > attrs ) ;
2005-04-17 02:20:36 +04:00
/* now decode the pathname, which might be larger than the first page.
* As we have to check for nul ' s anyway , we copy it into a new page
* This page appears in the rq_res . pages list , but as pages_len is always
* 0 , it won ' t get in the way
*/
len = ntohl ( * p + + ) ;
if ( len = = 0 | | len > NFS3_MAXPATHLEN | | len > = PAGE_SIZE )
return 0 ;
2012-12-11 03:01:37 +04:00
args - > tname = new = page_address ( * ( rqstp - > rq_next_page + + ) ) ;
2005-04-17 02:20:36 +04:00
args - > tlen = len ;
/* first copy and check from the first page */
old = ( char * ) p ;
vec = & rqstp - > rq_arg . head [ 0 ] ;
2017-04-21 22:26:30 +03:00
if ( ( void * ) old > vec - > iov_base + vec - > iov_len )
return 0 ;
2005-04-17 02:20:36 +04:00
avail = vec - > iov_len - ( old - ( char * ) vec - > iov_base ) ;
while ( len & & avail & & * old ) {
* new + + = * old + + ;
len - - ;
avail - - ;
}
/* now copy next page if there is one */
if ( len & & ! avail & & rqstp - > rq_arg . page_len ) {
2014-06-10 14:08:19 +04:00
avail = min_t ( unsigned int , rqstp - > rq_arg . page_len , PAGE_SIZE ) ;
2005-04-17 02:20:36 +04:00
old = page_address ( rqstp - > rq_arg . pages [ 0 ] ) ;
}
while ( len & & avail & & * old ) {
* new + + = * old + + ;
len - - ;
avail - - ;
}
* new = ' \0 ' ;
if ( len )
return 0 ;
return 1 ;
}
int
2017-05-08 20:01:48 +03:00
nfs3svc_decode_mknodargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_mknodargs * args = rqstp - > rq_argp ;
2005-04-17 02:20:36 +04:00
if ( ! ( p = decode_fh ( p , & args - > fh ) )
| | ! ( p = decode_filename ( p , & args - > name , & args - > len ) ) )
return 0 ;
args - > ftype = ntohl ( * p + + ) ;
if ( args - > ftype = = NF3BLK | | args - > ftype = = NF3CHR
2007-05-09 13:34:57 +04:00
| | args - > ftype = = NF3SOCK | | args - > ftype = = NF3FIFO )
p = decode_sattr3 ( p , & args - > attrs ) ;
2005-04-17 02:20:36 +04:00
if ( args - > ftype = = NF3BLK | | args - > ftype = = NF3CHR ) {
args - > major = ntohl ( * p + + ) ;
args - > minor = ntohl ( * p + + ) ;
}
return xdr_argsize_check ( rqstp , p ) ;
}
int
2017-05-08 20:01:48 +03:00
nfs3svc_decode_renameargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_renameargs * args = rqstp - > rq_argp ;
2005-04-17 02:20:36 +04:00
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
2017-05-08 20:01:48 +03:00
nfs3svc_decode_readlinkargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_readlinkargs * args = rqstp - > rq_argp ;
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
2017-05-16 22:57:42 +03:00
return xdr_argsize_check ( rqstp , p ) ;
2005-04-17 02:20:36 +04:00
}
int
2017-05-08 20:01:48 +03:00
nfs3svc_decode_linkargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_linkargs * args = rqstp - > rq_argp ;
2005-04-17 02:20:36 +04:00
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
2017-05-08 20:01:48 +03:00
nfs3svc_decode_readdirargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_readdirargs * args = rqstp - > rq_argp ;
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 = xdr_decode_hyper ( p , & args - > cookie ) ;
args - > verf = p ; p + = 2 ;
args - > dircount = ~ 0 ;
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
2017-05-16 22:57:42 +03:00
return xdr_argsize_check ( rqstp , p ) ;
2005-04-17 02:20:36 +04:00
}
int
2017-05-08 20:01:48 +03:00
nfs3svc_decode_readdirplusargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_readdirargs * args = rqstp - > rq_argp ;
2012-12-11 03:01:37 +04:00
int len ;
2006-10-04 13:15:47 +04:00
u32 max_blocksize = svc_max_payload ( rqstp ) ;
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 ;
p = xdr_decode_hyper ( p , & args - > cookie ) ;
args - > verf = p ; p + = 2 ;
args - > dircount = ntohl ( * p + + ) ;
args - > count = ntohl ( * p + + ) ;
2014-06-10 14:08:19 +04:00
len = args - > count = min ( args - > count , max_blocksize ) ;
2005-04-17 02:20:36 +04:00
while ( len > 0 ) {
2012-12-11 03:01:37 +04:00
struct page * p = * ( rqstp - > rq_next_page + + ) ;
2005-04-17 02:20:36 +04:00
if ( ! args - > buffer )
2012-12-11 03:01:37 +04:00
args - > buffer = page_address ( p ) ;
2005-04-17 02:20:36 +04:00
len - = PAGE_SIZE ;
}
2017-05-16 22:57:42 +03:00
return xdr_argsize_check ( rqstp , p ) ;
2005-04-17 02:20:36 +04:00
}
int
2017-05-08 20:01:48 +03:00
nfs3svc_decode_commitargs ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:01:48 +03:00
struct nfsd3_commitargs * args = rqstp - > rq_argp ;
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 = xdr_decode_hyper ( p , & args - > offset ) ;
args - > count = ntohl ( * p + + ) ;
return xdr_argsize_check ( rqstp , p ) ;
}
/*
* XDR encode functions
*/
/*
* There must be an encoding function for void results so svc_process
* will work properly .
*/
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_voidres ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
return xdr_ressize_check ( rqstp , p ) ;
}
/* GETATTR */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_attrstat ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_attrstat * resp = rqstp - > rq_resp ;
2007-08-16 20:10:07 +04:00
if ( resp - > status = = 0 ) {
2015-03-18 01:25:59 +03:00
lease_get_mtime ( d_inode ( resp - > fh . fh_dentry ) ,
2007-08-16 20:10:07 +04:00
& resp - > stat . mtime ) ;
2006-01-06 11:19:58 +03:00
p = encode_fattr3 ( rqstp , p , & resp - > fh , & resp - > stat ) ;
2007-08-16 20:10:07 +04:00
}
2005-04-17 02:20:36 +04:00
return xdr_ressize_check ( rqstp , p ) ;
}
/* SETATTR, REMOVE, RMDIR */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_wccstat ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_attrstat * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
p = encode_wcc_data ( rqstp , p , & resp - > fh ) ;
return xdr_ressize_check ( rqstp , p ) ;
}
/* LOOKUP */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_diropres ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_diropres * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
if ( resp - > status = = 0 ) {
p = encode_fh ( p , & resp - > fh ) ;
p = encode_post_op_attr ( rqstp , p , & resp - > fh ) ;
}
p = encode_post_op_attr ( rqstp , p , & resp - > dirfh ) ;
return xdr_ressize_check ( rqstp , p ) ;
}
/* ACCESS */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_accessres ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_accessres * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
p = encode_post_op_attr ( rqstp , p , & resp - > fh ) ;
if ( resp - > status = = 0 )
* p + + = htonl ( resp - > access ) ;
return xdr_ressize_check ( rqstp , p ) ;
}
/* READLINK */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_readlinkres ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_readlinkres * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
p = encode_post_op_attr ( rqstp , p , & resp - > fh ) ;
if ( resp - > status = = 0 ) {
* 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 ;
} else
return xdr_ressize_check ( rqstp , p ) ;
}
/* READ */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_readres ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_readres * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
p = encode_post_op_attr ( rqstp , p , & resp - > fh ) ;
if ( resp - > status = = 0 ) {
* p + + = htonl ( resp - > count ) ;
* p + + = htonl ( resp - > eof ) ;
* p + + = htonl ( resp - > count ) ; /* xdr opaque 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 ;
} else
return xdr_ressize_check ( rqstp , p ) ;
}
/* WRITE */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_writeres ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_writeres * resp = rqstp - > rq_resp ;
2012-12-06 15:23:19 +04:00
struct nfsd_net * nn = net_generic ( SVC_NET ( rqstp ) , nfsd_net_id ) ;
2005-04-17 02:20:36 +04:00
p = encode_wcc_data ( rqstp , p , & resp - > fh ) ;
if ( resp - > status = = 0 ) {
* p + + = htonl ( resp - > count ) ;
* p + + = htonl ( resp - > committed ) ;
2012-12-06 15:23:19 +04:00
* p + + = htonl ( nn - > nfssvc_boot . tv_sec ) ;
* p + + = htonl ( nn - > nfssvc_boot . tv_usec ) ;
2005-04-17 02:20:36 +04:00
}
return xdr_ressize_check ( rqstp , p ) ;
}
/* CREATE, MKDIR, SYMLINK, MKNOD */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_createres ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_diropres * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
if ( resp - > status = = 0 ) {
* p + + = xdr_one ;
p = encode_fh ( p , & resp - > fh ) ;
p = encode_post_op_attr ( rqstp , p , & resp - > fh ) ;
}
p = encode_wcc_data ( rqstp , p , & resp - > dirfh ) ;
return xdr_ressize_check ( rqstp , p ) ;
}
/* RENAME */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_renameres ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_renameres * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
p = encode_wcc_data ( rqstp , p , & resp - > ffh ) ;
p = encode_wcc_data ( rqstp , p , & resp - > tfh ) ;
return xdr_ressize_check ( rqstp , p ) ;
}
/* LINK */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_linkres ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_linkres * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
p = encode_post_op_attr ( rqstp , p , & resp - > fh ) ;
p = encode_wcc_data ( rqstp , p , & resp - > tfh ) ;
return xdr_ressize_check ( rqstp , p ) ;
}
/* READDIR */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_readdirres ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_readdirres * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
p = encode_post_op_attr ( rqstp , p , & resp - > fh ) ;
if ( resp - > status = = 0 ) {
/* stupid readdir cookie */
memcpy ( p , resp - > verf , 8 ) ; p + = 2 ;
xdr_ressize_check ( rqstp , p ) ;
if ( rqstp - > rq_res . head [ 0 ] . iov_len + ( 2 < < 2 ) > PAGE_SIZE )
return 1 ; /*No room for trailer */
rqstp - > rq_res . page_len = ( resp - > count ) < < 2 ;
/* add the 'tail' to the end of the 'head' page - page 0. */
rqstp - > rq_res . tail [ 0 ] . iov_base = p ;
* p + + = 0 ; /* no more entries */
* p + + = htonl ( resp - > common . err = = nfserr_eof ) ;
rqstp - > rq_res . tail [ 0 ] . iov_len = 2 < < 2 ;
return 1 ;
} else
return xdr_ressize_check ( rqstp , p ) ;
}
2006-12-07 07:40:23 +03:00
static __be32 *
2006-10-20 10:28:57 +04:00
encode_entry_baggage ( struct nfsd3_readdirres * cd , __be32 * p , const char * name ,
2007-08-16 20:10:07 +04:00
int namlen , u64 ino )
2005-04-17 02:20:36 +04:00
{
* p + + = xdr_one ; /* mark entry present */
p = xdr_encode_hyper ( p , ino ) ; /* file id */
p = xdr_encode_array ( p , name , namlen ) ; /* name length & name */
cd - > offset = p ; /* remember pointer */
p = xdr_encode_hyper ( p , NFS_OFFSET_MAX ) ; /* offset of next entry */
return p ;
}
2012-04-13 08:32:14 +04:00
static __be32
2005-04-17 02:20:36 +04:00
compose_entry_fh ( struct nfsd3_readdirres * cd , struct svc_fh * fhp ,
2015-05-03 02:16:53 +03:00
const char * name , int namlen , u64 ino )
2005-04-17 02:20:36 +04:00
{
struct svc_export * exp ;
struct dentry * dparent , * dchild ;
2012-04-13 08:32:14 +04:00
__be32 rv = nfserr_noent ;
2005-04-17 02:20:36 +04:00
dparent = cd - > fh . fh_dentry ;
exp = cd - > fh . fh_export ;
if ( isdotent ( name , namlen ) ) {
if ( namlen = = 2 ) {
dchild = dget_parent ( dparent ) ;
2012-04-13 08:32:14 +04:00
/* filesystem root - cannot return filehandle for ".." */
if ( dchild = = dparent )
goto out ;
2005-04-17 02:20:36 +04:00
} else
dchild = dget ( dparent ) ;
} else
2016-01-08 00:08:20 +03:00
dchild = lookup_one_len_unlocked ( name , dparent , namlen ) ;
2005-04-17 02:20:36 +04:00
if ( IS_ERR ( dchild ) )
2012-04-13 08:32:14 +04:00
return rv ;
2009-09-04 22:13:09 +04:00
if ( d_mountpoint ( dchild ) )
goto out ;
2015-03-18 01:25:59 +03:00
if ( d_really_is_negative ( dchild ) )
2009-09-04 22:13:09 +04:00
goto out ;
2015-05-03 02:16:53 +03:00
if ( dchild - > d_inode - > i_ino ! = ino )
goto out ;
2012-04-13 08:32:14 +04:00
rv = fh_compose ( fhp , exp , dchild , & cd - > fh ) ;
2009-09-04 22:13:09 +04:00
out :
2005-04-17 02:20:36 +04:00
dput ( dchild ) ;
return rv ;
}
2015-05-03 02:16:53 +03:00
static __be32 * encode_entryplus_baggage ( struct nfsd3_readdirres * cd , __be32 * p , const char * name , int namlen , u64 ino )
2009-09-04 22:13:09 +04:00
{
2014-01-10 01:24:35 +04:00
struct svc_fh * fh = & cd - > scratch ;
2012-04-13 08:32:14 +04:00
__be32 err ;
2009-09-04 22:13:09 +04:00
2014-01-10 01:24:35 +04:00
fh_init ( fh , NFS3_FHSIZE ) ;
2015-05-03 02:16:53 +03:00
err = compose_entry_fh ( cd , fh , name , namlen , ino ) ;
2009-09-04 22:13:09 +04:00
if ( err ) {
* p + + = 0 ;
* p + + = 0 ;
2009-09-04 22:40:36 +04:00
goto out ;
2009-09-04 22:13:09 +04:00
}
2014-01-10 01:24:35 +04:00
p = encode_post_op_attr ( cd - > rqstp , p , fh ) ;
2009-09-04 22:13:09 +04:00
* p + + = xdr_one ; /* yes, a file handle follows */
2014-01-10 01:24:35 +04:00
p = encode_fh ( p , fh ) ;
2009-09-04 22:40:36 +04:00
out :
2014-01-10 01:24:35 +04:00
fh_put ( fh ) ;
2009-09-04 22:13:09 +04:00
return p ;
}
2005-04-17 02:20:36 +04:00
/*
* Encode a directory entry . This one works for both normal readdir
* and readdirplus .
* The normal readdir reply requires 2 ( fileid ) + 1 ( stringlen )
* + string + 2 ( cookie ) + 1 ( next ) words , i . e . 6 + strlen .
*
* The readdirplus baggage is 1 + 21 words for post_op_attr , plus the
* file handle .
*/
# define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
# define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
static int
2007-03-27 09:32:08 +04:00
encode_entry ( struct readdir_cd * ccd , const char * name , int namlen ,
2007-08-16 20:10:07 +04:00
loff_t offset , u64 ino , unsigned int d_type , int plus )
2005-04-17 02:20:36 +04:00
{
struct nfsd3_readdirres * cd = container_of ( ccd , struct nfsd3_readdirres ,
common ) ;
2006-10-20 10:28:57 +04:00
__be32 * p = cd - > buffer ;
2005-04-17 02:20:36 +04:00
caddr_t curr_page_addr = NULL ;
2012-12-11 03:01:37 +04:00
struct page * * page ;
2005-04-17 02:20:36 +04:00
int slen ; /* string (name) length */
int elen ; /* estimated entry length in words */
int num_entry_words = 0 ; /* actual number of words */
if ( cd - > offset ) {
u64 offset64 = offset ;
if ( unlikely ( cd - > offset1 ) ) {
/* we ended up with offset on a page boundary */
* cd - > offset = htonl ( offset64 > > 32 ) ;
* cd - > offset1 = htonl ( offset64 & 0xffffffff ) ;
cd - > offset1 = NULL ;
} else {
2007-03-27 09:32:08 +04:00
xdr_encode_hyper ( cd - > offset , offset64 ) ;
2005-04-17 02:20:36 +04:00
}
}
/*
dprintk ( " encode_entry(%.*s @%ld%s) \n " ,
namlen , name , ( long ) offset , plus ? " plus " : " " ) ;
*/
/* truncate filename if too long */
2014-06-10 14:08:19 +04:00
namlen = min ( namlen , NFS3_MAXNAMLEN ) ;
2005-04-17 02:20:36 +04:00
slen = XDR_QUADLEN ( namlen ) ;
elen = slen + NFS3_ENTRY_BAGGAGE
+ ( plus ? NFS3_ENTRYPLUS_BAGGAGE : 0 ) ;
if ( cd - > buflen < elen ) {
cd - > common . err = nfserr_toosmall ;
return - EINVAL ;
}
/* determine which page in rq_respages[] we are currently filling */
2012-12-11 03:01:37 +04:00
for ( page = cd - > rqstp - > rq_respages + 1 ;
page < cd - > rqstp - > rq_next_page ; page + + ) {
curr_page_addr = page_address ( * page ) ;
2005-04-17 02:20:36 +04:00
if ( ( ( caddr_t ) cd - > buffer > = curr_page_addr ) & &
( ( caddr_t ) cd - > buffer < curr_page_addr + PAGE_SIZE ) )
break ;
}
if ( ( caddr_t ) ( cd - > buffer + elen ) < ( curr_page_addr + PAGE_SIZE ) ) {
/* encode entry in current page */
p = encode_entry_baggage ( cd , p , name , namlen , ino ) ;
2009-09-04 22:13:09 +04:00
if ( plus )
2015-05-03 02:16:53 +03:00
p = encode_entryplus_baggage ( cd , p , name , namlen , ino ) ;
2005-04-17 02:20:36 +04:00
num_entry_words = p - cd - > buffer ;
2012-12-11 03:01:37 +04:00
} else if ( * ( page + 1 ) ! = NULL ) {
2005-04-17 02:20:36 +04:00
/* temporarily encode entry into next page, then move back to
* current and next page in rq_respages [ ] */
2006-10-20 10:28:57 +04:00
__be32 * p1 , * tmp ;
2005-04-17 02:20:36 +04:00
int len1 , len2 ;
/* grab next page for temporary storage of entry */
2012-12-11 03:01:37 +04:00
p1 = tmp = page_address ( * ( page + 1 ) ) ;
2005-04-17 02:20:36 +04:00
p1 = encode_entry_baggage ( cd , p1 , name , namlen , ino ) ;
2009-09-04 22:13:09 +04:00
if ( plus )
2015-05-03 02:16:53 +03:00
p1 = encode_entryplus_baggage ( cd , p1 , name , namlen , ino ) ;
2005-04-17 02:20:36 +04:00
/* determine entry word length and lengths to go in pages */
num_entry_words = p1 - tmp ;
len1 = curr_page_addr + PAGE_SIZE - ( caddr_t ) cd - > buffer ;
if ( ( num_entry_words < < 2 ) < len1 ) {
/* the actual number of words in the entry is less
* than elen and can still fit in the current page
*/
memmove ( p , tmp , num_entry_words < < 2 ) ;
p + = num_entry_words ;
/* update offset */
cd - > offset = cd - > buffer + ( cd - > offset - tmp ) ;
} else {
unsigned int offset_r = ( cd - > offset - tmp ) < < 2 ;
/* update pointer to offset location.
* This is a 64 bit quantity , so we need to
* deal with 3 cases :
* - entirely in first page
* - entirely in second page
* - 4 bytes in each page
*/
if ( offset_r + 8 < = len1 ) {
cd - > offset = p + ( cd - > offset - tmp ) ;
} else if ( offset_r > = len1 ) {
cd - > offset - = len1 > > 2 ;
} else {
/* sitting on the fence */
BUG_ON ( offset_r ! = len1 - 4 ) ;
cd - > offset = p + ( cd - > offset - tmp ) ;
cd - > offset1 = tmp ;
}
len2 = ( num_entry_words < < 2 ) - len1 ;
/* move from temp page to current and next pages */
memmove ( p , tmp , len1 ) ;
memmove ( tmp , ( caddr_t ) tmp + len1 , len2 ) ;
p = tmp + ( len2 > > 2 ) ;
}
}
else {
cd - > common . err = nfserr_toosmall ;
return - EINVAL ;
}
cd - > buflen - = num_entry_words ;
cd - > buffer = p ;
cd - > common . err = nfs_ok ;
return 0 ;
}
int
2007-01-26 11:57:10 +03:00
nfs3svc_encode_entry ( void * cd , const char * name ,
int namlen , loff_t offset , u64 ino , unsigned int d_type )
2005-04-17 02:20:36 +04:00
{
return encode_entry ( cd , name , namlen , offset , ino , d_type , 0 ) ;
}
int
2007-01-26 11:57:10 +03:00
nfs3svc_encode_entry_plus ( void * cd , const char * name ,
int namlen , loff_t offset , u64 ino ,
unsigned int d_type )
2005-04-17 02:20:36 +04:00
{
return encode_entry ( cd , name , namlen , offset , ino , d_type , 1 ) ;
}
/* FSSTAT */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_fsstatres ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_fsstatres * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
struct kstatfs * s = & resp - > stats ;
u64 bs = s - > f_bsize ;
* p + + = xdr_zero ; /* no post_op_attr */
if ( resp - > status = = 0 ) {
p = xdr_encode_hyper ( p , bs * s - > f_blocks ) ; /* total bytes */
p = xdr_encode_hyper ( p , bs * s - > f_bfree ) ; /* free bytes */
p = xdr_encode_hyper ( p , bs * s - > f_bavail ) ; /* user available bytes */
p = xdr_encode_hyper ( p , s - > f_files ) ; /* total inodes */
p = xdr_encode_hyper ( p , s - > f_ffree ) ; /* free inodes */
p = xdr_encode_hyper ( p , s - > f_ffree ) ; /* user available inodes */
* p + + = htonl ( resp - > invarsec ) ; /* mean unchanged time */
}
return xdr_ressize_check ( rqstp , p ) ;
}
/* FSINFO */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_fsinfores ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_fsinfores * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
* p + + = xdr_zero ; /* no post_op_attr */
if ( resp - > status = = 0 ) {
* p + + = htonl ( resp - > f_rtmax ) ;
* p + + = htonl ( resp - > f_rtpref ) ;
* p + + = htonl ( resp - > f_rtmult ) ;
* p + + = htonl ( resp - > f_wtmax ) ;
* p + + = htonl ( resp - > f_wtpref ) ;
* p + + = htonl ( resp - > f_wtmult ) ;
* p + + = htonl ( resp - > f_dtpref ) ;
p = xdr_encode_hyper ( p , resp - > f_maxfilesize ) ;
* p + + = xdr_one ;
* p + + = xdr_zero ;
* p + + = htonl ( resp - > f_properties ) ;
}
return xdr_ressize_check ( rqstp , p ) ;
}
/* PATHCONF */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_pathconfres ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_pathconfres * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
* p + + = xdr_zero ; /* no post_op_attr */
if ( resp - > status = = 0 ) {
* p + + = htonl ( resp - > p_link_max ) ;
* p + + = htonl ( resp - > p_name_max ) ;
* p + + = htonl ( resp - > p_no_trunc ) ;
* p + + = htonl ( resp - > p_chown_restricted ) ;
* p + + = htonl ( resp - > p_case_insensitive ) ;
* p + + = htonl ( resp - > p_case_preserving ) ;
}
return xdr_ressize_check ( rqstp , p ) ;
}
/* COMMIT */
int
2017-05-08 20:42:02 +03:00
nfs3svc_encode_commitres ( struct svc_rqst * rqstp , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2017-05-08 20:42:02 +03:00
struct nfsd3_commitres * resp = rqstp - > rq_resp ;
2012-12-06 15:23:19 +04:00
struct nfsd_net * nn = net_generic ( SVC_NET ( rqstp ) , nfsd_net_id ) ;
2005-04-17 02:20:36 +04:00
p = encode_wcc_data ( rqstp , p , & resp - > fh ) ;
/* Write verifier */
if ( resp - > status = = 0 ) {
2012-12-06 15:23:19 +04:00
* p + + = htonl ( nn - > nfssvc_boot . tv_sec ) ;
* p + + = htonl ( nn - > nfssvc_boot . tv_usec ) ;
2005-04-17 02:20:36 +04:00
}
return xdr_ressize_check ( rqstp , p ) ;
}
/*
* XDR release functions
*/
2017-05-08 19:48:24 +03:00
void
nfs3svc_release_fhandle ( struct svc_rqst * rqstp )
2005-04-17 02:20:36 +04:00
{
2017-05-08 19:48:24 +03:00
struct nfsd3_attrstat * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
fh_put ( & resp - > fh ) ;
}
2017-05-08 19:48:24 +03:00
void
nfs3svc_release_fhandle2 ( struct svc_rqst * rqstp )
2005-04-17 02:20:36 +04:00
{
2017-05-08 19:48:24 +03:00
struct nfsd3_fhandle_pair * resp = rqstp - > rq_resp ;
2005-04-17 02:20:36 +04:00
fh_put ( & resp - > fh1 ) ;
fh_put ( & resp - > fh2 ) ;
}