diff options
author | Marc Eshel <eshel@almaden.ibm.com> | 2009-04-03 01:27:52 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-04-03 20:41:14 -0400 |
commit | 5282fd724b667b7d65f2e41e405a825e58a78813 (patch) | |
tree | 6603d2895c789db0e2244e9966f3a2246a6addb9 | |
parent | c4bf7868064ce8b9c75d8049d077e593c20602b3 (diff) |
nfsd41: sessionid hashing
Simple sessionid hashing using its monotonically increasing sequence number.
Locking considerations:
sessionid_hashtbl access is controlled by the sessionid_lock spin lock.
It must be taken for insert, delete, and lookup.
nfsd4_sequence looks up the session id and if the session is found,
it calls nfsd4_get_session (still under the sessionid_lock).
nfsd4_destroy_session calls nfsd4_put_session after unhashing
it, so when the session's kref reaches zero it's going to get freed.
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[we don't use a prime for sessionid hash table size]
[use sessionid_lock spin lock]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
-rw-r--r-- | fs/nfsd/nfs4state.c | 55 | ||||
-rw-r--r-- | include/linux/nfsd/state.h | 7 |
2 files changed, 61 insertions, 1 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f23385b13065..fc20e1f38d75 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -382,11 +382,62 @@ static void release_openowner(struct nfs4_stateowner *sop) | |||
382 | nfs4_put_stateowner(sop); | 382 | nfs4_put_stateowner(sop); |
383 | } | 383 | } |
384 | 384 | ||
385 | static DEFINE_SPINLOCK(sessionid_lock); | ||
386 | #define SESSION_HASH_SIZE 512 | ||
387 | static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE]; | ||
388 | |||
389 | static inline int | ||
390 | hash_sessionid(struct nfs4_sessionid *sessionid) | ||
391 | { | ||
392 | struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; | ||
393 | |||
394 | return sid->sequence % SESSION_HASH_SIZE; | ||
395 | } | ||
396 | |||
397 | static inline void | ||
398 | dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) | ||
399 | { | ||
400 | u32 *ptr = (u32 *)(&sessionid->data[0]); | ||
401 | dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); | ||
402 | } | ||
403 | |||
404 | /* caller must hold sessionid_lock */ | ||
405 | static struct nfsd4_session * | ||
406 | find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) | ||
407 | { | ||
408 | struct nfsd4_session *elem; | ||
409 | int idx; | ||
410 | |||
411 | dump_sessionid(__func__, sessionid); | ||
412 | idx = hash_sessionid(sessionid); | ||
413 | dprintk("%s: idx is %d\n", __func__, idx); | ||
414 | /* Search in the appropriate list */ | ||
415 | list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { | ||
416 | dump_sessionid("list traversal", &elem->se_sessionid); | ||
417 | if (!memcmp(elem->se_sessionid.data, sessionid->data, | ||
418 | NFS4_MAX_SESSIONID_LEN)) { | ||
419 | return elem; | ||
420 | } | ||
421 | } | ||
422 | |||
423 | dprintk("%s: session not found\n", __func__); | ||
424 | return NULL; | ||
425 | } | ||
426 | |||
427 | /* caller must hold sessionid_lock */ | ||
385 | static void | 428 | static void |
386 | release_session(struct nfsd4_session *ses) | 429 | unhash_session(struct nfsd4_session *ses) |
387 | { | 430 | { |
388 | list_del(&ses->se_hash); | 431 | list_del(&ses->se_hash); |
389 | list_del(&ses->se_perclnt); | 432 | list_del(&ses->se_perclnt); |
433 | } | ||
434 | |||
435 | static void | ||
436 | release_session(struct nfsd4_session *ses) | ||
437 | { | ||
438 | spin_lock(&sessionid_lock); | ||
439 | unhash_session(ses); | ||
440 | spin_unlock(&sessionid_lock); | ||
390 | nfsd4_put_session(ses); | 441 | nfsd4_put_session(ses); |
391 | } | 442 | } |
392 | 443 | ||
@@ -3205,6 +3256,8 @@ nfs4_state_init(void) | |||
3205 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); | 3256 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); |
3206 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); | 3257 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); |
3207 | } | 3258 | } |
3259 | for (i = 0; i < SESSION_HASH_SIZE; i++) | ||
3260 | INIT_LIST_HEAD(&sessionid_hashtbl[i]); | ||
3208 | for (i = 0; i < FILE_HASH_SIZE; i++) { | 3261 | for (i = 0; i < FILE_HASH_SIZE; i++) { |
3209 | INIT_LIST_HEAD(&file_hashtbl[i]); | 3262 | INIT_LIST_HEAD(&file_hashtbl[i]); |
3210 | } | 3263 | } |
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 7faefc7c9d9a..5b3a6660f3af 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h | |||
@@ -132,6 +132,13 @@ nfsd4_get_session(struct nfsd4_session *ses) | |||
132 | kref_get(&ses->se_ref); | 132 | kref_get(&ses->se_ref); |
133 | } | 133 | } |
134 | 134 | ||
135 | /* formatted contents of nfs4_sessionid */ | ||
136 | struct nfsd4_sessionid { | ||
137 | clientid_t clientid; | ||
138 | u32 sequence; | ||
139 | u32 reserved; | ||
140 | }; | ||
141 | |||
135 | #define HEXDIR_LEN 33 /* hex version of 16 byte md5 of cl_name plus '\0' */ | 142 | #define HEXDIR_LEN 33 /* hex version of 16 byte md5 of cl_name plus '\0' */ |
136 | 143 | ||
137 | /* | 144 | /* |