2005-04-17 02:20:36 +04:00
/*
* fs / nfs / nfs4renewd . c
*
* Copyright ( c ) 2002 The Regents of the University of Michigan .
* All rights reserved .
*
* Kendrick Smith < kmsmith @ 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 .
*
* Implementation of the NFSv4 " renew daemon " , which wakes up periodically to
* send a RENEW , to keep state alive on the server . The daemon is implemented
* as an rpc_task , not a real kernel thread , so it always runs in rpciod ' s
* context . There is one renewd per nfs_server .
*
* TODO : If the send queue gets backlogged ( e . g . , if the server goes down ) ,
* we will keep filling the queue with periodic RENEW requests . We need a
* mechanism for ensuring that if renewd successfully sends off a request ,
* then it only wakes up when the request is finished . Maybe use the
* child task framework of the RPC layer ?
*/
# include <linux/mm.h>
# include <linux/pagemap.h>
# include <linux/sunrpc/sched.h>
# include <linux/sunrpc/clnt.h>
# include <linux/nfs.h>
# include <linux/nfs4.h>
# include <linux/nfs_fs.h>
2005-06-22 21:16:21 +04:00
# include "nfs4_fs.h"
2006-01-03 11:55:24 +03:00
# include "delegation.h"
2005-04-17 02:20:36 +04:00
# define NFSDBG_FACILITY NFSDBG_PROC
void
2006-11-22 17:55:48 +03:00
nfs4_renew_state ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
2006-11-22 17:55:48 +03:00
struct nfs_client * clp =
container_of ( work , struct nfs_client , cl_renewd . work ) ;
2006-01-03 11:55:25 +03:00
struct rpc_cred * cred ;
2005-04-17 02:20:36 +04:00
long lease , timeout ;
unsigned long last , now ;
2008-05-03 00:42:44 +04:00
dprintk ( " %s: start \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* Are there any active superblocks? */
if ( list_empty ( & clp - > cl_superblocks ) )
2006-01-03 11:55:24 +03:00
goto out ;
2005-04-17 02:20:36 +04:00
spin_lock ( & clp - > cl_lock ) ;
lease = clp - > cl_lease_time ;
last = clp - > cl_last_renewal ;
now = jiffies ;
timeout = ( 2 * lease ) / 3 + ( long ) last - ( long ) now ;
/* Are we close to a lease timeout? */
if ( time_after ( now , last + lease / 3 ) ) {
2008-12-23 23:21:41 +03:00
cred = nfs4_get_renew_cred_locked ( clp ) ;
2008-12-23 23:21:50 +03:00
spin_unlock ( & clp - > cl_lock ) ;
2006-01-03 11:55:25 +03:00
if ( cred = = NULL ) {
2008-12-23 23:21:50 +03:00
if ( list_empty ( & clp - > cl_delegations ) ) {
set_bit ( NFS4CLNT_LEASE_EXPIRED , & clp - > cl_state ) ;
goto out ;
}
2006-01-03 11:55:24 +03:00
nfs_expire_all_delegations ( clp ) ;
2008-12-23 23:21:50 +03:00
} else {
/* Queue an asynchronous RENEW. */
nfs4_proc_async_renew ( clp , cred ) ;
put_rpccred ( cred ) ;
2006-01-03 11:55:24 +03:00
}
2005-04-17 02:20:36 +04:00
timeout = ( 2 * lease ) / 3 ;
spin_lock ( & clp - > cl_lock ) ;
} else
dprintk ( " %s: failed to call renewd. Reason: lease not expired \n " ,
2008-05-03 00:42:44 +04:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
if ( timeout < 5 * HZ ) /* safeguard */
timeout = 5 * HZ ;
dprintk ( " %s: requeueing work. Lease period = %ld \n " ,
2008-05-03 00:42:44 +04:00
__func__ , ( timeout + HZ - 1 ) / HZ ) ;
2005-04-17 02:20:36 +04:00
cancel_delayed_work ( & clp - > cl_renewd ) ;
schedule_delayed_work ( & clp - > cl_renewd , timeout ) ;
spin_unlock ( & clp - > cl_lock ) ;
2008-12-23 23:21:52 +03:00
nfs_expire_unreferenced_delegations ( clp ) ;
2005-04-17 02:20:36 +04:00
out :
2008-05-03 00:42:44 +04:00
dprintk ( " %s: done \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
void
2006-08-23 04:06:08 +04:00
nfs4_schedule_state_renewal ( struct nfs_client * clp )
2005-04-17 02:20:36 +04:00
{
long timeout ;
spin_lock ( & clp - > cl_lock ) ;
timeout = ( 2 * clp - > cl_lease_time ) / 3 + ( long ) clp - > cl_last_renewal
- ( long ) jiffies ;
if ( timeout < 5 * HZ )
timeout = 5 * HZ ;
dprintk ( " %s: requeueing work. Lease period = %ld \n " ,
2008-05-03 00:42:44 +04:00
__func__ , ( timeout + HZ - 1 ) / HZ ) ;
2005-04-17 02:20:36 +04:00
cancel_delayed_work ( & clp - > cl_renewd ) ;
schedule_delayed_work ( & clp - > cl_renewd , timeout ) ;
2006-08-24 09:03:05 +04:00
set_bit ( NFS_CS_RENEWD , & clp - > cl_res_state ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & clp - > cl_lock ) ;
}
void
nfs4_renewd_prepare_shutdown ( struct nfs_server * server )
{
2007-08-07 23:28:33 +04:00
cancel_delayed_work ( & server - > nfs_client - > cl_renewd ) ;
2005-04-17 02:20:36 +04:00
}
void
2006-08-23 04:06:08 +04:00
nfs4_kill_renewd ( struct nfs_client * clp )
2005-04-17 02:20:36 +04:00
{
2007-08-07 23:28:33 +04:00
cancel_delayed_work_sync ( & clp - > cl_renewd ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Local variables :
* c - basic - offset : 8
* End :
*/