2005-04-17 02:20:36 +04:00
/*
* fs / nfsd / nfs4proc . c
*
* Server - side procedures for NFSv4 .
*
* Copyright ( c ) 2002 The Regents of the University of Michigan .
* All rights reserved .
*
* Kendrick Smith < kmsmith @ umich . edu >
* Andy Adamson < andros @ umich . edu >
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR
* BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include <linux/param.h>
# include <linux/major.h>
# include <linux/slab.h>
2005-06-24 09:03:13 +04:00
# include <linux/file.h>
2005-04-17 02:20:36 +04:00
# include <linux/sunrpc/svc.h>
# include <linux/nfsd/nfsd.h>
# include <linux/nfsd/cache.h>
# include <linux/nfs4.h>
# include <linux/nfsd/state.h>
# include <linux/nfsd/xdr4.h>
# include <linux/nfs4_acl.h>
2007-07-17 15:04:51 +04:00
# include <linux/sunrpc/gss_api.h>
2005-04-17 02:20:36 +04:00
# define NFSDDBG_FACILITY NFSDDBG_PROC
static inline void
fh_dup2 ( struct svc_fh * dst , struct svc_fh * src )
{
fh_put ( dst ) ;
dget ( src - > fh_dentry ) ;
if ( src - > fh_export )
cache_get ( & src - > fh_export - > h ) ;
* dst = * src ;
}
2006-10-20 10:28:59 +04:00
static __be32
2006-10-17 11:10:13 +04:00
do_open_permission ( struct svc_rqst * rqstp , struct svc_fh * current_fh , struct nfsd4_open * open , int accmode )
2005-04-17 02:20:36 +04:00
{
2006-10-20 10:28:59 +04:00
__be32 status ;
2005-04-17 02:20:36 +04:00
if ( open - > op_truncate & &
! ( open - > op_share_access & NFS4_SHARE_ACCESS_WRITE ) )
return nfserr_inval ;
if ( open - > op_share_access & NFS4_SHARE_ACCESS_READ )
2008-06-16 15:20:29 +04:00
accmode | = NFSD_MAY_READ ;
2006-10-17 11:10:14 +04:00
if ( open - > op_share_access & NFS4_SHARE_ACCESS_WRITE )
2008-06-16 15:20:29 +04:00
accmode | = ( NFSD_MAY_WRITE | NFSD_MAY_TRUNC ) ;
2006-10-17 11:10:14 +04:00
if ( open - > op_share_deny & NFS4_SHARE_DENY_WRITE )
2008-06-16 15:20:29 +04:00
accmode | = NFSD_MAY_WRITE ;
2005-04-17 02:20:36 +04:00
status = fh_verify ( rqstp , current_fh , S_IFREG , accmode ) ;
return status ;
}
2006-10-20 10:28:59 +04:00
static __be32
2005-04-17 02:20:36 +04:00
do_open_lookup ( struct svc_rqst * rqstp , struct svc_fh * current_fh , struct nfsd4_open * open )
{
struct svc_fh resfh ;
2006-10-20 10:28:59 +04:00
__be32 status ;
2006-11-09 04:44:40 +03:00
int created = 0 ;
2005-04-17 02:20:36 +04:00
fh_init ( & resfh , NFS4_FHSIZE ) ;
open - > op_truncate = 0 ;
if ( open - > op_create ) {
/*
* Note : create modes ( UNCHECKED , GUARDED . . . ) are the same
* in NFSv4 as in v3 .
*/
status = nfsd_create_v3 ( rqstp , current_fh , open - > op_fname . data ,
open - > op_fname . len , & open - > op_iattr ,
& resfh , open - > op_createmode ,
2007-07-31 11:37:51 +04:00
( u32 * ) open - > op_verf . data ,
& open - > op_truncate , & created ) ;
/* If we ever decide to use different attrs to store the
* verifier in nfsd_create_v3 , then we ' ll need to change this
*/
if ( open - > op_createmode = = NFS4_CREATE_EXCLUSIVE & & status = = 0 )
open - > op_bmval [ 1 ] | = ( FATTR4_WORD1_TIME_ACCESS |
FATTR4_WORD1_TIME_MODIFY ) ;
2006-11-09 04:44:39 +03:00
} else {
2005-04-17 02:20:36 +04:00
status = nfsd_lookup ( rqstp , current_fh ,
open - > op_fname . data , open - > op_fname . len , & resfh ) ;
fh_unlock ( current_fh ) ;
}
2006-11-09 04:44:39 +03:00
if ( status )
goto out ;
2005-04-17 02:20:36 +04:00
2006-11-09 04:44:39 +03:00
set_change_info ( & open - > op_cinfo , current_fh ) ;
2005-04-17 02:20:36 +04:00
2006-11-09 04:44:39 +03:00
/* set reply cache */
fh_dup2 ( current_fh , & resfh ) ;
open - > op_stateowner - > so_replay . rp_openfh_len = resfh . fh_handle . fh_size ;
memcpy ( open - > op_stateowner - > so_replay . rp_openfh ,
& resfh . fh_handle . fh_base , resfh . fh_handle . fh_size ) ;
2005-04-17 02:20:36 +04:00
2006-11-09 04:44:40 +03:00
if ( ! created )
2008-06-16 15:20:29 +04:00
status = do_open_permission ( rqstp , current_fh , open ,
NFSD_MAY_NOP ) ;
2005-04-17 02:20:36 +04:00
2006-11-09 04:44:39 +03:00
out :
2005-04-17 02:20:36 +04:00
fh_put ( & resfh ) ;
return status ;
}
2006-10-20 10:28:59 +04:00
static __be32
2005-04-17 02:20:36 +04:00
do_open_fhandle ( struct svc_rqst * rqstp , struct svc_fh * current_fh , struct nfsd4_open * open )
{
2006-10-20 10:28:59 +04:00
__be32 status ;
2005-04-17 02:20:36 +04:00
/* Only reclaims from previously confirmed clients are valid */
if ( ( status = nfs4_check_open_reclaim ( & open - > op_clientid ) ) )
return status ;
/* We don't know the target directory, and therefore can not
* set the change info
*/
memset ( & open - > op_cinfo , 0 , sizeof ( struct nfsd4_change_info ) ) ;
/* set replay cache */
open - > op_stateowner - > so_replay . rp_openfh_len = current_fh - > fh_handle . fh_size ;
memcpy ( open - > op_stateowner - > so_replay . rp_openfh ,
& current_fh - > fh_handle . fh_base ,
current_fh - > fh_handle . fh_size ) ;
open - > op_truncate = ( open - > op_iattr . ia_valid & ATTR_SIZE ) & &
( open - > op_iattr . ia_size = = 0 ) ;
2008-06-16 15:20:29 +04:00
status = do_open_permission ( rqstp , current_fh , open ,
NFSD_MAY_OWNER_OVERRIDE ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_open ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
2006-12-13 11:35:28 +03:00
struct nfsd4_open * open )
2005-04-17 02:20:36 +04:00
{
2006-10-20 10:28:59 +04:00
__be32 status ;
2005-04-17 02:20:36 +04:00
dprintk ( " NFSD: nfsd4_open filename %.*s op_stateowner %p \n " ,
( int ) open - > op_fname . len , open - > op_fname . data ,
open - > op_stateowner ) ;
/* This check required by spec. */
if ( open - > op_create & & open - > op_claim_type ! = NFS4_OPEN_CLAIM_NULL )
return nfserr_inval ;
nfs4_lock_state ( ) ;
/* check seqid for replay. set nfs4_owner */
status = nfsd4_process_open1 ( open ) ;
2006-10-20 10:29:03 +04:00
if ( status = = nfserr_replay_me ) {
2005-04-17 02:20:36 +04:00
struct nfs4_replay * rp = & open - > op_stateowner - > so_replay ;
2006-12-13 11:35:27 +03:00
fh_put ( & cstate - > current_fh ) ;
cstate - > current_fh . fh_handle . fh_size = rp - > rp_openfh_len ;
memcpy ( & cstate - > current_fh . fh_handle . fh_base , rp - > rp_openfh ,
2005-04-17 02:20:36 +04:00
rp - > rp_openfh_len ) ;
2008-06-16 15:20:29 +04:00
status = fh_verify ( rqstp , & cstate - > current_fh , 0 , NFSD_MAY_NOP ) ;
2005-04-17 02:20:36 +04:00
if ( status )
dprintk ( " nfsd4_open: replay failed "
" restoring previous filehandle \n " ) ;
else
2006-10-20 10:29:03 +04:00
status = nfserr_replay_me ;
2005-04-17 02:20:36 +04:00
}
if ( status )
goto out ;
2006-01-19 04:43:36 +03:00
/* Openowner is now set, so sequence id will get bumped. Now we need
* these checks before we do any creates : */
2006-02-07 23:58:32 +03:00
status = nfserr_grace ;
2006-01-19 04:43:36 +03:00
if ( nfs4_in_grace ( ) & & open - > op_claim_type ! = NFS4_OPEN_CLAIM_PREVIOUS )
2006-02-07 23:58:32 +03:00
goto out ;
status = nfserr_no_grace ;
2006-01-19 04:43:36 +03:00
if ( ! nfs4_in_grace ( ) & & open - > op_claim_type = = NFS4_OPEN_CLAIM_PREVIOUS )
2006-02-07 23:58:32 +03:00
goto out ;
2006-01-19 04:43:36 +03:00
2005-04-17 02:20:36 +04:00
switch ( open - > op_claim_type ) {
2005-06-24 09:02:56 +04:00
case NFS4_OPEN_CLAIM_DELEGATE_CUR :
status = nfserr_inval ;
if ( open - > op_create )
goto out ;
/* fall through */
2005-04-17 02:20:36 +04:00
case NFS4_OPEN_CLAIM_NULL :
/*
* ( 1 ) set CURRENT_FH to the file being opened ,
* creating it if necessary , ( 2 ) set open - > op_cinfo ,
* ( 3 ) set open - > op_truncate if the file is to be
* truncated after opening , ( 4 ) do permission checking .
*/
2006-12-13 11:35:27 +03:00
status = do_open_lookup ( rqstp , & cstate - > current_fh ,
open ) ;
2005-04-17 02:20:36 +04:00
if ( status )
goto out ;
break ;
case NFS4_OPEN_CLAIM_PREVIOUS :
2006-01-19 04:43:30 +03:00
open - > op_stateowner - > so_confirmed = 1 ;
2005-04-17 02:20:36 +04:00
/*
* The CURRENT_FH is already set to the file being
* opened . ( 1 ) set open - > op_cinfo , ( 2 ) set
* open - > op_truncate if the file is to be truncated
* after opening , ( 3 ) do permission checking .
*/
2006-12-13 11:35:27 +03:00
status = do_open_fhandle ( rqstp , & cstate - > current_fh ,
open ) ;
2005-04-17 02:20:36 +04:00
if ( status )
goto out ;
break ;
case NFS4_OPEN_CLAIM_DELEGATE_PREV :
2006-01-19 04:43:30 +03:00
open - > op_stateowner - > so_confirmed = 1 ;
2007-07-28 00:10:37 +04:00
dprintk ( " NFSD: unsupported OPEN claim type %d \n " ,
2005-04-17 02:20:36 +04:00
open - > op_claim_type ) ;
status = nfserr_notsupp ;
goto out ;
default :
2007-07-28 00:10:37 +04:00
dprintk ( " NFSD: Invalid OPEN claim type %d \n " ,
2005-04-17 02:20:36 +04:00
open - > op_claim_type ) ;
status = nfserr_inval ;
goto out ;
}
/*
* nfsd4_process_open2 ( ) does the actual opening of the file . If
* successful , it ( 1 ) truncates the file if open - > op_truncate was
* set , ( 2 ) sets open - > op_stateid , ( 3 ) sets open - > op_delegation .
*/
2006-12-13 11:35:27 +03:00
status = nfsd4_process_open2 ( rqstp , & cstate - > current_fh , open ) ;
2005-04-17 02:20:36 +04:00
out :
2005-09-13 12:25:37 +04:00
if ( open - > op_stateowner ) {
2005-04-17 02:20:36 +04:00
nfs4_get_stateowner ( open - > op_stateowner ) ;
2006-12-13 11:35:28 +03:00
cstate - > replay_owner = open - > op_stateowner ;
2005-09-13 12:25:37 +04:00
}
2005-04-17 02:20:36 +04:00
nfs4_unlock_state ( ) ;
return status ;
}
/*
* filehandle - manipulating ops .
*/
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:38 +03:00
nfsd4_getfh ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct svc_fh * * getfh )
2005-04-17 02:20:36 +04:00
{
2006-12-13 11:35:27 +03:00
if ( ! cstate - > current_fh . fh_dentry )
2005-04-17 02:20:36 +04:00
return nfserr_nofilehandle ;
2006-12-13 11:35:27 +03:00
* getfh = & cstate - > current_fh ;
2005-04-17 02:20:36 +04:00
return nfs_ok ;
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_putfh ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_putfh * putfh )
2005-04-17 02:20:36 +04:00
{
2006-12-13 11:35:27 +03:00
fh_put ( & cstate - > current_fh ) ;
cstate - > current_fh . fh_handle . fh_size = putfh - > pf_fhlen ;
memcpy ( & cstate - > current_fh . fh_handle . fh_base , putfh - > pf_fhval ,
putfh - > pf_fhlen ) ;
2008-06-16 15:20:29 +04:00
return fh_verify ( rqstp , & cstate - > current_fh , 0 , NFSD_MAY_NOP ) ;
2005-04-17 02:20:36 +04:00
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:38 +03:00
nfsd4_putrootfh ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
void * arg )
2005-04-17 02:20:36 +04:00
{
2006-10-20 10:28:59 +04:00
__be32 status ;
2005-04-17 02:20:36 +04:00
2006-12-13 11:35:27 +03:00
fh_put ( & cstate - > current_fh ) ;
2007-07-17 15:04:43 +04:00
status = exp_pseudoroot ( rqstp , & cstate - > current_fh ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:38 +03:00
nfsd4_restorefh ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
void * arg )
2005-04-17 02:20:36 +04:00
{
2006-12-13 11:35:27 +03:00
if ( ! cstate - > save_fh . fh_dentry )
2005-04-17 02:20:36 +04:00
return nfserr_restorefh ;
2006-12-13 11:35:27 +03:00
fh_dup2 ( & cstate - > current_fh , & cstate - > save_fh ) ;
2005-04-17 02:20:36 +04:00
return nfs_ok ;
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:38 +03:00
nfsd4_savefh ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
void * arg )
2005-04-17 02:20:36 +04:00
{
2006-12-13 11:35:27 +03:00
if ( ! cstate - > current_fh . fh_dentry )
2005-04-17 02:20:36 +04:00
return nfserr_nofilehandle ;
2006-12-13 11:35:27 +03:00
fh_dup2 ( & cstate - > save_fh , & cstate - > current_fh ) ;
2005-04-17 02:20:36 +04:00
return nfs_ok ;
}
/*
* misc nfsv4 ops
*/
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_access ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_access * access )
2005-04-17 02:20:36 +04:00
{
if ( access - > ac_req_access & ~ NFS3_ACCESS_FULL )
return nfserr_inval ;
access - > ac_resp_access = access - > ac_req_access ;
2006-12-13 11:35:27 +03:00
return nfsd_access ( rqstp , & cstate - > current_fh , & access - > ac_resp_access ,
& access - > ac_supported ) ;
2005-04-17 02:20:36 +04:00
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_commit ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_commit * commit )
2005-04-17 02:20:36 +04:00
{
2006-10-20 10:28:59 +04:00
__be32 status ;
2005-04-17 02:20:36 +04:00
u32 * p = ( u32 * ) commit - > co_verf . data ;
* p + + = nfssvc_boot . tv_sec ;
* p + + = nfssvc_boot . tv_usec ;
2006-12-13 11:35:27 +03:00
status = nfsd_commit ( rqstp , & cstate - > current_fh , commit - > co_offset ,
commit - > co_count ) ;
2005-04-17 02:20:36 +04:00
if ( status = = nfserr_symlink )
status = nfserr_inval ;
return status ;
}
2006-10-20 10:28:59 +04:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_create ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_create * create )
2005-04-17 02:20:36 +04:00
{
struct svc_fh resfh ;
2006-10-20 10:28:59 +04:00
__be32 status ;
2005-04-17 02:20:36 +04:00
dev_t rdev ;
fh_init ( & resfh , NFS4_FHSIZE ) ;
2008-06-16 15:20:29 +04:00
status = fh_verify ( rqstp , & cstate - > current_fh , S_IFDIR ,
NFSD_MAY_CREATE ) ;
2005-04-17 02:20:36 +04:00
if ( status = = nfserr_symlink )
status = nfserr_notdir ;
if ( status )
return status ;
switch ( create - > cr_type ) {
case NF4LNK :
/* ugh! we have to null-terminate the linktext, or
* vfs_symlink ( ) will choke . it is always safe to
* null - terminate by brute force , since at worst we
* will overwrite the first byte of the create namelen
* in the XDR buffer , which has already been extracted
* during XDR decode .
*/
create - > cr_linkname [ create - > cr_linklen ] = 0 ;
2006-12-13 11:35:27 +03:00
status = nfsd_symlink ( rqstp , & cstate - > current_fh ,
create - > cr_name , create - > cr_namelen ,
create - > cr_linkname , create - > cr_linklen ,
& resfh , & create - > cr_iattr ) ;
2005-04-17 02:20:36 +04:00
break ;
case NF4BLK :
rdev = MKDEV ( create - > cr_specdata1 , create - > cr_specdata2 ) ;
if ( MAJOR ( rdev ) ! = create - > cr_specdata1 | |
MINOR ( rdev ) ! = create - > cr_specdata2 )
return nfserr_inval ;
2006-12-13 11:35:27 +03:00
status = nfsd_create ( rqstp , & cstate - > current_fh ,
create - > cr_name , create - > cr_namelen ,
& create - > cr_iattr , S_IFBLK , rdev , & resfh ) ;
2005-04-17 02:20:36 +04:00
break ;
case NF4CHR :
rdev = MKDEV ( create - > cr_specdata1 , create - > cr_specdata2 ) ;
if ( MAJOR ( rdev ) ! = create - > cr_specdata1 | |
MINOR ( rdev ) ! = create - > cr_specdata2 )
return nfserr_inval ;
2006-12-13 11:35:27 +03:00
status = nfsd_create ( rqstp , & cstate - > current_fh ,
create - > cr_name , create - > cr_namelen ,
& create - > cr_iattr , S_IFCHR , rdev , & resfh ) ;
2005-04-17 02:20:36 +04:00
break ;
case NF4SOCK :
2006-12-13 11:35:27 +03:00
status = nfsd_create ( rqstp , & cstate - > current_fh ,
create - > cr_name , create - > cr_namelen ,
& create - > cr_iattr , S_IFSOCK , 0 , & resfh ) ;
2005-04-17 02:20:36 +04:00
break ;
case NF4FIFO :
2006-12-13 11:35:27 +03:00
status = nfsd_create ( rqstp , & cstate - > current_fh ,
create - > cr_name , create - > cr_namelen ,
& create - > cr_iattr , S_IFIFO , 0 , & resfh ) ;
2005-04-17 02:20:36 +04:00
break ;
case NF4DIR :
create - > cr_iattr . ia_valid & = ~ ATTR_SIZE ;
2006-12-13 11:35:27 +03:00
status = nfsd_create ( rqstp , & cstate - > current_fh ,
create - > cr_name , create - > cr_namelen ,
& create - > cr_iattr , S_IFDIR , 0 , & resfh ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
status = nfserr_badtype ;
}
if ( ! status ) {
2006-12-13 11:35:27 +03:00
fh_unlock ( & cstate - > current_fh ) ;
set_change_info ( & create - > cr_cinfo , & cstate - > current_fh ) ;
fh_dup2 ( & cstate - > current_fh , & resfh ) ;
2005-04-17 02:20:36 +04:00
}
fh_put ( & resfh ) ;
return status ;
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_getattr ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_getattr * getattr )
2005-04-17 02:20:36 +04:00
{
2006-10-20 10:28:59 +04:00
__be32 status ;
2005-04-17 02:20:36 +04:00
2008-06-16 15:20:29 +04:00
status = fh_verify ( rqstp , & cstate - > current_fh , 0 , NFSD_MAY_NOP ) ;
2005-04-17 02:20:36 +04:00
if ( status )
return status ;
if ( getattr - > ga_bmval [ 1 ] & NFSD_WRITEONLY_ATTRS_WORD1 )
return nfserr_inval ;
getattr - > ga_bmval [ 0 ] & = NFSD_SUPPORTED_ATTRS_WORD0 ;
getattr - > ga_bmval [ 1 ] & = NFSD_SUPPORTED_ATTRS_WORD1 ;
2006-12-13 11:35:27 +03:00
getattr - > ga_fhp = & cstate - > current_fh ;
2005-04-17 02:20:36 +04:00
return nfs_ok ;
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_link ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_link * link )
2005-04-17 02:20:36 +04:00
{
2006-10-20 10:28:59 +04:00
__be32 status = nfserr_nofilehandle ;
2005-04-17 02:20:36 +04:00
2006-12-13 11:35:27 +03:00
if ( ! cstate - > save_fh . fh_dentry )
2005-04-17 02:20:36 +04:00
return status ;
2006-12-13 11:35:27 +03:00
status = nfsd_link ( rqstp , & cstate - > current_fh ,
link - > li_name , link - > li_namelen , & cstate - > save_fh ) ;
2005-04-17 02:20:36 +04:00
if ( ! status )
2006-12-13 11:35:27 +03:00
set_change_info ( & link - > li_cinfo , & cstate - > current_fh ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
2006-10-20 10:28:59 +04:00
static __be32
2006-12-13 11:35:38 +03:00
nfsd4_lookupp ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
void * arg )
2005-04-17 02:20:36 +04:00
{
struct svc_fh tmp_fh ;
2006-10-20 10:28:59 +04:00
__be32 ret ;
2005-04-17 02:20:36 +04:00
fh_init ( & tmp_fh , NFS4_FHSIZE ) ;
2007-07-17 15:04:43 +04:00
ret = exp_pseudoroot ( rqstp , & tmp_fh ) ;
if ( ret )
2005-04-17 02:20:36 +04:00
return ret ;
2006-12-13 11:35:27 +03:00
if ( tmp_fh . fh_dentry = = cstate - > current_fh . fh_dentry ) {
2005-04-17 02:20:36 +04:00
fh_put ( & tmp_fh ) ;
return nfserr_noent ;
}
fh_put ( & tmp_fh ) ;
2006-12-13 11:35:27 +03:00
return nfsd_lookup ( rqstp , & cstate - > current_fh ,
" .. " , 2 , & cstate - > current_fh ) ;
2005-04-17 02:20:36 +04:00
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_lookup ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_lookup * lookup )
2005-04-17 02:20:36 +04:00
{
2006-12-13 11:35:27 +03:00
return nfsd_lookup ( rqstp , & cstate - > current_fh ,
lookup - > lo_name , lookup - > lo_len ,
& cstate - > current_fh ) ;
2005-04-17 02:20:36 +04:00
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_read ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_read * read )
2005-04-17 02:20:36 +04:00
{
2006-10-20 10:28:59 +04:00
__be32 status ;
2005-04-17 02:20:36 +04:00
/* no need to check permission - this will be done in nfsd_read() */
2005-06-24 09:03:13 +04:00
read - > rd_filp = NULL ;
2005-04-17 02:20:36 +04:00
if ( read - > rd_offset > = OFFSET_MAX )
return nfserr_inval ;
nfs4_lock_state ( ) ;
/* check stateid */
2006-12-13 11:35:27 +03:00
if ( ( status = nfs4_preprocess_stateid_op ( & cstate - > current_fh ,
& read - > rd_stateid ,
2005-06-24 09:03:13 +04:00
CHECK_FH | RD_STATE , & read - > rd_filp ) ) ) {
2005-04-17 02:20:36 +04:00
dprintk ( " NFSD: nfsd4_read: couldn't process stateid! \n " ) ;
goto out ;
}
2005-06-24 09:03:13 +04:00
if ( read - > rd_filp )
get_file ( read - > rd_filp ) ;
2005-04-17 02:20:36 +04:00
status = nfs_ok ;
out :
nfs4_unlock_state ( ) ;
read - > rd_rqstp = rqstp ;
2006-12-13 11:35:27 +03:00
read - > rd_fhp = & cstate - > current_fh ;
2005-04-17 02:20:36 +04:00
return status ;
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_readdir ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_readdir * readdir )
2005-04-17 02:20:36 +04:00
{
u64 cookie = readdir - > rd_cookie ;
static const nfs4_verifier zeroverf ;
/* no need to check permission - this will be done in nfsd_readdir() */
if ( readdir - > rd_bmval [ 1 ] & NFSD_WRITEONLY_ATTRS_WORD1 )
return nfserr_inval ;
readdir - > rd_bmval [ 0 ] & = NFSD_SUPPORTED_ATTRS_WORD0 ;
readdir - > rd_bmval [ 1 ] & = NFSD_SUPPORTED_ATTRS_WORD1 ;
if ( ( cookie > ~ ( u32 ) 0 ) | | ( cookie = = 1 ) | | ( cookie = = 2 ) | |
( cookie = = 0 & & memcmp ( readdir - > rd_verf . data , zeroverf . data , NFS4_VERIFIER_SIZE ) ) )
return nfserr_bad_cookie ;
readdir - > rd_rqstp = rqstp ;
2006-12-13 11:35:27 +03:00
readdir - > rd_fhp = & cstate - > current_fh ;
2005-04-17 02:20:36 +04:00
return nfs_ok ;
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_readlink ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_readlink * readlink )
2005-04-17 02:20:36 +04:00
{
readlink - > rl_rqstp = rqstp ;
2006-12-13 11:35:27 +03:00
readlink - > rl_fhp = & cstate - > current_fh ;
2005-04-17 02:20:36 +04:00
return nfs_ok ;
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_remove ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_remove * remove )
2005-04-17 02:20:36 +04:00
{
2006-10-20 10:28:59 +04:00
__be32 status ;
2005-04-17 02:20:36 +04:00
2005-06-24 09:03:00 +04:00
if ( nfs4_in_grace ( ) )
return nfserr_grace ;
2006-12-13 11:35:27 +03:00
status = nfsd_unlink ( rqstp , & cstate - > current_fh , 0 ,
remove - > rm_name , remove - > rm_namelen ) ;
2005-04-17 02:20:36 +04:00
if ( status = = nfserr_symlink )
return nfserr_notdir ;
if ( ! status ) {
2006-12-13 11:35:27 +03:00
fh_unlock ( & cstate - > current_fh ) ;
set_change_info ( & remove - > rm_cinfo , & cstate - > current_fh ) ;
2005-04-17 02:20:36 +04:00
}
return status ;
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_rename ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_rename * rename )
2005-04-17 02:20:36 +04:00
{
2006-10-20 10:28:59 +04:00
__be32 status = nfserr_nofilehandle ;
2005-04-17 02:20:36 +04:00
2006-12-13 11:35:27 +03:00
if ( ! cstate - > save_fh . fh_dentry )
2005-04-17 02:20:36 +04:00
return status ;
2006-12-13 11:35:27 +03:00
if ( nfs4_in_grace ( ) & & ! ( cstate - > save_fh . fh_export - > ex_flags
2005-06-24 09:03:00 +04:00
& NFSEXP_NOSUBTREECHECK ) )
return nfserr_grace ;
2006-12-13 11:35:27 +03:00
status = nfsd_rename ( rqstp , & cstate - > save_fh , rename - > rn_sname ,
rename - > rn_snamelen , & cstate - > current_fh ,
2005-04-17 02:20:36 +04:00
rename - > rn_tname , rename - > rn_tnamelen ) ;
/* the underlying filesystem returns different error's than required
* by NFSv4 . both save_fh and current_fh have been verified . . */
if ( status = = nfserr_isdir )
status = nfserr_exist ;
else if ( ( status = = nfserr_notdir ) & &
2006-12-13 11:35:27 +03:00
( S_ISDIR ( cstate - > save_fh . fh_dentry - > d_inode - > i_mode ) & &
S_ISDIR ( cstate - > current_fh . fh_dentry - > d_inode - > i_mode ) ) )
2005-04-17 02:20:36 +04:00
status = nfserr_exist ;
else if ( status = = nfserr_symlink )
status = nfserr_notdir ;
if ( ! status ) {
2006-12-13 11:35:27 +03:00
set_change_info ( & rename - > rn_sinfo , & cstate - > current_fh ) ;
set_change_info ( & rename - > rn_tinfo , & cstate - > save_fh ) ;
2005-04-17 02:20:36 +04:00
}
return status ;
}
2007-07-17 15:04:51 +04:00
static __be32
nfsd4_secinfo ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_secinfo * secinfo )
{
struct svc_fh resfh ;
struct svc_export * exp ;
struct dentry * dentry ;
__be32 err ;
fh_init ( & resfh , NFS4_FHSIZE ) ;
err = nfsd_lookup_dentry ( rqstp , & cstate - > current_fh ,
secinfo - > si_name , secinfo - > si_namelen ,
& exp , & dentry ) ;
if ( err )
return err ;
if ( dentry - > d_inode = = NULL ) {
exp_put ( exp ) ;
err = nfserr_noent ;
} else
secinfo - > si_exp = exp ;
dput ( dentry ) ;
return err ;
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_setattr ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_setattr * setattr )
2005-04-17 02:20:36 +04:00
{
2006-10-20 10:28:59 +04:00
__be32 status = nfs_ok ;
2005-04-17 02:20:36 +04:00
if ( setattr - > sa_iattr . ia_valid & ATTR_SIZE ) {
nfs4_lock_state ( ) ;
2006-12-13 11:35:27 +03:00
status = nfs4_preprocess_stateid_op ( & cstate - > current_fh ,
2006-01-19 04:43:33 +03:00
& setattr - > sa_stateid , CHECK_FH | WR_STATE , NULL ) ;
2005-04-17 02:20:36 +04:00
nfs4_unlock_state ( ) ;
2006-01-19 04:43:33 +03:00
if ( status ) {
2006-10-02 13:17:41 +04:00
dprintk ( " NFSD: nfsd4_setattr: couldn't process stateid! \n " ) ;
2006-01-19 04:43:33 +03:00
return status ;
}
2005-04-17 02:20:36 +04:00
}
2008-02-16 01:37:38 +03:00
status = mnt_want_write ( cstate - > current_fh . fh_export - > ex_path . mnt ) ;
if ( status )
return status ;
2005-04-17 02:20:36 +04:00
status = nfs_ok ;
if ( setattr - > sa_acl ! = NULL )
2006-12-13 11:35:27 +03:00
status = nfsd4_set_nfs4_acl ( rqstp , & cstate - > current_fh ,
setattr - > sa_acl ) ;
2005-04-17 02:20:36 +04:00
if ( status )
2008-02-16 01:37:38 +03:00
goto out ;
2006-12-13 11:35:27 +03:00
status = nfsd_setattr ( rqstp , & cstate - > current_fh , & setattr - > sa_iattr ,
2005-04-17 02:20:36 +04:00
0 , ( time_t ) 0 ) ;
2008-02-16 01:37:38 +03:00
out :
mnt_drop_write ( cstate - > current_fh . fh_export - > ex_path . mnt ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
2006-12-13 11:35:29 +03:00
static __be32
2006-12-13 11:35:27 +03:00
nfsd4_write ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_write * write )
2005-04-17 02:20:36 +04:00
{
stateid_t * stateid = & write - > wr_stateid ;
struct file * filp = NULL ;
u32 * p ;
2006-10-20 10:28:59 +04:00
__be32 status = nfs_ok ;
2005-04-17 02:20:36 +04:00
/* no need to check permission - this will be done in nfsd_write() */
if ( write - > wr_offset > = OFFSET_MAX )
return nfserr_inval ;
nfs4_lock_state ( ) ;
2006-12-13 11:35:27 +03:00
status = nfs4_preprocess_stateid_op ( & cstate - > current_fh , stateid ,
2006-01-19 04:43:33 +03:00
CHECK_FH | WR_STATE , & filp ) ;
2005-06-24 09:03:13 +04:00
if ( filp )
get_file ( filp ) ;
2005-04-17 02:20:36 +04:00
nfs4_unlock_state ( ) ;
2006-01-19 04:43:33 +03:00
if ( status ) {
dprintk ( " NFSD: nfsd4_write: couldn't process stateid! \n " ) ;
return status ;
}
2005-04-17 02:20:36 +04:00
write - > wr_bytes_written = write - > wr_buflen ;
write - > wr_how_written = write - > wr_stable_how ;
p = ( u32 * ) write - > wr_verifier . data ;
* p + + = nfssvc_boot . tv_sec ;
* p + + = nfssvc_boot . tv_usec ;
2006-12-13 11:35:27 +03:00
status = nfsd_write ( rqstp , & cstate - > current_fh , filp ,
write - > wr_offset , rqstp - > rq_vec , write - > wr_vlen ,
write - > wr_buflen , & write - > wr_how_written ) ;
2005-06-24 09:03:13 +04:00
if ( filp )
fput ( filp ) ;
2005-04-17 02:20:36 +04:00
if ( status = = nfserr_symlink )
status = nfserr_inval ;
return status ;
}
/* This routine never returns NFS_OK! If there are no other errors, it
* will return NFSERR_SAME or NFSERR_NOT_SAME depending on whether the
* attributes matched . VERIFY is implemented by mapping NFSERR_SAME
* to NFS_OK after the call ; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK .
*/
2006-10-20 10:28:59 +04:00
static __be32
2006-12-13 11:35:31 +03:00
_nfsd4_verify ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
2006-12-13 11:35:27 +03:00
struct nfsd4_verify * verify )
2005-04-17 02:20:36 +04:00
{
2006-10-20 10:28:58 +04:00
__be32 * buf , * p ;
2005-04-17 02:20:36 +04:00
int count ;
2006-10-20 10:28:59 +04:00
__be32 status ;
2005-04-17 02:20:36 +04:00
2008-06-16 15:20:29 +04:00
status = fh_verify ( rqstp , & cstate - > current_fh , 0 , NFSD_MAY_NOP ) ;
2005-04-17 02:20:36 +04:00
if ( status )
return status ;
if ( ( verify - > ve_bmval [ 0 ] & ~ NFSD_SUPPORTED_ATTRS_WORD0 )
| | ( verify - > ve_bmval [ 1 ] & ~ NFSD_SUPPORTED_ATTRS_WORD1 ) )
return nfserr_attrnotsupp ;
if ( ( verify - > ve_bmval [ 0 ] & FATTR4_WORD0_RDATTR_ERROR )
| | ( verify - > ve_bmval [ 1 ] & NFSD_WRITEONLY_ATTRS_WORD1 ) )
return nfserr_inval ;
if ( verify - > ve_attrlen & 3 )
return nfserr_inval ;
/* count in words:
* bitmap_len ( 1 ) + bitmap ( 2 ) + attr_len ( 1 ) = 4
*/
count = 4 + ( verify - > ve_attrlen > > 2 ) ;
buf = kmalloc ( count < < 2 , GFP_KERNEL ) ;
if ( ! buf )
return nfserr_resource ;
2006-12-13 11:35:27 +03:00
status = nfsd4_encode_fattr ( & cstate - > current_fh ,
cstate - > current_fh . fh_export ,
cstate - > current_fh . fh_dentry , buf ,
2005-04-17 02:20:36 +04:00
& count , verify - > ve_bmval ,
2007-11-27 22:34:05 +03:00
rqstp , 0 ) ;
2005-04-17 02:20:36 +04:00
/* this means that nfsd4_encode_fattr() ran out of space */
if ( status = = nfserr_resource & & count = = 0 )
status = nfserr_not_same ;
if ( status )
goto out_kfree ;
p = buf + 3 ;
status = nfserr_not_same ;
if ( ntohl ( * p + + ) ! = verify - > ve_attrlen )
goto out_kfree ;
if ( ! memcmp ( p , verify - > ve_attrval , verify - > ve_attrlen ) )
status = nfserr_same ;
out_kfree :
kfree ( buf ) ;
return status ;
}
2006-12-13 11:35:31 +03:00
static __be32
nfsd4_nverify ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_verify * verify )
{
__be32 status ;
status = _nfsd4_verify ( rqstp , cstate , verify ) ;
return status = = nfserr_not_same ? nfs_ok : status ;
}
static __be32
nfsd4_verify ( struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
struct nfsd4_verify * verify )
{
__be32 status ;
status = _nfsd4_verify ( rqstp , cstate , verify ) ;
return status = = nfserr_same ? nfs_ok : status ;
}
2005-04-17 02:20:36 +04:00
/*
* NULL call .
*/
2006-10-20 10:28:45 +04:00
static __be32
2005-04-17 02:20:36 +04:00
nfsd4_proc_null ( struct svc_rqst * rqstp , void * argp , void * resp )
{
return nfs_ok ;
}
2006-07-10 15:45:44 +04:00
static inline void nfsd4_increment_op_stats ( u32 opnum )
{
if ( opnum > = FIRST_NFS4_OP & & opnum < = LAST_NFS4_OP )
nfsdstats . nfs4_opcount [ opnum ] + + ;
}
2006-12-13 11:35:27 +03:00
static void cstate_free ( struct nfsd4_compound_state * cstate )
{
if ( cstate = = NULL )
return ;
fh_put ( & cstate - > current_fh ) ;
fh_put ( & cstate - > save_fh ) ;
2006-12-13 11:35:28 +03:00
BUG_ON ( cstate - > replay_owner ) ;
2006-12-13 11:35:27 +03:00
kfree ( cstate ) ;
}
static struct nfsd4_compound_state * cstate_alloc ( void )
{
struct nfsd4_compound_state * cstate ;
cstate = kmalloc ( sizeof ( struct nfsd4_compound_state ) , GFP_KERNEL ) ;
if ( cstate = = NULL )
return NULL ;
fh_init ( & cstate - > current_fh , NFS4_FHSIZE ) ;
fh_init ( & cstate - > save_fh , NFS4_FHSIZE ) ;
2006-12-13 11:35:28 +03:00
cstate - > replay_owner = NULL ;
2006-12-13 11:35:27 +03:00
return cstate ;
}
2005-04-17 02:20:36 +04:00
2006-12-13 11:35:38 +03:00
typedef __be32 ( * nfsd4op_func ) ( struct svc_rqst * , struct nfsd4_compound_state * ,
void * ) ;
struct nfsd4_operation {
nfsd4op_func op_func ;
u32 op_flags ;
2006-12-13 11:35:43 +03:00
/* Most ops require a valid current filehandle; a few don't: */
# define ALLOWED_WITHOUT_FH 1
2006-12-13 11:35:39 +03:00
/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */
2006-12-13 11:35:43 +03:00
# define ALLOWED_ON_ABSENT_FS 2
2008-07-02 12:15:03 +04:00
char * op_name ;
2006-12-13 11:35:38 +03:00
} ;
static struct nfsd4_operation nfsd4_ops [ ] ;
2008-08-08 20:26:42 +04:00
static const char * nfsd4_op_name ( unsigned opnum ) ;
2008-07-02 12:15:03 +04:00
2005-04-17 02:20:36 +04:00
/*
* COMPOUND call .
*/
2006-10-20 10:28:45 +04:00
static __be32
2005-04-17 02:20:36 +04:00
nfsd4_proc_compound ( struct svc_rqst * rqstp ,
struct nfsd4_compoundargs * args ,
struct nfsd4_compoundres * resp )
{
struct nfsd4_op * op ;
2006-12-13 11:35:38 +03:00
struct nfsd4_operation * opdesc ;
2006-12-13 11:35:27 +03:00
struct nfsd4_compound_state * cstate = NULL ;
2006-12-13 11:35:20 +03:00
int slack_bytes ;
2006-10-20 10:28:59 +04:00
__be32 status ;
2005-04-17 02:20:36 +04:00
resp - > xbuf = & rqstp - > rq_res ;
resp - > p = rqstp - > rq_res . head [ 0 ] . iov_base + rqstp - > rq_res . head [ 0 ] . iov_len ;
resp - > tagp = resp - > p ;
/* reserve space for: taglen, tag, and opcnt */
resp - > p + = 2 + XDR_QUADLEN ( args - > taglen ) ;
resp - > end = rqstp - > rq_res . head [ 0 ] . iov_base + PAGE_SIZE ;
resp - > taglen = args - > taglen ;
resp - > tag = args - > tag ;
resp - > opcnt = 0 ;
resp - > rqstp = rqstp ;
/*
* According to RFC3010 , this takes precedence over all other errors .
*/
status = nfserr_minor_vers_mismatch ;
if ( args - > minorversion > NFSD_SUPPORTED_MINOR_VERSION )
goto out ;
2008-08-21 16:42:16 +04:00
status = nfserr_resource ;
cstate = cstate_alloc ( ) ;
if ( cstate = = NULL )
goto out ;
2005-04-17 02:20:36 +04:00
status = nfs_ok ;
while ( ! status & & resp - > opcnt < args - > opcnt ) {
op = & args - > ops [ resp - > opcnt + + ] ;
2008-07-02 12:15:03 +04:00
dprintk ( " nfsv4 compound op #%d/%d: %d (%s) \n " ,
resp - > opcnt , args - > opcnt , op - > opnum ,
nfsd4_op_name ( op - > opnum ) ) ;
2006-01-19 04:43:23 +03:00
2005-04-17 02:20:36 +04:00
/*
* The XDR decode routines may have pre - set op - > status ;
* for example , if there is a miscellaneous XDR error
* it will be set to nfserr_bad_xdr .
*/
if ( op - > status )
goto encode_op ;
/* We must be able to encode a successful response to
* this operation , with enough room left over to encode a
* failed response to the next operation . If we don ' t
* have enough room , fail with ERR_RESOURCE .
*/
2006-12-13 11:35:20 +03:00
slack_bytes = ( char * ) resp - > end - ( char * ) resp - > p ;
if ( slack_bytes < COMPOUND_SLACK_SPACE
+ COMPOUND_ERR_SLACK_SPACE ) {
BUG_ON ( slack_bytes < COMPOUND_ERR_SLACK_SPACE ) ;
2005-04-17 02:20:36 +04:00
op - > status = nfserr_resource ;
goto encode_op ;
}
2006-12-13 11:35:38 +03:00
opdesc = & nfsd4_ops [ op - > opnum ] ;
2006-12-13 11:35:27 +03:00
if ( ! cstate - > current_fh . fh_dentry ) {
2006-12-13 11:35:43 +03:00
if ( ! ( opdesc - > op_flags & ALLOWED_WITHOUT_FH ) ) {
2006-10-04 13:16:20 +04:00
op - > status = nfserr_nofilehandle ;
goto encode_op ;
}
2006-12-13 11:35:39 +03:00
} else if ( cstate - > current_fh . fh_export - > ex_fslocs . migrated & &
! ( opdesc - > op_flags & ALLOWED_ON_ABSENT_FS ) ) {
2006-10-04 13:16:20 +04:00
op - > status = nfserr_moved ;
2005-04-17 02:20:36 +04:00
goto encode_op ;
}
2006-12-13 11:35:38 +03:00
if ( opdesc - > op_func )
op - > status = opdesc - > op_func ( rqstp , cstate , & op - > u ) ;
else
2005-04-17 02:20:36 +04:00
BUG_ON ( op - > status = = nfs_ok ) ;
encode_op :
2006-10-20 10:29:03 +04:00
if ( op - > status = = nfserr_replay_me ) {
2006-12-13 11:35:28 +03:00
op - > replay = & cstate - > replay_owner - > so_replay ;
2005-04-17 02:20:36 +04:00
nfsd4_encode_replay ( resp , op ) ;
status = op - > status = op - > replay - > rp_status ;
} else {
nfsd4_encode_operation ( resp , op ) ;
status = op - > status ;
}
2006-12-13 11:35:28 +03:00
if ( cstate - > replay_owner ) {
nfs4_put_stateowner ( cstate - > replay_owner ) ;
cstate - > replay_owner = NULL ;
2005-04-17 02:20:36 +04:00
}
2005-06-24 09:03:13 +04:00
/* XXX Ugh, we need to get rid of this kind of special case: */
if ( op - > opnum = = OP_READ & & op - > u . read . rd_filp )
fput ( op - > u . read . rd_filp ) ;
2006-07-10 15:45:44 +04:00
nfsd4_increment_op_stats ( op - > opnum ) ;
2005-04-17 02:20:36 +04:00
}
2008-08-21 16:42:16 +04:00
cstate_free ( cstate ) ;
2005-04-17 02:20:36 +04:00
out :
nfsd4_release_compoundargs ( args ) ;
2008-05-06 01:17:44 +04:00
dprintk ( " nfsv4 compound returned %d \n " , ntohl ( status ) ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
2006-12-13 11:35:38 +03:00
static struct nfsd4_operation nfsd4_ops [ OP_RELEASE_LOCKOWNER + 1 ] = {
[ OP_ACCESS ] = {
. op_func = ( nfsd4op_func ) nfsd4_access ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_ACCESS " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_CLOSE ] = {
. op_func = ( nfsd4op_func ) nfsd4_close ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_CLOSE " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_COMMIT ] = {
. op_func = ( nfsd4op_func ) nfsd4_commit ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_COMMIT " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_CREATE ] = {
. op_func = ( nfsd4op_func ) nfsd4_create ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_CREATE " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_DELEGRETURN ] = {
. op_func = ( nfsd4op_func ) nfsd4_delegreturn ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_DELEGRETURN " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_GETATTR ] = {
. op_func = ( nfsd4op_func ) nfsd4_getattr ,
2006-12-13 11:35:39 +03:00
. op_flags = ALLOWED_ON_ABSENT_FS ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_GETATTR " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_GETFH ] = {
. op_func = ( nfsd4op_func ) nfsd4_getfh ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_GETFH " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_LINK ] = {
. op_func = ( nfsd4op_func ) nfsd4_link ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_LINK " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_LOCK ] = {
. op_func = ( nfsd4op_func ) nfsd4_lock ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_LOCK " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_LOCKT ] = {
. op_func = ( nfsd4op_func ) nfsd4_lockt ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_LOCKT " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_LOCKU ] = {
. op_func = ( nfsd4op_func ) nfsd4_locku ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_LOCKU " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_LOOKUP ] = {
. op_func = ( nfsd4op_func ) nfsd4_lookup ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_LOOKUP " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_LOOKUPP ] = {
. op_func = ( nfsd4op_func ) nfsd4_lookupp ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_LOOKUPP " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_NVERIFY ] = {
. op_func = ( nfsd4op_func ) nfsd4_nverify ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_NVERIFY " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_OPEN ] = {
. op_func = ( nfsd4op_func ) nfsd4_open ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_OPEN " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_OPEN_CONFIRM ] = {
. op_func = ( nfsd4op_func ) nfsd4_open_confirm ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_OPEN_CONFIRM " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_OPEN_DOWNGRADE ] = {
. op_func = ( nfsd4op_func ) nfsd4_open_downgrade ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_OPEN_DOWNGRADE " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_PUTFH ] = {
. op_func = ( nfsd4op_func ) nfsd4_putfh ,
2006-12-13 11:35:43 +03:00
. op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_PUTFH " ,
2006-12-13 11:35:38 +03:00
} ,
2006-12-13 11:35:39 +03:00
[ OP_PUTPUBFH ] = {
2008-07-02 12:15:03 +04:00
/* unsupported, just for future reference: */
2006-12-13 11:35:43 +03:00
. op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_PUTPUBFH " ,
2006-12-13 11:35:39 +03:00
} ,
2006-12-13 11:35:38 +03:00
[ OP_PUTROOTFH ] = {
. op_func = ( nfsd4op_func ) nfsd4_putrootfh ,
2006-12-13 11:35:43 +03:00
. op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_PUTROOTFH " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_READ ] = {
. op_func = ( nfsd4op_func ) nfsd4_read ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_READ " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_READDIR ] = {
. op_func = ( nfsd4op_func ) nfsd4_readdir ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_READDIR " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_READLINK ] = {
. op_func = ( nfsd4op_func ) nfsd4_readlink ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_READLINK " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_REMOVE ] = {
. op_func = ( nfsd4op_func ) nfsd4_remove ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_REMOVE " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_RENAME ] = {
2008-07-02 12:15:03 +04:00
. op_name = " OP_RENAME " ,
2006-12-13 11:35:38 +03:00
. op_func = ( nfsd4op_func ) nfsd4_rename ,
} ,
[ OP_RENEW ] = {
. op_func = ( nfsd4op_func ) nfsd4_renew ,
2006-12-13 11:35:43 +03:00
. op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_RENEW " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_RESTOREFH ] = {
. op_func = ( nfsd4op_func ) nfsd4_restorefh ,
2006-12-13 11:35:43 +03:00
. op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_RESTOREFH " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_SAVEFH ] = {
. op_func = ( nfsd4op_func ) nfsd4_savefh ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_SAVEFH " ,
2006-12-13 11:35:38 +03:00
} ,
2007-07-17 15:04:51 +04:00
[ OP_SECINFO ] = {
. op_func = ( nfsd4op_func ) nfsd4_secinfo ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_SECINFO " ,
2007-07-17 15:04:51 +04:00
} ,
2006-12-13 11:35:38 +03:00
[ OP_SETATTR ] = {
. op_func = ( nfsd4op_func ) nfsd4_setattr ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_SETATTR " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_SETCLIENTID ] = {
. op_func = ( nfsd4op_func ) nfsd4_setclientid ,
2006-12-13 11:35:43 +03:00
. op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_SETCLIENTID " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_SETCLIENTID_CONFIRM ] = {
. op_func = ( nfsd4op_func ) nfsd4_setclientid_confirm ,
2006-12-13 11:35:43 +03:00
. op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_SETCLIENTID_CONFIRM " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_VERIFY ] = {
. op_func = ( nfsd4op_func ) nfsd4_verify ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_VERIFY " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_WRITE ] = {
. op_func = ( nfsd4op_func ) nfsd4_write ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_WRITE " ,
2006-12-13 11:35:38 +03:00
} ,
[ OP_RELEASE_LOCKOWNER ] = {
. op_func = ( nfsd4op_func ) nfsd4_release_lockowner ,
2006-12-13 11:35:43 +03:00
. op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS ,
2008-07-02 12:15:03 +04:00
. op_name = " OP_RELEASE_LOCKOWNER " ,
2006-12-13 11:35:38 +03:00
} ,
} ;
2008-08-08 20:26:42 +04:00
static const char * nfsd4_op_name ( unsigned opnum )
2008-07-02 12:15:03 +04:00
{
if ( opnum < ARRAY_SIZE ( nfsd4_ops ) )
return nfsd4_ops [ opnum ] . op_name ;
return " unknown_operation " ;
}
2005-04-17 02:20:36 +04:00
# define nfs4svc_decode_voidargs NULL
# define nfs4svc_release_void NULL
# define nfsd4_voidres nfsd4_voidargs
# define nfs4svc_release_compound NULL
struct nfsd4_voidargs { int dummy ; } ;
# define PROC(name, argt, rest, relt, cache, respsize) \
{ ( svc_procfunc ) nfsd4_proc_ # # name , \
( kxdrproc_t ) nfs4svc_decode_ # # argt # # args , \
( kxdrproc_t ) nfs4svc_encode_ # # rest # # res , \
( kxdrproc_t ) nfs4svc_release_ # # relt , \
sizeof ( struct nfsd4_ # # argt # # args ) , \
sizeof ( struct nfsd4_ # # rest # # res ) , \
0 , \
cache , \
respsize , \
}
/*
* TODO : At the present time , the NFSv4 server does not do XID caching
* of requests . Implementing XID caching would not be a serious problem ,
* although it would require a mild change in interfaces since one
* doesn ' t know whether an NFSv4 request is idempotent until after the
* XDR decode . However , XID caching totally confuses pynfs ( Peter
* Astrand ' s regression testsuite for NFSv4 servers ) , which reuses
* XID ' s liberally , so I ' ve left it unimplemented until pynfs generates
* better XID ' s .
*/
static struct svc_procedure nfsd_procedures4 [ 2 ] = {
PROC ( null , void , void , void , RC_NOCACHE , 1 ) ,
2006-04-11 09:55:20 +04:00
PROC ( compound , compound , compound , compound , RC_NOCACHE , NFSD_BUFSIZE / 4 )
2005-04-17 02:20:36 +04:00
} ;
struct svc_version nfsd_version4 = {
. vs_vers = 4 ,
. vs_nproc = 2 ,
. vs_proc = nfsd_procedures4 ,
. vs_dispatch = nfsd_dispatch ,
. vs_xdrsize = NFS4_SVC_XDRSIZE ,
} ;
/*
* Local variables :
* c - basic - offset : 8
* End :
*/