diff options
-rw-r--r-- | fs/nfs/nfs4_fs.h | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 153 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 46 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 4 |
4 files changed, 196 insertions, 11 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 4f48000b2b97..e59d3b4c7944 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -205,6 +205,8 @@ struct nfs4_state_maintenance_ops { | |||
205 | }; | 205 | }; |
206 | 206 | ||
207 | struct nfs4_mig_recovery_ops { | 207 | struct nfs4_mig_recovery_ops { |
208 | int (*get_locations)(struct inode *, struct nfs4_fs_locations *, | ||
209 | struct page *, struct rpc_cred *); | ||
208 | }; | 210 | }; |
209 | 211 | ||
210 | extern const struct dentry_operations nfs4_dentry_operations; | 212 | extern const struct dentry_operations nfs4_dentry_operations; |
@@ -237,6 +239,8 @@ extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait); | |||
237 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); | 239 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); |
238 | extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *, | 240 | extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *, |
239 | struct nfs4_fs_locations *, struct page *); | 241 | struct nfs4_fs_locations *, struct page *); |
242 | extern int nfs4_proc_get_locations(struct inode *, struct nfs4_fs_locations *, | ||
243 | struct page *page, struct rpc_cred *); | ||
240 | extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *, | 244 | extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *, |
241 | struct nfs_fh *, struct nfs_fattr *); | 245 | struct nfs_fh *, struct nfs_fattr *); |
242 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); | 246 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); |
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 | */ | ||
5994 | static 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 | */ | ||
6052 | static 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 | */ | ||
6112 | int 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 | ||
7884 | static const struct nfs4_mig_recovery_ops nfs40_mig_recovery_ops = { | 8035 | static 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) |
7888 | static const struct nfs4_mig_recovery_ops nfs41_mig_recovery_ops = { | 8040 | static 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 | ||
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 | } | ||
6834 | out: | 6858 | out: |
6835 | return status; | 6859 | return status; |
6836 | } | 6860 | } |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 49f52c8f4422..405dfadcbc3b 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -1053,14 +1053,18 @@ struct nfs4_fs_locations { | |||
1053 | struct nfs4_fs_locations_arg { | 1053 | struct nfs4_fs_locations_arg { |
1054 | struct nfs4_sequence_args seq_args; | 1054 | struct nfs4_sequence_args seq_args; |
1055 | const struct nfs_fh *dir_fh; | 1055 | const struct nfs_fh *dir_fh; |
1056 | const struct nfs_fh *fh; | ||
1056 | const struct qstr *name; | 1057 | const struct qstr *name; |
1057 | struct page *page; | 1058 | struct page *page; |
1058 | const u32 *bitmask; | 1059 | const u32 *bitmask; |
1060 | clientid4 clientid; | ||
1061 | unsigned char migration:1, renew:1; | ||
1059 | }; | 1062 | }; |
1060 | 1063 | ||
1061 | struct nfs4_fs_locations_res { | 1064 | struct nfs4_fs_locations_res { |
1062 | struct nfs4_sequence_res seq_res; | 1065 | struct nfs4_sequence_res seq_res; |
1063 | struct nfs4_fs_locations *fs_locations; | 1066 | struct nfs4_fs_locations *fs_locations; |
1067 | unsigned char migration:1, renew:1; | ||
1064 | }; | 1068 | }; |
1065 | 1069 | ||
1066 | struct nfs4_secinfo4 { | 1070 | struct nfs4_secinfo4 { |