aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfs4state.c144
-rw-r--r--fs/nfsd/state.h3
2 files changed, 95 insertions, 52 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 559ab574d46..99998a1eb42 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -412,10 +412,10 @@ static unsigned int clientstr_hashval(const char *name)
412 * reclaim_str_hashtbl[] holds known client info from previous reset/reboot 412 * reclaim_str_hashtbl[] holds known client info from previous reset/reboot
413 * used in reboot/reset lease grace period processing 413 * used in reboot/reset lease grace period processing
414 * 414 *
415 * conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed 415 * conf_id_hashtbl[], and conf_name_tree hold confirmed
416 * setclientid_confirmed info. 416 * setclientid_confirmed info.
417 * 417 *
418 * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed 418 * unconf_id_hashtbl[] and unconf_name_tree hold unconfirmed
419 * setclientid info. 419 * setclientid info.
420 * 420 *
421 * client_lru holds client queue ordered by nfs4_client.cl_time 421 * client_lru holds client queue ordered by nfs4_client.cl_time
@@ -423,13 +423,15 @@ static unsigned int clientstr_hashval(const char *name)
423 * 423 *
424 * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time 424 * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time
425 * for last close replay. 425 * for last close replay.
426 *
427 * All of the above fields are protected by the client_mutex.
426 */ 428 */
427static struct list_head reclaim_str_hashtbl[CLIENT_HASH_SIZE]; 429static struct list_head reclaim_str_hashtbl[CLIENT_HASH_SIZE];
428static int reclaim_str_hashtbl_size = 0; 430static int reclaim_str_hashtbl_size = 0;
429static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE]; 431static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE];
430static struct list_head conf_str_hashtbl[CLIENT_HASH_SIZE];
431static struct list_head unconf_str_hashtbl[CLIENT_HASH_SIZE];
432static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; 432static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE];
433static struct rb_root conf_name_tree;
434static struct rb_root unconf_name_tree;
433static struct list_head client_lru; 435static struct list_head client_lru;
434static struct list_head close_lru; 436static struct list_head close_lru;
435 437
@@ -1144,7 +1146,10 @@ destroy_client(struct nfs4_client *clp)
1144 if (clp->cl_cb_conn.cb_xprt) 1146 if (clp->cl_cb_conn.cb_xprt)
1145 svc_xprt_put(clp->cl_cb_conn.cb_xprt); 1147 svc_xprt_put(clp->cl_cb_conn.cb_xprt);
1146 list_del(&clp->cl_idhash); 1148 list_del(&clp->cl_idhash);
1147 list_del(&clp->cl_strhash); 1149 if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
1150 rb_erase(&clp->cl_namenode, &conf_name_tree);
1151 else
1152 rb_erase(&clp->cl_namenode, &unconf_name_tree);
1148 spin_lock(&client_lock); 1153 spin_lock(&client_lock);
1149 unhash_client_locked(clp); 1154 unhash_client_locked(clp);
1150 if (atomic_read(&clp->cl_refcount) == 0) 1155 if (atomic_read(&clp->cl_refcount) == 0)
@@ -1187,6 +1192,17 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source)
1187 return 0; 1192 return 0;
1188} 1193}
1189 1194
1195static long long
1196compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
1197{
1198 long long res;
1199
1200 res = o1->len - o2->len;
1201 if (res)
1202 return res;
1203 return (long long)memcmp(o1->data, o2->data, o1->len);
1204}
1205
1190static int same_name(const char *n1, const char *n2) 1206static int same_name(const char *n1, const char *n2)
1191{ 1207{
1192 return 0 == memcmp(n1, n2, HEXDIR_LEN); 1208 return 0 == memcmp(n1, n2, HEXDIR_LEN);
@@ -1307,7 +1323,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
1307 atomic_set(&clp->cl_refcount, 0); 1323 atomic_set(&clp->cl_refcount, 0);
1308 clp->cl_cb_state = NFSD4_CB_UNKNOWN; 1324 clp->cl_cb_state = NFSD4_CB_UNKNOWN;
1309 INIT_LIST_HEAD(&clp->cl_idhash); 1325 INIT_LIST_HEAD(&clp->cl_idhash);
1310 INIT_LIST_HEAD(&clp->cl_strhash);
1311 INIT_LIST_HEAD(&clp->cl_openowners); 1326 INIT_LIST_HEAD(&clp->cl_openowners);
1312 INIT_LIST_HEAD(&clp->cl_delegations); 1327 INIT_LIST_HEAD(&clp->cl_delegations);
1313 INIT_LIST_HEAD(&clp->cl_lru); 1328 INIT_LIST_HEAD(&clp->cl_lru);
@@ -1325,11 +1340,52 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
1325} 1340}
1326 1341
1327static void 1342static void
1328add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) 1343add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root)
1344{
1345 struct rb_node **new = &(root->rb_node), *parent = NULL;
1346 struct nfs4_client *clp;
1347
1348 while (*new) {
1349 clp = rb_entry(*new, struct nfs4_client, cl_namenode);
1350 parent = *new;
1351
1352 if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0)
1353 new = &((*new)->rb_left);
1354 else
1355 new = &((*new)->rb_right);
1356 }
1357
1358 rb_link_node(&new_clp->cl_namenode, parent, new);
1359 rb_insert_color(&new_clp->cl_namenode, root);
1360}
1361
1362static struct nfs4_client *
1363find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root)
1364{
1365 long long cmp;
1366 struct rb_node *node = root->rb_node;
1367 struct nfs4_client *clp;
1368
1369 while (node) {
1370 clp = rb_entry(node, struct nfs4_client, cl_namenode);
1371 cmp = compare_blob(&clp->cl_name, name);
1372 if (cmp > 0)
1373 node = node->rb_left;
1374 else if (cmp < 0)
1375 node = node->rb_right;
1376 else
1377 return clp;
1378 }
1379 return NULL;
1380}
1381
1382static void
1383add_to_unconfirmed(struct nfs4_client *clp)
1329{ 1384{
1330 unsigned int idhashval; 1385 unsigned int idhashval;
1331 1386
1332 list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); 1387 clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
1388 add_clp_to_name_tree(clp, &unconf_name_tree);
1333 idhashval = clientid_hashval(clp->cl_clientid.cl_id); 1389 idhashval = clientid_hashval(clp->cl_clientid.cl_id);
1334 list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); 1390 list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]);
1335 renew_client(clp); 1391 renew_client(clp);
@@ -1339,12 +1395,12 @@ static void
1339move_to_confirmed(struct nfs4_client *clp) 1395move_to_confirmed(struct nfs4_client *clp)
1340{ 1396{
1341 unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 1397 unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
1342 unsigned int strhashval;
1343 1398
1344 dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); 1399 dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
1345 list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); 1400 list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
1346 strhashval = clientstr_hashval(clp->cl_recdir); 1401 rb_erase(&clp->cl_namenode, &unconf_name_tree);
1347 list_move(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); 1402 add_clp_to_name_tree(clp, &conf_name_tree);
1403 set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
1348 renew_client(clp); 1404 renew_client(clp);
1349} 1405}
1350 1406
@@ -1387,27 +1443,15 @@ static bool clp_used_exchangeid(struct nfs4_client *clp)
1387} 1443}
1388 1444
1389static struct nfs4_client * 1445static struct nfs4_client *
1390find_confirmed_client_by_str(const char *dname, unsigned int hashval) 1446find_confirmed_client_by_name(struct xdr_netobj *name)
1391{ 1447{
1392 struct nfs4_client *clp; 1448 return find_clp_in_name_tree(name, &conf_name_tree);
1393
1394 list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) {
1395 if (same_name(clp->cl_recdir, dname))
1396 return clp;
1397 }
1398 return NULL;
1399} 1449}
1400 1450
1401static struct nfs4_client * 1451static struct nfs4_client *
1402find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) 1452find_unconfirmed_client_by_name(struct xdr_netobj *name)
1403{ 1453{
1404 struct nfs4_client *clp; 1454 return find_clp_in_name_tree(name, &unconf_name_tree);
1405
1406 list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) {
1407 if (same_name(clp->cl_recdir, dname))
1408 return clp;
1409 }
1410 return NULL;
1411} 1455}
1412 1456
1413static void 1457static void
@@ -1572,7 +1616,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
1572{ 1616{
1573 struct nfs4_client *unconf, *conf, *new; 1617 struct nfs4_client *unconf, *conf, *new;
1574 __be32 status; 1618 __be32 status;
1575 unsigned int strhashval;
1576 char dname[HEXDIR_LEN]; 1619 char dname[HEXDIR_LEN];
1577 char addr_str[INET6_ADDRSTRLEN]; 1620 char addr_str[INET6_ADDRSTRLEN];
1578 nfs4_verifier verf = exid->verifier; 1621 nfs4_verifier verf = exid->verifier;
@@ -1605,11 +1648,9 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
1605 if (status) 1648 if (status)
1606 return status; 1649 return status;
1607 1650
1608 strhashval = clientstr_hashval(dname);
1609
1610 /* Cases below refer to rfc 5661 section 18.35.4: */ 1651 /* Cases below refer to rfc 5661 section 18.35.4: */
1611 nfs4_lock_state(); 1652 nfs4_lock_state();
1612 conf = find_confirmed_client_by_str(dname, strhashval); 1653 conf = find_confirmed_client_by_name(&exid->clname);
1613 if (conf) { 1654 if (conf) {
1614 bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 1655 bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred);
1615 bool verfs_match = same_verf(&verf, &conf->cl_verifier); 1656 bool verfs_match = same_verf(&verf, &conf->cl_verifier);
@@ -1654,7 +1695,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
1654 goto out; 1695 goto out;
1655 } 1696 }
1656 1697
1657 unconf = find_unconfirmed_client_by_str(dname, strhashval); 1698 unconf = find_unconfirmed_client_by_name(&exid->clname);
1658 if (unconf) /* case 4, possible retry or client restart */ 1699 if (unconf) /* case 4, possible retry or client restart */
1659 expire_client(unconf); 1700 expire_client(unconf);
1660 1701
@@ -1668,7 +1709,7 @@ out_new:
1668 new->cl_minorversion = 1; 1709 new->cl_minorversion = 1;
1669 1710
1670 gen_clid(new); 1711 gen_clid(new);
1671 add_to_unconfirmed(new, strhashval); 1712 add_to_unconfirmed(new);
1672out_copy: 1713out_copy:
1673 exid->clientid.cl_boot = new->cl_clientid.cl_boot; 1714 exid->clientid.cl_boot = new->cl_clientid.cl_boot;
1674 exid->clientid.cl_id = new->cl_clientid.cl_id; 1715 exid->clientid.cl_id = new->cl_clientid.cl_id;
@@ -1789,7 +1830,6 @@ nfsd4_create_session(struct svc_rqst *rqstp,
1789 goto out_free_conn; 1830 goto out_free_conn;
1790 } 1831 }
1791 } else if (unconf) { 1832 } else if (unconf) {
1792 unsigned int hash;
1793 struct nfs4_client *old; 1833 struct nfs4_client *old;
1794 if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 1834 if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
1795 !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 1835 !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
@@ -1803,8 +1843,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
1803 status = nfserr_seq_misordered; 1843 status = nfserr_seq_misordered;
1804 goto out_free_conn; 1844 goto out_free_conn;
1805 } 1845 }
1806 hash = clientstr_hashval(unconf->cl_recdir); 1846 old = find_confirmed_client_by_name(&unconf->cl_name);
1807 old = find_confirmed_client_by_str(unconf->cl_recdir, hash);
1808 if (old) 1847 if (old)
1809 expire_client(old); 1848 expire_client(old);
1810 move_to_confirmed(unconf); 1849 move_to_confirmed(unconf);
@@ -2195,7 +2234,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2195{ 2234{
2196 struct xdr_netobj clname = setclid->se_name; 2235 struct xdr_netobj clname = setclid->se_name;
2197 nfs4_verifier clverifier = setclid->se_verf; 2236 nfs4_verifier clverifier = setclid->se_verf;
2198 unsigned int strhashval;
2199 struct nfs4_client *conf, *unconf, *new; 2237 struct nfs4_client *conf, *unconf, *new;
2200 __be32 status; 2238 __be32 status;
2201 char dname[HEXDIR_LEN]; 2239 char dname[HEXDIR_LEN];
@@ -2204,11 +2242,9 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2204 if (status) 2242 if (status)
2205 return status; 2243 return status;
2206 2244
2207 strhashval = clientstr_hashval(dname);
2208
2209 /* Cases below refer to rfc 3530 section 14.2.33: */ 2245 /* Cases below refer to rfc 3530 section 14.2.33: */
2210 nfs4_lock_state(); 2246 nfs4_lock_state();
2211 conf = find_confirmed_client_by_str(dname, strhashval); 2247 conf = find_confirmed_client_by_name(&clname);
2212 if (conf) { 2248 if (conf) {
2213 /* case 0: */ 2249 /* case 0: */
2214 status = nfserr_clid_inuse; 2250 status = nfserr_clid_inuse;
@@ -2223,7 +2259,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2223 goto out; 2259 goto out;
2224 } 2260 }
2225 } 2261 }
2226 unconf = find_unconfirmed_client_by_str(dname, strhashval); 2262 unconf = find_unconfirmed_client_by_name(&clname);
2227 if (unconf) 2263 if (unconf)
2228 expire_client(unconf); 2264 expire_client(unconf);
2229 status = nfserr_jukebox; 2265 status = nfserr_jukebox;
@@ -2237,7 +2273,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2237 gen_clid(new); 2273 gen_clid(new);
2238 new->cl_minorversion = 0; 2274 new->cl_minorversion = 0;
2239 gen_callback(new, setclid, rqstp); 2275 gen_callback(new, setclid, rqstp);
2240 add_to_unconfirmed(new, strhashval); 2276 add_to_unconfirmed(new);
2241 setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 2277 setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
2242 setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 2278 setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
2243 memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 2279 memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
@@ -2290,9 +2326,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
2290 nfsd4_probe_callback(conf); 2326 nfsd4_probe_callback(conf);
2291 expire_client(unconf); 2327 expire_client(unconf);
2292 } else { /* case 3: normal case; new or rebooted client */ 2328 } else { /* case 3: normal case; new or rebooted client */
2293 unsigned int hash = clientstr_hashval(unconf->cl_recdir); 2329 conf = find_confirmed_client_by_name(&unconf->cl_name);
2294
2295 conf = find_confirmed_client_by_str(unconf->cl_recdir, hash);
2296 if (conf) 2330 if (conf)
2297 expire_client(conf); 2331 expire_client(conf);
2298 move_to_confirmed(unconf); 2332 move_to_confirmed(unconf);
@@ -4706,11 +4740,11 @@ nfs4_state_init(void)
4706 4740
4707 for (i = 0; i < CLIENT_HASH_SIZE; i++) { 4741 for (i = 0; i < CLIENT_HASH_SIZE; i++) {
4708 INIT_LIST_HEAD(&conf_id_hashtbl[i]); 4742 INIT_LIST_HEAD(&conf_id_hashtbl[i]);
4709 INIT_LIST_HEAD(&conf_str_hashtbl[i]);
4710 INIT_LIST_HEAD(&unconf_str_hashtbl[i]);
4711 INIT_LIST_HEAD(&unconf_id_hashtbl[i]); 4743 INIT_LIST_HEAD(&unconf_id_hashtbl[i]);
4712 INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); 4744 INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
4713 } 4745 }
4746 conf_name_tree = RB_ROOT;
4747 unconf_name_tree = RB_ROOT;
4714 for (i = 0; i < SESSION_HASH_SIZE; i++) 4748 for (i = 0; i < SESSION_HASH_SIZE; i++)
4715 INIT_LIST_HEAD(&sessionid_hashtbl[i]); 4749 INIT_LIST_HEAD(&sessionid_hashtbl[i]);
4716 for (i = 0; i < FILE_HASH_SIZE; i++) { 4750 for (i = 0; i < FILE_HASH_SIZE; i++) {
@@ -4795,6 +4829,7 @@ out_recovery:
4795 return ret; 4829 return ret;
4796} 4830}
4797 4831
4832/* should be called with the state lock held */
4798static void 4833static void
4799__nfs4_state_shutdown(void) 4834__nfs4_state_shutdown(void)
4800{ 4835{
@@ -4802,17 +4837,24 @@ __nfs4_state_shutdown(void)
4802 struct nfs4_client *clp = NULL; 4837 struct nfs4_client *clp = NULL;
4803 struct nfs4_delegation *dp = NULL; 4838 struct nfs4_delegation *dp = NULL;
4804 struct list_head *pos, *next, reaplist; 4839 struct list_head *pos, *next, reaplist;
4840 struct rb_node *node, *tmp;
4805 4841
4806 for (i = 0; i < CLIENT_HASH_SIZE; i++) { 4842 for (i = 0; i < CLIENT_HASH_SIZE; i++) {
4807 while (!list_empty(&conf_id_hashtbl[i])) { 4843 while (!list_empty(&conf_id_hashtbl[i])) {
4808 clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 4844 clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
4809 destroy_client(clp); 4845 destroy_client(clp);
4810 } 4846 }
4811 while (!list_empty(&unconf_str_hashtbl[i])) {
4812 clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash);
4813 destroy_client(clp);
4814 }
4815 } 4847 }
4848
4849 node = rb_first(&unconf_name_tree);
4850 while (node != NULL) {
4851 tmp = node;
4852 node = rb_next(tmp);
4853 clp = rb_entry(tmp, struct nfs4_client, cl_namenode);
4854 rb_erase(tmp, &unconf_name_tree);
4855 destroy_client(clp);
4856 }
4857
4816 INIT_LIST_HEAD(&reaplist); 4858 INIT_LIST_HEAD(&reaplist);
4817 spin_lock(&recall_lock); 4859 spin_lock(&recall_lock);
4818 list_for_each_safe(pos, next, &del_recall_lru) { 4860 list_for_each_safe(pos, next, &del_recall_lru) {
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index cf9f7ba4df8..6c342bd806e 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -232,7 +232,7 @@ struct nfsd4_sessionid {
232 */ 232 */
233struct nfs4_client { 233struct nfs4_client {
234 struct list_head cl_idhash; /* hash by cl_clientid.id */ 234 struct list_head cl_idhash; /* hash by cl_clientid.id */
235 struct list_head cl_strhash; /* hash by cl_name */ 235 struct rb_node cl_namenode; /* link into by-name trees */
236 struct list_head cl_openowners; 236 struct list_head cl_openowners;
237 struct idr cl_stateids; /* stateid lookup */ 237 struct idr cl_stateids; /* stateid lookup */
238 struct list_head cl_delegations; 238 struct list_head cl_delegations;
@@ -253,6 +253,7 @@ struct nfs4_client {
253#define NFSD4_CLIENT_CB_KILL (1) 253#define NFSD4_CLIENT_CB_KILL (1)
254#define NFSD4_CLIENT_STABLE (2) /* client on stable storage */ 254#define NFSD4_CLIENT_STABLE (2) /* client on stable storage */
255#define NFSD4_CLIENT_RECLAIM_COMPLETE (3) /* reclaim_complete done */ 255#define NFSD4_CLIENT_RECLAIM_COMPLETE (3) /* reclaim_complete done */
256#define NFSD4_CLIENT_CONFIRMED (4) /* client is confirmed */
256#define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \ 257#define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \
257 1 << NFSD4_CLIENT_CB_KILL) 258 1 << NFSD4_CLIENT_CB_KILL)
258 unsigned long cl_flags; 259 unsigned long cl_flags;