Exemplo n.º 1
0
cache_inode_status_t cache_inode_kill_entry( cache_entry_t          * pentry,
                                             cache_inode_lock_how_t   lock_how,  
                                             hash_table_t           * ht,
                                             cache_inode_client_t   * pclient,
                                             cache_inode_status_t   * pstatus )
{
  fsal_handle_t *pfsal_handle = NULL;
  cache_inode_fsal_data_t fsaldata;
  cache_inode_parent_entry_t *parent_iter = NULL;
  cache_inode_parent_entry_t *parent_iter_next = NULL;
  hash_buffer_t key, old_key;
  hash_buffer_t old_value;
  int rc;
  fsal_status_t fsal_status;

  memset( (char *)&fsaldata, 0, sizeof( fsaldata ) ) ;

  LogInfo(COMPONENT_CACHE_INODE,
          "Using cache_inode_kill_entry for entry %p", pentry);

  /* Invalidation is not for junctions or special files */
  if( ( pentry->internal_md.type == FS_JUNCTION )    ||
      ( pentry->internal_md.type == SOCKET_FILE )    ||
      ( pentry->internal_md.type == FIFO_FILE )      ||
      ( pentry->internal_md.type == CHARACTER_FILE ) ||
      ( pentry->internal_md.type == BLOCK_FILE ) )
   {
     free_lock( pentry, lock_how ) ; 

     *pstatus = CACHE_INODE_SUCCESS;
     return *pstatus;
   }

#if 0
  /** @todo: BUGAZOMEU : directory invalidation seems quite tricky, temporarily avoid it */
  if( pentry->internal_md.type == DIRECTORY )
   {
     free_lock( pentry, lock_how ) ; 

     *pstatus = CACHE_INODE_SUCCESS;
     return *pstatus;
   }

  /** @todo: BUGAZOMEU : file invalidation seems quite tricky, temporarily avoid it */
  /* We need to know how to manage how to deal with "files with states"  */
  if( pentry->internal_md.type == REGULAR_FILE )
   {
     free_lock( pentry, lock_how ) ; 

     *pstatus = CACHE_INODE_SUCCESS;
     return *pstatus;
   }
#endif

  if(pstatus == NULL)
    return CACHE_INODE_INVALID_ARGUMENT;

  if(pentry == NULL || pclient == NULL || ht == NULL)
    {
      free_lock( pentry, lock_how ) ; 

      *pstatus = CACHE_INODE_INVALID_ARGUMENT;
      return *pstatus;
    }

  /* Get the FSAL handle */
  if((pfsal_handle = cache_inode_get_fsal_handle(pentry, pstatus)) == NULL)
    {
      free_lock( pentry, lock_how ) ; 

      LogCrit(COMPONENT_CACHE_INODE,
              "cache_inode_kill_entry: unable to retrieve pentry's specific filesystem info");
      return *pstatus;
    }

  /* Invalidate the related LRU gc entry (no more required) */
  if(pentry->gc_lru_entry != NULL)
    {
      if(LRU_invalidate(pentry->gc_lru, pentry->gc_lru_entry) != LRU_LIST_SUCCESS)
        {
          free_lock( pentry, lock_how ) ; 

          *pstatus = CACHE_INODE_LRU_ERROR;
          return *pstatus;
        }
    }

  fsaldata.handle = *pfsal_handle;
  fsaldata.cookie = DIR_START;

  /* Use the handle to build the key */
  if(cache_inode_fsaldata_2_key(&key, &fsaldata, pclient))
    {
      free_lock( pentry, lock_how ) ; 

      LogCrit(COMPONENT_CACHE_INODE,
              "cache_inode_kill_entry: could not build hashtable key");

      cache_inode_release_fsaldata_key(&key, pclient);
      *pstatus = CACHE_INODE_NOT_FOUND;
      return *pstatus;
    }

  /* use the key to delete the entry */
  if((rc = HashTable_Del(ht, &key, &old_key, &old_value)) != HASHTABLE_SUCCESS)
    {
      if( rc != HASHTABLE_ERROR_NO_SUCH_KEY) /* rc=3 => Entry was previously removed */
        LogCrit( COMPONENT_CACHE_INODE,
                 "cache_inode_kill_entry: entry could not be deleted, status = %d",
                 rc);

      cache_inode_release_fsaldata_key(&key, pclient);

      *pstatus = CACHE_INODE_NOT_FOUND;
      return *pstatus;
    }

  /* Release the hash key data */
  cache_inode_release_fsaldata_key(&old_key, pclient);

  /* Clean up the associated ressources in the FSAL */
  if(FSAL_IS_ERROR(fsal_status = FSAL_CleanObjectResources(pfsal_handle)))
    {
      LogCrit(COMPONENT_CACHE_INODE,
              "cache_inode_kill_entry: Couldn't free FSAL ressources fsal_status.major=%u",
              fsal_status.major);
    }

  /* Sanity check: old_value.pdata is expected to be equal to pentry,
   * and is released later in this function */
  if((cache_entry_t *) old_value.pdata != pentry)
    {
      LogCrit(COMPONENT_CACHE_INODE,
              "cache_inode_kill_entry: unexpected pdata %p from hash table (pentry=%p)",
              old_value.pdata, pentry);
    }

  /* Release the current key */
  cache_inode_release_fsaldata_key(&key, pclient);

  /* Recover the parent list entries */
  parent_iter = pentry->parent_list;
  while(parent_iter != NULL)
    {
      parent_iter_next = parent_iter->next_parent;

      ReleaseToPool(parent_iter, &pclient->pool_parent);

      parent_iter = parent_iter_next;
    }

  /* If entry is datacached, remove it from the cache */
  if(pentry->internal_md.type == REGULAR_FILE)
    {
      cache_content_status_t cache_content_status;

      if(pentry->object.file.pentry_content != NULL)
        if(cache_content_release_entry
           ((cache_content_entry_t *) pentry->object.file.pentry_content,
            (cache_content_client_t *) pclient->pcontent_client,
            &cache_content_status) != CACHE_CONTENT_SUCCESS)
          LogCrit(COMPONENT_CACHE_INODE,
                  "Could not removed datacached entry for pentry %p", pentry);
    }

  /* If entry is a DIRECTORY, invalidate dirents */
  if(pentry->internal_md.type == DIRECTORY)
    {
	cache_inode_invalidate_related_dirents(pentry, pclient);
    }

  // free_lock( pentry, lock_how ) ; /* Really needed ? The pentry is unaccessible now and will be destroyed */

  /* Destroy the mutex associated with the pentry */
  cache_inode_mutex_destroy(pentry);

  /* Put the pentry back to the pool */
  ReleaseToPool(pentry, &pclient->pool_entry);

  *pstatus = CACHE_INODE_SUCCESS;
  return *pstatus;
}                               /* cache_inode_kill_entry */
Exemplo n.º 2
0
/**
 * cache_inode_clean_internal: remove a pentry from cache and all LRUs,
 *                             and release related resources.
 *
 * @param pentry [IN] entry to be deleted from cache
 * @param hash_table_t [IN] The cache hash table
 * @param pclient [INOUT] ressource allocated by the client for the nfs management.
 */
cache_inode_status_t cache_inode_clean_internal(cache_entry_t * to_remove_entry,
                                                hash_table_t * ht,
                                                cache_inode_client_t * pclient)
{
  fsal_handle_t *pfsal_handle_remove;
  cache_inode_parent_entry_t *parent_iter = NULL;
  cache_inode_parent_entry_t *parent_iter_next = NULL;
  cache_inode_fsal_data_t fsaldata;
  cache_inode_status_t status;
  hash_buffer_t key, old_key, old_value;
  int rc;
 
  memset( (char *)&fsaldata, 0, sizeof( fsaldata ) ) ;

  if((pfsal_handle_remove =
      cache_inode_get_fsal_handle(to_remove_entry, &status)) == NULL)
    {
      return status;
    }

  /* Invalidate the related LRU gc entry (no more required) */
  if(to_remove_entry->gc_lru_entry != NULL)
    {
      if(LRU_invalidate(to_remove_entry->gc_lru, to_remove_entry->gc_lru_entry)
         != LRU_LIST_SUCCESS)
        {
          return CACHE_INODE_LRU_ERROR;
        }
    }

  /* delete the entry from the cache */
  fsaldata.handle = *pfsal_handle_remove;

  /* XXX always DIR_START */
  fsaldata.cookie = DIR_START;

  if(cache_inode_fsaldata_2_key(&key, &fsaldata, pclient))
    {
      return CACHE_INODE_INCONSISTENT_ENTRY;
    }

  /* use the key to delete the entry */
  rc = HashTable_Del(ht, &key, &old_key, &old_value);

  if(rc)
    LogCrit(COMPONENT_CACHE_INODE,
            "HashTable_Del error %d in cache_inode_clean_internal", rc);

  if((rc != HASHTABLE_SUCCESS) && (rc != HASHTABLE_ERROR_NO_SUCH_KEY))
    {
      cache_inode_release_fsaldata_key(&key, pclient);
      return CACHE_INODE_INCONSISTENT_ENTRY;
    }

  /* release the key that was stored in hash table */
  if(rc != HASHTABLE_ERROR_NO_SUCH_KEY)
    {
      cache_inode_release_fsaldata_key(&old_key, pclient);

      /* Sanity check: old_value.pdata is expected to be equal to pentry,
       * and is released later in this function */
      if((cache_entry_t *) old_value.pdata != to_remove_entry)
        {
          LogCrit(COMPONENT_CACHE_INODE,
                  "cache_inode_remove: unexpected pdata %p from hash table (pentry=%p)",
                  old_value.pdata, to_remove_entry);
        }
    }

  /* release the key used for hash query */
  cache_inode_release_fsaldata_key(&key, pclient);

  /* Free the parent list entries */

  parent_iter = to_remove_entry->parent_list;
  while(parent_iter != NULL)
    {
      parent_iter_next = parent_iter->next_parent;

      ReleaseToPool(parent_iter, &pclient->pool_parent);

      parent_iter = parent_iter_next;
    }

  return CACHE_INODE_SUCCESS;
}                               /* cache_inode_clean_internal */
Exemplo n.º 3
0
/**
 *
 * cache_inode_get: Gets an entry by using its fsdata as a key and caches it if needed.
 * 
 * Gets an entry by using its fsdata as a key and caches it if needed.
 * ASSUMPTION: DIR_CONT entries are always garbabbaged before their related DIR_BEGINNG 
 *
 * @param fsdata [IN] file system data
 * @param pattr [OUT] pointer to the attributes for the result. 
 * @param ht [IN] hash table used for the cache, unused in this call.
 * @param pclient [INOUT] ressource allocated by the client for the nfs management.
 * @param pcontext [IN] FSAL credentials 
 * @param pstatus [OUT] returned status.
 * 
 * @return the pointer to the entry is successfull, NULL otherwise.
 *
 */
cache_entry_t *cache_inode_get(cache_inode_fsal_data_t * pfsdata,
                               fsal_attrib_list_t * pattr,
                               hash_table_t * ht,
                               cache_inode_client_t * pclient,
                               fsal_op_context_t * pcontext,
                               cache_inode_status_t * pstatus)
{
  hash_buffer_t key, value;
  cache_entry_t *pentry = NULL;
  fsal_status_t fsal_status;
  cache_inode_create_arg_t create_arg;
  cache_inode_file_type_t type;
  int hrc = 0;
  fsal_attrib_list_t fsal_attributes;
  cache_inode_fsal_data_t *ppoolfsdata = NULL;

  /* Set the return default to CACHE_INODE_SUCCESS */
  *pstatus = CACHE_INODE_SUCCESS;

  /* stats */
  pclient->stat.nb_call_total += 1;
  pclient->stat.func_stats.nb_call[CACHE_INODE_GET] += 1;

  /* Turn the input to a hash key */
  if(cache_inode_fsaldata_2_key(&key, pfsdata, pclient))
    {
      *pstatus = CACHE_INODE_UNAPPROPRIATED_KEY;

      /* stats */
      pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

      ppoolfsdata = (cache_inode_fsal_data_t *) key.pdata;
      RELEASE_PREALLOC(ppoolfsdata, pclient->pool_key, next_alloc);

      return NULL;
    }

  switch (hrc = HashTable_Get(ht, &key, &value))
    {
    case HASHTABLE_SUCCESS:
      /* Entry exists in the cache and was found */
      pentry = (cache_entry_t *) value.pdata;

      /* return attributes additionally */
      cache_inode_get_attributes(pentry, pattr);

      break;

    case HASHTABLE_ERROR_NO_SUCH_KEY:
      /* Cache miss, allocate a new entry */

      /* If we ask for a dir cont (in this case pfsdata.cookie != FSAL_DIR_BEGINNING, we have 
       * a client who performs a readdir in the middle of a directory, when the direcctories
       * have been garbbage. we must search for the DIR_BEGIN related to this DIR_CONT */
      if(pfsdata->cookie != DIR_START)
        {
          /* added for sanity check */
          LogDebug(COMPONENT_CACHE_INODE_GC,
              "=======> Pb cache_inode_get: line %u pfsdata->cookie != DIR_START (=%u) on object whose type is %u",
               __LINE__, pfsdata->cookie,
               cache_inode_fsal_type_convert(fsal_attributes.type));

          pfsdata->cookie = DIR_START;

          /* Free this key */
          cache_inode_release_fsaldata_key(&key, pclient);

          /* redo the call */
          return cache_inode_get(pfsdata, pattr, ht, pclient, pcontext, pstatus);
        }

      /* First, call FSAL to know what the object is */
      fsal_attributes.asked_attributes = pclient->attrmask;
      fsal_status = FSAL_getattrs(&pfsdata->handle, pcontext, &fsal_attributes);
      if(FSAL_IS_ERROR(fsal_status))
        {
          *pstatus = cache_inode_error_convert(fsal_status);

          LogDebug(COMPONENT_CACHE_INODE_GC, "cache_inode_get: line %u cache_inode_status=%u fsal_status=%u,%u ",
                     __LINE__, *pstatus, fsal_status.major, fsal_status.minor);

          if(fsal_status.major == ERR_FSAL_STALE)
            {
              char handle_str[256];

              snprintHandle(handle_str, 256, &pfsdata->handle);
              LogEvent(COMPONENT_CACHE_INODE_GC,"cache_inode_get: Stale FSAL File Handle %s", handle_str);

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }

          /* stats */
          pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

          /* Free this key */
          cache_inode_release_fsaldata_key(&key, pclient);

          return NULL;
        }

      /* The type has to be set in the attributes */
      if(!FSAL_TEST_MASK(fsal_attributes.supported_attributes, FSAL_ATTR_TYPE))
        {
          *pstatus = CACHE_INODE_FSAL_ERROR;

          /* stats */
          pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

          /* Free this key */
          cache_inode_release_fsaldata_key(&key, pclient);

          return NULL;
        }

      /* Get the cache_inode file type */
      type = cache_inode_fsal_type_convert(fsal_attributes.type);

      if(type == SYMBOLIC_LINK)
        {
          FSAL_CLEAR_MASK(fsal_attributes.asked_attributes);
          FSAL_SET_MASK(fsal_attributes.asked_attributes, pclient->attrmask);
          fsal_status =
              FSAL_readlink(&pfsdata->handle, pcontext, &create_arg.link_content,
                            &fsal_attributes);
          if(FSAL_IS_ERROR(fsal_status))
            {
              *pstatus = cache_inode_error_convert(fsal_status);

              /* stats */
              pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

              /* Free this key */
              cache_inode_release_fsaldata_key(&key, pclient);

              if(fsal_status.major == ERR_FSAL_STALE)
                {
                  cache_inode_status_t kill_status;

                  LogDebug(COMPONENT_CACHE_INODE_GC,
                      "cache_inode_get: Stale FSAL File Handle detected for pentry = %p",
                       pentry);

                  if(cache_inode_kill_entry(pentry, ht, pclient, &kill_status) !=
                     CACHE_INODE_SUCCESS)
                    LogCrit(COMPONENT_CACHE_INODE_GC,"cache_inode_get: Could not kill entry %p, status = %u",
                               pentry, kill_status);

                  *pstatus = CACHE_INODE_FSAL_ESTALE;

                }

              return NULL;
            }
        }

      /* Add the entry to the cache */
      if((pentry = cache_inode_new_entry(pfsdata, &fsal_attributes, type, &create_arg, NULL,    /* never used to add a new DIR_CONTINUE within the scope of this function */
                                         ht, pclient, pcontext, FALSE,  /* This is a population, not a creation */
                                         pstatus)) == NULL)
        {
          /* stats */
          pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

          /* Free this key */
          cache_inode_release_fsaldata_key(&key, pclient);

          return NULL;
        }

      /* Set the returned attributes */
      *pattr = fsal_attributes;

      /* Now, exit the switch/case and returns */
      break;

    default:
      /* This should not happened */
      *pstatus = CACHE_INODE_INVALID_ARGUMENT;

      /* stats */
      pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

      /* Free this key */
      cache_inode_release_fsaldata_key(&key, pclient);

      return NULL;
      break;
    }

  *pstatus = CACHE_INODE_SUCCESS;

  /* valid the found entry, if this is not feasable, returns nothing to the client */
  P_w(&pentry->lock);
  if((*pstatus =
      cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient)) != CACHE_INODE_SUCCESS)
    {
      V_w(&pentry->lock);
      pentry = NULL;
    }
  V_w(&pentry->lock);

  /* stats */
  pclient->stat.func_stats.nb_success[CACHE_INODE_GET] += 1;

  /* Free this key */
  cache_inode_release_fsaldata_key(&key, pclient);

  return pentry;
}                               /* cache_inode_get */
Exemplo n.º 4
0
/**
 *
 * cache_inode_gc_clean_entry: cleans a entry in the cache_inode.
 *
 * cleans an entry in the cache_inode.
 *
 * @param pentry [INOUT] entry to be cleaned.
 * @param addparam [IN] additional parameter used for cleaning.
 *
 * @return  LRU_LIST_SET_INVALID if ok,  LRU_LIST_DO_NOT_SET_INVALID otherwise
 *
 */
static int cache_inode_gc_clean_entry(cache_entry_t * pentry,
                                      cache_inode_param_gc_t * pgcparam)
{
  fsal_handle_t *pfsal_handle = NULL;
  cache_inode_parent_entry_t *parent_iter = NULL;
  cache_inode_parent_entry_t *parent_iter_next = NULL;
  cache_inode_fsal_data_t fsaldata;
  cache_inode_status_t status;
  fsal_status_t fsal_status;
  hash_buffer_t key, old_key, old_value;
  int rc;

  LogFullDebug(COMPONENT_CACHE_INODE_GC,
               "(pthread_self=%p): About to remove pentry=%p, type=%d",
               (caddr_t)pthread_self(),
               pentry, pentry->internal_md.type);

  /* sanity check */
  if((pentry->gc_lru_entry != NULL) &&
     ((cache_entry_t *) pentry->gc_lru_entry->buffdata.pdata) != pentry)
    {
      LogCrit(COMPONENT_CACHE_INODE_GC,
              "cache_inode_gc_clean_entry: LRU entry pointed by this pentry doesn't match the GC LRU");
    }

  /* Get the FSAL handle */
  if((pfsal_handle = cache_inode_get_fsal_handle(pentry, &status)) == NULL)
    {
      LogCrit(COMPONENT_CACHE_INODE_GC,
              "cache_inode_gc_clean_entry: unable to retrieve pentry's specific filesystem info");
      return LRU_LIST_DO_NOT_SET_INVALID;
    }

  fsaldata.handle = *pfsal_handle;

  if(pentry->internal_md.type != DIR_CONTINUE)
    fsaldata.cookie = DIR_START;
  else
    fsaldata.cookie = pentry->object.dir_cont.dir_cont_pos;

  /* Use the handle to build the key */
  if(cache_inode_fsaldata_2_key(&key, &fsaldata, pgcparam->pclient))
    {
      LogCrit(COMPONENT_CACHE_INODE_GC,
              "cache_inode_gc_clean_entry: could not build hashtable key");

      cache_inode_release_fsaldata_key(&key, pgcparam->pclient);

      return LRU_LIST_DO_NOT_SET_INVALID;
    }

  /* use the key to delete the entry */
  rc = HashTable_Del(pgcparam->ht, &key, &old_key, &old_value);

  if((rc != HASHTABLE_SUCCESS) && (rc != HASHTABLE_ERROR_NO_SUCH_KEY))
    {
      LogCrit(COMPONENT_CACHE_INODE_GC,
              "cache_inode_gc_clean_entry: entry could not be deleted, status = %d",
              rc);

      cache_inode_release_fsaldata_key(&key, pgcparam->pclient);

      return LRU_LIST_DO_NOT_SET_INVALID;
    }
  else if(rc == HASHTABLE_ERROR_NO_SUCH_KEY)
    {
      LogEvent(COMPONENT_CACHE_INODE_GC,
               "cache_inode_gc_clean_entry: entry already deleted, type=%d, status=%d",
               pentry->internal_md.type, rc);

      cache_inode_release_fsaldata_key(&key, pgcparam->pclient);
      return LRU_LIST_SET_INVALID;
    }

  /* Clean up the associated ressources in the FSAL */
  if(FSAL_IS_ERROR(fsal_status = FSAL_CleanObjectResources(pfsal_handle)))
    {
      LogCrit(COMPONENT_CACHE_INODE_GC,
              "cache_inode_gc_clean_entry: Could'nt free FSAL ressources fsal_status.major=%u",
              fsal_status.major);
    }
  LogFullDebug(COMPONENT_CACHE_INODE_GC,
               "++++> pentry %p deleted from HashTable", pentry);

  /* Release the hash key data */
  cache_inode_release_fsaldata_key(&old_key, pgcparam->pclient);

  /* Sanity check: old_value.pdata is expected to be equal to pentry,
   * and is released later in this function */
  if((cache_entry_t *) old_value.pdata != pentry)
    {
      LogCrit(COMPONENT_CACHE_INODE_GC,
              "cache_inode_gc_clean_entry: unexpected pdata %p from hash table (pentry=%p)",
              old_value.pdata, pentry);
    }

  cache_inode_release_fsaldata_key(&key, pgcparam->pclient);

  /* Recover the parent list entries */
  parent_iter = pentry->parent_list;
  while(parent_iter != NULL)
    {
      parent_iter_next = parent_iter->next_parent;

      ReleaseToPool(parent_iter, &pgcparam->pclient->pool_parent);

      parent_iter = parent_iter_next;
    }

  LogFullDebug(COMPONENT_CACHE_INODE_GC,
               "++++> parent directory sent back to pool");

  /* If entry is a DIR_CONTINUE or a DIR_BEGINNING, release pdir_data */
  if(pentry->internal_md.type == DIR_BEGINNING)
    {
      /* Put the pentry back to the pool */
      ReleaseToPool(pentry->object.dir_begin.pdir_data, &pgcparam->pclient->pool_dir_data);
    }

  if(pentry->internal_md.type == DIR_CONTINUE)
    {
      /* Put the pentry back to the pool */
      ReleaseToPool(pentry->object.dir_cont.pdir_data, &pgcparam->pclient->pool_dir_data);
    }
  LogFullDebug(COMPONENT_CACHE_INODE_GC,
               "++++> pdir_data (if needed) sent back to pool");

#ifdef _USE_NFS4_ACL
  /* If entry has NFS4 ACL, release it. */
  cache_inode_gc_acl(pentry);
#endif                          /* _USE_NFS4_ACL */

  /* Free and Destroy the mutex associated with the pentry */
  V_w(&pentry->lock);

  cache_inode_mutex_destroy(pentry);

  /* Put the pentry back to the pool */
  ReleaseToPool(pentry, &pgcparam->pclient->pool_entry);

  /* Regular exit */
  pgcparam->nb_to_be_purged = pgcparam->nb_to_be_purged - 1;

  LogFullDebug(COMPONENT_CACHE_INODE_GC,
               "++++> pentry %p: clean entry is ok", pentry);

  return LRU_LIST_SET_INVALID;  /* Cleaning ok */
}
Exemplo n.º 5
0
cache_entry_t *cache_inode_get_located(cache_inode_fsal_data_t * pfsdata,
                                       cache_entry_t * plocation, 
                                       cache_inode_policy_t policy,
                                       fsal_attrib_list_t * pattr,
                                       hash_table_t * ht,
                                       cache_inode_client_t * pclient,
                                       fsal_op_context_t * pcontext,
                                       cache_inode_status_t * pstatus)
{
  hash_buffer_t key, value;
  cache_entry_t *pentry = NULL;
  fsal_status_t fsal_status;
  cache_inode_create_arg_t create_arg;
  cache_inode_file_type_t type;
  int hrc = 0;
  fsal_attrib_list_t fsal_attributes;
  cache_inode_fsal_data_t *ppoolfsdata = NULL;

  memset(&create_arg, 0, sizeof(create_arg));

  /* Set the return default to CACHE_INODE_SUCCESS */
  *pstatus = CACHE_INODE_SUCCESS;

  /* stats */
  /* cache_invalidate calls this with no context or client */
  if (pclient) {
    pclient->stat.nb_call_total += 1;
    pclient->stat.func_stats.nb_call[CACHE_INODE_GET] += 1;
  }

  /* Turn the input to a hash key */
  if(cache_inode_fsaldata_2_key(&key, pfsdata, pclient))
    {
      *pstatus = CACHE_INODE_UNAPPROPRIATED_KEY;

      /* stats */
      /* cache_invalidate calls this with no context or client */
      if (pclient) {
	pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;
	ppoolfsdata = (cache_inode_fsal_data_t *) key.pdata;
	ReleaseToPool(ppoolfsdata, &pclient->pool_key);
      }
      return NULL;
    }

  switch (hrc = HashTable_Get(ht, &key, &value))
    {
    case HASHTABLE_SUCCESS:
      /* Entry exists in the cache and was found */
      pentry = (cache_entry_t *) value.pdata;

      /* return attributes additionally */
      *pattr = pentry->attributes;

      if ( !pclient ) {
	/* invalidate. Just return it to mark it stale and go on. */
	return( pentry );
      }

      break;

    case HASHTABLE_ERROR_NO_SUCH_KEY:
      if ( !pclient ) {
	/* invalidate. Just return */
	return( NULL );
      }
      /* Cache miss, allocate a new entry */

      /* XXX I do not think this can happen with avl dirent cache */
      if(pfsdata->cookie != DIR_START)
        {
          /* added for sanity check */
          LogDebug(COMPONENT_CACHE_INODE,
                       "cache_inode_get: pfsdata->cookie != DIR_START (=%"PRIu64") on object whose type is %u",
                       pfsdata->cookie,
                       cache_inode_fsal_type_convert(fsal_attributes.type));

          pfsdata->cookie = DIR_START;

          /* Free this key */
          cache_inode_release_fsaldata_key(&key, pclient);

          /* redo the call */
          return cache_inode_get(pfsdata, policy, pattr, ht, pclient, pcontext, pstatus);
        }

      /* First, call FSAL to know what the object is */
      fsal_attributes.asked_attributes = pclient->attrmask;
      fsal_status = FSAL_getattrs(&pfsdata->handle, pcontext, &fsal_attributes);
      if(FSAL_IS_ERROR(fsal_status))
        {
          *pstatus = cache_inode_error_convert(fsal_status);

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_get: cache_inode_status=%u fsal_status=%u,%u ",
                   *pstatus, fsal_status.major, fsal_status.minor);

          if(fsal_status.major == ERR_FSAL_STALE)
            {
              char handle_str[256];

              snprintHandle(handle_str, 256, &pfsdata->handle);
              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_get: Stale FSAL File Handle %s, fsal_status=(%u,%u)",
                       handle_str, fsal_status.major, fsal_status.minor);

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }

          /* stats */
          pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

          /* Free this key */
          cache_inode_release_fsaldata_key(&key, pclient);

          return NULL;
        }

      /* The type has to be set in the attributes */
      if(!FSAL_TEST_MASK(fsal_attributes.supported_attributes, FSAL_ATTR_TYPE))
        {
          *pstatus = CACHE_INODE_FSAL_ERROR;

          /* stats */
          pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

          /* Free this key */
          cache_inode_release_fsaldata_key(&key, pclient);

          return NULL;
        }

      /* Get the cache_inode file type */
      type = cache_inode_fsal_type_convert(fsal_attributes.type);

      if(type == SYMBOLIC_LINK)
        {
          if( CACHE_INODE_KEEP_CONTENT( policy ) )
           {
             FSAL_CLEAR_MASK(fsal_attributes.asked_attributes);
             FSAL_SET_MASK(fsal_attributes.asked_attributes, pclient->attrmask);
             fsal_status =
                FSAL_readlink(&pfsdata->handle, pcontext, &create_arg.link_content,
                              &fsal_attributes);
            }
          else
            { 
               fsal_status.major = ERR_FSAL_NO_ERROR ;
               fsal_status.minor = 0 ;
            }

          if(FSAL_IS_ERROR(fsal_status))
            {
              *pstatus = cache_inode_error_convert(fsal_status);

              /* stats */
              pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

              /* Free this key */
              cache_inode_release_fsaldata_key(&key, pclient);

              if(fsal_status.major == ERR_FSAL_STALE)
                {
                  cache_inode_status_t kill_status;

                  LogEvent(COMPONENT_CACHE_INODE,
                           "cache_inode_get: Stale FSAL File Handle detected for pentry = %p, fsal_status=(%u,%u)",
                           pentry, fsal_status.major, fsal_status.minor);

                  if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) !=
                     CACHE_INODE_SUCCESS)
                    LogCrit(COMPONENT_CACHE_INODE,
                            "cache_inode_get: Could not kill entry %p, status = %u, fsal_status=(%u,%u)",
                            pentry, kill_status, fsal_status.major, fsal_status.minor);

                  *pstatus = CACHE_INODE_FSAL_ESTALE;

                }

              return NULL;
            }
        }

      /* Add the entry to the cache */
      if ( type == 1)
	LogCrit(COMPONENT_CACHE_INODE,"inode get");

      if((pentry = cache_inode_new_entry( pfsdata,
                                          &fsal_attributes, 
                                          type,
                                          policy, 
                                          &create_arg, 
                                          NULL,    /* never used to add a new DIR_CONTINUE within this function */
                                          ht, 
                                          pclient, 
                                          pcontext, 
                                          FALSE,  /* This is a population, not a creation */
                                          pstatus ) ) == NULL )
        {
          /* stats */
          pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

          /* Free this key */
          cache_inode_release_fsaldata_key(&key, pclient);

          return NULL;
        }

      /* Set the returned attributes */
      *pattr = fsal_attributes;

      /* Now, exit the switch/case and returns */
      break;

    default:
      /* This should not happened */
      *pstatus = CACHE_INODE_INVALID_ARGUMENT;
      LogCrit(COMPONENT_CACHE_INODE,
              "cache_inode_get returning CACHE_INODE_INVALID_ARGUMENT - this should not have happened");

      if ( !pclient ) {
        /* invalidate. Just return */
        return( NULL );
      }

      /* stats */
      pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

      /* Free this key */
      cache_inode_release_fsaldata_key(&key, pclient);

      return NULL;
      break;
    }

  /* Want to ASSERT pclient at this point */
  *pstatus = CACHE_INODE_SUCCESS;
  
  if (pentry->object.symlink != NULL) {
  	int stop_here;
	stop_here = 1;
	if (stop_here) {
		stop_here = 2;
	}
  }

  /* valid the found entry, if this is not feasable, returns nothing to the client */
  if( plocation != NULL )
   {
     if( plocation != pentry )
      {
        P_w(&pentry->lock);
        if((*pstatus =
           cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient)) != CACHE_INODE_SUCCESS)
          {
            V_w(&pentry->lock);
            pentry = NULL;
          }
        V_w(&pentry->lock);
      }
   }

  /* stats */
  pclient->stat.func_stats.nb_success[CACHE_INODE_GET] += 1;

  /* Free this key */
  cache_inode_release_fsaldata_key(&key, pclient);

  return pentry;
}  /* cache_inode_get_located */