diff options
-rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 128 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 67 | ||||
-rw-r--r-- | include/linux/nfs4.h | 1 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 13 |
5 files changed, 209 insertions, 2 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 94e783ffcf08..2f0f8c216441 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -208,6 +208,7 @@ struct nfs4_state_maintenance_ops { | |||
208 | struct nfs4_mig_recovery_ops { | 208 | struct nfs4_mig_recovery_ops { |
209 | int (*get_locations)(struct inode *, struct nfs4_fs_locations *, | 209 | int (*get_locations)(struct inode *, struct nfs4_fs_locations *, |
210 | struct page *, struct rpc_cred *); | 210 | struct page *, struct rpc_cred *); |
211 | int (*fsid_present)(struct inode *, struct rpc_cred *); | ||
211 | }; | 212 | }; |
212 | 213 | ||
213 | extern const struct dentry_operations nfs4_dentry_operations; | 214 | extern const struct dentry_operations nfs4_dentry_operations; |
@@ -242,6 +243,7 @@ extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struc | |||
242 | struct nfs4_fs_locations *, struct page *); | 243 | struct nfs4_fs_locations *, struct page *); |
243 | extern int nfs4_proc_get_locations(struct inode *, struct nfs4_fs_locations *, | 244 | extern int nfs4_proc_get_locations(struct inode *, struct nfs4_fs_locations *, |
244 | struct page *page, struct rpc_cred *); | 245 | struct page *page, struct rpc_cred *); |
246 | extern int nfs4_proc_fsid_present(struct inode *, struct rpc_cred *); | ||
245 | extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *, | 247 | extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *, |
246 | struct nfs_fh *, struct nfs_fattr *); | 248 | struct nfs_fh *, struct nfs_fattr *); |
247 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); | 249 | 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 552e4f7a8225..01b90bd341bb 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -6153,6 +6153,132 @@ int nfs4_proc_get_locations(struct inode *inode, | |||
6153 | return status; | 6153 | return status; |
6154 | } | 6154 | } |
6155 | 6155 | ||
6156 | /* | ||
6157 | * This operation also signals the server that this client is | ||
6158 | * performing "lease moved" recovery. The server can stop | ||
6159 | * returning NFS4ERR_LEASE_MOVED to this client. A RENEW operation | ||
6160 | * is appended to this compound to identify the client ID which is | ||
6161 | * performing recovery. | ||
6162 | */ | ||
6163 | static int _nfs40_proc_fsid_present(struct inode *inode, struct rpc_cred *cred) | ||
6164 | { | ||
6165 | struct nfs_server *server = NFS_SERVER(inode); | ||
6166 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | ||
6167 | struct rpc_clnt *clnt = server->client; | ||
6168 | struct nfs4_fsid_present_arg args = { | ||
6169 | .fh = NFS_FH(inode), | ||
6170 | .clientid = clp->cl_clientid, | ||
6171 | .renew = 1, /* append RENEW */ | ||
6172 | }; | ||
6173 | struct nfs4_fsid_present_res res = { | ||
6174 | .renew = 1, | ||
6175 | }; | ||
6176 | struct rpc_message msg = { | ||
6177 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSID_PRESENT], | ||
6178 | .rpc_argp = &args, | ||
6179 | .rpc_resp = &res, | ||
6180 | .rpc_cred = cred, | ||
6181 | }; | ||
6182 | unsigned long now = jiffies; | ||
6183 | int status; | ||
6184 | |||
6185 | res.fh = nfs_alloc_fhandle(); | ||
6186 | if (res.fh == NULL) | ||
6187 | return -ENOMEM; | ||
6188 | |||
6189 | nfs4_init_sequence(&args.seq_args, &res.seq_res, 0); | ||
6190 | nfs4_set_sequence_privileged(&args.seq_args); | ||
6191 | status = nfs4_call_sync_sequence(clnt, server, &msg, | ||
6192 | &args.seq_args, &res.seq_res); | ||
6193 | nfs_free_fhandle(res.fh); | ||
6194 | if (status) | ||
6195 | return status; | ||
6196 | |||
6197 | do_renew_lease(clp, now); | ||
6198 | return 0; | ||
6199 | } | ||
6200 | |||
6201 | #ifdef CONFIG_NFS_V4_1 | ||
6202 | |||
6203 | /* | ||
6204 | * This operation also signals the server that this client is | ||
6205 | * performing "lease moved" recovery. The server can stop asserting | ||
6206 | * SEQ4_STATUS_LEASE_MOVED for this client. The client ID performing | ||
6207 | * this operation is identified in the SEQUENCE operation in this | ||
6208 | * compound. | ||
6209 | */ | ||
6210 | static int _nfs41_proc_fsid_present(struct inode *inode, struct rpc_cred *cred) | ||
6211 | { | ||
6212 | struct nfs_server *server = NFS_SERVER(inode); | ||
6213 | struct rpc_clnt *clnt = server->client; | ||
6214 | struct nfs4_fsid_present_arg args = { | ||
6215 | .fh = NFS_FH(inode), | ||
6216 | }; | ||
6217 | struct nfs4_fsid_present_res res = { | ||
6218 | }; | ||
6219 | struct rpc_message msg = { | ||
6220 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSID_PRESENT], | ||
6221 | .rpc_argp = &args, | ||
6222 | .rpc_resp = &res, | ||
6223 | .rpc_cred = cred, | ||
6224 | }; | ||
6225 | int status; | ||
6226 | |||
6227 | res.fh = nfs_alloc_fhandle(); | ||
6228 | if (res.fh == NULL) | ||
6229 | return -ENOMEM; | ||
6230 | |||
6231 | nfs4_init_sequence(&args.seq_args, &res.seq_res, 0); | ||
6232 | nfs4_set_sequence_privileged(&args.seq_args); | ||
6233 | status = nfs4_call_sync_sequence(clnt, server, &msg, | ||
6234 | &args.seq_args, &res.seq_res); | ||
6235 | nfs_free_fhandle(res.fh); | ||
6236 | if (status == NFS4_OK && | ||
6237 | res.seq_res.sr_status_flags & SEQ4_STATUS_LEASE_MOVED) | ||
6238 | status = -NFS4ERR_LEASE_MOVED; | ||
6239 | return status; | ||
6240 | } | ||
6241 | |||
6242 | #endif /* CONFIG_NFS_V4_1 */ | ||
6243 | |||
6244 | /** | ||
6245 | * nfs4_proc_fsid_present - Is this FSID present or absent on server? | ||
6246 | * @inode: inode on FSID to check | ||
6247 | * @cred: credential to use for this operation | ||
6248 | * | ||
6249 | * Server indicates whether the FSID is present, moved, or not | ||
6250 | * recognized. This operation is necessary to clear a LEASE_MOVED | ||
6251 | * condition for this client ID. | ||
6252 | * | ||
6253 | * Returns NFS4_OK if the FSID is present on this server, | ||
6254 | * -NFS4ERR_MOVED if the FSID is no longer present, a negative | ||
6255 | * NFS4ERR code if some error occurred on the server, or a | ||
6256 | * negative errno if a local failure occurred. | ||
6257 | */ | ||
6258 | int nfs4_proc_fsid_present(struct inode *inode, struct rpc_cred *cred) | ||
6259 | { | ||
6260 | struct nfs_server *server = NFS_SERVER(inode); | ||
6261 | struct nfs_client *clp = server->nfs_client; | ||
6262 | const struct nfs4_mig_recovery_ops *ops = | ||
6263 | clp->cl_mvops->mig_recovery_ops; | ||
6264 | struct nfs4_exception exception = { }; | ||
6265 | int status; | ||
6266 | |||
6267 | dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__, | ||
6268 | (unsigned long long)server->fsid.major, | ||
6269 | (unsigned long long)server->fsid.minor, | ||
6270 | clp->cl_hostname); | ||
6271 | nfs_display_fhandle(NFS_FH(inode), __func__); | ||
6272 | |||
6273 | do { | ||
6274 | status = ops->fsid_present(inode, cred); | ||
6275 | if (status != -NFS4ERR_DELAY) | ||
6276 | break; | ||
6277 | nfs4_handle_exception(server, status, &exception); | ||
6278 | } while (exception.retry); | ||
6279 | return status; | ||
6280 | } | ||
6281 | |||
6156 | /** | 6282 | /** |
6157 | * If 'use_integrity' is true and the state managment nfs_client | 6283 | * If 'use_integrity' is true and the state managment nfs_client |
6158 | * cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient | 6284 | * cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient |
@@ -8052,11 +8178,13 @@ static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | |||
8052 | 8178 | ||
8053 | static const struct nfs4_mig_recovery_ops nfs40_mig_recovery_ops = { | 8179 | static const struct nfs4_mig_recovery_ops nfs40_mig_recovery_ops = { |
8054 | .get_locations = _nfs40_proc_get_locations, | 8180 | .get_locations = _nfs40_proc_get_locations, |
8181 | .fsid_present = _nfs40_proc_fsid_present, | ||
8055 | }; | 8182 | }; |
8056 | 8183 | ||
8057 | #if defined(CONFIG_NFS_V4_1) | 8184 | #if defined(CONFIG_NFS_V4_1) |
8058 | static const struct nfs4_mig_recovery_ops nfs41_mig_recovery_ops = { | 8185 | static const struct nfs4_mig_recovery_ops nfs41_mig_recovery_ops = { |
8059 | .get_locations = _nfs41_proc_get_locations, | 8186 | .get_locations = _nfs41_proc_get_locations, |
8187 | .fsid_present = _nfs41_proc_fsid_present, | ||
8060 | }; | 8188 | }; |
8061 | #endif /* CONFIG_NFS_V4_1 */ | 8189 | #endif /* CONFIG_NFS_V4_1 */ |
8062 | 8190 | ||
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 1854b04f828f..f903389d90f1 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -595,11 +595,13 @@ static int nfs4_stat_to_errno(int); | |||
595 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ | 595 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ |
596 | encode_sequence_maxsz + \ | 596 | encode_sequence_maxsz + \ |
597 | encode_putfh_maxsz + \ | 597 | encode_putfh_maxsz + \ |
598 | encode_getattr_maxsz) | 598 | encode_getattr_maxsz + \ |
599 | encode_renew_maxsz) | ||
599 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ | 600 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ |
600 | decode_sequence_maxsz + \ | 601 | decode_sequence_maxsz + \ |
601 | decode_putfh_maxsz + \ | 602 | decode_putfh_maxsz + \ |
602 | decode_getattr_maxsz) | 603 | decode_getattr_maxsz + \ |
604 | decode_renew_maxsz) | ||
603 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ | 605 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ |
604 | encode_sequence_maxsz + \ | 606 | encode_sequence_maxsz + \ |
605 | encode_putfh_maxsz + \ | 607 | encode_putfh_maxsz + \ |
@@ -753,6 +755,18 @@ static int nfs4_stat_to_errno(int); | |||
753 | decode_sequence_maxsz + \ | 755 | decode_sequence_maxsz + \ |
754 | decode_putfh_maxsz + \ | 756 | decode_putfh_maxsz + \ |
755 | decode_secinfo_maxsz) | 757 | decode_secinfo_maxsz) |
758 | #define NFS4_enc_fsid_present_sz \ | ||
759 | (compound_encode_hdr_maxsz + \ | ||
760 | encode_sequence_maxsz + \ | ||
761 | encode_putfh_maxsz + \ | ||
762 | encode_getfh_maxsz + \ | ||
763 | encode_renew_maxsz) | ||
764 | #define NFS4_dec_fsid_present_sz \ | ||
765 | (compound_decode_hdr_maxsz + \ | ||
766 | decode_sequence_maxsz + \ | ||
767 | decode_putfh_maxsz + \ | ||
768 | decode_getfh_maxsz + \ | ||
769 | decode_renew_maxsz) | ||
756 | #if defined(CONFIG_NFS_V4_1) | 770 | #if defined(CONFIG_NFS_V4_1) |
757 | #define NFS4_enc_bind_conn_to_session_sz \ | 771 | #define NFS4_enc_bind_conn_to_session_sz \ |
758 | (compound_encode_hdr_maxsz + \ | 772 | (compound_encode_hdr_maxsz + \ |
@@ -2726,6 +2740,26 @@ static void nfs4_xdr_enc_secinfo(struct rpc_rqst *req, | |||
2726 | encode_nops(&hdr); | 2740 | encode_nops(&hdr); |
2727 | } | 2741 | } |
2728 | 2742 | ||
2743 | /* | ||
2744 | * Encode FSID_PRESENT request | ||
2745 | */ | ||
2746 | static void nfs4_xdr_enc_fsid_present(struct rpc_rqst *req, | ||
2747 | struct xdr_stream *xdr, | ||
2748 | struct nfs4_fsid_present_arg *args) | ||
2749 | { | ||
2750 | struct compound_hdr hdr = { | ||
2751 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), | ||
2752 | }; | ||
2753 | |||
2754 | encode_compound_hdr(xdr, req, &hdr); | ||
2755 | encode_sequence(xdr, &args->seq_args, &hdr); | ||
2756 | encode_putfh(xdr, args->fh, &hdr); | ||
2757 | encode_getfh(xdr, &hdr); | ||
2758 | if (args->renew) | ||
2759 | encode_renew(xdr, args->clientid, &hdr); | ||
2760 | encode_nops(&hdr); | ||
2761 | } | ||
2762 | |||
2729 | #if defined(CONFIG_NFS_V4_1) | 2763 | #if defined(CONFIG_NFS_V4_1) |
2730 | /* | 2764 | /* |
2731 | * BIND_CONN_TO_SESSION request | 2765 | * BIND_CONN_TO_SESSION request |
@@ -6883,6 +6917,34 @@ out: | |||
6883 | return status; | 6917 | return status; |
6884 | } | 6918 | } |
6885 | 6919 | ||
6920 | /* | ||
6921 | * Decode FSID_PRESENT response | ||
6922 | */ | ||
6923 | static int nfs4_xdr_dec_fsid_present(struct rpc_rqst *rqstp, | ||
6924 | struct xdr_stream *xdr, | ||
6925 | struct nfs4_fsid_present_res *res) | ||
6926 | { | ||
6927 | struct compound_hdr hdr; | ||
6928 | int status; | ||
6929 | |||
6930 | status = decode_compound_hdr(xdr, &hdr); | ||
6931 | if (status) | ||
6932 | goto out; | ||
6933 | status = decode_sequence(xdr, &res->seq_res, rqstp); | ||
6934 | if (status) | ||
6935 | goto out; | ||
6936 | status = decode_putfh(xdr); | ||
6937 | if (status) | ||
6938 | goto out; | ||
6939 | status = decode_getfh(xdr, res->fh); | ||
6940 | if (status) | ||
6941 | goto out; | ||
6942 | if (res->renew) | ||
6943 | status = decode_renew(xdr); | ||
6944 | out: | ||
6945 | return status; | ||
6946 | } | ||
6947 | |||
6886 | #if defined(CONFIG_NFS_V4_1) | 6948 | #if defined(CONFIG_NFS_V4_1) |
6887 | /* | 6949 | /* |
6888 | * Decode BIND_CONN_TO_SESSION response | 6950 | * Decode BIND_CONN_TO_SESSION response |
@@ -7397,6 +7459,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
7397 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), | 7459 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), |
7398 | PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner), | 7460 | PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner), |
7399 | PROC(SECINFO, enc_secinfo, dec_secinfo), | 7461 | PROC(SECINFO, enc_secinfo, dec_secinfo), |
7462 | PROC(FSID_PRESENT, enc_fsid_present, dec_fsid_present), | ||
7400 | #if defined(CONFIG_NFS_V4_1) | 7463 | #if defined(CONFIG_NFS_V4_1) |
7401 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), | 7464 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), |
7402 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), | 7465 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), |
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index e36dee52f224..c56fa8fedce9 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h | |||
@@ -460,6 +460,7 @@ enum { | |||
460 | NFSPROC4_CLNT_FS_LOCATIONS, | 460 | NFSPROC4_CLNT_FS_LOCATIONS, |
461 | NFSPROC4_CLNT_RELEASE_LOCKOWNER, | 461 | NFSPROC4_CLNT_RELEASE_LOCKOWNER, |
462 | NFSPROC4_CLNT_SECINFO, | 462 | NFSPROC4_CLNT_SECINFO, |
463 | NFSPROC4_CLNT_FSID_PRESENT, | ||
463 | 464 | ||
464 | /* nfs41 */ | 465 | /* nfs41 */ |
465 | NFSPROC4_CLNT_EXCHANGE_ID, | 466 | NFSPROC4_CLNT_EXCHANGE_ID, |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 405dfadcbc3b..8fe5b940c5f2 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -1088,6 +1088,19 @@ struct nfs4_secinfo_res { | |||
1088 | struct nfs4_secinfo_flavors *flavors; | 1088 | struct nfs4_secinfo_flavors *flavors; |
1089 | }; | 1089 | }; |
1090 | 1090 | ||
1091 | struct nfs4_fsid_present_arg { | ||
1092 | struct nfs4_sequence_args seq_args; | ||
1093 | const struct nfs_fh *fh; | ||
1094 | clientid4 clientid; | ||
1095 | unsigned char renew:1; | ||
1096 | }; | ||
1097 | |||
1098 | struct nfs4_fsid_present_res { | ||
1099 | struct nfs4_sequence_res seq_res; | ||
1100 | struct nfs_fh *fh; | ||
1101 | unsigned char renew:1; | ||
1102 | }; | ||
1103 | |||
1091 | #endif /* CONFIG_NFS_V4 */ | 1104 | #endif /* CONFIG_NFS_V4 */ |
1092 | 1105 | ||
1093 | struct nfstime4 { | 1106 | struct nfstime4 { |