aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2013-10-17 14:13:35 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-10-28 15:30:21 -0400
commitb7f7a66e420a9f3ec82a5124720013cee317e73a (patch)
treebe7da5ca8b2bf98e2e91237503101eb77d389d87 /fs
parent44c9993384e9311cd56acf6ead3baffab616ae50 (diff)
NFS: Support NFS4ERR_LEASE_MOVED recovery in state manager
A migration on the FSID in play for the current NFS operation is reported via the error status code NFS4ERR_MOVED. "Lease moved" means that a migration has occurred on some other FSID than the one for the current operation. It's a signal that the client should take action immediately to handle a migration that it may not have noticed otherwise. This is so that the client's lease does not expire unnoticed on the destination server. In NFSv4.0, a moved lease is reported with the NFS4ERR_LEASE_MOVED error status code. To recover from NFS4ERR_LEASE_MOVED, check each FSID for that server to see if it is still present. Invoke nfs4_try_migration() if the FSID is no longer present on the server. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/nfs4_fs.h2
-rw-r--r--fs/nfs/nfs4state.c73
2 files changed, 74 insertions, 1 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 2f0f8c216441..210e44ed1d2a 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -30,6 +30,7 @@ enum nfs4_client_state {
30 NFS4CLNT_PURGE_STATE, 30 NFS4CLNT_PURGE_STATE,
31 NFS4CLNT_BIND_CONN_TO_SESSION, 31 NFS4CLNT_BIND_CONN_TO_SESSION,
32 NFS4CLNT_MOVED, 32 NFS4CLNT_MOVED,
33 NFS4CLNT_LEASE_MOVED,
33}; 34};
34 35
35#define NFS4_RENEW_TIMEOUT 0x01 36#define NFS4_RENEW_TIMEOUT 0x01
@@ -425,6 +426,7 @@ extern void nfs4_schedule_state_manager(struct nfs_client *);
425extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp); 426extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp);
426extern int nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *); 427extern int nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *);
427extern int nfs4_schedule_migration_recovery(const struct nfs_server *); 428extern int nfs4_schedule_migration_recovery(const struct nfs_server *);
429extern void nfs4_schedule_lease_moved_recovery(struct nfs_client *);
428extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); 430extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags);
429extern void nfs41_handle_server_scope(struct nfs_client *, 431extern void nfs41_handle_server_scope(struct nfs_client *,
430 struct nfs41_server_scope **); 432 struct nfs41_server_scope **);
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index ba0db18b5f67..552706d2d776 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1233,6 +1233,22 @@ int nfs4_schedule_migration_recovery(const struct nfs_server *server)
1233} 1233}
1234EXPORT_SYMBOL_GPL(nfs4_schedule_migration_recovery); 1234EXPORT_SYMBOL_GPL(nfs4_schedule_migration_recovery);
1235 1235
1236/**
1237 * nfs4_schedule_lease_moved_recovery - start lease-moved recovery
1238 *
1239 * @clp: server to check for moved leases
1240 *
1241 */
1242void nfs4_schedule_lease_moved_recovery(struct nfs_client *clp)
1243{
1244 dprintk("%s: scheduling lease-moved recovery for client ID %llx on %s\n",
1245 __func__, clp->cl_clientid, clp->cl_hostname);
1246
1247 set_bit(NFS4CLNT_LEASE_MOVED, &clp->cl_state);
1248 nfs4_schedule_state_manager(clp);
1249}
1250EXPORT_SYMBOL_GPL(nfs4_schedule_lease_moved_recovery);
1251
1236int nfs4_wait_clnt_recover(struct nfs_client *clp) 1252int nfs4_wait_clnt_recover(struct nfs_client *clp)
1237{ 1253{
1238 int res; 1254 int res;
@@ -1661,7 +1677,6 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
1661 nfs4_state_end_reclaim_reboot(clp); 1677 nfs4_state_end_reclaim_reboot(clp);
1662 break; 1678 break;
1663 case -NFS4ERR_STALE_CLIENTID: 1679 case -NFS4ERR_STALE_CLIENTID:
1664 case -NFS4ERR_LEASE_MOVED:
1665 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); 1680 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1666 nfs4_state_clear_reclaim_reboot(clp); 1681 nfs4_state_clear_reclaim_reboot(clp);
1667 nfs4_state_start_reclaim_reboot(clp); 1682 nfs4_state_start_reclaim_reboot(clp);
@@ -1975,6 +1990,55 @@ restart:
1975 return 0; 1990 return 0;
1976} 1991}
1977 1992
1993/*
1994 * Test each nfs_server on the clp's cl_superblocks list to see
1995 * if it's moved to another server. Stop when the server no longer
1996 * returns NFS4ERR_LEASE_MOVED.
1997 */
1998static int nfs4_handle_lease_moved(struct nfs_client *clp)
1999{
2000 const struct nfs4_state_maintenance_ops *ops =
2001 clp->cl_mvops->state_renewal_ops;
2002 struct nfs_server *server;
2003 struct rpc_cred *cred;
2004
2005 dprintk("%s: lease moved reported on \"%s\"\n", __func__,
2006 clp->cl_hostname);
2007
2008 spin_lock(&clp->cl_lock);
2009 cred = ops->get_state_renewal_cred_locked(clp);
2010 spin_unlock(&clp->cl_lock);
2011 if (cred == NULL)
2012 return -NFS4ERR_NOENT;
2013
2014 clp->cl_mig_gen++;
2015restart:
2016 rcu_read_lock();
2017 list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
2018 struct inode *inode;
2019 int status;
2020
2021 if (server->mig_gen == clp->cl_mig_gen)
2022 continue;
2023 server->mig_gen = clp->cl_mig_gen;
2024
2025 rcu_read_unlock();
2026
2027 inode = server->super->s_root->d_inode;
2028 status = nfs4_proc_fsid_present(inode, cred);
2029 if (status != -NFS4ERR_MOVED)
2030 goto restart; /* wasn't this one */
2031 if (nfs4_try_migration(server, cred) == -NFS4ERR_LEASE_MOVED)
2032 goto restart; /* there are more */
2033 goto out;
2034 }
2035 rcu_read_unlock();
2036
2037out:
2038 put_rpccred(cred);
2039 return 0;
2040}
2041
1978/** 2042/**
1979 * nfs4_discover_server_trunking - Detect server IP address trunking 2043 * nfs4_discover_server_trunking - Detect server IP address trunking
1980 * 2044 *
@@ -2312,6 +2376,13 @@ static void nfs4_state_manager(struct nfs_client *clp)
2312 goto out_error; 2376 goto out_error;
2313 } 2377 }
2314 2378
2379 if (test_and_clear_bit(NFS4CLNT_LEASE_MOVED, &clp->cl_state)) {
2380 section = "lease moved";
2381 status = nfs4_handle_lease_moved(clp);
2382 if (status < 0)
2383 goto out_error;
2384 }
2385
2315 /* First recover reboot state... */ 2386 /* First recover reboot state... */
2316 if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { 2387 if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
2317 section = "reclaim reboot"; 2388 section = "reclaim reboot";