2005-04-16 15:20:36 -07:00
/*
* linux / fs / nfs / delegation . c
*
* Copyright ( C ) 2004 Trond Myklebust
*
* NFS file delegation management
*
*/
# include <linux/completion.h>
2006-01-03 09:55:24 +01:00
# include <linux/kthread.h>
2005-04-16 15:20:36 -07: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 17:16:21 +00:00
# include "nfs4_fs.h"
2005-04-16 15:20:36 -07:00
# include "delegation.h"
2006-08-22 20:06:10 -04:00
# include "internal.h"
2005-04-16 15:20:36 -07:00
2007-08-06 12:18:34 -04:00
static void nfs_do_free_delegation ( struct nfs_delegation * delegation )
2005-04-16 15:20:36 -07:00
{
kfree ( delegation ) ;
}
2007-07-06 15: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 12: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 15:12:04 -04:00
}
2008-12-23 15:21:52 -05:00
void nfs_mark_delegation_referenced ( struct nfs_delegation * delegation )
{
set_bit ( NFS_DELEGATION_REFERENCED , & delegation - > flags ) ;
}
2008-12-23 15:21:53 -05:00
int nfs_have_delegation ( struct inode * inode , fmode_t flags )
2008-12-23 15:21:52 -05:00
{
struct nfs_delegation * delegation ;
int ret = 0 ;
flags & = FMODE_READ | FMODE_WRITE ;
rcu_read_lock ( ) ;
delegation = rcu_dereference ( NFS_I ( inode ) - > delegation ) ;
if ( delegation ! = NULL & & ( delegation - > type & flags ) = = flags ) {
nfs_mark_delegation_referenced ( delegation ) ;
ret = 1 ;
}
rcu_read_unlock ( ) ;
return ret ;
}
2005-11-04 15:38:11 -05: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-20 13:03:05 -08:00
for ( fl = inode - > i_flock ; fl ! = NULL ; fl = fl - > fl_next ) {
2005-11-04 15:38:11 -05:00
if ( ! ( fl - > fl_flags & ( FL_POSIX | FL_FLOCK ) ) )
continue ;
2007-08-10 17:44:32 -04:00
if ( nfs_file_open_context ( fl - > fl_file ) ! = ctx )
2005-11-04 15:38:11 -05: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-02 13:42:44 -07:00
__func__ , status ) ;
2005-11-04 15:38:11 -05:00
case - NFS4ERR_EXPIRED :
/* kill_proc(fl->fl_pid, SIGLOST, 1); */
case - NFS4ERR_STALE_CLIENTID :
2006-08-22 20:06:09 -04:00
nfs4_schedule_state_recovery ( NFS_SERVER ( inode ) - > nfs_client ) ;
2005-11-04 15:38:11 -05:00
goto out_err ;
}
}
return 0 ;
out_err :
return status ;
}
2007-07-05 14:55:18 -04:00
static void nfs_delegation_claim_opens ( struct inode * inode , const nfs4_stateid * stateid )
2005-04-16 15:20:36 -07:00
{
struct nfs_inode * nfsi = NFS_I ( inode ) ;
struct nfs_open_context * ctx ;
struct nfs4_state * state ;
2005-11-04 15:38:11 -05:00
int err ;
2005-04-16 15:20:36 -07: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 14:55:18 -04:00
if ( memcmp ( state - > stateid . data , stateid - > data , sizeof ( state - > stateid . data ) ) ! = 0 )
continue ;
2005-04-16 15:20:36 -07:00
get_nfs_open_context ( ctx ) ;
spin_unlock ( & inode - > i_lock ) ;
2007-07-06 15:10:43 -04:00
err = nfs4_open_delegation_recall ( ctx , state , stateid ) ;
2005-11-04 15:38:11 -05:00
if ( err > = 0 )
err = nfs_delegation_claim_locks ( ctx , state ) ;
2005-04-16 15:20:36 -07:00
put_nfs_open_context ( ctx ) ;
2005-11-04 15:38:11 -05:00
if ( err ! = 0 )
return ;
2005-04-16 15:20:36 -07: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 15:11:51 -04:00
struct rpc_cred * oldcred ;
2005-04-16 15:20:36 -07: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 15:11:51 -04:00
oldcred = delegation - > cred ;
2005-04-16 15:20:36 -07:00
delegation - > cred = get_rpccred ( cred ) ;
2008-12-23 15:21:39 -05:00
clear_bit ( NFS_DELEGATION_NEED_RECLAIM , & delegation - > flags ) ;
2005-04-16 15:20:36 -07:00
NFS_I ( inode ) - > delegation_state = delegation - > type ;
smp_wmb ( ) ;
2007-10-11 15:11:51 -04:00
put_rpccred ( oldcred ) ;
2005-04-16 15:20:36 -07:00
}
2008-01-25 16:38:18 -05: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 ;
}
2008-12-23 15:21:39 -05:00
static struct inode * nfs_delegation_grab_inode ( struct nfs_delegation * delegation )
{
struct inode * inode = NULL ;
spin_lock ( & delegation - > lock ) ;
if ( delegation - > inode ! = NULL )
inode = igrab ( delegation - > inode ) ;
spin_unlock ( & delegation - > lock ) ;
return inode ;
}
2008-01-25 16:38:18 -05:00
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 ;
2008-12-23 15:21:38 -05:00
spin_lock ( & delegation - > lock ) ;
2008-01-25 16:38:18 -05:00
if ( stateid ! = NULL & & memcmp ( delegation - > stateid . data , stateid - > data ,
sizeof ( delegation - > stateid . data ) ) ! = 0 )
2008-12-23 15:21:38 -05:00
goto nomatch_unlock ;
2008-01-25 16:38:18 -05:00
list_del_rcu ( & delegation - > super_list ) ;
2008-12-23 15:21:39 -05:00
delegation - > inode = NULL ;
2008-01-25 16:38:18 -05:00
nfsi - > delegation_state = 0 ;
rcu_assign_pointer ( nfsi - > delegation , NULL ) ;
2008-12-23 15:21:38 -05:00
spin_unlock ( & delegation - > lock ) ;
2008-01-25 16:38:18 -05:00
return delegation ;
2008-12-23 15:21:38 -05:00
nomatch_unlock :
spin_unlock ( & delegation - > lock ) ;
2008-01-25 16:38:18 -05:00
nomatch :
return NULL ;
}
2005-04-16 15:20:36 -07: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-22 20:06:09 -04:00
struct nfs_client * clp = NFS_SERVER ( inode ) - > nfs_client ;
2005-04-16 15:20:36 -07:00
struct nfs_inode * nfsi = NFS_I ( inode ) ;
struct nfs_delegation * delegation ;
2008-01-25 16:38:18 -05:00
struct nfs_delegation * freeme = NULL ;
2005-04-16 15:20:36 -07:00
int status = 0 ;
2006-09-27 01:49:39 -07:00
delegation = kmalloc ( sizeof ( * delegation ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07: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 09:55:37 +01:00
delegation - > change_attr = nfsi - > change_attr ;
2005-04-16 15:20:36 -07:00
delegation - > cred = get_rpccred ( cred ) ;
delegation - > inode = inode ;
2008-12-23 15:21:52 -05:00
delegation - > flags = 1 < < NFS_DELEGATION_REFERENCED ;
2008-12-23 15:21:38 -05:00
spin_lock_init ( & delegation - > lock ) ;
2005-04-16 15:20:36 -07:00
spin_lock ( & clp - > cl_lock ) ;
2008-01-25 16:38:18 -05:00
if ( rcu_dereference ( nfsi - > delegation ) ! = NULL ) {
2005-04-16 15:20:36 -07:00
if ( memcmp ( & delegation - > stateid , & nfsi - > delegation - > stateid ,
2008-01-25 16:38:18 -05:00
sizeof ( delegation - > stateid ) ) = = 0 & &
delegation - > type = = nfsi - > delegation - > type ) {
goto out ;
2005-04-16 15:20:36 -07:00
}
2008-01-25 16:38:18 -05: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-02 13:42:44 -07:00
__func__ , clp - > cl_hostname ) ;
2008-01-25 16:38:18 -05:00
if ( delegation - > type < = nfsi - > delegation - > type ) {
freeme = delegation ;
delegation = NULL ;
goto out ;
}
freeme = nfs_detach_delegation_locked ( nfsi , NULL ) ;
2005-04-16 15:20:36 -07:00
}
2008-01-25 16:38:18 -05: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-03 16: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-25 16:38:18 -05:00
out :
2005-04-16 15:20:36 -07:00
spin_unlock ( & clp - > cl_lock ) ;
2007-10-18 19:59:20 -04:00
if ( delegation ! = NULL )
nfs_free_delegation ( delegation ) ;
2008-01-25 16:38:18 -05:00
if ( freeme ! = NULL )
nfs_do_return_delegation ( inode , freeme , 0 ) ;
2005-04-16 15:20:36 -07: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 14:55:18 -04:00
static int __nfs_inode_return_delegation ( struct inode * inode , struct nfs_delegation * delegation )
2005-04-16 15:20:36 -07:00
{
struct nfs_inode * nfsi = NFS_I ( inode ) ;
nfs_msync_inode ( inode ) ;
/* Guard against new delegated open calls */
down_write ( & nfsi - > rwsem ) ;
2007-07-05 14:55:18 -04:00
nfs_delegation_claim_opens ( inode , & delegation - > stateid ) ;
2005-04-16 15:20:36 -07:00
up_write ( & nfsi - > rwsem ) ;
nfs_msync_inode ( inode ) ;
2008-01-24 18:14:34 -05:00
return nfs_do_return_delegation ( inode , delegation , 1 ) ;
2007-07-05 14:55:18 -04:00
}
2008-12-23 15:21:46 -05:00
/*
* Return all delegations that have been marked for return
*/
2008-12-23 15:21:47 -05:00
void nfs_client_return_marked_delegations ( struct nfs_client * clp )
2008-12-23 15:21:46 -05:00
{
struct nfs_delegation * delegation ;
struct inode * inode ;
restart :
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( delegation , & clp - > cl_delegations , super_list ) {
if ( ! test_and_clear_bit ( NFS_DELEGATION_RETURN , & delegation - > flags ) )
continue ;
inode = nfs_delegation_grab_inode ( delegation ) ;
if ( inode = = NULL )
continue ;
spin_lock ( & clp - > cl_lock ) ;
delegation = nfs_detach_delegation_locked ( NFS_I ( inode ) , NULL ) ;
spin_unlock ( & clp - > cl_lock ) ;
rcu_read_unlock ( ) ;
if ( delegation ! = NULL )
__nfs_inode_return_delegation ( inode , delegation ) ;
iput ( inode ) ;
goto restart ;
}
rcu_read_unlock ( ) ;
}
2008-01-24 18:14:34 -05: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 14: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 15:12:04 -04:00
if ( rcu_dereference ( nfsi - > delegation ) ! = NULL ) {
2007-07-05 14: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-16 15:20:36 -07:00
}
2008-12-23 15:21:51 -05:00
static void nfs_mark_return_delegation ( struct nfs_client * clp , struct nfs_delegation * delegation )
{
set_bit ( NFS_DELEGATION_RETURN , & delegation - > flags ) ;
set_bit ( NFS4CLNT_DELEGRETURN , & clp - > cl_state ) ;
}
2005-04-16 15:20:36 -07:00
/*
* Return all delegations associated to a super block
*/
2008-12-23 15:21:46 -05:00
void nfs_super_return_all_delegations ( struct super_block * sb )
2005-04-16 15:20:36 -07:00
{
2006-08-22 20:06:09 -04:00
struct nfs_client * clp = NFS_SB ( sb ) - > nfs_client ;
2005-04-16 15:20:36 -07:00
struct nfs_delegation * delegation ;
if ( clp = = NULL )
return ;
2007-07-06 15:12:04 -04:00
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( delegation , & clp - > cl_delegations , super_list ) {
2008-12-23 15:21:39 -05:00
spin_lock ( & delegation - > lock ) ;
if ( delegation - > inode ! = NULL & & delegation - > inode - > i_sb = = sb )
2008-12-23 15:21:46 -05:00
set_bit ( NFS_DELEGATION_RETURN , & delegation - > flags ) ;
2008-12-23 15:21:39 -05:00
spin_unlock ( & delegation - > lock ) ;
2005-04-16 15:20:36 -07:00
}
2007-07-06 15:12:04 -04:00
rcu_read_unlock ( ) ;
2008-12-23 15:21:46 -05:00
nfs_client_return_marked_delegations ( clp ) ;
}
2008-12-23 15:21:47 -05:00
static void nfs_client_mark_return_all_delegations ( struct nfs_client * clp )
2008-12-23 15:21:46 -05:00
{
struct nfs_delegation * delegation ;
rcu_read_lock ( ) ;
2008-12-23 15:21:47 -05:00
list_for_each_entry_rcu ( delegation , & clp - > cl_delegations , super_list ) {
2008-12-23 15:21:46 -05:00
set_bit ( NFS_DELEGATION_RETURN , & delegation - > flags ) ;
2008-12-23 15:21:47 -05:00
set_bit ( NFS4CLNT_DELEGRETURN , & clp - > cl_state ) ;
}
2008-12-23 15:21:46 -05:00
rcu_read_unlock ( ) ;
2005-04-16 15:20:36 -07:00
}
2008-12-23 15:21:50 -05:00
static void nfs_delegation_run_state_manager ( struct nfs_client * clp )
2006-01-03 09:55:24 +01:00
{
2008-12-23 15:21:50 -05:00
if ( test_bit ( NFS4CLNT_DELEGRETURN , & clp - > cl_state ) )
nfs4_schedule_state_manager ( clp ) ;
2006-01-03 09:55:24 +01:00
}
2006-08-22 20:06:08 -04:00
void nfs_expire_all_delegations ( struct nfs_client * clp )
2006-01-03 09:55:24 +01:00
{
2008-12-23 15:21:50 -05:00
nfs_client_mark_return_all_delegations ( clp ) ;
nfs_delegation_run_state_manager ( clp ) ;
2006-01-03 09:55:24 +01:00
}
2005-04-16 15:20:36 -07:00
/*
* Return all delegations following an NFS4ERR_CB_PATH_DOWN error .
*/
2006-08-22 20:06:08 -04:00
void nfs_handle_cb_pathdown ( struct nfs_client * clp )
2005-04-16 15:20:36 -07:00
{
if ( clp = = NULL )
return ;
2008-12-23 15:21:47 -05:00
nfs_client_mark_return_all_delegations ( clp ) ;
2005-04-16 15:20:36 -07:00
}
2008-12-23 15:21:52 -05:00
static void nfs_client_mark_return_unreferenced_delegations ( struct nfs_client * clp )
{
struct nfs_delegation * delegation ;
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( delegation , & clp - > cl_delegations , super_list ) {
if ( test_and_clear_bit ( NFS_DELEGATION_REFERENCED , & delegation - > flags ) )
continue ;
set_bit ( NFS_DELEGATION_RETURN , & delegation - > flags ) ;
set_bit ( NFS4CLNT_DELEGRETURN , & clp - > cl_state ) ;
}
rcu_read_unlock ( ) ;
}
void nfs_expire_unreferenced_delegations ( struct nfs_client * clp )
{
nfs_client_mark_return_unreferenced_delegations ( clp ) ;
nfs_delegation_run_state_manager ( clp ) ;
}
2005-04-16 15:20:36 -07:00
/*
* Asynchronous delegation recall !
*/
int nfs_async_inode_return_delegation ( struct inode * inode , const nfs4_stateid * stateid )
{
2008-12-23 15:21:51 -05:00
struct nfs_client * clp = NFS_SERVER ( inode ) - > nfs_client ;
struct nfs_delegation * delegation ;
2005-04-16 15:20:36 -07:00
2008-12-23 15:21:51 -05:00
rcu_read_lock ( ) ;
delegation = rcu_dereference ( NFS_I ( inode ) - > delegation ) ;
if ( delegation = = NULL | | memcmp ( delegation - > stateid . data , stateid - > data ,
sizeof ( delegation - > stateid . data ) ) ! = 0 ) {
rcu_read_unlock ( ) ;
return - ENOENT ;
}
nfs_mark_return_delegation ( clp , delegation ) ;
rcu_read_unlock ( ) ;
nfs_delegation_run_state_manager ( clp ) ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
/*
* Retrieve the inode associated with a delegation
*/
2006-08-22 20:06:08 -04:00
struct inode * nfs_delegation_find_inode ( struct nfs_client * clp , const struct nfs_fh * fhandle )
2005-04-16 15:20:36 -07:00
{
struct nfs_delegation * delegation ;
struct inode * res = NULL ;
2007-07-06 15:12:04 -04:00
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( delegation , & clp - > cl_delegations , super_list ) {
2008-12-23 15:21:39 -05:00
spin_lock ( & delegation - > lock ) ;
if ( delegation - > inode ! = NULL & &
nfs_compare_fh ( fhandle , & NFS_I ( delegation - > inode ) - > fh ) = = 0 ) {
2005-04-16 15:20:36 -07:00
res = igrab ( delegation - > inode ) ;
}
2008-12-23 15:21:39 -05:00
spin_unlock ( & delegation - > lock ) ;
if ( res ! = NULL )
break ;
2005-04-16 15:20:36 -07:00
}
2007-07-06 15:12:04 -04:00
rcu_read_unlock ( ) ;
2005-04-16 15:20:36 -07:00
return res ;
}
/*
* Mark all delegations as needing to be reclaimed
*/
2006-08-22 20:06:08 -04:00
void nfs_delegation_mark_reclaim ( struct nfs_client * clp )
2005-04-16 15:20:36 -07:00
{
struct nfs_delegation * delegation ;
2007-07-06 15:12:04 -04:00
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( delegation , & clp - > cl_delegations , super_list )
2008-12-23 15:21:39 -05:00
set_bit ( NFS_DELEGATION_NEED_RECLAIM , & delegation - > flags ) ;
2007-07-06 15:12:04 -04:00
rcu_read_unlock ( ) ;
2005-04-16 15:20:36 -07:00
}
/*
* Reap all unclaimed delegations after reboot recovery is done
*/
2006-08-22 20:06:08 -04:00
void nfs_delegation_reap_unclaimed ( struct nfs_client * clp )
2005-04-16 15:20:36 -07:00
{
2007-07-06 15:12:04 -04:00
struct nfs_delegation * delegation ;
2008-12-23 15:21:39 -05:00
struct inode * inode ;
2007-07-06 15:12:04 -04:00
restart :
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( delegation , & clp - > cl_delegations , super_list ) {
2008-12-23 15:21:39 -05:00
if ( test_bit ( NFS_DELEGATION_NEED_RECLAIM , & delegation - > flags ) = = 0 )
2005-04-16 15:20:36 -07:00
continue ;
2008-12-23 15:21:39 -05:00
inode = nfs_delegation_grab_inode ( delegation ) ;
if ( inode = = NULL )
continue ;
2007-07-06 15:12:04 -04:00
spin_lock ( & clp - > cl_lock ) ;
2008-12-23 15:21:39 -05:00
delegation = nfs_detach_delegation_locked ( NFS_I ( inode ) , NULL ) ;
2007-07-06 15:12:04 -04:00
spin_unlock ( & clp - > cl_lock ) ;
rcu_read_unlock ( ) ;
if ( delegation ! = NULL )
2007-08-06 12:18:34 -04:00
nfs_free_delegation ( delegation ) ;
2008-12-23 15:21:39 -05:00
iput ( inode ) ;
2007-07-06 15:12:04 -04:00
goto restart ;
2005-04-16 15:20:36 -07:00
}
2007-07-06 15:12:04 -04:00
rcu_read_unlock ( ) ;
2005-04-16 15:20:36 -07:00
}
2006-03-20 13:44:46 -05: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 15:12:04 -04:00
int ret = 0 ;
2006-03-20 13:44:46 -05:00
2007-07-06 15:12:04 -04:00
rcu_read_lock ( ) ;
delegation = rcu_dereference ( nfsi - > delegation ) ;
2006-03-20 13:44:46 -05:00
if ( delegation ! = NULL ) {
memcpy ( dst - > data , delegation - > stateid . data , sizeof ( dst - > data ) ) ;
2007-07-06 15:12:04 -04:00
ret = 1 ;
2006-03-20 13:44:46 -05:00
}
2007-07-06 15:12:04 -04:00
rcu_read_unlock ( ) ;
return ret ;
2006-03-20 13:44:46 -05:00
}