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; }
fsal_acl_t *nfs4_acl_new_entry(fsal_acl_data_t *pacldata, fsal_acl_status_t *pstatus) { fsal_acl_t *pacl = NULL; hash_buffer_t buffkey; hash_buffer_t buffvalue; int rc; /* Set the return default to NFS_V4_ACL_SUCCESS */ *pstatus = NFS_V4_ACL_SUCCESS; LogDebug(COMPONENT_NFS_V4_ACL, "nfs4_acl_new_entry: acl hash table size = %u", HashTable_GetSize(fsal_acl_hash)); /* Turn the input to a hash key */ if(nfs4_acldata_2_key(&buffkey, pacldata)) { *pstatus = NFS_V4_ACL_UNAPPROPRIATED_KEY; nfs4_release_acldata_key(&buffkey); nfs4_ace_free(pacldata->aces); return NULL; } /* Check if the entry doesn't already exists */ if(HashTable_Get(fsal_acl_hash, &buffkey, &buffvalue) == HASHTABLE_SUCCESS) { /* Entry is already in the cache, do not add it */ pacl = (fsal_acl_t *) buffvalue.pdata; *pstatus = NFS_V4_ACL_EXISTS; nfs4_release_acldata_key(&buffkey); nfs4_ace_free(pacldata->aces); return pacl; } /* Adding the entry in the cache */ pacl = nfs4_acl_alloc(); if(rw_lock_init(&(pacl->lock)) != 0) { nfs4_acl_free(pacl); LogCrit(COMPONENT_NFS_V4_ACL, "nfs4_acl_new_entry: rw_lock_init returned %d (%s)", errno, strerror(errno)); *pstatus = NFS_V4_ACL_INIT_ENTRY_FAILED; nfs4_release_acldata_key(&buffkey); nfs4_ace_free(pacldata->aces); return NULL; } pacl->naces = pacldata->naces; pacl->aces = pacldata->aces; pacl->ref = 0; /* Build the value */ buffvalue.pdata = (caddr_t) pacl; buffvalue.len = sizeof(fsal_acl_t); if((rc = HashTable_Test_And_Set(fsal_acl_hash, &buffkey, &buffvalue, HASHTABLE_SET_HOW_SET_NO_OVERWRITE)) != HASHTABLE_SUCCESS) { /* Put the entry back in its pool */ nfs4_acl_free(pacl); LogWarn(COMPONENT_NFS_V4_ACL, "nfs4_acl_new_entry: entry could not be added to hash, rc=%d", rc); if( rc != HASHTABLE_ERROR_KEY_ALREADY_EXISTS ) { *pstatus = NFS_V4_ACL_HASH_SET_ERROR; nfs4_release_acldata_key(&buffkey); return NULL; } else { LogDebug(COMPONENT_NFS_V4_ACL, "nfs4_acl_new_entry: concurrency detected during acl insertion"); /* This situation occurs when several threads try to init the same uncached entry * at the same time. The first creates the entry and the others got HASHTABLE_ERROR_KEY_ALREADY_EXISTS * In this case, the already created entry (by the very first thread) is returned */ if((rc = HashTable_Get(fsal_acl_hash, &buffkey, &buffvalue)) != HASHTABLE_SUCCESS) { *pstatus = NFS_V4_ACL_HASH_SET_ERROR; nfs4_release_acldata_key(&buffkey); return NULL; } pacl = (fsal_acl_t *) buffvalue.pdata; *pstatus = NFS_V4_ACL_SUCCESS; nfs4_release_acldata_key(&buffkey); return pacl; } } return pacl; }