nfs-ganesha 1.4
|
00001 00032 #ifdef HAVE_CONFIG_H 00033 #include "config.h" 00034 #endif 00035 00036 #ifdef _SOLARIS 00037 #include "solaris_port.h" 00038 #endif 00039 00040 #include <assert.h> 00041 #include "HashData.h" 00042 #include "HashTable.h" 00043 #include "log.h" 00044 #include "nfs_core.h" 00045 #include "nfs_exports.h" 00046 #include "config_parsing.h" 00047 #include <stdlib.h> 00048 #include <string.h> 00049 #include <pthread.h> 00050 #include "nfs4.h" 00051 #include "sal_data.h" 00052 #include "sal_functions.h" 00053 #include "cache_inode_lru.h" 00054 #include "abstract_atomic.h" 00055 00056 /* Hashtables used to cache NFSv4 clientids */ 00057 hash_table_t * ht_client_record; 00058 hash_table_t * ht_confirmed_client_id; 00059 hash_table_t * ht_unconfirmed_client_id; 00060 pthread_mutex_t clientid_mutex = PTHREAD_MUTEX_INITIALIZER; 00061 uint32_t clientid_counter; 00062 uint64_t clientid_verifier; 00063 pool_t * client_id_pool; 00064 pool_t * client_record_pool; 00065 00066 const char * clientid_confirm_state_to_str(nfs_clientid_confirm_state_t confirmed) 00067 { 00068 switch(confirmed) 00069 { 00070 case CONFIRMED_CLIENT_ID: return "CONFIRMED"; 00071 case UNCONFIRMED_CLIENT_ID: return "UNCONFIRMED"; 00072 case EXPIRED_CLIENT_ID: return "EXPIRED"; 00073 } 00074 return "UNKNOWN STATE"; 00075 } 00076 00077 int display_client_id_rec(nfs_client_id_t * pclientid, char * str) 00078 { 00079 int delta; 00080 char * tmpstr = str; 00081 00082 tmpstr += sprintf(tmpstr, "%p ClientID=%"PRIx64" %s Client={", 00083 pclientid, 00084 pclientid->cid_clientid, 00085 clientid_confirm_state_to_str(pclientid->cid_confirmed)); 00086 00087 if(pclientid->cid_client_record != NULL) 00088 tmpstr += display_client_record(pclientid->cid_client_record, tmpstr); 00089 else 00090 tmpstr += sprintf(tmpstr, "<NULL>"); 00091 00092 if(pclientid->cid_lease_reservations > 0) 00093 delta = 0; 00094 else 00095 delta = time(NULL) - pclientid->cid_last_renew; 00096 00097 tmpstr += sprintf(tmpstr, "} cb_prog=%u r_addr=%s r_netid=%s t_delta=%d reservations=%d refcount=%"PRId32, 00098 pclientid->cid_cb.cid_program, 00099 pclientid->cid_cb.cid_client_r_addr, 00100 netid_nc_table[pclientid->cid_cb.cid_addr.nc].netid, 00101 delta, 00102 pclientid->cid_lease_reservations, 00103 atomic_fetch_int32_t(&pclientid->cid_refcount)); 00104 00105 return tmpstr - str; 00106 } 00107 00108 int display_clientid_name(nfs_client_id_t * pclientid, char * str) 00109 { 00110 if(pclientid->cid_client_record != NULL) 00111 return DisplayOpaqueValue(pclientid->cid_client_record->cr_client_val, 00112 pclientid->cid_client_record->cr_client_val_len, 00113 str); 00114 else 00115 return sprintf(str, "<NULL>"); 00116 } 00117 00118 static void Hash_inc_client_id_ref(hash_buffer_t *buffval) 00119 { 00120 nfs_client_id_t *pclientid = buffval->pdata; 00121 00122 inc_client_id_ref(pclientid); 00123 } 00124 00125 void inc_client_id_ref(nfs_client_id_t *pclientid) 00126 { 00127 int32_t cid_refcount = atomic_inc_int32_t(&pclientid->cid_refcount); 00128 00129 if(isFullDebug(COMPONENT_CLIENTID)) 00130 { 00131 char str[HASHTABLE_DISPLAY_STRLEN]; 00132 00133 display_client_id_rec(pclientid, str); 00134 LogFullDebug(COMPONENT_CLIENTID, 00135 "Increment refcount Clientid {%s} to %"PRId32, 00136 str, cid_refcount); 00137 } 00138 } 00139 00140 void free_client_id(nfs_client_id_t *pclientid) 00141 { 00142 assert(atomic_fetch_int32_t(&pclientid->cid_refcount) == 0); 00143 00144 if(pclientid->cid_client_record != NULL) 00145 dec_client_record_ref(pclientid->cid_client_record); 00146 00147 if(pthread_mutex_destroy(&pclientid->cid_mutex) != 0) 00148 LogDebug(COMPONENT_CLIENTID, 00149 "pthread_mutex_destroy returned errno %d (%s)", 00150 errno, strerror(errno)); 00151 00152 pool_free(client_id_pool, pclientid); 00153 } 00154 00155 void dec_client_id_ref(nfs_client_id_t *pclientid) 00156 { 00157 char str[HASHTABLE_DISPLAY_STRLEN]; 00158 int32_t cid_refcount; 00159 00160 if(isFullDebug(COMPONENT_CLIENTID)) 00161 display_client_id_rec(pclientid, str); 00162 00163 cid_refcount = atomic_dec_int32_t(&pclientid->cid_refcount); 00164 00165 LogFullDebug(COMPONENT_CLIENTID, 00166 "Decrement refcount Clientid {%s} refcount to %"PRId32, 00167 str, cid_refcount); 00168 00169 if(cid_refcount > 0) 00170 return; 00171 00172 /* We don't need a lock to look at cid_confirmed because when refcount has 00173 * gone to 0, no other threads can have a pointer to the clientid record. 00174 */ 00175 if(pclientid->cid_confirmed != EXPIRED_CLIENT_ID) 00176 { 00177 /* Is not in any hash table, so we can just delete it */ 00178 LogFullDebug(COMPONENT_CLIENTID, 00179 "Free Clientid {%s} refcount now=0", 00180 str); 00181 00182 free_client_id(pclientid); 00183 } 00184 else 00185 { 00186 /* Clientid records should not be freed unless marked expired. */ 00187 LogDebug(COMPONENT_CLIENTID, 00188 "Should not be here, try to remove last ref {%s}", 00189 str); 00190 00191 assert(pclientid->cid_confirmed == EXPIRED_CLIENT_ID); 00192 } 00193 } 00194 00212 uint32_t client_id_value_hash_func(hash_parameter_t * p_hparam, 00213 hash_buffer_t * buffclef) 00214 { 00215 clientid4 clientid; 00216 00217 memcpy(&clientid, buffclef->pdata, sizeof(clientid)); 00218 00219 return (uint32_t) clientid % p_hparam->index_size; 00220 } /* client_id_value_hash_func */ 00221 00238 uint64_t client_id_rbt_hash_func(hash_parameter_t * p_hparam, 00239 hash_buffer_t * buffclef) 00240 { 00241 clientid4 clientid; 00242 00243 memcpy(&clientid, buffclef->pdata, sizeof(clientid)); 00244 00245 return clientid; 00246 } /* client_id_rbt_hash_func */ 00247 00261 int compare_client_id(hash_buffer_t * buff1, hash_buffer_t * buff2) 00262 { 00263 clientid4 cl1 = *((clientid4 *) (buff1->pdata)); 00264 clientid4 cl2 = *((clientid4 *) (buff2->pdata)); 00265 return (cl1 == cl2) ? 0 : 1; 00266 } 00267 00281 int display_client_id_key(hash_buffer_t * pbuff, char *str) 00282 { 00283 clientid4 clientid; 00284 00285 clientid = *((clientid4 *) (pbuff->pdata)); 00286 00287 return sprintf(str, "%"PRIx64, clientid); 00288 } 00289 00290 int display_client_id_val(hash_buffer_t * pbuff, char *str) 00291 { 00292 return display_client_id_rec(pbuff->pdata, str); 00293 } 00294 00295 nfs_client_id_t * create_client_id(clientid4 clientid, 00296 nfs_client_record_t * pclient_record, 00297 sockaddr_t * pclient_addr, 00298 nfs_client_cred_t * pcredential) 00299 { 00300 nfs_client_id_t * pclientid = pool_alloc(client_id_pool, NULL); 00301 state_owner_t * powner; 00302 00303 if(pclientid == NULL) 00304 { 00305 LogDebug(COMPONENT_CLIENTID, 00306 "Unable to allocate memory for clientid %"PRIx64, 00307 clientid); 00308 return NULL; 00309 } 00310 00311 if(pthread_mutex_init(&pclientid->cid_mutex, NULL) == -1) 00312 { 00313 if(isDebug(COMPONENT_CLIENTID)) 00314 { 00315 char str_client[NFS4_OPAQUE_LIMIT * 2 + 1]; 00316 00317 display_clientid_name(pclientid, str_client); 00318 00319 LogDebug(COMPONENT_CLIENTID, 00320 "Could not init mutex for clientid %"PRIx64"->%s", 00321 clientid, str_client); 00322 } 00323 00324 /* Directly free the clientid record since we failed to initialize it */ 00325 pool_free(client_id_pool, pclientid); 00326 00327 return NULL; 00328 } 00329 00330 powner = &pclientid->cid_owner; 00331 00332 if(pthread_mutex_init(&powner->so_mutex, NULL) == -1) 00333 { 00334 LogDebug(COMPONENT_CLIENTID, 00335 "Unable to create clientid owner for clientid %"PRIx64, 00336 clientid); 00337 00338 /* Directly free the clientid record since we failed to initialize it */ 00339 pool_free(client_id_pool, pclientid); 00340 00341 return NULL; 00342 } 00343 00344 if(clientid == 0) 00345 clientid = new_clientid(); 00346 00347 pclientid->cid_confirmed = UNCONFIRMED_CLIENT_ID; 00348 pclientid->cid_clientid = clientid; 00349 pclientid->cid_last_renew = time(NULL); 00350 pclientid->cid_client_record = pclient_record; 00351 pclientid->cid_client_addr = *pclient_addr; 00352 pclientid->cid_credential = *pcredential; 00353 00354 /* need to init the list_head */ 00355 init_glist(&pclientid->cid_openowners); 00356 init_glist(&pclientid->cid_lockowners); 00357 00358 /* set up the content of the clientid_owner */ 00359 powner->so_type = STATE_CLIENTID_OWNER_NFSV4; 00360 powner->so_owner.so_nfs4_owner.so_clientid = clientid; 00361 powner->so_owner.so_nfs4_owner.so_pclientid = pclientid; 00362 powner->so_owner.so_nfs4_owner.so_resp.resop = NFS4_OP_ILLEGAL; 00363 powner->so_owner.so_nfs4_owner.so_args.argop = NFS4_OP_ILLEGAL; 00364 powner->so_refcount = 1; 00365 00366 /* Init the lists for the clientid_owner */ 00367 init_glist(&powner->so_lock_list); 00368 init_glist(&powner->so_owner.so_nfs4_owner.so_state_list); 00369 00370 /* Get a reference to the client record */ 00371 inc_client_record_ref(pclientid->cid_client_record); 00372 00373 return pclientid; 00374 } 00375 00389 int nfs_client_id_insert(nfs_client_id_t * pclientid) 00390 { 00391 hash_buffer_t buffkey; 00392 hash_buffer_t buffdata; 00393 int rc; 00394 00395 /* Create key from cid_clientid */ 00396 buffkey.pdata = &pclientid->cid_clientid; 00397 buffkey.len = sizeof(pclientid->cid_clientid); 00398 00399 buffdata.pdata = (caddr_t) pclientid; 00400 buffdata.len = sizeof(nfs_client_id_t); 00401 00402 rc = HashTable_Test_And_Set(ht_unconfirmed_client_id, 00403 &buffkey, 00404 &buffdata, 00405 HASHTABLE_SET_HOW_SET_NO_OVERWRITE); 00406 00407 if(rc != HASHTABLE_SUCCESS) 00408 { 00409 LogDebug(COMPONENT_CLIENTID, 00410 "Could not insert unconfirmed clientid %"PRIx64" error=%s", 00411 pclientid->cid_clientid, 00412 hash_table_err_to_str(rc)); 00413 00414 /* Free the clientid record and return */ 00415 free_client_id(pclientid); 00416 00417 return CLIENT_ID_INSERT_MALLOC_ERROR; 00418 } 00419 00420 /* Take a reference to the unconfirmed clientid for the hash table. */ 00421 inc_client_id_ref(pclientid); 00422 00423 if(isFullDebug(COMPONENT_CLIENTID) && isFullDebug(COMPONENT_HASHTABLE)) 00424 { 00425 LogFullDebug(COMPONENT_CLIENTID, 00426 "-=-=-=-=-=-=-=-=-=-> ht_unconfirmed_client_id "); 00427 HashTable_Log(COMPONENT_CLIENTID, ht_unconfirmed_client_id); 00428 } 00429 00430 /* Attach new clientid to client record's cr_punconfirmed_id. */ 00431 pclientid->cid_client_record->cr_punconfirmed_id = pclientid; 00432 00433 return CLIENT_ID_SUCCESS; 00434 } /* nfs_client_id_insert */ 00435 00447 int remove_unconfirmed_client_id(nfs_client_id_t * pclientid) 00448 { 00449 int rc; 00450 hash_buffer_t buffkey; 00451 hash_buffer_t old_key; 00452 hash_buffer_t old_value; 00453 00454 buffkey.pdata = (caddr_t) &pclientid->cid_clientid; 00455 buffkey.len = sizeof(pclientid->cid_clientid); 00456 00457 rc = HashTable_Del(ht_unconfirmed_client_id, 00458 &buffkey, 00459 &old_key, 00460 &old_value); 00461 00462 if(rc != HASHTABLE_SUCCESS) 00463 { 00464 LogDebug(COMPONENT_CLIENTID, 00465 "Could not remove unconfirmed clientid %"PRIx64" error=%s", 00466 pclientid->cid_clientid, 00467 hash_table_err_to_str(rc)); 00468 return rc; 00469 } 00470 00471 pclientid->cid_client_record->cr_punconfirmed_id = NULL; 00472 00473 /* Set this up so this client id record will be freed. */ 00474 pclientid->cid_confirmed = EXPIRED_CLIENT_ID; 00475 00476 /* Release hash table reference to the unconfirmed record */ 00477 dec_client_id_ref(pclientid); 00478 00479 return rc; 00480 } 00481 00496 int nfs_client_id_confirm(nfs_client_id_t * pclientid, 00497 log_components_t component) 00498 { 00499 int rc; 00500 hash_buffer_t buffkey; 00501 hash_buffer_t old_key; 00502 hash_buffer_t old_value; 00503 00504 buffkey.pdata = (caddr_t) &pclientid->cid_clientid; 00505 buffkey.len = sizeof(pclientid->cid_clientid); 00506 00507 /* Remove the clientid as the unconfirmed entry for the client record */ 00508 pclientid->cid_client_record->cr_punconfirmed_id = NULL; 00509 00510 rc = HashTable_Del(ht_unconfirmed_client_id, 00511 &buffkey, 00512 &old_key, 00513 &old_value); 00514 00515 if(rc != HASHTABLE_SUCCESS) 00516 { 00517 if(isDebug(COMPONENT_CLIENTID)) 00518 { 00519 char str[HASHTABLE_DISPLAY_STRLEN]; 00520 00521 display_client_id_rec(pclientid, str); 00522 00523 LogDebug(COMPONENT_CLIENTID, 00524 "Unexpected problem %s, could not remove {%s}", 00525 hash_table_err_to_str(rc), str); 00526 } 00527 00528 return CLIENT_ID_INVALID_ARGUMENT; 00529 } 00530 00531 pclientid->cid_confirmed = CONFIRMED_CLIENT_ID; 00532 00533 rc = HashTable_Test_And_Set(ht_confirmed_client_id, 00534 &old_key, 00535 &old_value, 00536 HASHTABLE_SET_HOW_SET_NO_OVERWRITE); 00537 00538 if(rc != HASHTABLE_SUCCESS) 00539 { 00540 if(isDebug(COMPONENT_CLIENTID)) 00541 { 00542 char str[HASHTABLE_DISPLAY_STRLEN]; 00543 00544 display_client_id_rec(pclientid, str); 00545 00546 LogDebug(COMPONENT_CLIENTID, 00547 "Unexpected problem %s, could not insert {%s}", 00548 hash_table_err_to_str(rc), str); 00549 } 00550 00551 /* Set this up so this client id record will be freed. */ 00552 pclientid->cid_confirmed = EXPIRED_CLIENT_ID; 00553 00554 /* Release hash table reference to the unconfirmed record */ 00555 dec_client_id_ref(pclientid); 00556 00557 return CLIENT_ID_INSERT_MALLOC_ERROR; 00558 } 00559 00560 /* Add the clientid as the confirmed entry for the client record */ 00561 pclientid->cid_client_record->cr_pconfirmed_id = pclientid; 00562 00563 return CLIENT_ID_SUCCESS; 00564 } 00565 00575 int nfs_client_id_expire(nfs_client_id_t * pclientid) 00576 { 00577 struct glist_head * glist, * glistn; 00578 struct glist_head * glist2, * glistn2; 00579 state_status_t pstatus; 00580 int rc; 00581 hash_buffer_t buffkey; 00582 hash_buffer_t old_key; 00583 hash_buffer_t old_value; 00584 hash_table_t * ht_expire; 00585 nfs_client_record_t * precord; 00586 00587 P(pclientid->cid_mutex); 00588 if (pclientid->cid_confirmed == EXPIRED_CLIENT_ID) 00589 { 00590 if(isFullDebug(COMPONENT_CLIENTID)) 00591 { 00592 char str[HASHTABLE_DISPLAY_STRLEN]; 00593 display_client_id_rec(pclientid, str); 00594 LogFullDebug(COMPONENT_CLIENTID, 00595 "Expired (skipped) {%s}", str); 00596 } 00597 00598 V(pclientid->cid_mutex); 00599 return FALSE; 00600 } 00601 00602 if(isDebug(COMPONENT_CLIENTID)) 00603 { 00604 char str[HASHTABLE_DISPLAY_STRLEN]; 00605 display_client_id_rec(pclientid, str); 00606 LogDebug(COMPONENT_CLIENTID, 00607 "Expiring {%s}", str); 00608 } 00609 00610 if(pclientid->cid_confirmed == CONFIRMED_CLIENT_ID) 00611 ht_expire = ht_confirmed_client_id; 00612 else 00613 ht_expire = ht_unconfirmed_client_id; 00614 00615 pclientid->cid_confirmed = EXPIRED_CLIENT_ID; 00616 00617 /* Need to clean up the client record. */ 00618 precord = pclientid->cid_client_record; 00619 00620 V(pclientid->cid_mutex); 00621 00622 /* Detach the clientid record from the client record */ 00623 if(precord->cr_pconfirmed_id == pclientid) 00624 precord->cr_pconfirmed_id = NULL; 00625 00626 if(precord->cr_punconfirmed_id == pclientid) 00627 precord->cr_punconfirmed_id = NULL; 00628 00629 buffkey.pdata = (caddr_t) &pclientid->cid_clientid; 00630 buffkey.len = sizeof(pclientid->cid_clientid); 00631 00632 rc = HashTable_Del(ht_expire, 00633 &buffkey, 00634 &old_key, 00635 &old_value); 00636 00637 if(rc != HASHTABLE_SUCCESS) 00638 { 00639 LogDebug(COMPONENT_CLIENTID, 00640 "Could not remove expired clientid %"PRIx64" error=%s", 00641 pclientid->cid_clientid, 00642 hash_table_err_to_str(rc)); 00643 assert(rc == HASHTABLE_SUCCESS); 00644 } 00645 00646 /* traverse the client's lock owners, and release all locks */ 00647 glist_for_each_safe(glist, glistn, &pclientid->cid_lockowners) 00648 { 00649 state_owner_t * plock_owner = glist_entry(glist, 00650 state_owner_t, 00651 so_owner.so_nfs4_owner.so_perclient); 00652 00653 glist_for_each_safe(glist2, glistn2, &plock_owner->so_owner.so_nfs4_owner.so_state_list) 00654 { 00655 fsal_op_context_t fsal_context; 00656 fsal_status_t fsal_status; 00657 00658 state_t* plock_state = glist_entry(glist2, 00659 state_t, 00660 state_owner_list); 00661 00662 /* construct the fsal context based on the export and root credential */ 00663 fsal_status = FSAL_GetClientContext(&fsal_context, 00664 &plock_state->state_pexport->FS_export_context, 00665 0, 00666 0, 00667 NULL, 00668 0); 00669 if(FSAL_IS_ERROR(fsal_status)) 00670 { 00671 /* log error here , and continue? */ 00672 LogDebug(COMPONENT_CLIENTID, 00673 "FSAL_GetClientConext failed"); 00674 continue; 00675 } 00676 00677 state_owner_unlock_all(&fsal_context, 00678 plock_owner, 00679 plock_state, 00680 &pstatus); 00681 } 00682 } 00683 00684 /* traverse the client's lock owners, and release all locks states and owners */ 00685 glist_for_each_safe(glist, glistn, &pclientid->cid_lockowners) 00686 { 00687 state_owner_t * plock_owner = glist_entry(glist, 00688 state_owner_t, 00689 so_owner.so_nfs4_owner.so_perclient); 00690 release_lockstate(plock_owner); 00691 00692 if(isFullDebug(COMPONENT_CLIENTID)) 00693 { 00694 char owner[HASHTABLE_DISPLAY_STRLEN]; 00695 00696 DisplayOwner(plock_owner, owner); 00697 LogFullDebug(COMPONENT_CLIENTID, 00698 "Expired lock state for {%s}", 00699 owner); 00700 } 00701 } 00702 00703 /* release the corresponding open states , close files*/ 00704 glist_for_each_safe(glist, glistn, &pclientid->cid_openowners) 00705 { 00706 state_owner_t * popen_owner = glist_entry(glist, 00707 state_owner_t, 00708 so_owner.so_nfs4_owner.so_perclient); 00709 release_openstate(popen_owner); 00710 00711 if(isFullDebug(COMPONENT_CLIENTID)) 00712 { 00713 char owner[HASHTABLE_DISPLAY_STRLEN]; 00714 00715 DisplayOwner(popen_owner, owner); 00716 LogFullDebug(COMPONENT_CLIENTID, 00717 "Expired open state for {%s}", 00718 owner); 00719 } 00720 } 00721 00722 if (pclientid->cid_recov_dir != NULL) 00723 { 00724 nfs4_rm_clid(pclientid->cid_recov_dir); 00725 gsh_free(pclientid->cid_recov_dir); 00726 pclientid->cid_recov_dir = NULL; 00727 } 00728 00729 if(isFullDebug(COMPONENT_CLIENTID)) 00730 { 00731 char str[HASHTABLE_DISPLAY_STRLEN]; 00732 display_client_id_rec(pclientid, str); 00733 LogFullDebug(COMPONENT_CLIENTID, 00734 "Expired (done) {%s}", str); 00735 } 00736 00737 if(isDebug(COMPONENT_CLIENTID)) 00738 { 00739 char str[HASHTABLE_DISPLAY_STRLEN]; 00740 display_client_id_rec(pclientid, str); 00741 LogDebug(COMPONENT_CLIENTID, 00742 "About to release last reference to {%s}", str); 00743 } 00744 00745 /* Release the hash table reference to the clientid. */ 00746 dec_client_id_ref(pclientid); 00747 00748 return TRUE; 00749 } 00750 00751 int nfs_client_id_get(hash_table_t * ht, 00752 clientid4 clientid, 00753 nfs_client_id_t ** p_pclientid) 00754 { 00755 hash_buffer_t buffkey; 00756 hash_buffer_t buffval; 00757 int status; 00758 00759 if(p_pclientid == NULL) 00760 return CLIENT_ID_INVALID_ARGUMENT; 00761 00762 buffkey.pdata = (caddr_t) &clientid; 00763 buffkey.len = sizeof(clientid4); 00764 00765 if(isFullDebug(COMPONENT_CLIENTID) && isDebug(COMPONENT_HASHTABLE)) 00766 { 00767 LogFullDebug(COMPONENT_CLIENTID, 00768 "%s KEY {%"PRIx64"}", ht->parameter.ht_name, clientid); 00769 } 00770 00771 if(isFullDebug(COMPONENT_CLIENTID) && 00772 isFullDebug(COMPONENT_HASHTABLE)) 00773 { 00774 LogFullDebug(COMPONENT_CLIENTID, 00775 "-=-=-=-=-=-=-=-=-=-> %s", ht->parameter.ht_name); 00776 HashTable_Log(COMPONENT_CLIENTID, ht); 00777 } 00778 00779 if(HashTable_GetRef(ht, 00780 &buffkey, 00781 &buffval, 00782 Hash_inc_client_id_ref) == HASHTABLE_SUCCESS) 00783 { 00784 if(isDebug(COMPONENT_HASHTABLE)) 00785 LogFullDebug(COMPONENT_CLIENTID, 00786 "%s FOUND", ht->parameter.ht_name); 00787 *p_pclientid = buffval.pdata; 00788 00789 status = CLIENT_ID_SUCCESS; 00790 } 00791 else 00792 { 00793 if(isDebug(COMPONENT_HASHTABLE)) 00794 LogFullDebug(COMPONENT_CLIENTID, 00795 "%s NOTFOUND", ht->parameter.ht_name); 00796 *p_pclientid = NULL; 00797 status = CLIENT_ID_NOT_FOUND; 00798 } 00799 00800 return status; 00801 } /* nfs_client_id_Get_Pointer */ 00802 00815 int nfs_client_id_get_unconfirmed(clientid4 clientid, 00816 nfs_client_id_t ** p_pclientid) 00817 { 00818 return nfs_client_id_get(ht_unconfirmed_client_id, clientid, p_pclientid); 00819 } 00820 00833 int nfs_client_id_get_confirmed(clientid4 clientid, 00834 nfs_client_id_t ** p_pclientid) 00835 { 00836 return nfs_client_id_get(ht_confirmed_client_id, clientid, p_pclientid); 00837 } 00838 00850 int nfs_Init_client_id(nfs_client_id_parameter_t * param) 00851 { 00852 if((ht_confirmed_client_id = HashTable_Init(¶m->cid_confirmed_hash_param)) == NULL) 00853 { 00854 LogCrit(COMPONENT_INIT, "NFS CLIENT_ID: Cannot init Client Id cache"); 00855 return -1; 00856 } 00857 00858 if((ht_unconfirmed_client_id = HashTable_Init(¶m->cid_unconfirmed_hash_param)) == NULL) 00859 { 00860 LogCrit(COMPONENT_INIT, "NFS CLIENT_ID: Cannot init Client Id cache"); 00861 return -1; 00862 } 00863 00864 if((ht_client_record = HashTable_Init(¶m->cr_hash_param)) == NULL) 00865 { 00866 LogCrit(COMPONENT_INIT, "NFS CLIENT_ID: Cannot init Client Record cache"); 00867 return -1; 00868 } 00869 00870 client_id_pool = pool_init("NFS4 Client ID Pool", 00871 sizeof(nfs_client_id_t), 00872 pool_basic_substrate, 00873 NULL, 00874 NULL, 00875 NULL); 00876 00877 if(client_id_pool == NULL) 00878 { 00879 LogCrit(COMPONENT_INIT, "NFS CLIENT_ID: Cannot init Client Id Pool"); 00880 return -1; 00881 } 00882 00883 client_record_pool = pool_init("NFS4 Client Record Pool", 00884 sizeof(nfs_client_record_t), 00885 pool_basic_substrate, 00886 NULL, 00887 NULL, 00888 NULL); 00889 00890 if(client_record_pool == NULL) 00891 { 00892 LogCrit(COMPONENT_INIT, "NFS CLIENT_ID: Cannot init Client Record Pool"); 00893 return -1; 00894 } 00895 00896 return CLIENT_ID_SUCCESS; 00897 } /* nfs_Init_client_id */ 00898 00906 clientid4 new_clientid(void) 00907 { 00908 clientid4 newid; 00909 uint64_t epoch_low = ServerEpoch & 0xFFFFFFFF; 00910 00911 P(clientid_mutex); 00912 00913 newid = ++clientid_counter + (epoch_low << (clientid4) 32); 00914 00915 V(clientid_mutex); 00916 00917 return newid; 00918 } 00919 00927 void new_clientifd_verifier(char * pverf) 00928 { 00929 P(clientid_mutex); 00930 00931 ++clientid_verifier; 00932 00933 memcpy(pverf, &clientid_verifier, NFS4_VERIFIER_SIZE); 00934 00935 V(clientid_mutex); 00936 } 00937 00938 /******************************************************************************* 00939 * 00940 * Functions to handle lookup of clientid by nfs_client_id4 received from 00941 * client. 00942 * 00943 ******************************************************************************/ 00944 00945 int display_client_record(nfs_client_record_t * precord, char *str) 00946 { 00947 char * strtmp = str; 00948 00949 strtmp += sprintf(strtmp, "%p name=", precord); 00950 00951 strtmp += DisplayOpaqueValue(precord->cr_client_val, 00952 precord->cr_client_val_len, 00953 strtmp); 00954 00955 strtmp += sprintf(strtmp, " refcount=%"PRId32, 00956 atomic_fetch_int32_t(&precord->cr_refcount)); 00957 00958 return strtmp - str; 00959 } 00960 00961 void inc_client_record_ref(nfs_client_record_t *precord) 00962 { 00963 atomic_inc_int32_t(&precord->cr_refcount); 00964 00965 if(isFullDebug(COMPONENT_CLIENTID)) 00966 { 00967 char str[HASHTABLE_DISPLAY_STRLEN]; 00968 00969 display_client_record(precord, str); 00970 LogFullDebug(COMPONENT_CLIENTID, 00971 "Increment refcount {%s}", 00972 str); 00973 } 00974 } 00975 00976 void free_client_record(nfs_client_record_t * precord) 00977 { 00978 if(pthread_mutex_destroy(&precord->cr_mutex) != 0) 00979 LogDebug(COMPONENT_CLIENTID, 00980 "pthread_mutex_destroy returned errno %d(%s)", 00981 errno, strerror(errno)); 00982 00983 pool_free(client_record_pool, precord); 00984 } 00985 00986 void dec_client_record_ref(nfs_client_record_t *precord) 00987 { 00988 char str[HASHTABLE_DISPLAY_STRLEN]; 00989 struct hash_latch latch; 00990 hash_error_t rc; 00991 hash_buffer_t buffkey; 00992 hash_buffer_t old_value; 00993 hash_buffer_t old_key; 00994 int32_t refcount; 00995 00996 if(isDebug(COMPONENT_CLIENTID)) 00997 display_client_record(precord, str); 00998 00999 refcount = atomic_dec_int32_t(&precord->cr_refcount); 01000 01001 if(refcount > 0) 01002 { 01003 LogFullDebug(COMPONENT_CLIENTID, 01004 "Decrement refcount {%s} refcount now=%"PRId32, 01005 str, refcount); 01006 01007 return; 01008 } 01009 01010 LogFullDebug(COMPONENT_CLIENTID, 01011 "Try to remove {%s}", 01012 str); 01013 01014 buffkey.pdata = (caddr_t) precord; 01015 buffkey.len = sizeof(*precord); 01016 01017 /* Get the hash table entry and hold latch */ 01018 rc = HashTable_GetLatch(ht_client_record, 01019 &buffkey, 01020 &old_value, 01021 TRUE, 01022 &latch); 01023 01024 if(rc != HASHTABLE_SUCCESS) 01025 { 01026 if(rc == HASHTABLE_ERROR_NO_SUCH_KEY) 01027 HashTable_ReleaseLatched(ht_client_record, &latch); 01028 01029 LogDebug(COMPONENT_CLIENTID, 01030 "Error %s, could not find {%s}", 01031 hash_table_err_to_str(rc), str); 01032 } 01033 01034 refcount = atomic_fetch_int32_t(&precord->cr_refcount); 01035 01036 if(refcount > 0) 01037 { 01038 LogDebug(COMPONENT_CLIENTID, 01039 "Did not release {%s} refcount now=%"PRId32, 01040 str, refcount); 01041 01042 HashTable_ReleaseLatched(ht_client_record, &latch); 01043 01044 return; 01045 } 01046 01047 /* use the key to delete the entry */ 01048 rc = HashTable_DeleteLatched(ht_client_record, 01049 &buffkey, 01050 &latch, 01051 &old_key, 01052 &old_value); 01053 01054 if(rc != HASHTABLE_SUCCESS) 01055 { 01056 if(rc == HASHTABLE_ERROR_NO_SUCH_KEY) 01057 HashTable_ReleaseLatched(ht_client_record, &latch); 01058 01059 LogDebug(COMPONENT_CLIENTID, 01060 "Error %s, could not remove {%s}", 01061 hash_table_err_to_str(rc), str); 01062 } 01063 01064 LogFullDebug(COMPONENT_CLIENTID, 01065 "Free {%s}", 01066 str); 01067 01068 free_client_record(old_value.pdata); 01069 } 01070 01071 uint64_t client_record_value_hash(nfs_client_record_t * pkey) 01072 { 01073 unsigned int i; 01074 uint64_t res = 0; 01075 unsigned char * sum = (unsigned char *) &res; 01076 01077 /* Compute the sum of all the characters across the uint64_t */ 01078 for(i = 0; i < pkey->cr_client_val_len; i++) 01079 sum[i % sizeof(res)] += (unsigned char)pkey->cr_client_val[i]; 01080 01081 return res; 01082 } 01083 01099 uint32_t client_record_value_hash_func(hash_parameter_t * p_hparam, 01100 hash_buffer_t * buffclef) 01101 { 01102 uint64_t res; 01103 01104 res = client_record_value_hash(buffclef->pdata) % 01105 p_hparam->index_size; 01106 01107 if(isDebug(COMPONENT_HASHTABLE)) 01108 LogFullDebug(COMPONENT_CLIENTID, 01109 "value = %"PRIu64, res); 01110 01111 return (uint32_t) res; 01112 } 01113 01129 unsigned long client_record_rbt_hash_func(hash_parameter_t * p_hparam, 01130 hash_buffer_t * buffclef) 01131 { 01132 uint64_t res; 01133 01134 res = client_record_value_hash(buffclef->pdata); 01135 01136 if(isDebug(COMPONENT_HASHTABLE)) 01137 LogFullDebug(COMPONENT_CLIENTID, 01138 "value = %"PRIu64, res); 01139 01140 return res; 01141 } 01142 01156 int compare_client_record(hash_buffer_t * buff1, hash_buffer_t * buff2) 01157 { 01158 nfs_client_record_t * pkey1 = buff1->pdata; 01159 nfs_client_record_t * pkey2 = buff2->pdata; 01160 01161 if(pkey1->cr_client_val_len != pkey2->cr_client_val_len) 01162 return 1; 01163 01164 return memcmp(pkey1->cr_client_val, 01165 pkey2->cr_client_val, 01166 pkey1->cr_client_val_len); 01167 } 01168 01182 int display_client_record_key(hash_buffer_t * pbuff, char *str) 01183 { 01184 return display_client_record(pbuff->pdata, str); 01185 } 01186 01187 int display_client_record_val(hash_buffer_t * pbuff, char *str) 01188 { 01189 return display_client_record(pbuff->pdata, str); 01190 } 01191 01192 nfs_client_record_t *get_client_record(char * value, int len) 01193 { 01194 nfs_client_record_t * precord; 01195 hash_buffer_t buffkey; 01196 hash_buffer_t buffval; 01197 struct hash_latch latch; 01198 hash_error_t rc; 01199 01200 precord = pool_alloc(client_record_pool, NULL); 01201 01202 if(precord == NULL) 01203 return NULL; 01204 01205 precord->cr_refcount = 1; 01206 precord->cr_client_val_len = len; 01207 memcpy(precord->cr_client_val, value, len); 01208 buffkey.pdata = (caddr_t) precord; 01209 buffkey.len = sizeof(*precord); 01210 01211 if(isFullDebug(COMPONENT_CLIENTID)) 01212 { 01213 char str[HASHTABLE_DISPLAY_STRLEN]; 01214 01215 display_client_record(precord, str); 01216 01217 LogFullDebug(COMPONENT_CLIENTID, 01218 "Find Client Record KEY {%s}", str); 01219 } 01220 01221 /* If we found it, return it, if we don't care, return NULL */ 01222 rc = HashTable_GetLatch(ht_client_record, 01223 &buffkey, 01224 &buffval, 01225 TRUE, 01226 &latch); 01227 01228 if(rc == HASHTABLE_SUCCESS) 01229 { 01230 /* Discard the key we created and return the found Client Record. 01231 * Directly free since we didn't complete initialization. 01232 */ 01233 pool_free(client_record_pool, precord); 01234 01235 precord = buffval.pdata; 01236 01237 inc_client_record_ref(precord); 01238 01239 HashTable_ReleaseLatched(ht_client_record, &latch); 01240 01241 if(isFullDebug(COMPONENT_CLIENTID)) 01242 { 01243 char str[HASHTABLE_DISPLAY_STRLEN]; 01244 01245 display_client_record(precord, str); 01246 LogFullDebug(COMPONENT_CLIENTID, 01247 "Found {%s}", 01248 str); 01249 } 01250 01251 return precord; 01252 } 01253 01254 /* Any other result other than no such key is an error */ 01255 if(rc != HASHTABLE_ERROR_NO_SUCH_KEY) 01256 { 01257 /* Discard the key we created and return. 01258 * Directly free since we didn't complete initialization. 01259 */ 01260 01261 if(isFullDebug(COMPONENT_CLIENTID)) 01262 { 01263 char str[HASHTABLE_DISPLAY_STRLEN]; 01264 01265 display_client_record(precord, str); 01266 01267 LogDebug(COMPONENT_CLIENTID, 01268 "Error %s, failed to find {%s}", 01269 hash_table_err_to_str(rc), str); 01270 } 01271 01272 pool_free(client_record_pool, precord); 01273 01274 return NULL; 01275 } 01276 01277 if(pthread_mutex_init(&precord->cr_mutex, NULL) == -1) 01278 { 01279 /* Mutex initialization failed, directly free the record since we failed 01280 * to initialize it. Also release hash latch since we failed to add 01281 * record. 01282 */ 01283 HashTable_ReleaseLatched(ht_client_record, &latch); 01284 pool_free(client_record_pool, precord); 01285 return NULL; 01286 } 01287 01288 /* Use same record for record and key */ 01289 buffval.pdata = (caddr_t) precord; 01290 buffval.len = sizeof(*precord); 01291 01292 if(isFullDebug(COMPONENT_CLIENTID)) 01293 { 01294 char str[HASHTABLE_DISPLAY_STRLEN]; 01295 01296 display_client_record(precord, str); 01297 01298 LogFullDebug(COMPONENT_CLIENTID, 01299 "New {%s}", str); 01300 } 01301 01302 rc = HashTable_SetLatched(ht_client_record, 01303 &buffkey, 01304 &buffval, 01305 &latch, 01306 HASHTABLE_SET_HOW_SET_NO_OVERWRITE, 01307 NULL, 01308 NULL); 01309 01310 if(rc == HASHTABLE_SUCCESS) 01311 { 01312 if(isFullDebug(COMPONENT_CLIENTID)) 01313 { 01314 char str[HASHTABLE_DISPLAY_STRLEN]; 01315 01316 display_client_record(precord, str); 01317 LogFullDebug(COMPONENT_CLIENTID, 01318 "Set Client Record {%s}", 01319 str); 01320 } 01321 01322 return precord; 01323 } 01324 01325 if(isFullDebug(COMPONENT_CLIENTID)) 01326 { 01327 char str[HASHTABLE_DISPLAY_STRLEN]; 01328 01329 display_client_record(precord, str); 01330 01331 LogDebug(COMPONENT_CLIENTID, 01332 "Error %s Failed to add {%s}", 01333 hash_table_err_to_str(rc), str); 01334 } 01335 01336 free_client_record(precord); 01337 01338 return NULL; 01339 }