summaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4xdr.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/nfs4xdr.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/nfs4xdr.c')
-rw-r--r--fs/nfs/nfs4xdr.c46
1 files changed, 35 insertions, 11 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 79210d23f607..1854b04f828f 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -736,13 +736,15 @@ static int nfs4_stat_to_errno(int);
736 encode_sequence_maxsz + \ 736 encode_sequence_maxsz + \
737 encode_putfh_maxsz + \ 737 encode_putfh_maxsz + \
738 encode_lookup_maxsz + \ 738 encode_lookup_maxsz + \
739 encode_fs_locations_maxsz) 739 encode_fs_locations_maxsz + \
740 encode_renew_maxsz)
740#define NFS4_dec_fs_locations_sz \ 741#define NFS4_dec_fs_locations_sz \
741 (compound_decode_hdr_maxsz + \ 742 (compound_decode_hdr_maxsz + \
742 decode_sequence_maxsz + \ 743 decode_sequence_maxsz + \
743 decode_putfh_maxsz + \ 744 decode_putfh_maxsz + \
744 decode_lookup_maxsz + \ 745 decode_lookup_maxsz + \
745 decode_fs_locations_maxsz) 746 decode_fs_locations_maxsz + \
747 decode_renew_maxsz)
746#define NFS4_enc_secinfo_sz (compound_encode_hdr_maxsz + \ 748#define NFS4_enc_secinfo_sz (compound_encode_hdr_maxsz + \
747 encode_sequence_maxsz + \ 749 encode_sequence_maxsz + \
748 encode_putfh_maxsz + \ 750 encode_putfh_maxsz + \
@@ -2687,11 +2689,20 @@ static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req,
2687 2689
2688 encode_compound_hdr(xdr, req, &hdr); 2690 encode_compound_hdr(xdr, req, &hdr);
2689 encode_sequence(xdr, &args->seq_args, &hdr); 2691 encode_sequence(xdr, &args->seq_args, &hdr);
2690 encode_putfh(xdr, args->dir_fh, &hdr); 2692 if (args->migration) {
2691 encode_lookup(xdr, args->name, &hdr); 2693 encode_putfh(xdr, args->fh, &hdr);
2692 replen = hdr.replen; /* get the attribute into args->page */ 2694 replen = hdr.replen;
2693 encode_fs_locations(xdr, args->bitmask, &hdr); 2695 encode_fs_locations(xdr, args->bitmask, &hdr);
2696 if (args->renew)
2697 encode_renew(xdr, args->clientid, &hdr);
2698 } else {
2699 encode_putfh(xdr, args->dir_fh, &hdr);
2700 encode_lookup(xdr, args->name, &hdr);
2701 replen = hdr.replen;
2702 encode_fs_locations(xdr, args->bitmask, &hdr);
2703 }
2694 2704
2705 /* Set up reply kvec to capture returned fs_locations array. */
2695 xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page, 2706 xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page,
2696 0, PAGE_SIZE); 2707 0, PAGE_SIZE);
2697 encode_nops(&hdr); 2708 encode_nops(&hdr);
@@ -6824,13 +6835,26 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
6824 status = decode_putfh(xdr); 6835 status = decode_putfh(xdr);
6825 if (status) 6836 if (status)
6826 goto out; 6837 goto out;
6827 status = decode_lookup(xdr); 6838 if (res->migration) {
6828 if (status) 6839 xdr_enter_page(xdr, PAGE_SIZE);
6829 goto out; 6840 status = decode_getfattr_generic(xdr,
6830 xdr_enter_page(xdr, PAGE_SIZE); 6841 &res->fs_locations->fattr,
6831 status = decode_getfattr_generic(xdr, &res->fs_locations->fattr,
6832 NULL, res->fs_locations, 6842 NULL, res->fs_locations,
6833 NULL, res->fs_locations->server); 6843 NULL, res->fs_locations->server);
6844 if (status)
6845 goto out;
6846 if (res->renew)
6847 status = decode_renew(xdr);
6848 } else {
6849 status = decode_lookup(xdr);
6850 if (status)
6851 goto out;
6852 xdr_enter_page(xdr, PAGE_SIZE);
6853 status = decode_getfattr_generic(xdr,
6854 &res->fs_locations->fattr,
6855 NULL, res->fs_locations,
6856 NULL, res->fs_locations->server);
6857 }
6834out: 6858out:
6835 return status; 6859 return status;
6836} 6860}