aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2013-10-17 14:12:50 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-10-28 15:24:00 -0400
commitb03d735b4ca2375d2251195cd848713bc55e7d79 (patch)
tree5c351a0fbdc47022c74c7db5a9f80235f9105f6a /fs/nfs/nfs4proc.c
parent9e6ee76dfb7cd747fac5679542a9b45930173eec (diff)
NFS: Add method to retrieve fs_locations during migration recovery
The nfs4_proc_fs_locations() function is invoked during referral processing to perform a GETATTR(fs_locations) on an object's parent directory in order to discover the target of the referral. It performs a LOOKUP in the compound, so the client needs to know the parent's file handle a priori. Unfortunately this function is not adequate for handling migration recovery. We need to probe fs_locations information on an FSID, but there's no parent directory available for many operations that can return NFS4ERR_MOVED. Another subtlety: recovering from NFS4ERR_LEASE_MOVED is a process of walking over a list of known FSIDs that reside on the server, and probing whether they have migrated. Once the server has detected that the client has probed all migrated file systems, it stops returning NFS4ERR_LEASE_MOVED. A minor version zero server needs to know what client ID is requesting fs_locations information so it can clear the flag that forces it to continue returning NFS4ERR_LEASE_MOVED. This flag is set per client ID and per FSID. However, the client ID is not an argument of either the PUTFH or GETATTR operations. Later minor versions have client ID information embedded in the compound's SEQUENCE operation. Therefore, by convention, minor version zero clients send a RENEW operation in the same compound as the GETATTR(fs_locations), since RENEW's one argument is a clientid4. This allows a minor version zero server to identify correctly the client that is probing for a migration. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 2aacd1357dc5..c71c16e0ac22 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -5984,6 +5984,157 @@ int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
5984 return err; 5984 return err;
5985} 5985}
5986 5986
5987/*
5988 * This operation also signals the server that this client is
5989 * performing migration recovery. The server can stop returning
5990 * NFS4ERR_LEASE_MOVED to this client. A RENEW operation is
5991 * appended to this compound to identify the client ID which is
5992 * performing recovery.
5993 */
5994static int _nfs40_proc_get_locations(struct inode *inode,
5995 struct nfs4_fs_locations *locations,
5996 struct page *page, struct rpc_cred *cred)
5997{
5998 struct nfs_server *server = NFS_SERVER(inode);
5999 struct rpc_clnt *clnt = server->client;
6000 u32 bitmask[2] = {
6001 [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
6002 };
6003 struct nfs4_fs_locations_arg args = {
6004 .clientid = server->nfs_client->cl_clientid,
6005 .fh = NFS_FH(inode),
6006 .page = page,
6007 .bitmask = bitmask,
6008 .migration = 1, /* skip LOOKUP */
6009 .renew = 1, /* append RENEW */
6010 };
6011 struct nfs4_fs_locations_res res = {
6012 .fs_locations = locations,
6013 .migration = 1,
6014 .renew = 1,
6015 };
6016 struct rpc_message msg = {
6017 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
6018 .rpc_argp = &args,
6019 .rpc_resp = &res,
6020 .rpc_cred = cred,
6021 };
6022 unsigned long now = jiffies;
6023 int status;
6024
6025 nfs_fattr_init(&locations->fattr);
6026 locations->server = server;
6027 locations->nlocations = 0;
6028
6029 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0);
6030 nfs4_set_sequence_privileged(&args.seq_args);
6031 status = nfs4_call_sync_sequence(clnt, server, &msg,
6032 &args.seq_args, &res.seq_res);
6033 if (status)
6034 return status;
6035
6036 renew_lease(server, now);
6037 return 0;
6038}
6039
6040#ifdef CONFIG_NFS_V4_1
6041
6042/*
6043 * This operation also signals the server that this client is
6044 * performing migration recovery. The server can stop asserting
6045 * SEQ4_STATUS_LEASE_MOVED for this client. The client ID
6046 * performing this operation is identified in the SEQUENCE
6047 * operation in this compound.
6048 *
6049 * When the client supports GETATTR(fs_locations_info), it can
6050 * be plumbed in here.
6051 */
6052static int _nfs41_proc_get_locations(struct inode *inode,
6053 struct nfs4_fs_locations *locations,
6054 struct page *page, struct rpc_cred *cred)
6055{
6056 struct nfs_server *server = NFS_SERVER(inode);
6057 struct rpc_clnt *clnt = server->client;
6058 u32 bitmask[2] = {
6059 [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
6060 };
6061 struct nfs4_fs_locations_arg args = {
6062 .fh = NFS_FH(inode),
6063 .page = page,
6064 .bitmask = bitmask,
6065 .migration = 1, /* skip LOOKUP */
6066 };
6067 struct nfs4_fs_locations_res res = {
6068 .fs_locations = locations,
6069 .migration = 1,
6070 };
6071 struct rpc_message msg = {
6072 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
6073 .rpc_argp = &args,
6074 .rpc_resp = &res,
6075 .rpc_cred = cred,
6076 };
6077 int status;
6078
6079 nfs_fattr_init(&locations->fattr);
6080 locations->server = server;
6081 locations->nlocations = 0;
6082
6083 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0);
6084 nfs4_set_sequence_privileged(&args.seq_args);
6085 status = nfs4_call_sync_sequence(clnt, server, &msg,
6086 &args.seq_args, &res.seq_res);
6087 if (status == NFS4_OK &&
6088 res.seq_res.sr_status_flags & SEQ4_STATUS_LEASE_MOVED)
6089 status = -NFS4ERR_LEASE_MOVED;
6090 return status;
6091}
6092
6093#endif /* CONFIG_NFS_V4_1 */
6094
6095/**
6096 * nfs4_proc_get_locations - discover locations for a migrated FSID
6097 * @inode: inode on FSID that is migrating
6098 * @locations: result of query
6099 * @page: buffer
6100 * @cred: credential to use for this operation
6101 *
6102 * Returns NFS4_OK on success, a negative NFS4ERR status code if the
6103 * operation failed, or a negative errno if a local error occurred.
6104 *
6105 * On success, "locations" is filled in, but if the server has
6106 * no locations information, NFS_ATTR_FATTR_V4_LOCATIONS is not
6107 * asserted.
6108 *
6109 * -NFS4ERR_LEASE_MOVED is returned if the server still has leases
6110 * from this client that require migration recovery.
6111 */
6112int nfs4_proc_get_locations(struct inode *inode,
6113 struct nfs4_fs_locations *locations,
6114 struct page *page, struct rpc_cred *cred)
6115{
6116 struct nfs_server *server = NFS_SERVER(inode);
6117 struct nfs_client *clp = server->nfs_client;
6118 const struct nfs4_mig_recovery_ops *ops =
6119 clp->cl_mvops->mig_recovery_ops;
6120 struct nfs4_exception exception = { };
6121 int status;
6122
6123 dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__,
6124 (unsigned long long)server->fsid.major,
6125 (unsigned long long)server->fsid.minor,
6126 clp->cl_hostname);
6127 nfs_display_fhandle(NFS_FH(inode), __func__);
6128
6129 do {
6130 status = ops->get_locations(inode, locations, page, cred);
6131 if (status != -NFS4ERR_DELAY)
6132 break;
6133 nfs4_handle_exception(server, status, &exception);
6134 } while (exception.retry);
6135 return status;
6136}
6137
5987/** 6138/**
5988 * If 'use_integrity' is true and the state managment nfs_client 6139 * If 'use_integrity' is true and the state managment nfs_client
5989 * cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient 6140 * cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient
@@ -7882,10 +8033,12 @@ static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
7882#endif 8033#endif
7883 8034
7884static const struct nfs4_mig_recovery_ops nfs40_mig_recovery_ops = { 8035static const struct nfs4_mig_recovery_ops nfs40_mig_recovery_ops = {
8036 .get_locations = _nfs40_proc_get_locations,
7885}; 8037};
7886 8038
7887#if defined(CONFIG_NFS_V4_1) 8039#if defined(CONFIG_NFS_V4_1)
7888static const struct nfs4_mig_recovery_ops nfs41_mig_recovery_ops = { 8040static const struct nfs4_mig_recovery_ops nfs41_mig_recovery_ops = {
8041 .get_locations = _nfs41_proc_get_locations,
7889}; 8042};
7890#endif /* CONFIG_NFS_V4_1 */ 8043#endif /* CONFIG_NFS_V4_1 */
7891 8044