/**
 *
 * cache_inode_getattr: Gets the attributes for a cached entry.
 *
 * Gets the attributes for a cached entry. The FSAL attributes are kept in a structure when the entry
 * is added to the cache.
 *
 * @param pentry [IN] entry to be managed.
 * @param pattr [OUT] pointer to the results
 * @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 CACHE_INODE_SUCCESS if operation is a success \n
 * @return CACHE_INODE_LRU_ERROR if allocation error occured when validating the entry
 *
 */
cache_inode_status_t
cache_inode_getattr(cache_entry_t * pentry,
                    fsal_attrib_list_t * pattr,
                    hash_table_t * ht, /* Unused, kept for protototype's homogeneity */
                    cache_inode_client_t * pclient,
                    fsal_op_context_t * pcontext,
                    cache_inode_status_t * pstatus)
{
    cache_inode_status_t status;
    fsal_handle_t *pfsal_handle = NULL;
    fsal_status_t fsal_status;

    /* sanity check */
    if(pentry == NULL || pattr == NULL ||
       ht == NULL || pclient == NULL || pcontext == NULL)
        {
            *pstatus = CACHE_INODE_INVALID_ARGUMENT;
            LogDebug(COMPONENT_CACHE_INODE,
                     "cache_inode_getattr: returning CACHE_INODE_INVALID_ARGUMENT because of bad arg");
            return *pstatus;
        }

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

    /* stats */
    pclient->stat.nb_call_total += 1;
    inc_func_call(pclient, CACHE_INODE_GETATTR);

    /* Lock the entry */
    P_w(&pentry->lock);
    status = cache_inode_renew_entry(pentry, pattr, ht,
                                     pclient, pcontext, pstatus);
    if(status != CACHE_INODE_SUCCESS)
        {
            V_w(&pentry->lock);
            inc_func_err_retryable(pclient, CACHE_INODE_GETATTR);
            LogFullDebug(COMPONENT_CACHE_INODE,
                         "cache_inode_getattr: returning %d(%s) from cache_inode_renew_entry",
                         *pstatus, cache_inode_err_str(*pstatus));
            return *pstatus;
        }

    /* RW Lock goes for writer to reader */
    rw_lock_downgrade(&pentry->lock);

    cache_inode_get_attributes(pentry, pattr);

    if(FSAL_TEST_MASK(pattr->asked_attributes,
                      FSAL_ATTR_RDATTR_ERR))
        {
            switch (pentry->internal_md.type)
                {
                case REGULAR_FILE:
                    pfsal_handle = &pentry->object.file.handle;
                    break;

                case SYMBOLIC_LINK:
                    assert(pentry->object.symlink);
                    pfsal_handle = &pentry->object.symlink->handle;
                    break;

                case DIRECTORY:
                    pfsal_handle = &pentry->object.dir.handle;
                    break;
                case SOCKET_FILE:
                case FIFO_FILE:
                case BLOCK_FILE:
                case CHARACTER_FILE:
                    pfsal_handle = &pentry->object.special_obj.handle;
                    break;
                case FS_JUNCTION:
                case UNASSIGNED:
                case RECYCLED:
                    *pstatus = CACHE_INODE_INVALID_ARGUMENT;
                    LogFullDebug(COMPONENT_CACHE_INODE,
                                 "cache_inode_getattr: returning %d(%s) from cache_inode_renew_entry - unexpected md_type",
                                 *pstatus, cache_inode_err_str(*pstatus));
                    return *pstatus;
                }

            /*
             * An error occured when trying to get
             * the attributes, they have to be renewed
             */
#ifdef _USE_MFSL
            fsal_status = FSAL_getattrs_descriptor(&(cache_inode_fd(pentry)->fsal_file), pfsal_handle, pcontext, pattr);
#else
            fsal_status = FSAL_getattrs_descriptor(cache_inode_fd(pentry), pfsal_handle, pcontext, pattr);
#endif
            if(FSAL_IS_ERROR(fsal_status))
                {
                    *pstatus = cache_inode_error_convert(fsal_status);
                    
                    V_r(&pentry->lock);

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

                            LogEvent(COMPONENT_CACHE_INODE,
                                     "cache_inode_getattr: Stale FSAL File Handle detected for pentry = %p",
                                     pentry);

                            /* Locked flag is set to true to show entry has a read lock */
                            cache_inode_kill_entry( pentry, WT_LOCK, ht,
                                                    pclient, &kill_status);
                            if(kill_status != CACHE_INODE_SUCCESS)
                                LogCrit(COMPONENT_CACHE_INODE,
                                        "cache_inode_getattr: Could not kill entry %p, status = %u",
                                        pentry, kill_status);

                            *pstatus = CACHE_INODE_FSAL_ESTALE;
                        }

                    /* stat */
                    inc_func_err_unrecover(pclient, CACHE_INODE_GETATTR);
                    LogDebug(COMPONENT_CACHE_INODE,
                             "cache_inode_getattr: returning %d(%s) from FSAL_getattrs_descriptor",
                             *pstatus, cache_inode_err_str(*pstatus));
                    return *pstatus;
                }

            /* Set the new attributes */
            cache_inode_set_attributes(pentry, pattr);
        }
    *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient);

    V_r(&pentry->lock);

    /* stat */
    if(*pstatus != CACHE_INODE_SUCCESS)
        inc_func_err_retryable(pclient, CACHE_INODE_GETATTR);
    else
        inc_func_success(pclient, CACHE_INODE_GETATTR);

#ifdef _USE_NFS4_ACL
    if(isDebug(COMPONENT_NFS_V4_ACL))
      {
        LogDebug(COMPONENT_CACHE_INODE,
                 "cache_inode_getattr: pentry = %p, acl = %p",
                 pentry, pattr->acl);

        if(pattr->acl)
          {
            fsal_ace_t *pace;
            for(pace = pattr->acl->aces; pace < pattr->acl->aces + pattr->acl->naces; pace++)
              {
                LogDebug(COMPONENT_CACHE_INODE,
                         "cache_inode_getattr: ace type = 0x%x, flag = 0x%x, perm = 0x%x, special = %d, %s = 0x%x",
                         pace->type, pace->flag, pace->perm, IS_FSAL_ACE_SPECIAL_ID(*pace),
                         GET_FSAL_ACE_WHO_TYPE(*pace), GET_FSAL_ACE_WHO(*pace));
              }
          }
      }
#endif                          /* _USE_NFS4_ACL */

    LogFullDebug(COMPONENT_CACHE_INODE,
                 "cache_inode_getattr: returning %d(%s) from cache_inode_valid",
                 *pstatus, cache_inode_err_str(*pstatus));
    return *pstatus;
}
/**
 *
 * cache_inode_create: creates an entry through the cache.
 *
 * Creates an entry through the cache.
 *
 * @param pentry_parent [IN] pointer to the pentry parent
 * @param pname         [IN] pointer to the name of the object in the destination directory.
 * @param type          [IN] type of the object to be created.
 * @param mode          [IN] mode to be used at file creation
 * @param pcreate_arg   [IN] additional argument for object creation
 * @param pattr         [OUT] attributes for the new object.
 * @param ht            [INOUT] hash table used for the cache.
 * @param pclient       [INOUT] ressource allocated by the client for the nfs management.
 * @param pcontext      [IN] FSAL credentials
 * @param pstatus       [OUT] returned status.
 *
 * @return CACHE_INODE_SUCCESS if operation is a success \n
 * @return CACHE_INODE_LRU_ERROR if allocation error occured when validating the entry\n
 * @return CACHE_INODE_BAD_TYPE either source or destination have incorrect type\n
 * @return CACHE_INODE_ENTRY_EXISTS entry of that name already exists in destination.
 *
 */
cache_entry_t *
cache_inode_create(cache_entry_t * pentry_parent,
                   fsal_name_t * pname,
                   cache_inode_file_type_t type,
                   fsal_accessmode_t mode,
                   cache_inode_create_arg_t * pcreate_arg,
                   fsal_attrib_list_t * pattr,
                   hash_table_t * ht,
                   cache_inode_client_t * pclient,
                   fsal_op_context_t * pcontext,
                   cache_inode_status_t * pstatus)
{
    cache_entry_t *pentry = NULL;
    fsal_status_t fsal_status;
#ifdef _USE_MFSL
    mfsl_object_t object_handle;
#else
    fsal_handle_t object_handle;
#endif
    fsal_attrib_list_t parent_attributes;
    fsal_attrib_list_t object_attributes;
    fsal_handle_t dir_handle;
    cache_inode_fsal_data_t fsal_data;
    cache_inode_status_t status;
    struct cache_inode_dir_begin__ *dir_begin;
    int pnfs_status;

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

    /* stats */
    pclient->stat.nb_call_total += 1;
    inc_func_call(pclient, CACHE_INODE_CREATE);
    /*
     * Check if the required type is correct, with this
     * function, we manage file, dir and symlink
     */
    if(type != REGULAR_FILE && type != DIR_BEGINNING && type != SYMBOLIC_LINK &&
       type != SOCKET_FILE && type != FIFO_FILE && type != CHARACTER_FILE &&
       type != BLOCK_FILE)
        {
            *pstatus = CACHE_INODE_BAD_TYPE;

            /* stats */
            inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);
            return NULL;
        }
    /*
     * Check if caller is allowed to perform the operation
     */
    status = cache_inode_access(pentry_parent,
                                FSAL_W_OK, ht,
                                pclient, pcontext, &status);
    if (status != CACHE_INODE_SUCCESS)
        {
            *pstatus = status;

            /* stats */
            inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);

            /* pentry is a directory */
            return NULL;
        }
    /*
     * Check if an entry of the same name exists
     */
    pentry = cache_inode_lookup(pentry_parent,
                                pname, &object_attributes,
                                ht, pclient, pcontext, pstatus);
    if (pentry != NULL)
        {
            *pstatus = CACHE_INODE_ENTRY_EXISTS;

            if(pentry->internal_md.type != type)
                {
                    /*
                     * Incompatible types, returns NULL
                     */
                    /* stats */
                    inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);
                    return NULL;
                }
            else
                {
                    /* stats */
                    inc_func_success(pclient, CACHE_INODE_CREATE);
                    /*
                     * redondant creation, returned the
                     * previously created entry
                     */
                    return pentry;
                }
        }
    /*
     * At this point, the entry was not found, this means
     * that is doesn't exist is FSAL, we can create it
     */
    /* Get the lock for the parent */
    P_w(&pentry_parent->lock);

    if(pentry_parent->internal_md.type == DIR_BEGINNING)
        dir_handle = pentry_parent->object.dir_begin.handle;

    if(pentry_parent->internal_md.type == DIR_CONTINUE)
        {
            P_r(&pentry_parent->object.dir_cont.pdir_begin->lock);
            dir_handle = pentry_parent->object.dir_cont.pdir_begin->object.dir_begin.handle;
            V_r(&pentry_parent->object.dir_cont.pdir_begin->lock);
        }

    object_attributes.asked_attributes = pclient->attrmask;
    switch (type)
        {
        case REGULAR_FILE:
#ifdef _USE_MFSL
            cache_inode_get_attributes(pentry_parent, &parent_attributes);
            fsal_status = MFSL_create(&pentry_parent->mobject,
                                      pname, pcontext,
                                      &pclient->mfsl_context,
                                      mode, &object_handle,
                                      &object_attributes, &parent_attributes);
#else
            fsal_status = FSAL_create(&dir_handle,
                                      pname, pcontext, mode,
                                      &object_handle, &object_attributes);
#endif
            break;

        case DIR_BEGINNING:
#ifdef _USE_MFSL
            cache_inode_get_attributes(pentry_parent, &parent_attributes);
            fsal_status = MFSL_mkdir(&pentry_parent->mobject,
                                     pname, pcontext,
                                     &pclient->mfsl_context,
                                     mode, &object_handle,
                                     &object_attributes, &parent_attributes);
#else
            fsal_status = FSAL_mkdir(&dir_handle,
                                     pname, pcontext, mode,
                                     &object_handle, &object_attributes);
#endif
            break;

        case SYMBOLIC_LINK:
#ifdef _USE_MFSL
            cache_inode_get_attributes(pentry_parent, &object_attributes);
            fsal_status = MFSL_symlink(&pentry_parent->mobject,
                                       pname, &pcreate_arg->link_content,
                                       pcontext, &pclient->mfsl_context,
                                       mode, &object_handle, &object_attributes);
#else
            fsal_status = FSAL_symlink(&dir_handle,
                                       pname, &pcreate_arg->link_content,
                                       pcontext, mode, &object_handle,
                                       &object_attributes);
#endif
            break;

        case SOCKET_FILE:
#ifdef _USE_MFSL
            fsal_status = MFSL_mknode(&pentry_parent->mobject, pname,
                                      pcontext, &pclient->mfsl_context, mode,
                                      FSAL_TYPE_SOCK, NULL, /* no dev_t needed for socket file */
                                      &object_handle, &object_attributes);
#else
            fsal_status = FSAL_mknode(&dir_handle, pname, pcontext,
                                      mode, FSAL_TYPE_SOCK, NULL, /* no dev_t needed for socket file */
                                      &object_handle, &object_attributes);
#endif
            break;

        case FIFO_FILE:
#ifdef _USE_MFSL
            fsal_status = MFSL_mknode(&pentry_parent->mobject, pname,
                                      pcontext, &pclient->mfsl_context,
                                      mode, FSAL_TYPE_FIFO, NULL, /* no dev_t needed for FIFO file */
                                      &object_handle, &object_attributes);
#else
            fsal_status = FSAL_mknode(&dir_handle, pname, pcontext,
                                      mode, FSAL_TYPE_FIFO, NULL, /* no dev_t needed for FIFO file */
                                      &object_handle, &object_attributes);
#endif
            break;

        case BLOCK_FILE:
#ifdef _USE_MFSL
            fsal_status = MFSL_mknode(&pentry_parent->mobject,
                                      pname, pcontext,
                                      &pclient->mfsl_context,
                                      mode, FSAL_TYPE_BLK,
                                      &pcreate_arg->dev_spec,
                                      &object_handle, &object_attributes);
#else
            fsal_status = FSAL_mknode(&dir_handle,
                                      pname, pcontext,
                                      mode, FSAL_TYPE_BLK,
                                      &pcreate_arg->dev_spec,
                                      &object_handle, &object_attributes);
#endif
            break;

        case CHARACTER_FILE:
#ifdef _USE_MFSL
            fsal_status = MFSL_mknode(&pentry_parent->mobject,
                                      pname, pcontext,
                                      &pclient->mfsl_context,
                                      mode, FSAL_TYPE_CHR,
                                      &pcreate_arg->dev_spec,
                                      &object_handle, &object_attributes);
#else
            fsal_status = FSAL_mknode(&dir_handle,
                                      pname, pcontext,
                                      mode, FSAL_TYPE_CHR,
                                      &pcreate_arg->dev_spec,
                                      &object_handle, &object_attributes);
#endif
            break;

        default:
            /* we should never go there */
            *pstatus = CACHE_INODE_INCONSISTENT_ENTRY;
            V_w(&pentry_parent->lock);

            /* stats */
            inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);

            return NULL;
            break;
        }

    /* Check for the result */
    if(FSAL_IS_ERROR(fsal_status))
        {
            *pstatus = cache_inode_error_convert(fsal_status);
            V_w(&pentry_parent->lock);

            if(fsal_status.major == ERR_FSAL_STALE)
                {
                    cache_inode_status_t kill_status;
                    LogEvent(COMPONENT_CACHE_INODE,
                             "cache_inode_create: Stale FSAL File Handle "
                             "detected for pentry = %p",
                             pentry_parent);

                    cache_inode_kill_entry(pentry_parent, ht,
                                           pclient, &kill_status);
                    if(kill_status != CACHE_INODE_SUCCESS)
                        LogCrit(COMPONENT_CACHE_INODE, "cache_inode_create: "
                                "Could not kill entry %p, status = %u",
                                pentry_parent, kill_status);
                    *pstatus = CACHE_INODE_FSAL_ESTALE;
                }
            /* stats */
            inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);

            return NULL;
        }
    else
        {
#ifdef _USE_MFSL
            fsal_data.handle = object_handle.handle;
#else
            fsal_data.handle = object_handle;
#endif
            fsal_data.cookie = DIR_START;

            pentry = cache_inode_new_entry(&fsal_data, &object_attributes,
                                           type, pcreate_arg, NULL,
                                           ht, pclient, pcontext,
                                           TRUE, /* This is a creation and not a population */
                                           pstatus);
            if (pentry == NULL)
                {
                    *pstatus = CACHE_INODE_INSERT_ERROR;
                    V_w(&pentry_parent->lock);

                    /* stats */
                    inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);
                    return NULL;
                }
#ifdef _USE_MFSL
            /* Copy the MFSL object to the cache */
            memcpy((char *)&(pentry->mobject),
                   (char *)&object_handle, sizeof(mfsl_object_t));
#endif

            /* Add this entry to the directory */
            status = cache_inode_add_cached_dirent(pentry_parent,
                                                   pname, pentry,
                                                   NULL, ht,
                                                   pclient, pcontext,
                                                   pstatus);
            if (status != CACHE_INODE_SUCCESS)
                {
                    V_w(&pentry_parent->lock);

                    /* stats */
                    inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);
                    return NULL;
                }
        }

#ifdef _USE_PNFS
    if((type == REGULAR_FILE) &&
       (pcreate_arg != NULL) &&
       (pcreate_arg->use_pnfs == TRUE))
        {
            pnfs_status = pnfs_create_ds_file(&pclient->pnfsclient,
                                              pentry->object.file.attributes.fileid,
                                              &pentry->object.file.pnfs_file.ds_file);
            if (pnfs_status != NFS4_OK)
                {
                    V_w(&pentry_parent->lock);
                    LogDebug(COMPONENT_CACHE_INODE, "OPEN PNFS CREATE DS FILE : Error %u",
                             pnfs_status);

                    *pstatus = CACHE_INODE_IO_ERROR;
                    return NULL;
                }
        }
#endif

       /* Update the parent cached attributes */
       if(pentry_parent->internal_md.type == DIR_BEGINNING)
           dir_begin = &pentry_parent->object.dir_begin;
       else
           dir_begin = &pentry_parent->object.dir_cont.pdir_begin->object.dir_begin;

       dir_begin->attributes.mtime.seconds = time(NULL);
       dir_begin->attributes.mtime.nseconds = 0;
       dir_begin->attributes.ctime = dir_begin->attributes.mtime;
       /*
        * if the created object is a directory, it contains a link
        * to its parent : '..'. Thus the numlink attr must be increased.
        */
       if(type == DIR_BEGINNING)
           {
               dir_begin->attributes.numlinks++;
           }
       /* Get the attributes in return */
       *pattr = object_attributes;

       /* valid the parent */
       *pstatus = cache_inode_valid(pentry_parent,
                                    CACHE_INODE_OP_SET,
                                    pclient);
       /* release the lock for the parent */
       V_w(&pentry_parent->lock);

       /* stat */
       if(*pstatus != CACHE_INODE_SUCCESS)
           inc_func_err_retryable(pclient, CACHE_INODE_CREATE);
       else
           inc_func_success(pclient, CACHE_INODE_CREATE);

       return pentry;
}
/**
 *
 * cache_inode_getattr: Gets the attributes for a cached entry.
 *
 * Gets the attributes for a cached entry. The FSAL attributes are kept in a structure when the entry
 * is added to the cache.
 *
 * @param pentry [IN] entry to be managed.
 * @param pattr [OUT] pointer to the results
 * @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 CACHE_INODE_SUCCESS if operation is a success \n
 * @return CACHE_INODE_LRU_ERROR if allocation error occured when validating the entry
 *
 */
cache_inode_status_t
cache_inode_getattr(cache_entry_t * pentry,
                    fsal_attrib_list_t * pattr,
                    hash_table_t * ht, /* Unused, kept for protototype's homogeneity */
                    cache_inode_client_t * pclient,
                    fsal_op_context_t * pcontext,
                    cache_inode_status_t * pstatus)
{
    cache_inode_status_t status;
    fsal_handle_t *pfsal_handle;
    fsal_status_t fsal_status;

    /* sanity check */
    if(pentry == NULL || pattr == NULL ||
       ht == NULL || pclient == NULL || pcontext == NULL)
        {
            *pstatus = CACHE_INODE_INVALID_ARGUMENT;
            return *pstatus;
        }

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

    /* stats */
    pclient->stat.nb_call_total += 1;
    inc_func_call(pclient, CACHE_INODE_GETATTR);

    /* Lock the entry */
    P_w(&pentry->lock);
    status = cache_inode_renew_entry(pentry, pattr, ht,
                                     pclient, pcontext, pstatus);
    if(status != CACHE_INODE_SUCCESS)
        {
            V_w(&pentry->lock);
            inc_func_err_retryable(pclient, CACHE_INODE_GETATTR);
            return *pstatus;
        }

    /* RW Lock goes for writer to reader */
    rw_lock_downgrade(&pentry->lock);

    cache_inode_get_attributes(pentry, pattr);

    if(FSAL_TEST_MASK(pattr->asked_attributes,
                      FSAL_ATTR_RDATTR_ERR))
        {
            switch (pentry->internal_md.type)
                {
                case REGULAR_FILE:
                    pfsal_handle = &pentry->object.file.handle;
                    break;

                case SYMBOLIC_LINK:
                    pfsal_handle = &pentry->object.symlink.handle;
                    break;

                case DIR_BEGINNING:
                    pfsal_handle = &pentry->object.dir_begin.handle;
                    break;

                case DIR_CONTINUE:
                    /*
                     * lock the related dir_begin (dir begin are garbagge
                     * collected AFTER their related dir_cont)
                     * this means that if a DIR_CONTINUE exists,
                     * its pdir pointer is not endless
                     */
                    P_r(&pentry->object.dir_cont.pdir_begin->lock);
                    pfsal_handle = &pentry->object.dir_cont.pdir_begin->object.dir_begin.handle;
                    V_r(&pentry->object.dir_cont.pdir_begin->lock);
                    break;

                case SOCKET_FILE:
                case FIFO_FILE:
                case BLOCK_FILE:
                case CHARACTER_FILE:
                    pfsal_handle = &pentry->object.special_obj.handle;
                    break;
                }

            /*
             * An error occured when trying to get
             * the attributes, they have to be renewed
             */
            fsal_status = FSAL_getattrs(pfsal_handle, pcontext, pattr);
            if(FSAL_IS_ERROR(fsal_status))
                {
                    *pstatus = cache_inode_error_convert(fsal_status);
                    V_r(&pentry->lock);

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

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

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

                            *pstatus = CACHE_INODE_FSAL_ESTALE;
                        }

                    /* stat */
                    inc_func_err_unrecover(pclient, CACHE_INODE_GETATTR);
                    return *pstatus;
                }

            /* Set the new attributes */
            cache_inode_set_attributes(pentry, pattr);
        }
    *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient);

    V_r(&pentry->lock);

    /* stat */
    if(*pstatus != CACHE_INODE_SUCCESS)
        inc_func_err_retryable(pclient, CACHE_INODE_GETATTR);
    else
        inc_func_success(pclient, CACHE_INODE_GETATTR);

    return *pstatus;
}