@ -125,6 +125,32 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st
put_rpccred ( oldcred ) ;
}
static int nfs_do_return_delegation ( struct inode * inode , struct nfs_delegation * delegation , int issync )
{
int res = 0 ;
res = nfs4_proc_delegreturn ( inode , delegation - > cred , & delegation - > stateid , issync ) ;
nfs_free_delegation ( delegation ) ;
return res ;
}
static struct nfs_delegation * nfs_detach_delegation_locked ( struct nfs_inode * nfsi , const nfs4_stateid * stateid )
{
struct nfs_delegation * delegation = rcu_dereference ( nfsi - > delegation ) ;
if ( delegation = = NULL )
goto nomatch ;
if ( stateid ! = NULL & & memcmp ( delegation - > stateid . data , stateid - > data ,
sizeof ( delegation - > stateid . data ) ) ! = 0 )
goto nomatch ;
list_del_rcu ( & delegation - > super_list ) ;
nfsi - > delegation_state = 0 ;
rcu_assign_pointer ( nfsi - > delegation , NULL ) ;
return delegation ;
nomatch :
return NULL ;
}
/*
* Set up a delegation on an inode
*/
@ -133,6 +159,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
struct nfs_client * clp = NFS_SERVER ( inode ) - > nfs_client ;
struct nfs_inode * nfsi = NFS_I ( inode ) ;
struct nfs_delegation * delegation ;
struct nfs_delegation * freeme = NULL ;
int status = 0 ;
delegation = kmalloc ( sizeof ( * delegation ) , GFP_KERNEL ) ;
@ -147,42 +174,45 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
delegation - > inode = inode ;
spin_lock ( & clp - > cl_lock ) ;
if ( rcu_dereference ( nfsi - > delegation ) = = NULL ) {
list_add_rcu ( & delegation - > super_list , & clp - > cl_delegations ) ;
nfsi - > delegation_state = delegation - > type ;
rcu_assign_pointer ( nfsi - > delegation , delegation ) ;
delegation = NULL ;
} else {
if ( rcu_dereference ( nfsi - > delegation ) ! = NULL ) {
if ( memcmp ( & delegation - > stateid , & nfsi - > delegation - > stateid ,
sizeof ( delegation - > stateid ) ) ! = 0 | |
delegation - > type ! = nfsi - > delegation - > type ) {
printk ( KERN_WARNING " %s: server %s handed out "
" a duplicate delegation! \n " ,
__FUNCTION__ , clp - > cl_hostname ) ;
status = - EIO ;
sizeof ( delegation - > stateid ) ) = = 0 & &
delegation - > type = = nfsi - > delegation - > type ) {
goto out ;
}
/*
* Deal with broken servers that hand out two
* delegations for the same file .
*/
dfprintk ( FILE , " %s: server %s handed out "
" a duplicate delegation! \n " ,
__FUNCTION__ , clp - > cl_hostname ) ;
if ( delegation - > type < = nfsi - > delegation - > type ) {
freeme = delegation ;
delegation = NULL ;
goto out ;
}
freeme = nfs_detach_delegation_locked ( nfsi , NULL ) ;
}
list_add_rcu ( & delegation - > super_list , & clp - > cl_delegations ) ;
nfsi - > delegation_state = delegation - > type ;
rcu_assign_pointer ( nfsi - > delegation , delegation ) ;
delegation = NULL ;
/* Ensure we revalidate the attributes and page cache! */
spin_lock ( & inode - > i_lock ) ;
nfsi - > cache_validity | = NFS_INO_REVAL_FORCED ;
spin_unlock ( & inode - > i_lock ) ;
out :
spin_unlock ( & clp - > cl_lock ) ;
if ( delegation ! = NULL )
nfs_free_delegation ( delegation ) ;
if ( freeme ! = NULL )
nfs_do_return_delegation ( inode , freeme , 0 ) ;
return status ;
}
static int nfs_do_return_delegation ( struct inode * inode , struct nfs_delegation * delegation , int issync )
{
int res = 0 ;
res = nfs4_proc_delegreturn ( inode , delegation - > cred , & delegation - > stateid , issync ) ;
nfs_free_delegation ( delegation ) ;
return res ;
}
/* Sync all data to disk upon delegation return */
static void nfs_msync_inode ( struct inode * inode )
{
@ -211,23 +241,6 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat
return nfs_do_return_delegation ( inode , delegation , 1 ) ;
}
static struct nfs_delegation * nfs_detach_delegation_locked ( struct nfs_inode * nfsi , const nfs4_stateid * stateid )
{
struct nfs_delegation * delegation = rcu_dereference ( nfsi - > delegation ) ;
if ( delegation = = NULL )
goto nomatch ;
if ( stateid ! = NULL & & memcmp ( delegation - > stateid . data , stateid - > data ,
sizeof ( delegation - > stateid . data ) ) ! = 0 )
goto nomatch ;
list_del_rcu ( & delegation - > super_list ) ;
nfsi - > delegation_state = 0 ;
rcu_assign_pointer ( nfsi - > delegation , NULL ) ;
return delegation ;
nomatch :
return NULL ;
}
/*
* This function returns the delegation without reclaiming opens
* or protecting against delegation reclaims .