diff options
author | J. Bruce Fields <bfields@redhat.com> | 2010-11-24 17:30:54 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2010-12-17 15:48:01 -0500 |
commit | e203d506bd221bfa5b3acbb7336ae7b7646636a4 (patch) | |
tree | 237901e3b618d50f7ab65ff86dde3aaf1497c09f /fs/nfsd/nfs4state.c | |
parent | 6e5f15c93dc745d46c2bb9e4597b44463203844b (diff) |
nfsd4: fix mixed 4.0/4.1 handling, 4.1 reboot
Instead of failing to find client entries which don't match the
minorversion, we should be finding them, then either erroring out or
expiring them as appropriate.
This also fixes a problem which would cause the 4.1 server to fail to
recognize clients after a second reboot.
Reported-by: Casey Bodley <cbodley@citi.umich.edu>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 37 |
1 files changed, 17 insertions, 20 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 0c61cc1eadca..73adcfb2dc17 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -1134,39 +1134,30 @@ find_unconfirmed_client(clientid_t *clid) | |||
1134 | return NULL; | 1134 | return NULL; |
1135 | } | 1135 | } |
1136 | 1136 | ||
1137 | /* | ||
1138 | * FIXME: we need to unify the clientid namespaces for nfsv4.x | ||
1139 | * and correctly deal with client upgrade/downgrade in EXCHANGE_ID | ||
1140 | * and SET_CLIENTID{,_CONFIRM} | ||
1141 | */ | ||
1142 | static bool clp_used_exchangeid(struct nfs4_client *clp) | 1137 | static bool clp_used_exchangeid(struct nfs4_client *clp) |
1143 | { | 1138 | { |
1144 | return clp->cl_exchange_flags != 0; | 1139 | return clp->cl_exchange_flags != 0; |
1145 | } | 1140 | } |
1146 | 1141 | ||
1147 | static struct nfs4_client * | 1142 | static struct nfs4_client * |
1148 | find_confirmed_client_by_str(const char *dname, unsigned int hashval, | 1143 | find_confirmed_client_by_str(const char *dname, unsigned int hashval) |
1149 | bool use_exchange_id) | ||
1150 | { | 1144 | { |
1151 | struct nfs4_client *clp; | 1145 | struct nfs4_client *clp; |
1152 | 1146 | ||
1153 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { | 1147 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { |
1154 | if (same_name(clp->cl_recdir, dname) && | 1148 | if (same_name(clp->cl_recdir, dname)) |
1155 | clp_used_exchangeid(clp) == use_exchange_id) | ||
1156 | return clp; | 1149 | return clp; |
1157 | } | 1150 | } |
1158 | return NULL; | 1151 | return NULL; |
1159 | } | 1152 | } |
1160 | 1153 | ||
1161 | static struct nfs4_client * | 1154 | static struct nfs4_client * |
1162 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval, | 1155 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) |
1163 | bool use_exchange_id) | ||
1164 | { | 1156 | { |
1165 | struct nfs4_client *clp; | 1157 | struct nfs4_client *clp; |
1166 | 1158 | ||
1167 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { | 1159 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { |
1168 | if (same_name(clp->cl_recdir, dname) && | 1160 | if (same_name(clp->cl_recdir, dname)) |
1169 | clp_used_exchangeid(clp) == use_exchange_id) | ||
1170 | return clp; | 1161 | return clp; |
1171 | } | 1162 | } |
1172 | return NULL; | 1163 | return NULL; |
@@ -1357,8 +1348,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1357 | nfs4_lock_state(); | 1348 | nfs4_lock_state(); |
1358 | status = nfs_ok; | 1349 | status = nfs_ok; |
1359 | 1350 | ||
1360 | conf = find_confirmed_client_by_str(dname, strhashval, true); | 1351 | conf = find_confirmed_client_by_str(dname, strhashval); |
1361 | if (conf) { | 1352 | if (conf) { |
1353 | if (!clp_used_exchangeid(conf)) { | ||
1354 | status = nfserr_clid_inuse; /* XXX: ? */ | ||
1355 | goto out; | ||
1356 | } | ||
1362 | if (!same_verf(&verf, &conf->cl_verifier)) { | 1357 | if (!same_verf(&verf, &conf->cl_verifier)) { |
1363 | /* 18.35.4 case 8 */ | 1358 | /* 18.35.4 case 8 */ |
1364 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1359 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { |
@@ -1399,7 +1394,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1399 | goto out; | 1394 | goto out; |
1400 | } | 1395 | } |
1401 | 1396 | ||
1402 | unconf = find_unconfirmed_client_by_str(dname, strhashval, true); | 1397 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1403 | if (unconf) { | 1398 | if (unconf) { |
1404 | /* | 1399 | /* |
1405 | * Possible retry or client restart. Per 18.35.4 case 4, | 1400 | * Possible retry or client restart. Per 18.35.4 case 4, |
@@ -1799,10 +1794,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1799 | strhashval = clientstr_hashval(dname); | 1794 | strhashval = clientstr_hashval(dname); |
1800 | 1795 | ||
1801 | nfs4_lock_state(); | 1796 | nfs4_lock_state(); |
1802 | conf = find_confirmed_client_by_str(dname, strhashval, false); | 1797 | conf = find_confirmed_client_by_str(dname, strhashval); |
1803 | if (conf) { | 1798 | if (conf) { |
1804 | /* RFC 3530 14.2.33 CASE 0: */ | 1799 | /* RFC 3530 14.2.33 CASE 0: */ |
1805 | status = nfserr_clid_inuse; | 1800 | status = nfserr_clid_inuse; |
1801 | if (clp_used_exchangeid(conf)) | ||
1802 | goto out; | ||
1806 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { | 1803 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { |
1807 | char addr_str[INET6_ADDRSTRLEN]; | 1804 | char addr_str[INET6_ADDRSTRLEN]; |
1808 | rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, | 1805 | rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, |
@@ -1817,7 +1814,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1817 | * has a description of SETCLIENTID request processing consisting | 1814 | * has a description of SETCLIENTID request processing consisting |
1818 | * of 5 bullet points, labeled as CASE0 - CASE4 below. | 1815 | * of 5 bullet points, labeled as CASE0 - CASE4 below. |
1819 | */ | 1816 | */ |
1820 | unconf = find_unconfirmed_client_by_str(dname, strhashval, false); | 1817 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1821 | status = nfserr_resource; | 1818 | status = nfserr_resource; |
1822 | if (!conf) { | 1819 | if (!conf) { |
1823 | /* | 1820 | /* |
@@ -1962,7 +1959,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1962 | unsigned int hash = | 1959 | unsigned int hash = |
1963 | clientstr_hashval(unconf->cl_recdir); | 1960 | clientstr_hashval(unconf->cl_recdir); |
1964 | conf = find_confirmed_client_by_str(unconf->cl_recdir, | 1961 | conf = find_confirmed_client_by_str(unconf->cl_recdir, |
1965 | hash, false); | 1962 | hash); |
1966 | if (conf) { | 1963 | if (conf) { |
1967 | nfsd4_remove_clid_dir(conf); | 1964 | nfsd4_remove_clid_dir(conf); |
1968 | expire_client(conf); | 1965 | expire_client(conf); |
@@ -4106,7 +4103,7 @@ nfs4_has_reclaimed_state(const char *name, bool use_exchange_id) | |||
4106 | unsigned int strhashval = clientstr_hashval(name); | 4103 | unsigned int strhashval = clientstr_hashval(name); |
4107 | struct nfs4_client *clp; | 4104 | struct nfs4_client *clp; |
4108 | 4105 | ||
4109 | clp = find_confirmed_client_by_str(name, strhashval, use_exchange_id); | 4106 | clp = find_confirmed_client_by_str(name, strhashval); |
4110 | return clp ? 1 : 0; | 4107 | return clp ? 1 : 0; |
4111 | } | 4108 | } |
4112 | 4109 | ||