2005-04-16 15:20:36 -07:00
/*
* linux / fs / nfs / callback_xdr . c
*
* Copyright ( C ) 2004 Trond Myklebust
*
* NFSv4 callback encode / decode procedures
*/
# include <linux/kernel.h>
# include <linux/sunrpc/svc.h>
# include <linux/nfs4.h>
# include <linux/nfs_fs.h>
2005-06-22 17:16:21 +00:00
# include "nfs4_fs.h"
2005-04-16 15:20:36 -07:00
# include "callback.h"
# define CB_OP_TAGLEN_MAXSZ (512)
# define CB_OP_HDR_RES_MAXSZ (2 + CB_OP_TAGLEN_MAXSZ)
# define CB_OP_GETATTR_BITMAP_MAXSZ (4)
# define CB_OP_GETATTR_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \
CB_OP_GETATTR_BITMAP_MAXSZ + \
2 + 2 + 3 + 3 )
# define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
# define NFSDBG_FACILITY NFSDBG_CALLBACK
2006-10-19 23:28:50 -07:00
typedef __be32 ( * callback_process_op_t ) ( void * , void * ) ;
typedef __be32 ( * callback_decode_arg_t ) ( struct svc_rqst * , struct xdr_stream * , void * ) ;
typedef __be32 ( * callback_encode_res_t ) ( struct svc_rqst * , struct xdr_stream * , void * ) ;
2005-04-16 15:20:36 -07:00
struct callback_op {
callback_process_op_t process_op ;
callback_decode_arg_t decode_args ;
callback_encode_res_t encode_res ;
long res_maxsize ;
} ;
static struct callback_op callback_ops [ ] ;
2006-10-19 23:28:45 -07:00
static __be32 nfs4_callback_null ( struct svc_rqst * rqstp , void * argp , void * resp )
2005-04-16 15:20:36 -07:00
{
return htonl ( NFS4_OK ) ;
}
2006-10-19 23:28:51 -07:00
static int nfs4_decode_void ( struct svc_rqst * rqstp , __be32 * p , void * dummy )
2005-04-16 15:20:36 -07:00
{
return xdr_argsize_check ( rqstp , p ) ;
}
2006-10-19 23:28:51 -07:00
static int nfs4_encode_void ( struct svc_rqst * rqstp , __be32 * p , void * dummy )
2005-04-16 15:20:36 -07:00
{
return xdr_ressize_check ( rqstp , p ) ;
}
2006-10-19 23:28:51 -07:00
static __be32 * read_buf ( struct xdr_stream * xdr , int nbytes )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * p ;
2005-04-16 15:20:36 -07:00
p = xdr_inline_decode ( xdr , nbytes ) ;
if ( unlikely ( p = = NULL ) )
printk ( KERN_WARNING " NFSv4 callback reply buffer overflowed! \n " ) ;
return p ;
}
2006-10-19 23:28:50 -07:00
static __be32 decode_string ( struct xdr_stream * xdr , unsigned int * len , const char * * str )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * p ;
2005-04-16 15:20:36 -07:00
p = read_buf ( xdr , 4 ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
* len = ntohl ( * p ) ;
if ( * len ! = 0 ) {
p = read_buf ( xdr , * len ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
* str = ( const char * ) p ;
} else
* str = NULL ;
return 0 ;
}
2006-10-19 23:28:50 -07:00
static __be32 decode_fh ( struct xdr_stream * xdr , struct nfs_fh * fh )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * p ;
2005-04-16 15:20:36 -07:00
p = read_buf ( xdr , 4 ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
fh - > size = ntohl ( * p ) ;
if ( fh - > size > NFS4_FHSIZE )
return htonl ( NFS4ERR_BADHANDLE ) ;
p = read_buf ( xdr , fh - > size ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
memcpy ( & fh - > data [ 0 ] , p , fh - > size ) ;
memset ( & fh - > data [ fh - > size ] , 0 , sizeof ( fh - > data ) - fh - > size ) ;
return 0 ;
}
2006-10-19 23:28:50 -07:00
static __be32 decode_bitmap ( struct xdr_stream * xdr , uint32_t * bitmap )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * p ;
2005-04-16 15:20:36 -07:00
unsigned int attrlen ;
p = read_buf ( xdr , 4 ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
attrlen = ntohl ( * p ) ;
p = read_buf ( xdr , attrlen < < 2 ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
if ( likely ( attrlen > 0 ) )
bitmap [ 0 ] = ntohl ( * p + + ) ;
if ( attrlen > 1 )
bitmap [ 1 ] = ntohl ( * p ) ;
return 0 ;
}
2006-10-19 23:28:50 -07:00
static __be32 decode_stateid ( struct xdr_stream * xdr , nfs4_stateid * stateid )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * p ;
2005-04-16 15:20:36 -07:00
p = read_buf ( xdr , 16 ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
memcpy ( stateid - > data , p , 16 ) ;
return 0 ;
}
2006-10-19 23:28:50 -07:00
static __be32 decode_compound_hdr_arg ( struct xdr_stream * xdr , struct cb_compound_hdr_arg * hdr )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * p ;
2005-04-16 15:20:36 -07:00
unsigned int minor_version ;
2006-10-19 23:28:50 -07:00
__be32 status ;
2005-04-16 15:20:36 -07:00
status = decode_string ( xdr , & hdr - > taglen , & hdr - > tag ) ;
if ( unlikely ( status ! = 0 ) )
return status ;
/* We do not like overly long tags! */
2007-10-26 13:33:01 -04:00
if ( hdr - > taglen > CB_OP_TAGLEN_MAXSZ - 12 ) {
2005-04-16 15:20:36 -07:00
printk ( " NFSv4 CALLBACK %s: client sent tag of length %u \n " ,
2008-05-02 13:42:44 -07:00
__func__ , hdr - > taglen ) ;
2005-04-16 15:20:36 -07:00
return htonl ( NFS4ERR_RESOURCE ) ;
}
p = read_buf ( xdr , 12 ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
minor_version = ntohl ( * p + + ) ;
/* Check minor version is zero. */
if ( minor_version ! = 0 ) {
printk ( KERN_WARNING " %s: NFSv4 server callback with illegal minor version %u! \n " ,
2008-05-02 13:42:44 -07:00
__func__ , minor_version ) ;
2005-04-16 15:20:36 -07:00
return htonl ( NFS4ERR_MINOR_VERS_MISMATCH ) ;
}
hdr - > callback_ident = ntohl ( * p + + ) ;
hdr - > nops = ntohl ( * p ) ;
return 0 ;
}
2006-10-19 23:28:50 -07:00
static __be32 decode_op_hdr ( struct xdr_stream * xdr , unsigned int * op )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * p ;
2005-04-16 15:20:36 -07:00
p = read_buf ( xdr , 4 ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
* op = ntohl ( * p ) ;
return 0 ;
}
2006-10-19 23:28:50 -07:00
static __be32 decode_getattr_args ( struct svc_rqst * rqstp , struct xdr_stream * xdr , struct cb_getattrargs * args )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:50 -07:00
__be32 status ;
2005-04-16 15:20:36 -07:00
status = decode_fh ( xdr , & args - > fh ) ;
if ( unlikely ( status ! = 0 ) )
goto out ;
2007-12-10 14:58:22 -05:00
args - > addr = svc_addr ( rqstp ) ;
2005-04-16 15:20:36 -07:00
status = decode_bitmap ( xdr , args - > bitmap ) ;
out :
2008-05-02 13:42:44 -07:00
dprintk ( " %s: exit with status = %d \n " , __func__ , ntohl ( status ) ) ;
2005-04-16 15:20:36 -07:00
return status ;
}
2006-10-19 23:28:50 -07:00
static __be32 decode_recall_args ( struct svc_rqst * rqstp , struct xdr_stream * xdr , struct cb_recallargs * args )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * p ;
2006-10-19 23:28:50 -07:00
__be32 status ;
2005-04-16 15:20:36 -07:00
2007-12-10 14:58:29 -05:00
args - > addr = svc_addr ( rqstp ) ;
2005-04-16 15:20:36 -07:00
status = decode_stateid ( xdr , & args - > stateid ) ;
if ( unlikely ( status ! = 0 ) )
goto out ;
p = read_buf ( xdr , 4 ) ;
if ( unlikely ( p = = NULL ) ) {
status = htonl ( NFS4ERR_RESOURCE ) ;
goto out ;
}
args - > truncate = ntohl ( * p ) ;
status = decode_fh ( xdr , & args - > fh ) ;
out :
2008-05-02 13:42:44 -07:00
dprintk ( " %s: exit with status = %d \n " , __func__ , ntohl ( status ) ) ;
2006-05-27 03:31:12 +04:00
return status ;
2005-04-16 15:20:36 -07:00
}
2006-10-19 23:28:50 -07:00
static __be32 encode_string ( struct xdr_stream * xdr , unsigned int len , const char * str )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * p ;
2005-04-16 15:20:36 -07:00
p = xdr_reserve_space ( xdr , 4 + len ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
xdr_encode_opaque ( p , str , len ) ;
return 0 ;
}
# define CB_SUPPORTED_ATTR0 (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE)
# define CB_SUPPORTED_ATTR1 (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY)
2006-10-19 23:28:51 -07:00
static __be32 encode_attr_bitmap ( struct xdr_stream * xdr , const uint32_t * bitmap , __be32 * * savep )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 bm [ 2 ] ;
__be32 * p ;
2005-04-16 15:20:36 -07:00
bm [ 0 ] = htonl ( bitmap [ 0 ] & CB_SUPPORTED_ATTR0 ) ;
bm [ 1 ] = htonl ( bitmap [ 1 ] & CB_SUPPORTED_ATTR1 ) ;
if ( bm [ 1 ] ! = 0 ) {
p = xdr_reserve_space ( xdr , 16 ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
* p + + = htonl ( 2 ) ;
* p + + = bm [ 0 ] ;
* p + + = bm [ 1 ] ;
} else if ( bm [ 0 ] ! = 0 ) {
p = xdr_reserve_space ( xdr , 12 ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
* p + + = htonl ( 1 ) ;
* p + + = bm [ 0 ] ;
} else {
p = xdr_reserve_space ( xdr , 8 ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
* p + + = htonl ( 0 ) ;
}
* savep = p ;
return 0 ;
}
2006-10-19 23:28:50 -07:00
static __be32 encode_attr_change ( struct xdr_stream * xdr , const uint32_t * bitmap , uint64_t change )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * p ;
2005-04-16 15:20:36 -07:00
if ( ! ( bitmap [ 0 ] & FATTR4_WORD0_CHANGE ) )
return 0 ;
p = xdr_reserve_space ( xdr , 8 ) ;
2008-02-20 13:03:05 -08:00
if ( unlikely ( ! p ) )
2005-04-16 15:20:36 -07:00
return htonl ( NFS4ERR_RESOURCE ) ;
p = xdr_encode_hyper ( p , change ) ;
return 0 ;
}
2006-10-19 23:28:50 -07:00
static __be32 encode_attr_size ( struct xdr_stream * xdr , const uint32_t * bitmap , uint64_t size )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * p ;
2005-04-16 15:20:36 -07:00
if ( ! ( bitmap [ 0 ] & FATTR4_WORD0_SIZE ) )
return 0 ;
p = xdr_reserve_space ( xdr , 8 ) ;
2008-02-20 13:03:05 -08:00
if ( unlikely ( ! p ) )
2005-04-16 15:20:36 -07:00
return htonl ( NFS4ERR_RESOURCE ) ;
p = xdr_encode_hyper ( p , size ) ;
return 0 ;
}
2006-10-19 23:28:50 -07:00
static __be32 encode_attr_time ( struct xdr_stream * xdr , const struct timespec * time )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * p ;
2005-04-16 15:20:36 -07:00
p = xdr_reserve_space ( xdr , 12 ) ;
2008-02-20 13:03:05 -08:00
if ( unlikely ( ! p ) )
2005-04-16 15:20:36 -07:00
return htonl ( NFS4ERR_RESOURCE ) ;
p = xdr_encode_hyper ( p , time - > tv_sec ) ;
* p = htonl ( time - > tv_nsec ) ;
return 0 ;
}
2006-10-19 23:28:50 -07:00
static __be32 encode_attr_ctime ( struct xdr_stream * xdr , const uint32_t * bitmap , const struct timespec * time )
2005-04-16 15:20:36 -07:00
{
if ( ! ( bitmap [ 1 ] & FATTR4_WORD1_TIME_METADATA ) )
return 0 ;
return encode_attr_time ( xdr , time ) ;
}
2006-10-19 23:28:50 -07:00
static __be32 encode_attr_mtime ( struct xdr_stream * xdr , const uint32_t * bitmap , const struct timespec * time )
2005-04-16 15:20:36 -07:00
{
if ( ! ( bitmap [ 1 ] & FATTR4_WORD1_TIME_MODIFY ) )
return 0 ;
return encode_attr_time ( xdr , time ) ;
}
2006-10-19 23:28:50 -07:00
static __be32 encode_compound_hdr_res ( struct xdr_stream * xdr , struct cb_compound_hdr_res * hdr )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:50 -07:00
__be32 status ;
2005-04-16 15:20:36 -07:00
hdr - > status = xdr_reserve_space ( xdr , 4 ) ;
if ( unlikely ( hdr - > status = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
status = encode_string ( xdr , hdr - > taglen , hdr - > tag ) ;
if ( unlikely ( status ! = 0 ) )
return status ;
hdr - > nops = xdr_reserve_space ( xdr , 4 ) ;
if ( unlikely ( hdr - > nops = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
return 0 ;
}
2006-10-19 23:28:50 -07:00
static __be32 encode_op_hdr ( struct xdr_stream * xdr , uint32_t op , __be32 res )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * p ;
2005-04-16 15:20:36 -07:00
p = xdr_reserve_space ( xdr , 8 ) ;
if ( unlikely ( p = = NULL ) )
return htonl ( NFS4ERR_RESOURCE ) ;
* p + + = htonl ( op ) ;
* p = res ;
return 0 ;
}
2006-10-19 23:28:50 -07:00
static __be32 encode_getattr_res ( struct svc_rqst * rqstp , struct xdr_stream * xdr , const struct cb_getattrres * res )
2005-04-16 15:20:36 -07:00
{
2006-10-19 23:28:51 -07:00
__be32 * savep = NULL ;
2006-10-19 23:28:50 -07:00
__be32 status = res - > status ;
2005-04-16 15:20:36 -07:00
if ( unlikely ( status ! = 0 ) )
goto out ;
status = encode_attr_bitmap ( xdr , res - > bitmap , & savep ) ;
if ( unlikely ( status ! = 0 ) )
goto out ;
status = encode_attr_change ( xdr , res - > bitmap , res - > change_attr ) ;
if ( unlikely ( status ! = 0 ) )
goto out ;
status = encode_attr_size ( xdr , res - > bitmap , res - > size ) ;
if ( unlikely ( status ! = 0 ) )
goto out ;
status = encode_attr_ctime ( xdr , res - > bitmap , & res - > ctime ) ;
if ( unlikely ( status ! = 0 ) )
goto out ;
status = encode_attr_mtime ( xdr , res - > bitmap , & res - > mtime ) ;
* savep = htonl ( ( unsigned int ) ( ( char * ) xdr - > p - ( char * ) ( savep + 1 ) ) ) ;
out :
2008-05-02 13:42:44 -07:00
dprintk ( " %s: exit with status = %d \n " , __func__ , ntohl ( status ) ) ;
2005-04-16 15:20:36 -07:00
return status ;
}
2006-10-19 23:28:50 -07:00
static __be32 process_op ( struct svc_rqst * rqstp ,
2005-04-16 15:20:36 -07:00
struct xdr_stream * xdr_in , void * argp ,
struct xdr_stream * xdr_out , void * resp )
{
2006-03-20 13:44:10 -05:00
struct callback_op * op = & callback_ops [ 0 ] ;
unsigned int op_nr = OP_CB_ILLEGAL ;
2006-10-19 23:28:50 -07:00
__be32 status = 0 ;
2005-04-16 15:20:36 -07:00
long maxlen ;
2006-10-19 23:28:50 -07:00
__be32 res ;
2005-04-16 15:20:36 -07:00
2008-05-02 13:42:44 -07:00
dprintk ( " %s: start \n " , __func__ ) ;
2005-04-16 15:20:36 -07:00
status = decode_op_hdr ( xdr_in , & op_nr ) ;
2006-03-20 13:44:10 -05:00
if ( likely ( status = = 0 ) ) {
switch ( op_nr ) {
case OP_CB_GETATTR :
case OP_CB_RECALL :
op = & callback_ops [ op_nr ] ;
break ;
default :
op_nr = OP_CB_ILLEGAL ;
op = & callback_ops [ 0 ] ;
status = htonl ( NFS4ERR_OP_ILLEGAL ) ;
}
}
2005-04-16 15:20:36 -07:00
maxlen = xdr_out - > end - xdr_out - > p ;
if ( maxlen > 0 & & maxlen < PAGE_SIZE ) {
if ( likely ( status = = 0 & & op - > decode_args ! = NULL ) )
status = op - > decode_args ( rqstp , xdr_in , argp ) ;
if ( likely ( status = = 0 & & op - > process_op ! = NULL ) )
status = op - > process_op ( argp , resp ) ;
} else
status = htonl ( NFS4ERR_RESOURCE ) ;
res = encode_op_hdr ( xdr_out , op_nr , status ) ;
if ( status = = 0 )
status = res ;
if ( op - > encode_res ! = NULL & & status = = 0 )
status = op - > encode_res ( rqstp , xdr_out , resp ) ;
2008-05-02 13:42:44 -07:00
dprintk ( " %s: done, status = %d \n " , __func__ , ntohl ( status ) ) ;
2005-04-16 15:20:36 -07:00
return status ;
}
/*
* Decode , process and encode a COMPOUND
*/
2006-10-19 23:28:45 -07:00
static __be32 nfs4_callback_compound ( struct svc_rqst * rqstp , void * argp , void * resp )
2005-04-16 15:20:36 -07:00
{
2008-05-06 13:32:40 -04:00
struct cb_compound_hdr_arg hdr_arg = { 0 } ;
struct cb_compound_hdr_res hdr_res = { NULL } ;
2005-04-16 15:20:36 -07:00
struct xdr_stream xdr_in , xdr_out ;
2006-10-19 23:28:51 -07:00
__be32 * p ;
2006-10-19 23:28:50 -07:00
__be32 status ;
2008-05-06 13:32:40 -04:00
unsigned int nops = 0 ;
2005-04-16 15:20:36 -07:00
2008-05-02 13:42:44 -07:00
dprintk ( " %s: start \n " , __func__ ) ;
2005-04-16 15:20:36 -07:00
xdr_init_decode ( & xdr_in , & rqstp - > rq_arg , rqstp - > rq_arg . head [ 0 ] . iov_base ) ;
2006-10-19 23:28:51 -07:00
p = ( __be32 * ) ( ( char * ) rqstp - > rq_res . head [ 0 ] . iov_base + rqstp - > rq_res . head [ 0 ] . iov_len ) ;
2005-04-16 15:20:36 -07:00
xdr_init_encode ( & xdr_out , & rqstp - > rq_res , p ) ;
2008-05-06 13:32:40 -04:00
status = decode_compound_hdr_arg ( & xdr_in , & hdr_arg ) ;
if ( status = = __constant_htonl ( NFS4ERR_RESOURCE ) )
return rpc_garbage_args ;
2005-04-16 15:20:36 -07:00
hdr_res . taglen = hdr_arg . taglen ;
hdr_res . tag = hdr_arg . tag ;
2008-05-06 13:32:40 -04:00
if ( encode_compound_hdr_res ( & xdr_out , & hdr_res ) ! = 0 )
return rpc_system_err ;
2005-04-16 15:20:36 -07:00
2008-05-06 13:32:40 -04:00
while ( status = = 0 & & nops ! = hdr_arg . nops ) {
2005-04-16 15:20:36 -07:00
status = process_op ( rqstp , & xdr_in , argp , & xdr_out , resp ) ;
nops + + ;
}
2008-05-06 13:32:40 -04:00
2005-04-16 15:20:36 -07:00
* hdr_res . status = status ;
* hdr_res . nops = htonl ( nops ) ;
2008-05-02 13:42:44 -07:00
dprintk ( " %s: done, status = %u \n " , __func__ , ntohl ( status ) ) ;
2005-04-16 15:20:36 -07:00
return rpc_success ;
}
/*
* Define NFS4 callback COMPOUND ops .
*/
static struct callback_op callback_ops [ ] = {
[ 0 ] = {
. res_maxsize = CB_OP_HDR_RES_MAXSZ ,
} ,
[ OP_CB_GETATTR ] = {
. process_op = ( callback_process_op_t ) nfs4_callback_getattr ,
. decode_args = ( callback_decode_arg_t ) decode_getattr_args ,
. encode_res = ( callback_encode_res_t ) encode_getattr_res ,
. res_maxsize = CB_OP_GETATTR_RES_MAXSZ ,
} ,
[ OP_CB_RECALL ] = {
. process_op = ( callback_process_op_t ) nfs4_callback_recall ,
. decode_args = ( callback_decode_arg_t ) decode_recall_args ,
. res_maxsize = CB_OP_RECALL_RES_MAXSZ ,
}
} ;
/*
* Define NFS4 callback procedures
*/
static struct svc_procedure nfs4_callback_procedures1 [ ] = {
[ CB_NULL ] = {
. pc_func = nfs4_callback_null ,
. pc_decode = ( kxdrproc_t ) nfs4_decode_void ,
. pc_encode = ( kxdrproc_t ) nfs4_encode_void ,
. pc_xdrressize = 1 ,
} ,
[ CB_COMPOUND ] = {
. pc_func = nfs4_callback_compound ,
. pc_encode = ( kxdrproc_t ) nfs4_encode_void ,
. pc_argsize = 256 ,
. pc_ressize = 256 ,
. pc_xdrressize = NFS4_CALLBACK_BUFSIZE ,
}
} ;
struct svc_version nfs4_callback_version1 = {
. vs_vers = 1 ,
. vs_nproc = ARRAY_SIZE ( nfs4_callback_procedures1 ) ,
. vs_proc = nfs4_callback_procedures1 ,
. vs_xdrsize = NFS4_CALLBACK_XDRSIZE ,
. vs_dispatch = NULL ,
} ;