2005-04-17 02:20:36 +04:00
/*
* linux / fs / nfsd / nfssvc . c
*
* Central processing for nfsd .
*
* Authors : Olaf Kirch ( okir @ monad . swb . de )
*
* Copyright ( C ) 1995 , 1996 , 1997 Olaf Kirch < okir @ monad . swb . de >
*/
# include <linux/module.h>
Detach sched.h from mm.h
First thing mm.h does is including sched.h solely for can_do_mlock() inline
function which has "current" dereference inside. By dealing with can_do_mlock()
mm.h can be detached from sched.h which is good. See below, why.
This patch
a) removes unconditional inclusion of sched.h from mm.h
b) makes can_do_mlock() normal function in mm/mlock.c
c) exports can_do_mlock() to not break compilation
d) adds sched.h inclusions back to files that were getting it indirectly.
e) adds less bloated headers to some files (asm/signal.h, jiffies.h) that were
getting them indirectly
Net result is:
a) mm.h users would get less code to open, read, preprocess, parse, ... if
they don't need sched.h
b) sched.h stops being dependency for significant number of files:
on x86_64 allmodconfig touching sched.h results in recompile of 4083 files,
after patch it's only 3744 (-8.3%).
Cross-compile tested on
all arm defconfigs, all mips defconfigs, all powerpc defconfigs,
alpha alpha-up
arm
i386 i386-up i386-defconfig i386-allnoconfig
ia64 ia64-up
m68k
mips
parisc parisc-up
powerpc powerpc-up
s390 s390-up
sparc sparc-up
sparc64 sparc64-up
um-x86_64
x86_64 x86_64-up x86_64-defconfig x86_64-allnoconfig
as well as my two usual configs.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-21 01:22:52 +04:00
# include <linux/sched.h>
2005-04-17 02:20:36 +04:00
# include <linux/time.h>
# include <linux/errno.h>
# include <linux/nfs.h>
# include <linux/in.h>
# include <linux/uio.h>
# include <linux/unistd.h>
# include <linux/slab.h>
# include <linux/smp.h>
# include <linux/smp_lock.h>
2007-07-17 15:03:35 +04:00
# include <linux/freezer.h>
2005-04-17 02:20:36 +04:00
# include <linux/fs_struct.h>
# include <linux/sunrpc/types.h>
# include <linux/sunrpc/stats.h>
# include <linux/sunrpc/svc.h>
# include <linux/sunrpc/svcsock.h>
# include <linux/sunrpc/cache.h>
# include <linux/nfsd/nfsd.h>
# include <linux/nfsd/stats.h>
# include <linux/nfsd/cache.h>
2005-11-07 12:00:25 +03:00
# include <linux/nfsd/syscall.h>
2005-04-17 02:20:36 +04:00
# include <linux/lockd/bind.h>
2005-06-22 21:16:26 +04:00
# include <linux/nfsacl.h>
2005-04-17 02:20:36 +04:00
# define NFSDDBG_FACILITY NFSDDBG_SVC
/* these signals will be delivered to an nfsd thread
* when handling a request
*/
# define ALLOWED_SIGS (sigmask(SIGKILL))
/* these signals will be delivered to an nfsd thread
* when not handling a request . i . e . when waiting
*/
# define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGQUIT))
/* if the last thread dies with SIGHUP, then the exports table is
* left unchanged ( like 2.4 - { 0 - 9 } ) . Any other signal will clear
* the exports table ( like 2.2 ) .
*/
# define SIG_NOCLEAN SIGHUP
extern struct svc_program nfsd_program ;
static void nfsd ( struct svc_rqst * rqstp ) ;
struct timeval nfssvc_boot ;
static atomic_t nfsd_busy ;
static unsigned long nfsd_last_call ;
static DEFINE_SPINLOCK ( nfsd_call_lock ) ;
2008-06-10 16:40:35 +04:00
/*
* nfsd_mutex protects nfsd_serv - - both the pointer itself and the members
* of the svc_serv struct . In particular , - > sv_nrthreads but also to some
* extent - > sv_temp_socks and - > sv_permsocks . It also protects nfsdstats . th_cnt
*
* If ( out side the lock ) nfsd_serv is non - NULL , then it must point to a
* properly initialised ' struct svc_serv ' with - > sv_nrthreads > 0. That number
* of nfsd threads must exist and each must listed in - > sp_all_threads in each
* entry of - > sv_pools [ ] .
*
* Transitions of the thread count between zero and non - zero are of particular
* interest since the svc_serv needs to be created and initialized at that
* point , or freed .
*/
DEFINE_MUTEX ( nfsd_mutex ) ;
struct svc_serv * nfsd_serv ;
2006-02-01 14:04:34 +03:00
# if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
static struct svc_stat nfsd_acl_svcstats ;
static struct svc_version * nfsd_acl_version [ ] = {
[ 2 ] = & nfsd_acl_version2 ,
[ 3 ] = & nfsd_acl_version3 ,
} ;
# define NFSD_ACL_MINVERS 2
2006-03-24 14:15:34 +03:00
# define NFSD_ACL_NRVERS ARRAY_SIZE(nfsd_acl_version)
2006-02-01 14:04:34 +03:00
static struct svc_version * nfsd_acl_versions [ NFSD_ACL_NRVERS ] ;
static struct svc_program nfsd_acl_program = {
. pg_prog = NFS_ACL_PROGRAM ,
. pg_nvers = NFSD_ACL_NRVERS ,
. pg_vers = nfsd_acl_versions ,
2007-01-26 11:56:58 +03:00
. pg_name = " nfsacl " ,
2006-02-01 14:04:34 +03:00
. pg_class = " nfsd " ,
. pg_stats = & nfsd_acl_svcstats ,
. pg_authenticate = & svc_set_client ,
} ;
static struct svc_stat nfsd_acl_svcstats = {
. program = & nfsd_acl_program ,
} ;
# endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
2005-11-07 12:00:25 +03:00
static struct svc_version * nfsd_version [ ] = {
[ 2 ] = & nfsd_version2 ,
# if defined(CONFIG_NFSD_V3)
[ 3 ] = & nfsd_version3 ,
# endif
# if defined(CONFIG_NFSD_V4)
[ 4 ] = & nfsd_version4 ,
# endif
} ;
# define NFSD_MINVERS 2
2006-03-24 14:15:34 +03:00
# define NFSD_NRVERS ARRAY_SIZE(nfsd_version)
2005-11-07 12:00:25 +03:00
static struct svc_version * nfsd_versions [ NFSD_NRVERS ] ;
struct svc_program nfsd_program = {
2006-02-01 14:04:34 +03:00
# if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
. pg_next = & nfsd_acl_program ,
# endif
2005-11-07 12:00:25 +03:00
. pg_prog = NFS_PROGRAM , /* program number */
. pg_nvers = NFSD_NRVERS , /* nr of entries in nfsd_version */
. pg_vers = nfsd_versions , /* version table */
. pg_name = " nfsd " , /* program name */
. pg_class = " nfsd " , /* authentication class */
. pg_stats = & nfsd_svcstats , /* version table */
. pg_authenticate = & svc_set_client , /* export authentication */
} ;
2006-10-02 13:17:46 +04:00
int nfsd_vers ( int vers , enum vers_op change )
{
if ( vers < NFSD_MINVERS | | vers > = NFSD_NRVERS )
return - 1 ;
switch ( change ) {
case NFSD_SET :
nfsd_versions [ vers ] = nfsd_version [ vers ] ;
# if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
if ( vers < NFSD_ACL_NRVERS )
2007-01-26 11:56:58 +03:00
nfsd_acl_versions [ vers ] = nfsd_acl_version [ vers ] ;
2006-10-02 13:17:46 +04:00
# endif
2007-01-26 11:56:58 +03:00
break ;
2006-10-02 13:17:46 +04:00
case NFSD_CLEAR :
nfsd_versions [ vers ] = NULL ;
# if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
if ( vers < NFSD_ACL_NRVERS )
2007-01-26 11:56:58 +03:00
nfsd_acl_versions [ vers ] = NULL ;
2006-10-02 13:17:46 +04:00
# endif
break ;
case NFSD_TEST :
return nfsd_versions [ vers ] ! = NULL ;
case NFSD_AVAIL :
return nfsd_version [ vers ] ! = NULL ;
}
return 0 ;
}
2005-04-17 02:20:36 +04:00
/*
* Maximum number of nfsd processes
*/
# define NFSD_MAXSERVS 8192
int nfsd_nrthreads ( void )
{
if ( nfsd_serv = = NULL )
return 0 ;
else
return nfsd_serv - > sv_nrthreads ;
}
2006-10-02 13:17:44 +04:00
static int killsig ; /* signal that was used to kill last nfsd */
static void nfsd_last_thread ( struct svc_serv * serv )
{
/* When last nfsd thread exits we need to do some clean-up */
2007-12-31 06:07:53 +03:00
struct svc_xprt * xprt ;
list_for_each_entry ( xprt , & serv - > sv_permsocks , xpt_list )
2006-10-02 13:17:45 +04:00
lockd_down ( ) ;
2006-10-02 13:17:44 +04:00
nfsd_serv = NULL ;
nfsd_racache_shutdown ( ) ;
nfs4_state_shutdown ( ) ;
printk ( KERN_WARNING " nfsd: last server has exited \n " ) ;
if ( killsig ! = SIG_NOCLEAN ) {
printk ( KERN_WARNING " nfsd: unexporting all filesystems \n " ) ;
nfsd_export_flush ( ) ;
}
}
2006-10-02 13:17:46 +04:00
void nfsd_reset_versions ( void )
{
int found_one = 0 ;
int i ;
for ( i = NFSD_MINVERS ; i < NFSD_NRVERS ; i + + ) {
if ( nfsd_program . pg_vers [ i ] )
found_one = 1 ;
}
if ( ! found_one ) {
for ( i = NFSD_MINVERS ; i < NFSD_NRVERS ; i + + )
nfsd_program . pg_vers [ i ] = nfsd_version [ i ] ;
# if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
for ( i = NFSD_ACL_MINVERS ; i < NFSD_ACL_NRVERS ; i + + )
nfsd_acl_program . pg_vers [ i ] =
nfsd_acl_version [ i ] ;
# endif
}
}
2008-06-10 16:40:35 +04:00
2006-10-02 13:17:48 +04:00
int nfsd_create_serv ( void )
2006-10-02 13:17:46 +04:00
{
int err = 0 ;
2008-06-10 16:40:35 +04:00
WARN_ON ( ! mutex_is_locked ( & nfsd_mutex ) ) ;
2006-10-02 13:17:46 +04:00
if ( nfsd_serv ) {
2006-10-02 13:17:58 +04:00
svc_get ( nfsd_serv ) ;
2006-10-02 13:17:46 +04:00
return 0 ;
}
2006-10-04 13:15:48 +04:00
if ( nfsd_max_blksize = = 0 ) {
/* choose a suitable default */
struct sysinfo i ;
si_meminfo ( & i ) ;
/* Aim for 1/4096 of memory per thread
* This gives 1 MB on 4 Gig machines
* But only uses 32 K on 128 M machines .
* Bottom out at 8 K on 32 M and smaller .
* Of course , this is only a default .
*/
nfsd_max_blksize = NFSSVC_MAXBLKSIZE ;
2006-10-04 13:16:15 +04:00
i . totalram < < = PAGE_SHIFT - 12 ;
2006-10-04 13:15:48 +04:00
while ( nfsd_max_blksize > i . totalram & &
nfsd_max_blksize > = 8 * 1024 * 2 )
nfsd_max_blksize / = 2 ;
}
2006-10-02 13:17:46 +04:00
atomic_set ( & nfsd_busy , 0 ) ;
2006-10-04 13:15:48 +04:00
nfsd_serv = svc_create_pooled ( & nfsd_program ,
2006-10-06 11:44:05 +04:00
nfsd_max_blksize ,
2006-10-02 13:18:00 +04:00
nfsd_last_thread ,
nfsd , SIG_NOCLEAN , THIS_MODULE ) ;
2006-10-02 13:17:46 +04:00
if ( nfsd_serv = = NULL )
err = - ENOMEM ;
2008-06-10 16:40:35 +04:00
2006-10-02 13:17:46 +04:00
do_gettimeofday ( & nfssvc_boot ) ; /* record boot time */
return err ;
}
static int nfsd_init_socks ( int port )
{
int error ;
if ( ! list_empty ( & nfsd_serv - > sv_permsocks ) )
return 0 ;
error = lockd_up ( IPPROTO_UDP ) ;
2006-10-02 13:17:53 +04:00
if ( error > = 0 ) {
2007-12-31 06:07:44 +03:00
error = svc_create_xprt ( nfsd_serv , " udp " , port ,
2007-02-12 11:53:29 +03:00
SVC_SOCK_DEFAULTS ) ;
2006-10-02 13:17:53 +04:00
if ( error < 0 )
lockd_down ( ) ;
}
2006-10-02 13:17:46 +04:00
if ( error < 0 )
return error ;
error = lockd_up ( IPPROTO_TCP ) ;
2006-10-02 13:17:53 +04:00
if ( error > = 0 ) {
2007-12-31 06:07:44 +03:00
error = svc_create_xprt ( nfsd_serv , " tcp " , port ,
2007-02-12 11:53:29 +03:00
SVC_SOCK_DEFAULTS ) ;
2006-10-02 13:17:53 +04:00
if ( error < 0 )
lockd_down ( ) ;
}
2006-10-02 13:17:46 +04:00
if ( error < 0 )
return error ;
return 0 ;
}
2006-10-02 13:18:02 +04:00
int nfsd_nrpools ( void )
{
if ( nfsd_serv = = NULL )
return 0 ;
else
return nfsd_serv - > sv_nrpools ;
}
int nfsd_get_nrthreads ( int n , int * nthreads )
{
int i = 0 ;
if ( nfsd_serv ! = NULL ) {
for ( i = 0 ; i < nfsd_serv - > sv_nrpools & & i < n ; i + + )
nthreads [ i ] = nfsd_serv - > sv_pools [ i ] . sp_nrthreads ;
}
return 0 ;
}
int nfsd_set_nrthreads ( int n , int * nthreads )
{
int i = 0 ;
int tot = 0 ;
int err = 0 ;
2008-06-10 16:40:35 +04:00
WARN_ON ( ! mutex_is_locked ( & nfsd_mutex ) ) ;
2006-10-02 13:18:02 +04:00
if ( nfsd_serv = = NULL | | n < = 0 )
return 0 ;
if ( n > nfsd_serv - > sv_nrpools )
n = nfsd_serv - > sv_nrpools ;
/* enforce a global maximum number of threads */
tot = 0 ;
for ( i = 0 ; i < n ; i + + ) {
if ( nthreads [ i ] > NFSD_MAXSERVS )
nthreads [ i ] = NFSD_MAXSERVS ;
tot + = nthreads [ i ] ;
}
if ( tot > NFSD_MAXSERVS ) {
/* total too large: scale down requested numbers */
for ( i = 0 ; i < n & & tot > 0 ; i + + ) {
int new = nthreads [ i ] * NFSD_MAXSERVS / tot ;
tot - = ( nthreads [ i ] - new ) ;
nthreads [ i ] = new ;
}
for ( i = 0 ; i < n & & tot > 0 ; i + + ) {
nthreads [ i ] - - ;
tot - - ;
}
}
/*
* There must always be a thread in pool 0 ; the admin
* can ' t shut down NFS completely using pool_threads .
*/
if ( nthreads [ 0 ] = = 0 )
nthreads [ 0 ] = 1 ;
/* apply the new numbers */
svc_get ( nfsd_serv ) ;
for ( i = 0 ; i < n ; i + + ) {
err = svc_set_num_threads ( nfsd_serv , & nfsd_serv - > sv_pools [ i ] ,
nthreads [ i ] ) ;
if ( err )
break ;
}
svc_destroy ( nfsd_serv ) ;
return err ;
}
2005-04-17 02:20:36 +04:00
int
nfsd_svc ( unsigned short port , int nrservs )
{
int error ;
2008-06-10 16:40:35 +04:00
mutex_lock ( & nfsd_mutex ) ;
2006-10-02 13:17:46 +04:00
dprintk ( " nfsd: creating service \n " ) ;
2005-04-17 02:20:36 +04:00
error = - EINVAL ;
if ( nrservs < = 0 )
nrservs = 0 ;
if ( nrservs > NFSD_MAXSERVS )
nrservs = NFSD_MAXSERVS ;
/* Readahead param cache - will no-op if it already exists */
error = nfsd_racache_init ( 2 * nrservs ) ;
if ( error < 0 )
goto out ;
2007-08-01 23:30:59 +04:00
nfs4_state_start ( ) ;
2006-10-02 13:17:46 +04:00
nfsd_reset_versions ( ) ;
error = nfsd_create_serv ( ) ;
if ( error )
goto out ;
error = nfsd_init_socks ( port ) ;
if ( error )
goto failure ;
2006-10-02 13:18:00 +04:00
error = svc_set_num_threads ( nfsd_serv , NULL , nrservs ) ;
2005-04-17 02:20:36 +04:00
failure :
svc_destroy ( nfsd_serv ) ; /* Release server */
out :
2008-06-10 16:40:35 +04:00
mutex_unlock ( & nfsd_mutex ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
static inline void
update_thread_usage ( int busy_threads )
{
unsigned long prev_call ;
unsigned long diff ;
int decile ;
spin_lock ( & nfsd_call_lock ) ;
prev_call = nfsd_last_call ;
nfsd_last_call = jiffies ;
decile = busy_threads * 10 / nfsdstats . th_cnt ;
if ( decile > 0 & & decile < = 10 ) {
diff = nfsd_last_call - prev_call ;
if ( ( nfsdstats . th_usage [ decile - 1 ] + = diff ) > = NFSD_USAGE_WRAP )
nfsdstats . th_usage [ decile - 1 ] - = NFSD_USAGE_WRAP ;
if ( decile = = 10 )
nfsdstats . th_fullcnt + + ;
}
spin_unlock ( & nfsd_call_lock ) ;
}
/*
* This is the NFS server kernel thread
*/
static void
nfsd ( struct svc_rqst * rqstp )
{
struct fs_struct * fsp ;
int err ;
sigset_t shutdown_mask , allowed_mask ;
/* Lock module and set up kernel thread */
2008-06-10 16:40:35 +04:00
mutex_lock ( & nfsd_mutex ) ;
2005-04-17 02:20:36 +04:00
daemonize ( " nfsd " ) ;
/* After daemonize() this kernel thread shares current->fs
* with the init process . We need to create files with a
* umask of 0 instead of init ' s umask . */
fsp = copy_fs_struct ( current - > fs ) ;
if ( ! fsp ) {
printk ( " Unable to start nfsd thread: out of memory \n " ) ;
goto out ;
}
exit_fs ( current ) ;
current - > fs = fsp ;
current - > fs - > umask = 0 ;
siginitsetinv ( & shutdown_mask , SHUTDOWN_SIGS ) ;
siginitsetinv ( & allowed_mask , ALLOWED_SIGS ) ;
2008-06-10 16:40:35 +04:00
2005-04-17 02:20:36 +04:00
nfsdstats . th_cnt + + ;
2006-10-02 13:18:00 +04:00
rqstp - > rq_task = current ;
2005-04-17 02:20:36 +04:00
2008-06-10 16:40:35 +04:00
mutex_unlock ( & nfsd_mutex ) ;
2005-04-17 02:20:36 +04:00
/*
* We want less throttling in balance_dirty_pages ( ) so that nfs to
* localhost doesn ' t cause nfsd to lock up due to all the client ' s
* dirty pages .
*/
current - > flags | = PF_LESS_THROTTLE ;
2007-07-17 15:03:35 +04:00
set_freezable ( ) ;
2005-04-17 02:20:36 +04:00
/*
* The main request loop
*/
for ( ; ; ) {
/* Block all but the shutdown signals */
sigprocmask ( SIG_SETMASK , & shutdown_mask , NULL ) ;
/*
* Find a socket with data available and call its
* recvfrom routine .
*/
2006-10-02 13:17:50 +04:00
while ( ( err = svc_recv ( rqstp , 60 * 60 * HZ ) ) = = - EAGAIN )
2005-04-17 02:20:36 +04:00
;
if ( err < 0 )
break ;
update_thread_usage ( atomic_read ( & nfsd_busy ) ) ;
atomic_inc ( & nfsd_busy ) ;
/* Lock the export hash tables for reading. */
exp_readlock ( ) ;
/* Process request with signals blocked. */
sigprocmask ( SIG_SETMASK , & allowed_mask , NULL ) ;
2006-10-02 13:17:50 +04:00
svc_process ( rqstp ) ;
2005-04-17 02:20:36 +04:00
/* Unlock export hash tables */
exp_readunlock ( ) ;
update_thread_usage ( atomic_read ( & nfsd_busy ) ) ;
atomic_dec ( & nfsd_busy ) ;
}
if ( err ! = - EINTR ) {
printk ( KERN_WARNING " nfsd: terminating on error %d \n " , - err ) ;
} else {
unsigned int signo ;
for ( signo = 1 ; signo < = _NSIG ; signo + + )
if ( sigismember ( & current - > pending . signal , signo ) & &
! sigismember ( & current - > blocked , signo ) )
break ;
2006-10-02 13:17:44 +04:00
killsig = signo ;
2005-04-17 02:20:36 +04:00
}
2006-10-02 13:17:45 +04:00
/* Clear signals before calling svc_exit_thread() */
2005-04-17 02:26:37 +04:00
flush_signals ( current ) ;
2005-04-17 02:20:36 +04:00
2008-06-10 16:40:35 +04:00
mutex_lock ( & nfsd_mutex ) ;
2005-04-17 02:20:36 +04:00
nfsdstats . th_cnt - - ;
out :
/* Release the thread */
svc_exit_thread ( rqstp ) ;
/* Release module */
2008-06-10 16:40:35 +04:00
mutex_unlock ( & nfsd_mutex ) ;
2005-04-17 02:20:36 +04:00
module_put_and_exit ( 0 ) ;
}
2007-07-17 15:04:48 +04:00
static __be32 map_new_errors ( u32 vers , __be32 nfserr )
{
if ( nfserr = = nfserr_jukebox & & vers = = 2 )
return nfserr_dropit ;
if ( nfserr = = nfserr_wrongsec & & vers < 4 )
return nfserr_acces ;
return nfserr ;
}
2005-04-17 02:20:36 +04:00
int
2006-10-20 10:29:02 +04:00
nfsd_dispatch ( struct svc_rqst * rqstp , __be32 * statp )
2005-04-17 02:20:36 +04:00
{
struct svc_procedure * proc ;
kxdrproc_t xdr ;
2006-10-20 10:28:55 +04:00
__be32 nfserr ;
__be32 * nfserrp ;
2005-04-17 02:20:36 +04:00
dprintk ( " nfsd_dispatch: vers %d proc %d \n " ,
rqstp - > rq_vers , rqstp - > rq_proc ) ;
proc = rqstp - > rq_procinfo ;
/* Check whether we have this call in the cache. */
switch ( nfsd_cache_lookup ( rqstp , proc - > pc_cachetype ) ) {
case RC_INTR :
case RC_DROPIT :
return 0 ;
case RC_REPLY :
return 1 ;
case RC_DOIT : ;
/* do it */
}
/* Decode arguments */
xdr = proc - > pc_decode ;
2006-10-20 10:28:55 +04:00
if ( xdr & & ! xdr ( rqstp , ( __be32 * ) rqstp - > rq_arg . head [ 0 ] . iov_base ,
2005-04-17 02:20:36 +04:00
rqstp - > rq_argp ) ) {
dprintk ( " nfsd: failed to decode arguments! \n " ) ;
nfsd_cache_update ( rqstp , RC_NOCACHE , NULL ) ;
* statp = rpc_garbage_args ;
return 1 ;
}
/* need to grab the location to store the status, as
* nfsv4 does some encoding while processing
*/
nfserrp = rqstp - > rq_res . head [ 0 ] . iov_base
+ rqstp - > rq_res . head [ 0 ] . iov_len ;
2006-10-20 10:28:55 +04:00
rqstp - > rq_res . head [ 0 ] . iov_len + = sizeof ( __be32 ) ;
2005-04-17 02:20:36 +04:00
/* Now call the procedure handler, and encode NFS status. */
nfserr = proc - > pc_func ( rqstp , rqstp - > rq_argp , rqstp - > rq_resp ) ;
2007-07-17 15:04:48 +04:00
nfserr = map_new_errors ( rqstp - > rq_vers , nfserr ) ;
2005-04-17 02:20:36 +04:00
if ( nfserr = = nfserr_dropit ) {
2007-06-23 01:26:32 +04:00
dprintk ( " nfsd: Dropping request; may be revisited later \n " ) ;
2005-04-17 02:20:36 +04:00
nfsd_cache_update ( rqstp , RC_NOCACHE , NULL ) ;
return 0 ;
}
if ( rqstp - > rq_proc ! = 0 )
* nfserrp + + = nfserr ;
/* Encode result.
* For NFSv2 , additional info is never returned in case of an error .
*/
if ( ! ( nfserr & & rqstp - > rq_vers = = 2 ) ) {
xdr = proc - > pc_encode ;
if ( xdr & & ! xdr ( rqstp , nfserrp ,
rqstp - > rq_resp ) ) {
/* Failed to encode result. Release cache entry */
dprintk ( " nfsd: failed to encode result! \n " ) ;
nfsd_cache_update ( rqstp , RC_NOCACHE , NULL ) ;
* statp = rpc_system_err ;
return 1 ;
}
}
/* Store reply in cache. */
nfsd_cache_update ( rqstp , proc - > pc_cachetype , statp + 1 ) ;
return 1 ;
}