aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2014-07-30 08:27:06 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-08-01 16:28:20 -0400
commit3dbacee6e127e7595f83654251cf129cbadc2c26 (patch)
tree4ecf2a4ea9a2a18b3d9117b56a222f666b117210 /fs/nfsd
parent5cc40fd7b623b306adfe1eba1b509e95890358f5 (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.c33
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
1929static void 1929static 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
1943static struct nfs4_client * 1943static 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) */
2242out_new: 2244out_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;
2250out_copy: 2253out_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
2261out: 2264out:
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;
2943out: 2951out:
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