2005-04-17 02:20:36 +04:00
/*
* linux / fs / nfs / delegation . c
*
* Copyright ( C ) 2004 Trond Myklebust
*
* NFS file delegation management
*
*/
# include <linux/completion.h>
2006-01-03 11:55:24 +03:00
# include <linux/kthread.h>
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/sched.h>
# include <linux/spinlock.h>
# include <linux/nfs4.h>
# include <linux/nfs_fs.h>
# include <linux/nfs_xdr.h>
2005-06-22 21:16:21 +04:00
# include "nfs4_fs.h"
2005-04-17 02:20:36 +04:00
# include "delegation.h"
2006-08-23 04:06:10 +04:00
# include "internal.h"
2005-04-17 02:20:36 +04:00
2007-08-06 20:18:34 +04:00
static void nfs_do_free_delegation ( struct nfs_delegation * delegation )
2005-04-17 02:20:36 +04:00
{
kfree ( delegation ) ;
}
2007-07-06 23:12:04 +04:00
static void nfs_free_delegation_callback ( struct rcu_head * head )
{
struct nfs_delegation * delegation = container_of ( head , struct nfs_delegation , rcu ) ;
2007-08-06 20:18:34 +04:00
nfs_do_free_delegation ( delegation ) ;
}
static void nfs_free_delegation ( struct nfs_delegation * delegation )
{
struct rpc_cred * cred ;
cred = rcu_dereference ( delegation - > cred ) ;
rcu_assign_pointer ( delegation - > cred , NULL ) ;
call_rcu ( & delegation - > rcu , nfs_free_delegation_callback ) ;
if ( cred )
put_rpccred ( cred ) ;
2007-07-06 23:12:04 +04:00
}
2005-11-04 23:38:11 +03:00
static int nfs_delegation_claim_locks ( struct nfs_open_context * ctx , struct nfs4_state * state )
{
struct inode * inode = state - > inode ;
struct file_lock * fl ;
int status ;
2008-02-21 00:03:05 +03:00
for ( fl = inode - > i_flock ; fl ! = NULL ; fl = fl - > fl_next ) {
2005-11-04 23:38:11 +03:00
if ( ! ( fl - > fl_flags & ( FL_POSIX | FL_FLOCK ) ) )
continue ;
2007-08-11 01:44:32 +04:00
if ( nfs_file_open_context ( fl - > fl_file ) ! = ctx )
2005-11-04 23:38:11 +03:00
continue ;
status = nfs4_lock_delegation_recall ( state , fl ) ;
if ( status > = 0 )
continue ;
switch ( status ) {
default :
printk ( KERN_ERR " %s: unhandled error %d. \n " ,
2008-05-03 00:42:44 +04:00
__func__ , status ) ;
2005-11-04 23:38:11 +03:00
case - NFS4ERR_EXPIRED :
/* kill_proc(fl->fl_pid, SIGLOST, 1); */
case - NFS4ERR_STALE_CLIENTID :
2006-08-23 04:06:09 +04:00
nfs4_schedule_state_recovery ( NFS_SERVER ( inode ) - > nfs_client ) ;
2005-11-04 23:38:11 +03:00
goto out_err ;
}
}
return 0 ;
out_err :
return status ;
}
2007-07-05 22:55:18 +04:00
static void nfs_delegation_claim_opens ( struct inode * inode , const nfs4_stateid * stateid )
2005-04-17 02:20:36 +04:00
{
struct nfs_inode * nfsi = NFS_I ( inode ) ;
struct nfs_open_context * ctx ;
struct nfs4_state * state ;
2005-11-04 23:38:11 +03:00
int err ;
2005-04-17 02:20:36 +04:00
again :
spin_lock ( & inode - > i_lock ) ;
list_for_each_entry ( ctx , & nfsi - > open_files , list ) {
state = ctx - > state ;
if ( state = = NULL )
continue ;
if ( ! test_bit ( NFS_DELEGATED_STATE , & state - > flags ) )
continue ;
2007-07-05 22:55:18 +04:00
if ( memcmp ( state - > stateid . data , stateid - > data , sizeof ( state - > stateid . data ) ) ! = 0 )
continue ;
2005-04-17 02:20:36 +04:00
get_nfs_open_context ( ctx ) ;
spin_unlock ( & inode - > i_lock ) ;
2007-07-06 23:10:43 +04:00
err = nfs4_open_delegation_recall ( ctx , state , stateid ) ;
2005-11-04 23:38:11 +03:00
if ( err > = 0 )
err = nfs_delegation_claim_locks ( ctx , state ) ;
2005-04-17 02:20:36 +04:00
put_nfs_open_context ( ctx ) ;
2005-11-04 23:38:11 +03:00
if ( err ! = 0 )
return ;
2005-04-17 02:20:36 +04:00
goto again ;
}
spin_unlock ( & inode - > i_lock ) ;
}
/*
* Set up a delegation on an inode
*/
void nfs_inode_reclaim_delegation ( struct inode * inode , struct rpc_cred * cred , struct nfs_openres * res )
{
struct nfs_delegation * delegation = NFS_I ( inode ) - > delegation ;
2007-10-11 23:11:51 +04:00
struct rpc_cred * oldcred ;
2005-04-17 02:20:36 +04:00
if ( delegation = = NULL )
return ;
memcpy ( delegation - > stateid . data , res - > delegation . data ,
sizeof ( delegation - > stateid . data ) ) ;
delegation - > type = res - > delegation_type ;
delegation - > maxsize = res - > maxsize ;
2007-10-11 23:11:51 +04:00
oldcred = delegation - > cred ;
2005-04-17 02:20:36 +04:00
delegation - > cred = get_rpccred ( cred ) ;
delegation - > flags & = ~ NFS_DELEGATION_NEED_RECLAIM ;
NFS_I ( inode ) - > delegation_state = delegation - > type ;
smp_wmb ( ) ;
2007-10-11 23:11:51 +04:00
put_rpccred ( oldcred ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-26 00:38:18 +03:00
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 ;
}
2005-04-17 02:20:36 +04:00
/*
* Set up a delegation on an inode
*/
int nfs_inode_set_delegation ( struct inode * inode , struct rpc_cred * cred , struct nfs_openres * res )
{
2006-08-23 04:06:09 +04:00
struct nfs_client * clp = NFS_SERVER ( inode ) - > nfs_client ;
2005-04-17 02:20:36 +04:00
struct nfs_inode * nfsi = NFS_I ( inode ) ;
struct nfs_delegation * delegation ;
2008-01-26 00:38:18 +03:00
struct nfs_delegation * freeme = NULL ;
2005-04-17 02:20:36 +04:00
int status = 0 ;
2006-09-27 12:49:39 +04:00
delegation = kmalloc ( sizeof ( * delegation ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( delegation = = NULL )
return - ENOMEM ;
memcpy ( delegation - > stateid . data , res - > delegation . data ,
sizeof ( delegation - > stateid . data ) ) ;
delegation - > type = res - > delegation_type ;
delegation - > maxsize = res - > maxsize ;
2006-01-03 11:55:37 +03:00
delegation - > change_attr = nfsi - > change_attr ;
2005-04-17 02:20:36 +04:00
delegation - > cred = get_rpccred ( cred ) ;
delegation - > inode = inode ;
spin_lock ( & clp - > cl_lock ) ;
2008-01-26 00:38:18 +03:00
if ( rcu_dereference ( nfsi - > delegation ) ! = NULL ) {
2005-04-17 02:20:36 +04:00
if ( memcmp ( & delegation - > stateid , & nfsi - > delegation - > stateid ,
2008-01-26 00:38:18 +03:00
sizeof ( delegation - > stateid ) ) = = 0 & &
delegation - > type = = nfsi - > delegation - > type ) {
goto out ;
2005-04-17 02:20:36 +04:00
}
2008-01-26 00:38:18 +03:00
/*
* Deal with broken servers that hand out two
* delegations for the same file .
*/
dfprintk ( FILE , " %s: server %s handed out "
" a duplicate delegation! \n " ,
2008-05-03 00:42:44 +04:00
__func__ , clp - > cl_hostname ) ;
2008-01-26 00:38:18 +03:00
if ( delegation - > type < = nfsi - > delegation - > type ) {
freeme = delegation ;
delegation = NULL ;
goto out ;
}
freeme = nfs_detach_delegation_locked ( nfsi , NULL ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-26 00:38:18 +03:00
list_add_rcu ( & delegation - > super_list , & clp - > cl_delegations ) ;
nfsi - > delegation_state = delegation - > type ;
rcu_assign_pointer ( nfsi - > delegation , delegation ) ;
delegation = NULL ;
2007-07-04 00:10:55 +04:00
/* 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 ) ;
2008-01-26 00:38:18 +03:00
out :
2005-04-17 02:20:36 +04:00
spin_unlock ( & clp - > cl_lock ) ;
2007-10-19 03:59:20 +04:00
if ( delegation ! = NULL )
nfs_free_delegation ( delegation ) ;
2008-01-26 00:38:18 +03:00
if ( freeme ! = NULL )
nfs_do_return_delegation ( inode , freeme , 0 ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
/* Sync all data to disk upon delegation return */
static void nfs_msync_inode ( struct inode * inode )
{
filemap_fdatawrite ( inode - > i_mapping ) ;
nfs_wb_all ( inode ) ;
filemap_fdatawait ( inode - > i_mapping ) ;
}
/*
* Basic procedure for returning a delegation to the server
*/
2007-07-05 22:55:18 +04:00
static int __nfs_inode_return_delegation ( struct inode * inode , struct nfs_delegation * delegation )
2005-04-17 02:20:36 +04:00
{
2006-08-23 04:06:09 +04:00
struct nfs_client * clp = NFS_SERVER ( inode ) - > nfs_client ;
2005-04-17 02:20:36 +04:00
struct nfs_inode * nfsi = NFS_I ( inode ) ;
nfs_msync_inode ( inode ) ;
down_read ( & clp - > cl_sem ) ;
/* Guard against new delegated open calls */
down_write ( & nfsi - > rwsem ) ;
2007-07-05 22:55:18 +04:00
nfs_delegation_claim_opens ( inode , & delegation - > stateid ) ;
2005-04-17 02:20:36 +04:00
up_write ( & nfsi - > rwsem ) ;
up_read ( & clp - > cl_sem ) ;
nfs_msync_inode ( inode ) ;
2008-01-25 02:14:34 +03:00
return nfs_do_return_delegation ( inode , delegation , 1 ) ;
2007-07-05 22:55:18 +04:00
}
2008-01-25 02:14:34 +03:00
/*
* This function returns the delegation without reclaiming opens
* or protecting against delegation reclaims .
* It is therefore really only safe to be called from
* nfs4_clear_inode ( )
*/
void nfs_inode_return_delegation_noreclaim ( struct inode * inode )
{
struct nfs_client * clp = NFS_SERVER ( inode ) - > nfs_client ;
struct nfs_inode * nfsi = NFS_I ( inode ) ;
struct nfs_delegation * delegation ;
if ( rcu_dereference ( nfsi - > delegation ) ! = NULL ) {
spin_lock ( & clp - > cl_lock ) ;
delegation = nfs_detach_delegation_locked ( nfsi , NULL ) ;
spin_unlock ( & clp - > cl_lock ) ;
if ( delegation ! = NULL )
nfs_do_return_delegation ( inode , delegation , 0 ) ;
}
}
2007-07-05 22:55:18 +04:00
int nfs_inode_return_delegation ( struct inode * inode )
{
struct nfs_client * clp = NFS_SERVER ( inode ) - > nfs_client ;
struct nfs_inode * nfsi = NFS_I ( inode ) ;
struct nfs_delegation * delegation ;
int err = 0 ;
2007-07-06 23:12:04 +04:00
if ( rcu_dereference ( nfsi - > delegation ) ! = NULL ) {
2007-07-05 22:55:18 +04:00
spin_lock ( & clp - > cl_lock ) ;
delegation = nfs_detach_delegation_locked ( nfsi , NULL ) ;
spin_unlock ( & clp - > cl_lock ) ;
if ( delegation ! = NULL )
err = __nfs_inode_return_delegation ( inode , delegation ) ;
}
return err ;
2005-04-17 02:20:36 +04:00
}
/*
* Return all delegations associated to a super block
*/
void nfs_return_all_delegations ( struct super_block * sb )
{
2006-08-23 04:06:09 +04:00
struct nfs_client * clp = NFS_SB ( sb ) - > nfs_client ;
2005-04-17 02:20:36 +04:00
struct nfs_delegation * delegation ;
struct inode * inode ;
if ( clp = = NULL )
return ;
restart :
2007-07-06 23:12:04 +04:00
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( delegation , & clp - > cl_delegations , super_list ) {
2005-04-17 02:20:36 +04:00
if ( delegation - > inode - > i_sb ! = sb )
continue ;
inode = igrab ( delegation - > inode ) ;
if ( inode = = NULL )
continue ;
2007-07-06 23:12:04 +04:00
spin_lock ( & clp - > cl_lock ) ;
delegation = nfs_detach_delegation_locked ( NFS_I ( inode ) , NULL ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & clp - > cl_lock ) ;
2007-07-06 23:12:04 +04:00
rcu_read_unlock ( ) ;
if ( delegation ! = NULL )
__nfs_inode_return_delegation ( inode , delegation ) ;
2005-04-17 02:20:36 +04:00
iput ( inode ) ;
goto restart ;
}
2007-07-06 23:12:04 +04:00
rcu_read_unlock ( ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-15 01:16:04 +04:00
static int nfs_do_expire_all_delegations ( void * ptr )
2006-01-03 11:55:24 +03:00
{
2006-08-23 04:06:08 +04:00
struct nfs_client * clp = ptr ;
2006-01-03 11:55:24 +03:00
struct nfs_delegation * delegation ;
struct inode * inode ;
allow_signal ( SIGKILL ) ;
restart :
if ( test_bit ( NFS4CLNT_STATE_RECOVER , & clp - > cl_state ) ! = 0 )
goto out ;
if ( test_bit ( NFS4CLNT_LEASE_EXPIRED , & clp - > cl_state ) = = 0 )
goto out ;
2007-07-06 23:12:04 +04:00
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( delegation , & clp - > cl_delegations , super_list ) {
2006-01-03 11:55:24 +03:00
inode = igrab ( delegation - > inode ) ;
if ( inode = = NULL )
continue ;
2007-07-06 23:12:04 +04:00
spin_lock ( & clp - > cl_lock ) ;
delegation = nfs_detach_delegation_locked ( NFS_I ( inode ) , NULL ) ;
2006-01-03 11:55:24 +03:00
spin_unlock ( & clp - > cl_lock ) ;
2007-07-06 23:12:04 +04:00
rcu_read_unlock ( ) ;
if ( delegation )
__nfs_inode_return_delegation ( inode , delegation ) ;
2006-01-03 11:55:24 +03:00
iput ( inode ) ;
2006-01-03 11:55:58 +03:00
goto restart ;
2006-01-03 11:55:24 +03:00
}
2007-07-06 23:12:04 +04:00
rcu_read_unlock ( ) ;
2006-01-03 11:55:24 +03:00
out :
2006-08-23 04:06:10 +04:00
nfs_put_client ( clp ) ;
2006-01-03 11:55:24 +03:00
module_put_and_exit ( 0 ) ;
}
2006-08-23 04:06:08 +04:00
void nfs_expire_all_delegations ( struct nfs_client * clp )
2006-01-03 11:55:24 +03:00
{
struct task_struct * task ;
__module_get ( THIS_MODULE ) ;
atomic_inc ( & clp - > cl_count ) ;
task = kthread_run ( nfs_do_expire_all_delegations , clp ,
2007-12-10 22:57:16 +03:00
" %s-delegreturn " ,
rpc_peeraddr2str ( clp - > cl_rpcclient ,
RPC_DISPLAY_ADDR ) ) ;
2006-01-03 11:55:24 +03:00
if ( ! IS_ERR ( task ) )
return ;
2006-08-23 04:06:10 +04:00
nfs_put_client ( clp ) ;
2006-01-03 11:55:24 +03:00
module_put ( THIS_MODULE ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Return all delegations following an NFS4ERR_CB_PATH_DOWN error .
*/
2006-08-23 04:06:08 +04:00
void nfs_handle_cb_pathdown ( struct nfs_client * clp )
2005-04-17 02:20:36 +04:00
{
struct nfs_delegation * delegation ;
struct inode * inode ;
if ( clp = = NULL )
return ;
restart :
2007-07-06 23:12:04 +04:00
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( delegation , & clp - > cl_delegations , super_list ) {
2005-04-17 02:20:36 +04:00
inode = igrab ( delegation - > inode ) ;
if ( inode = = NULL )
continue ;
2007-07-06 23:12:04 +04:00
spin_lock ( & clp - > cl_lock ) ;
delegation = nfs_detach_delegation_locked ( NFS_I ( inode ) , NULL ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & clp - > cl_lock ) ;
2007-07-06 23:12:04 +04:00
rcu_read_unlock ( ) ;
if ( delegation ! = NULL )
__nfs_inode_return_delegation ( inode , delegation ) ;
2005-04-17 02:20:36 +04:00
iput ( inode ) ;
goto restart ;
}
2007-07-06 23:12:04 +04:00
rcu_read_unlock ( ) ;
2005-04-17 02:20:36 +04:00
}
struct recall_threadargs {
struct inode * inode ;
2006-08-23 04:06:08 +04:00
struct nfs_client * clp ;
2005-04-17 02:20:36 +04:00
const nfs4_stateid * stateid ;
struct completion started ;
int result ;
} ;
static int recall_thread ( void * data )
{
struct recall_threadargs * args = ( struct recall_threadargs * ) data ;
struct inode * inode = igrab ( args - > inode ) ;
2006-08-23 04:06:09 +04:00
struct nfs_client * clp = NFS_SERVER ( inode ) - > nfs_client ;
2005-04-17 02:20:36 +04:00
struct nfs_inode * nfsi = NFS_I ( inode ) ;
struct nfs_delegation * delegation ;
daemonize ( " nfsv4-delegreturn " ) ;
nfs_msync_inode ( inode ) ;
down_read ( & clp - > cl_sem ) ;
down_write ( & nfsi - > rwsem ) ;
spin_lock ( & clp - > cl_lock ) ;
2007-07-05 22:55:18 +04:00
delegation = nfs_detach_delegation_locked ( nfsi , args - > stateid ) ;
if ( delegation ! = NULL )
2005-04-17 02:20:36 +04:00
args - > result = 0 ;
2007-07-05 22:55:18 +04:00
else
2005-04-17 02:20:36 +04:00
args - > result = - ENOENT ;
spin_unlock ( & clp - > cl_lock ) ;
complete ( & args - > started ) ;
2007-07-05 22:55:18 +04:00
nfs_delegation_claim_opens ( inode , args - > stateid ) ;
2005-04-17 02:20:36 +04:00
up_write ( & nfsi - > rwsem ) ;
up_read ( & clp - > cl_sem ) ;
nfs_msync_inode ( inode ) ;
if ( delegation ! = NULL )
2008-01-25 02:14:34 +03:00
nfs_do_return_delegation ( inode , delegation , 1 ) ;
2005-04-17 02:20:36 +04:00
iput ( inode ) ;
module_put_and_exit ( 0 ) ;
}
/*
* Asynchronous delegation recall !
*/
int nfs_async_inode_return_delegation ( struct inode * inode , const nfs4_stateid * stateid )
{
struct recall_threadargs data = {
. inode = inode ,
. stateid = stateid ,
} ;
int status ;
init_completion ( & data . started ) ;
__module_get ( THIS_MODULE ) ;
status = kernel_thread ( recall_thread , & data , CLONE_KERNEL ) ;
if ( status < 0 )
goto out_module_put ;
wait_for_completion ( & data . started ) ;
return data . result ;
out_module_put :
module_put ( THIS_MODULE ) ;
return status ;
}
/*
* Retrieve the inode associated with a delegation
*/
2006-08-23 04:06:08 +04:00
struct inode * nfs_delegation_find_inode ( struct nfs_client * clp , const struct nfs_fh * fhandle )
2005-04-17 02:20:36 +04:00
{
struct nfs_delegation * delegation ;
struct inode * res = NULL ;
2007-07-06 23:12:04 +04:00
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( delegation , & clp - > cl_delegations , super_list ) {
2005-04-17 02:20:36 +04:00
if ( nfs_compare_fh ( fhandle , & NFS_I ( delegation - > inode ) - > fh ) = = 0 ) {
res = igrab ( delegation - > inode ) ;
break ;
}
}
2007-07-06 23:12:04 +04:00
rcu_read_unlock ( ) ;
2005-04-17 02:20:36 +04:00
return res ;
}
/*
* Mark all delegations as needing to be reclaimed
*/
2006-08-23 04:06:08 +04:00
void nfs_delegation_mark_reclaim ( struct nfs_client * clp )
2005-04-17 02:20:36 +04:00
{
struct nfs_delegation * delegation ;
2007-07-06 23:12:04 +04:00
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( delegation , & clp - > cl_delegations , super_list )
2005-04-17 02:20:36 +04:00
delegation - > flags | = NFS_DELEGATION_NEED_RECLAIM ;
2007-07-06 23:12:04 +04:00
rcu_read_unlock ( ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Reap all unclaimed delegations after reboot recovery is done
*/
2006-08-23 04:06:08 +04:00
void nfs_delegation_reap_unclaimed ( struct nfs_client * clp )
2005-04-17 02:20:36 +04:00
{
2007-07-06 23:12:04 +04:00
struct nfs_delegation * delegation ;
restart :
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( delegation , & clp - > cl_delegations , super_list ) {
2005-04-17 02:20:36 +04:00
if ( ( delegation - > flags & NFS_DELEGATION_NEED_RECLAIM ) = = 0 )
continue ;
2007-07-06 23:12:04 +04:00
spin_lock ( & clp - > cl_lock ) ;
delegation = nfs_detach_delegation_locked ( NFS_I ( delegation - > inode ) , NULL ) ;
spin_unlock ( & clp - > cl_lock ) ;
rcu_read_unlock ( ) ;
if ( delegation ! = NULL )
2007-08-06 20:18:34 +04:00
nfs_free_delegation ( delegation ) ;
2007-07-06 23:12:04 +04:00
goto restart ;
2005-04-17 02:20:36 +04:00
}
2007-07-06 23:12:04 +04:00
rcu_read_unlock ( ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-20 21:44:46 +03:00
int nfs4_copy_delegation_stateid ( nfs4_stateid * dst , struct inode * inode )
{
struct nfs_inode * nfsi = NFS_I ( inode ) ;
struct nfs_delegation * delegation ;
2007-07-06 23:12:04 +04:00
int ret = 0 ;
2006-03-20 21:44:46 +03:00
2007-07-06 23:12:04 +04:00
rcu_read_lock ( ) ;
delegation = rcu_dereference ( nfsi - > delegation ) ;
2006-03-20 21:44:46 +03:00
if ( delegation ! = NULL ) {
memcpy ( dst - > data , delegation - > stateid . data , sizeof ( dst - > data ) ) ;
2007-07-06 23:12:04 +04:00
ret = 1 ;
2006-03-20 21:44:46 +03:00
}
2007-07-06 23:12:04 +04:00
rcu_read_unlock ( ) ;
return ret ;
2006-03-20 21:44:46 +03:00
}