diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-07-30 08:27:06 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-08-01 16:28:20 -0400 |
commit | 3dbacee6e127e7595f83654251cf129cbadc2c26 (patch) | |
tree | 4ecf2a4ea9a2a18b3d9117b56a222f666b117210 /fs/nfsd | |
parent | 5cc40fd7b623b306adfe1eba1b509e95890358f5 (diff) |
nfsd: Protect unconfirmed client creation using client_lock
...instead of relying on the client_mutex.
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4state.c | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 4b42cb95e315..f149e30475db 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -1923,7 +1923,7 @@ add_to_unconfirmed(struct nfs4_client *clp) | |||
1923 | add_clp_to_name_tree(clp, &nn->unconf_name_tree); | 1923 | add_clp_to_name_tree(clp, &nn->unconf_name_tree); |
1924 | idhashval = clientid_hashval(clp->cl_clientid.cl_id); | 1924 | idhashval = clientid_hashval(clp->cl_clientid.cl_id); |
1925 | list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); | 1925 | list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); |
1926 | renew_client(clp); | 1926 | renew_client_locked(clp); |
1927 | } | 1927 | } |
1928 | 1928 | ||
1929 | static void | 1929 | static void |
@@ -1937,7 +1937,7 @@ move_to_confirmed(struct nfs4_client *clp) | |||
1937 | rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); | 1937 | rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); |
1938 | add_clp_to_name_tree(clp, &nn->conf_name_tree); | 1938 | add_clp_to_name_tree(clp, &nn->conf_name_tree); |
1939 | set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); | 1939 | set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); |
1940 | renew_client(clp); | 1940 | renew_client_locked(clp); |
1941 | } | 1941 | } |
1942 | 1942 | ||
1943 | static struct nfs4_client * | 1943 | static struct nfs4_client * |
@@ -1950,7 +1950,7 @@ find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) | |||
1950 | if (same_clid(&clp->cl_clientid, clid)) { | 1950 | if (same_clid(&clp->cl_clientid, clid)) { |
1951 | if ((bool)clp->cl_minorversion != sessions) | 1951 | if ((bool)clp->cl_minorversion != sessions) |
1952 | return NULL; | 1952 | return NULL; |
1953 | renew_client(clp); | 1953 | renew_client_locked(clp); |
1954 | return clp; | 1954 | return clp; |
1955 | } | 1955 | } |
1956 | } | 1956 | } |
@@ -2152,7 +2152,8 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
2152 | struct nfsd4_compound_state *cstate, | 2152 | struct nfsd4_compound_state *cstate, |
2153 | struct nfsd4_exchange_id *exid) | 2153 | struct nfsd4_exchange_id *exid) |
2154 | { | 2154 | { |
2155 | struct nfs4_client *unconf, *conf, *new; | 2155 | struct nfs4_client *conf, *new; |
2156 | struct nfs4_client *unconf = NULL; | ||
2156 | __be32 status; | 2157 | __be32 status; |
2157 | char addr_str[INET6_ADDRSTRLEN]; | 2158 | char addr_str[INET6_ADDRSTRLEN]; |
2158 | nfs4_verifier verf = exid->verifier; | 2159 | nfs4_verifier verf = exid->verifier; |
@@ -2187,6 +2188,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
2187 | 2188 | ||
2188 | /* Cases below refer to rfc 5661 section 18.35.4: */ | 2189 | /* Cases below refer to rfc 5661 section 18.35.4: */ |
2189 | nfs4_lock_state(); | 2190 | nfs4_lock_state(); |
2191 | spin_lock(&nn->client_lock); | ||
2190 | conf = find_confirmed_client_by_name(&exid->clname, nn); | 2192 | conf = find_confirmed_client_by_name(&exid->clname, nn); |
2191 | if (conf) { | 2193 | if (conf) { |
2192 | bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); | 2194 | bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); |
@@ -2218,7 +2220,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
2218 | status = nfserr_clid_inuse; | 2220 | status = nfserr_clid_inuse; |
2219 | goto out; | 2221 | goto out; |
2220 | } | 2222 | } |
2221 | expire_client(conf); | ||
2222 | goto out_new; | 2223 | goto out_new; |
2223 | } | 2224 | } |
2224 | if (verfs_match) { /* case 2 */ | 2225 | if (verfs_match) { /* case 2 */ |
@@ -2226,6 +2227,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
2226 | goto out_copy; | 2227 | goto out_copy; |
2227 | } | 2228 | } |
2228 | /* case 5, client reboot */ | 2229 | /* case 5, client reboot */ |
2230 | conf = NULL; | ||
2229 | goto out_new; | 2231 | goto out_new; |
2230 | } | 2232 | } |
2231 | 2233 | ||
@@ -2236,17 +2238,18 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
2236 | 2238 | ||
2237 | unconf = find_unconfirmed_client_by_name(&exid->clname, nn); | 2239 | unconf = find_unconfirmed_client_by_name(&exid->clname, nn); |
2238 | if (unconf) /* case 4, possible retry or client restart */ | 2240 | if (unconf) /* case 4, possible retry or client restart */ |
2239 | expire_client(unconf); | 2241 | unhash_client_locked(unconf); |
2240 | 2242 | ||
2241 | /* case 1 (normal case) */ | 2243 | /* case 1 (normal case) */ |
2242 | out_new: | 2244 | out_new: |
2245 | if (conf) | ||
2246 | unhash_client_locked(conf); | ||
2243 | new->cl_minorversion = cstate->minorversion; | 2247 | new->cl_minorversion = cstate->minorversion; |
2244 | new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED); | 2248 | new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED); |
2245 | 2249 | ||
2246 | gen_clid(new, nn); | 2250 | gen_clid(new, nn); |
2247 | add_to_unconfirmed(new); | 2251 | add_to_unconfirmed(new); |
2248 | conf = new; | 2252 | swap(new, conf); |
2249 | new = NULL; | ||
2250 | out_copy: | 2253 | out_copy: |
2251 | exid->clientid.cl_boot = conf->cl_clientid.cl_boot; | 2254 | exid->clientid.cl_boot = conf->cl_clientid.cl_boot; |
2252 | exid->clientid.cl_id = conf->cl_clientid.cl_id; | 2255 | exid->clientid.cl_id = conf->cl_clientid.cl_id; |
@@ -2259,9 +2262,12 @@ out_copy: | |||
2259 | status = nfs_ok; | 2262 | status = nfs_ok; |
2260 | 2263 | ||
2261 | out: | 2264 | out: |
2265 | spin_unlock(&nn->client_lock); | ||
2262 | nfs4_unlock_state(); | 2266 | nfs4_unlock_state(); |
2263 | if (new) | 2267 | if (new) |
2264 | free_client(new); | 2268 | expire_client(new); |
2269 | if (unconf) | ||
2270 | expire_client(unconf); | ||
2265 | return status; | 2271 | return status; |
2266 | } | 2272 | } |
2267 | 2273 | ||
@@ -2900,7 +2906,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2900 | { | 2906 | { |
2901 | struct xdr_netobj clname = setclid->se_name; | 2907 | struct xdr_netobj clname = setclid->se_name; |
2902 | nfs4_verifier clverifier = setclid->se_verf; | 2908 | nfs4_verifier clverifier = setclid->se_verf; |
2903 | struct nfs4_client *conf, *unconf, *new; | 2909 | struct nfs4_client *conf, *new; |
2910 | struct nfs4_client *unconf = NULL; | ||
2904 | __be32 status; | 2911 | __be32 status; |
2905 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | 2912 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
2906 | 2913 | ||
@@ -2909,6 +2916,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2909 | return nfserr_jukebox; | 2916 | return nfserr_jukebox; |
2910 | /* Cases below refer to rfc 3530 section 14.2.33: */ | 2917 | /* Cases below refer to rfc 3530 section 14.2.33: */ |
2911 | nfs4_lock_state(); | 2918 | nfs4_lock_state(); |
2919 | spin_lock(&nn->client_lock); | ||
2912 | conf = find_confirmed_client_by_name(&clname, nn); | 2920 | conf = find_confirmed_client_by_name(&clname, nn); |
2913 | if (conf) { | 2921 | if (conf) { |
2914 | /* case 0: */ | 2922 | /* case 0: */ |
@@ -2926,7 +2934,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2926 | } | 2934 | } |
2927 | unconf = find_unconfirmed_client_by_name(&clname, nn); | 2935 | unconf = find_unconfirmed_client_by_name(&clname, nn); |
2928 | if (unconf) | 2936 | if (unconf) |
2929 | expire_client(unconf); | 2937 | unhash_client_locked(unconf); |
2930 | if (conf && same_verf(&conf->cl_verifier, &clverifier)) | 2938 | if (conf && same_verf(&conf->cl_verifier, &clverifier)) |
2931 | /* case 1: probable callback update */ | 2939 | /* case 1: probable callback update */ |
2932 | copy_clid(new, conf); | 2940 | copy_clid(new, conf); |
@@ -2941,9 +2949,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2941 | new = NULL; | 2949 | new = NULL; |
2942 | status = nfs_ok; | 2950 | status = nfs_ok; |
2943 | out: | 2951 | out: |
2952 | spin_unlock(&nn->client_lock); | ||
2944 | nfs4_unlock_state(); | 2953 | nfs4_unlock_state(); |
2945 | if (new) | 2954 | if (new) |
2946 | free_client(new); | 2955 | free_client(new); |
2956 | if (unconf) | ||
2957 | expire_client(unconf); | ||
2947 | return status; | 2958 | return status; |
2948 | } | 2959 | } |
2949 | 2960 | ||