/** * @brief Retrieves a full fsal_handle from a NFS3 digest. * * @param[in] nfs23_digest The NFS3 handle digest * @param[out] fsal_handle The fsal handle to be retrieved * * @note The caller must provide storage for nfs_fh4_val. * * @retval HANDLEMAP_SUCCESS if the handle is available * @retval HANDLEMAP_STALE if the disgest is unknown or the handle has been deleted */ int HandleMap_GetFH(const nfs23_map_handle_t *nfs23_digest, struct gsh_buffdesc *fsal_handle) { int rc; struct gsh_buffdesc buffkey; struct gsh_buffdesc buffval; digest_pool_entry_t digest; struct hash_latch hl; digest.nfs23_digest = *nfs23_digest; buffkey.addr = (caddr_t) &digest; buffkey.len = sizeof(digest_pool_entry_t); rc = hashtable_getlatch(handle_map_hash, &buffkey, &buffval, 0, &hl); if (rc == HASHTABLE_SUCCESS) { handle_pool_entry_t *h = (handle_pool_entry_t *) buffval.addr; if (h->fh_len < fsal_handle->len) { fsal_handle->len = h->fh_len; memcpy(fsal_handle->addr, h->fh_data, h->fh_len); rc = HANDLEMAP_SUCCESS; } else { rc = HANDLEMAP_INTERNAL_ERROR; } hashtable_releaselatched(handle_map_hash, &hl); return rc; } if (rc == HASHTABLE_ERROR_NO_SUCH_KEY) hashtable_releaselatched(handle_map_hash, &hl); return HANDLEMAP_STALE; } /* HandleMap_GetFH */
int nfs41_Session_Set(nfs41_session_t *session_data) { struct gsh_buffdesc key; struct gsh_buffdesc val; struct hash_latch latch; hash_error_t code; int rc = 0; key.addr = session_data->session_id; key.len = NFS4_SESSIONID_SIZE; val.addr = session_data; val.len = sizeof(nfs41_session_t); /* The latch idiom isn't strictly necessary here */ code = hashtable_getlatch(ht_session_id, &key, &val, true, &latch); if (code == HASHTABLE_SUCCESS) { hashtable_releaselatched(ht_session_id, &latch); goto out; } if (code == HASHTABLE_ERROR_NO_SUCH_KEY) { /* nfs4_op_create_session ensures refcount == 2 for new * session records */ code = hashtable_setlatched(ht_session_id, &key, &val, &latch, false, NULL, NULL); if (code == HASHTABLE_SUCCESS) rc = 1; } out: return rc; }
int nfs41_Session_Get_Pointer(char sessionid[NFS4_SESSIONID_SIZE], nfs41_session_t **session_data) { struct gsh_buffdesc key; struct gsh_buffdesc val; struct hash_latch latch; char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; bool str_valid = false; hash_error_t code; if (isFullDebug(COMPONENT_SESSIONS)) { display_session_id(&dspbuf, sessionid); LogFullDebug(COMPONENT_SESSIONS, "Get Session %s", str); str_valid = true; } key.addr = sessionid; key.len = NFS4_SESSIONID_SIZE; code = hashtable_getlatch(ht_session_id, &key, &val, false, &latch); if (code != HASHTABLE_SUCCESS) { hashtable_releaselatched(ht_session_id, &latch); if (str_valid) LogFullDebug(COMPONENT_SESSIONS, "Session %s Not Found", str); return 0; } *session_data = val.addr; inc_session_ref(*session_data); /* XXX more locks? */ hashtable_releaselatched(ht_session_id, &latch); if (str_valid) LogFullDebug(COMPONENT_SESSIONS, "Session %s Found", str); return 1; }
void nfs4_acl_release_entry(fsal_acl_t *acl, fsal_acl_status_t *status) { struct gsh_buffdesc key, old_key; struct gsh_buffdesc old_value; int rc; struct hash_latch latch; /* Set the return default to NFS_V4_ACL_SUCCESS */ *status = NFS_V4_ACL_SUCCESS; if (!acl) return; PTHREAD_RWLOCK_wrlock(&acl->lock); if (acl->ref > 1) { nfs4_acl_entry_dec_ref(acl); PTHREAD_RWLOCK_unlock(&acl->lock); return; } else LogDebug(COMPONENT_NFS_V4_ACL, "Free ACL %p", acl); key.addr = acl->aces; key.len = acl->naces * sizeof(fsal_ace_t); PTHREAD_RWLOCK_unlock(&acl->lock); /* Get the hash table entry and hold latch */ rc = hashtable_getlatch(fsal_acl_hash, &key, &old_value, true, &latch); switch (rc) { case HASHTABLE_ERROR_NO_SUCH_KEY: hashtable_releaselatched(fsal_acl_hash, &latch); return; case HASHTABLE_SUCCESS: PTHREAD_RWLOCK_wrlock(&acl->lock); nfs4_acl_entry_dec_ref(acl); if (acl->ref != 0) { /* Did not actually release last reference */ hashtable_releaselatched(fsal_acl_hash, &latch); PTHREAD_RWLOCK_unlock(&acl->lock); return; } /* use the key to delete the entry */ hashtable_deletelatched(fsal_acl_hash, &key, &latch, &old_key, &old_value); /* Release the latch */ hashtable_releaselatched(fsal_acl_hash, &latch); break; default: LogCrit(COMPONENT_NFS_V4_ACL, "ACL entry could not be deleted, status=%s", hash_table_err_to_str(rc)); return; } /* Sanity check: old_value.addr is expected to be equal to acl, * and is released later in this function */ assert(old_value.addr == acl); PTHREAD_RWLOCK_unlock(&acl->lock); /* Release acl */ nfs4_acl_free(acl); }
fsal_acl_t *nfs4_acl_new_entry(fsal_acl_data_t *acldata, fsal_acl_status_t *status) { fsal_acl_t *acl = NULL; struct gsh_buffdesc key; struct gsh_buffdesc value; int rc; struct hash_latch latch; /* Set the return default to NFS_V4_ACL_SUCCESS */ *status = NFS_V4_ACL_SUCCESS; key.addr = acldata->aces; key.len = acldata->naces * sizeof(fsal_ace_t); /* Check if the entry already exists */ rc = hashtable_getlatch(fsal_acl_hash, &key, &value, true, &latch); if (rc == HASHTABLE_SUCCESS) { /* Entry is already in the cache, do not add it */ acl = value.addr; *status = NFS_V4_ACL_EXISTS; nfs4_ace_free(acldata->aces); nfs4_acl_entry_inc_ref(acl); hashtable_releaselatched(fsal_acl_hash, &latch); return acl; } /* Any other result other than no such key is an error */ if (rc != HASHTABLE_ERROR_NO_SUCH_KEY) { *status = NFS_V4_ACL_INIT_ENTRY_FAILED; nfs4_ace_free(acldata->aces); return NULL; } /* Adding the entry in the cache */ acl = nfs4_acl_alloc(); if (pthread_rwlock_init(&(acl->lock), NULL) != 0) { nfs4_acl_free(acl); LogCrit(COMPONENT_NFS_V4_ACL, "New ACL RW lock init returned %d (%s)", errno, strerror(errno)); *status = NFS_V4_ACL_INIT_ENTRY_FAILED; nfs4_ace_free(acldata->aces); hashtable_releaselatched(fsal_acl_hash, &latch); return NULL; } acl->naces = acldata->naces; acl->aces = acldata->aces; acl->ref = 1; /* We give out one reference */ /* Build the value */ value.addr = acl; value.len = sizeof(fsal_acl_t); rc = hashtable_setlatched(fsal_acl_hash, &key, &value, &latch, HASHTABLE_SET_HOW_SET_NO_OVERWRITE, NULL, NULL); if (rc != HASHTABLE_SUCCESS) { /* Put the entry back in its pool */ nfs4_acl_free(acl); LogWarn(COMPONENT_NFS_V4_ACL, "New ACL entry could not be added to hash, rc=%s", hash_table_err_to_str(rc)); *status = NFS_V4_ACL_HASH_SET_ERROR; return NULL; } return acl; }
/** * @brief Get an NSM client * * @param[in] care Care status * @param[in] xprt RPC transport * @param[in] caller_name Caller name * * @return NSM client or NULL. */ state_nsm_client_t *get_nsm_client(care_t care, SVCXPRT *xprt, char *caller_name) { state_nsm_client_t key; state_nsm_client_t *pclient; char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; struct hash_latch latch; hash_error_t rc; struct gsh_buffdesc buffkey; struct gsh_buffdesc buffval; if (caller_name == NULL) return NULL; memset(&key, 0, sizeof(key)); if (nfs_param.core_param.nsm_use_caller_name) { key.ssc_nlm_caller_name_len = strlen(caller_name); if (key.ssc_nlm_caller_name_len > LM_MAXSTRLEN) return NULL; key.ssc_nlm_caller_name = caller_name; } else if (op_ctx->client == NULL) { LogCrit(COMPONENT_STATE, "No gsh_client for caller_name %s", caller_name); return NULL; } else { key.ssc_nlm_caller_name = op_ctx->client->hostaddr_str; key.ssc_nlm_caller_name_len = strlen(key.ssc_nlm_caller_name); key.ssc_client = op_ctx->client; } if (isFullDebug(COMPONENT_STATE)) { display_nsm_client(&dspbuf, &key); LogFullDebug(COMPONENT_STATE, "Find {%s}", str); } buffkey.addr = &key; buffkey.len = sizeof(key); rc = hashtable_getlatch(ht_nsm_client, &buffkey, &buffval, true, &latch); /* If we found it, return it */ if (rc == HASHTABLE_SUCCESS) { pclient = buffval.addr; /* Return the found NSM Client */ if (isFullDebug(COMPONENT_STATE)) { display_nsm_client(&dspbuf, pclient); LogFullDebug(COMPONENT_STATE, "Found {%s}", str); } /* Increment refcount under hash latch. * This prevents dec ref from removing this entry from hash * if a race occurs. */ inc_nsm_client_ref(pclient); hashtable_releaselatched(ht_nsm_client, &latch); if (care == CARE_MONITOR && !nsm_monitor(pclient)) { dec_nsm_client_ref(pclient); pclient = NULL; } return pclient; } /* An error occurred, return NULL */ if (rc != HASHTABLE_ERROR_NO_SUCH_KEY) { display_nsm_client(&dspbuf, &key); LogCrit(COMPONENT_STATE, "Error %s, could not find {%s}", hash_table_err_to_str(rc), str); return NULL; } /* Not found, but we don't care, return NULL */ if (care == CARE_NOT) { /* Return the found NSM Client */ if (isFullDebug(COMPONENT_STATE)) { display_nsm_client(&dspbuf, &key); LogFullDebug(COMPONENT_STATE, "Ignoring {%s}", str); } hashtable_releaselatched(ht_nsm_client, &latch); return NULL; } pclient = gsh_malloc(sizeof(*pclient)); if (pclient == NULL) { display_nsm_client(&dspbuf, &key); LogCrit(COMPONENT_STATE, "No memory for {%s}", str); return NULL; } /* Copy everything over */ memcpy(pclient, &key, sizeof(key)); PTHREAD_MUTEX_init(&pclient->ssc_mutex, NULL); pclient->ssc_nlm_caller_name = gsh_strdup(key.ssc_nlm_caller_name); if (pclient->ssc_nlm_caller_name == NULL) { /* Discard the created client */ PTHREAD_MUTEX_destroy(&pclient->ssc_mutex); free_nsm_client(pclient); return NULL; } glist_init(&pclient->ssc_lock_list); glist_init(&pclient->ssc_share_list); pclient->ssc_refcount = 1; if (op_ctx->client != NULL) { pclient->ssc_client = op_ctx->client; inc_gsh_client_refcount(op_ctx->client); } if (isFullDebug(COMPONENT_STATE)) { display_nsm_client(&dspbuf, pclient); LogFullDebug(COMPONENT_STATE, "New {%s}", str); } buffkey.addr = pclient; buffkey.len = sizeof(*pclient); buffval.addr = pclient; buffval.len = sizeof(*pclient); rc = hashtable_setlatched(ht_nsm_client, &buffval, &buffval, &latch, false, NULL, NULL); /* An error occurred, return NULL */ if (rc != HASHTABLE_SUCCESS) { display_nsm_client(&dspbuf, pclient); LogCrit(COMPONENT_STATE, "Error %s, inserting {%s}", hash_table_err_to_str(rc), str); PTHREAD_MUTEX_destroy(&pclient->ssc_mutex); free_nsm_client(pclient); return NULL; } if (care != CARE_MONITOR || nsm_monitor(pclient)) return pclient; /* Failed to monitor, release client reference * and almost certainly remove it from the hash table. */ dec_nsm_client_ref(pclient); return NULL; }
/** * @brief Relinquish a reference on an NSM client * * @param[in] client The client to release */ void dec_nsm_client_ref(state_nsm_client_t *client) { char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; bool str_valid = false; struct hash_latch latch; hash_error_t rc; struct gsh_buffdesc buffkey; struct gsh_buffdesc old_value; struct gsh_buffdesc old_key; int32_t refcount; if (isDebug(COMPONENT_STATE)) { display_nsm_client(&dspbuf, client); str_valid = true; } refcount = atomic_dec_int32_t(&client->ssc_refcount); if (refcount > 0) { if (str_valid) LogFullDebug(COMPONENT_STATE, "Decrement refcount now=%" PRId32 " {%s}", refcount, str); return; } if (str_valid) LogFullDebug(COMPONENT_STATE, "Try to remove {%s}", str); buffkey.addr = client; buffkey.len = sizeof(*client); /* Get the hash table entry and hold latch */ rc = hashtable_getlatch(ht_nsm_client, &buffkey, &old_value, true, &latch); if (rc != HASHTABLE_SUCCESS) { if (rc == HASHTABLE_ERROR_NO_SUCH_KEY) hashtable_releaselatched(ht_nsm_client, &latch); if (!str_valid) display_nsm_client(&dspbuf, client); LogCrit(COMPONENT_STATE, "Error %s, could not find {%s}", hash_table_err_to_str(rc), str); return; } refcount = atomic_fetch_int32_t(&client->ssc_refcount); if (refcount > 0) { if (str_valid) LogDebug(COMPONENT_STATE, "Did not release refcount now=%"PRId32" {%s}", refcount, str); hashtable_releaselatched(ht_nsm_client, &latch); return; } /* use the key to delete the entry */ rc = hashtable_deletelatched(ht_nsm_client, &buffkey, &latch, &old_key, &old_value); if (rc != HASHTABLE_SUCCESS) { if (rc == HASHTABLE_ERROR_NO_SUCH_KEY) hashtable_releaselatched(ht_nsm_client, &latch); if (!str_valid) display_nsm_client(&dspbuf, client); LogCrit(COMPONENT_STATE, "Error %s, could not remove {%s}", hash_table_err_to_str(rc), str); return; } LogFullDebug(COMPONENT_STATE, "Free {%s}", str); nsm_unmonitor(old_value.addr); free_nsm_client(old_value.addr); }
/** * @brief Get an NLM client * * @param[in] care Care status * @param[in] xprt RPC transport * @param[in] nsm_client Related NSM client * @param[in] caller_name Caller name * * @return NLM client or NULL. */ state_nlm_client_t *get_nlm_client(care_t care, SVCXPRT *xprt, state_nsm_client_t *nsm_client, char *caller_name) { state_nlm_client_t key; state_nlm_client_t *pclient; char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; struct hash_latch latch; hash_error_t rc; struct gsh_buffdesc buffkey; struct gsh_buffdesc buffval; struct sockaddr_storage local_addr; socklen_t addr_len; if (caller_name == NULL) return NULL; memset(&key, 0, sizeof(key)); key.slc_nsm_client = nsm_client; key.slc_nlm_caller_name_len = strlen(caller_name); key.slc_client_type = svc_get_xprt_type(xprt); addr_len = sizeof(local_addr); if (getsockname(xprt->xp_fd, (struct sockaddr *)&local_addr, &addr_len) == -1) { LogEvent(COMPONENT_CLIENTID, "Failed to get local addr."); } else { memcpy(&(key.slc_server_addr), &local_addr, sizeof(struct sockaddr_storage)); } if (key.slc_nlm_caller_name_len > LM_MAXSTRLEN) return NULL; key.slc_nlm_caller_name = caller_name; if (isFullDebug(COMPONENT_STATE)) { display_nlm_client(&dspbuf, &key); LogFullDebug(COMPONENT_STATE, "Find {%s}", str); } buffkey.addr = &key; buffkey.len = sizeof(key); rc = hashtable_getlatch(ht_nlm_client, &buffkey, &buffval, true, &latch); /* If we found it, return it */ if (rc == HASHTABLE_SUCCESS) { pclient = buffval.addr; /* Return the found NLM Client */ if (isFullDebug(COMPONENT_STATE)) { display_nlm_client(&dspbuf, pclient); LogFullDebug(COMPONENT_STATE, "Found {%s}", str); } /* Increment refcount under hash latch. * This prevents dec ref from removing this entry from hash * if a race occurs. */ inc_nlm_client_ref(pclient); hashtable_releaselatched(ht_nlm_client, &latch); if (care == CARE_MONITOR && !nsm_monitor(nsm_client)) { dec_nlm_client_ref(pclient); pclient = NULL; } return pclient; } /* An error occurred, return NULL */ if (rc != HASHTABLE_ERROR_NO_SUCH_KEY) { display_nlm_client(&dspbuf, &key); LogCrit(COMPONENT_STATE, "Error %s, could not find {%s}", hash_table_err_to_str(rc), str); return NULL; } /* Not found, but we don't care, return NULL */ if (care == CARE_NOT) { /* Return the found NLM Client */ if (isFullDebug(COMPONENT_STATE)) { display_nlm_client(&dspbuf, &key); LogFullDebug(COMPONENT_STATE, "Ignoring {%s}", str); } hashtable_releaselatched(ht_nlm_client, &latch); return NULL; } pclient = gsh_malloc(sizeof(*pclient)); if (pclient == NULL) { display_nlm_client(&dspbuf, &key); LogCrit(COMPONENT_STATE, "No memory for {%s}", str); return NULL; } /* Copy everything over */ memcpy(pclient, &key, sizeof(key)); pclient->slc_nlm_caller_name = gsh_strdup(key.slc_nlm_caller_name); /* Take a reference to the NSM Client */ inc_nsm_client_ref(nsm_client); if (pclient->slc_nlm_caller_name == NULL) { /* Discard the created client */ free_nlm_client(pclient); return NULL; } pclient->slc_refcount = 1; if (isFullDebug(COMPONENT_STATE)) { display_nlm_client(&dspbuf, pclient); LogFullDebug(COMPONENT_STATE, "New {%s}", str); } buffkey.addr = pclient; buffkey.len = sizeof(*pclient); buffval.addr = pclient; buffval.len = sizeof(*pclient); rc = hashtable_setlatched(ht_nlm_client, &buffval, &buffval, &latch, false, NULL, NULL); /* An error occurred, return NULL */ if (rc != HASHTABLE_SUCCESS) { display_nlm_client(&dspbuf, pclient); LogCrit(COMPONENT_STATE, "Error %s, inserting {%s}", hash_table_err_to_str(rc), str); free_nlm_client(pclient); return NULL; } if (care != CARE_MONITOR || nsm_monitor(nsm_client)) return pclient; /* Failed to monitor, release client reference * and almost certainly remove it from the hash table. */ dec_nlm_client_ref(pclient); return NULL; }