nfs-ganesha 1.4

nfs4_clientid.c

Go to the documentation of this file.
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(&param->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(&param->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(&param->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 }