Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}