Esempio n. 1
0
/**
 * FSAL_access :
 * Tests whether the user or entity identified by its cred
 * can access the object identified by object_handle,
 * as indicated by the access_type parameters.
 *
 * \param object_handle (input):
 *        The handle of the object to test permissions on.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param access_type (input):
 *        Indicates the permissions to test.
 *        This is an inclusive OR of the permissions
 *        to be checked for the user identified by cred.
 *        Permissions constants are :
 *        - FSAL_R_OK : test for read permission
 *        - FSAL_W_OK : test for write permission
 *        - FSAL_X_OK : test for exec permission
 *        - FSAL_F_OK : test for file existence
 * \param object_attributes (optional input/output):
 *        The post operation attributes for the object.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t VFSFSAL_access(fsal_handle_t * p_object_handle,      /* IN */
                          fsal_op_context_t * p_context,        /* IN */
                          fsal_accessflags_t access_type,       /* IN */
                          fsal_attrib_list_t * p_object_attributes      /* [ IN/OUT ] */
    )
{

  fsal_status_t status;

  /* sanity checks.
   * note : object_attributes is optionnal in VFSFSAL_getattrs.
   */
  if(!p_object_handle || !p_context)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_access);

  /* 
   * If an error occures during getattr operation,
   * it is returned, even though the access operation succeeded.
   */

  if(p_object_attributes)
    {

      FSAL_SET_MASK(p_object_attributes->asked_attributes,
                    FSAL_ATTR_OWNER | FSAL_ATTR_GROUP | FSAL_ATTR_ACL | FSAL_ATTR_MODE);
      status = FSAL_getattrs(p_object_handle, p_context, p_object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
          FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
          Return(status.major, status.minor, INDEX_FSAL_access);
        }

      status =
          fsal_check_access(p_context, access_type, NULL, p_object_attributes);

    }
  else
    {                           /* p_object_attributes is NULL */
      fsal_attrib_list_t attrs;

      FSAL_CLEAR_MASK(attrs.asked_attributes);
      FSAL_SET_MASK(attrs.asked_attributes,
                    FSAL_ATTR_OWNER | FSAL_ATTR_GROUP | FSAL_ATTR_ACL | FSAL_ATTR_MODE);

      status = FSAL_getattrs(p_object_handle, p_context, &attrs);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        Return(status.major, status.minor, INDEX_FSAL_access);

      status = fsal_check_access(p_context, access_type, NULL, &attrs);
    }

  Return(status.major, status.minor, INDEX_FSAL_access);

}
fsal_status_t MFSL_getattrs(mfsl_object_t * filehandle, /* IN */
                            fsal_op_context_t * p_context,      /* IN */
                            mfsl_context_t * p_mfsl_context,    /* IN */
                            fsal_attrib_list_t * object_attributes      /* IN/OUT */
    )
{
  return FSAL_getattrs(&filehandle->handle, p_context, object_attributes);
}                               /* MFSL_getattrs */
Esempio n. 3
0
fsal_status_t MFSL_getattrs(mfsl_object_t * filehandle, /* IN */
                            fsal_op_context_t * p_context,      /* IN */
                            mfsl_context_t * p_mfsl_context,    /* IN */
                            fsal_attrib_list_t * object_attributes,      /* IN/OUT */
			    void * pextra
    )
{
  struct timeval start, stop, delta ;
  fsal_status_t fsal_status = { ERR_FSAL_NO_ERROR, 0 } ;
  
  gettimeofday( &start, 0 ) ; 
  fsal_status = FSAL_getattrs(&filehandle->handle, p_context, object_attributes);
  gettimeofday( &stop, 0 ) ; 
  delta = mfsl_timer_diff( &stop, &start ) ;
  LogFullDebug( COMPONENT_MFSL, "%s: duration=%ld.%06ld", __FUNCTION__, delta.tv_sec, delta.tv_usec ) ;
  return fsal_status ;
}                               /* MFSL_getattrs */
Esempio n. 4
0
/**
 * Get the attributes of an extended attribute from its index.
 *
 * \param p_objecthandle Handle of the object you want to get attribute for.
 * \param p_context pointer to the current security context.
 * \param xattr_cookie xattr's cookie (as returned by listxattrs).
 * \param p_attrs xattr's attributes.
 */
fsal_status_t dpmfsal_GetXAttrAttrs(fsal_handle_t * p_objecthandle, // IN
                                    fsal_op_context_t * p_context, // IN
                                    unsigned int xattr_id, // IN
                                    fsal_attrib_list_t * p_attrs // IN/OUT
)
{
    int rc;
    char buff[MAXNAMLEN];
    fsal_status_t st;
    fsal_attrib_list_t file_attrs;

    LogInfo(COMPONENT_FSAL, "dpmfsal_GetXAttrAttrs: start");

    /* sanity checks */
    if (!p_objecthandle || !p_context || !p_attrs)
        Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_GetXAttrAttrs);

    /* object attributes we want to retrieve from parent */
    file_attrs.asked_attributes = FSAL_ATTR_MODE | FSAL_ATTR_FILEID
            | FSAL_ATTR_OWNER | FSAL_ATTR_GROUP | FSAL_ATTR_ATIME
            | FSAL_ATTR_MTIME | FSAL_ATTR_CTIME | FSAL_ATTR_CREATION
            | FSAL_ATTR_CHGTIME | FSAL_ATTR_FSID;

    /* don't retrieve attributes not asked */

    file_attrs.asked_attributes &= p_attrs->asked_attributes;

    st = FSAL_getattrs(p_objecthandle, p_context, &file_attrs);

    if (FSAL_IS_ERROR(st))
        Return(st.major, st.minor, INDEX_FSAL_GetXAttrAttrs);

    if ((rc = file_attributes_to_xattr_attrs(&file_attrs, p_attrs, xattr_id))) {
        Return(ERR_FSAL_INVAL, rc, INDEX_FSAL_GetXAttrAttrs);
    }

    LogFullDebug(COMPONENT_FSAL, "dpmfsal_GetXAttrAttrs: done");
    Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_GetXAttrAttrs);

} /* FSAL_GetXAttrAttrs */
Esempio n. 5
0
/**
 * Get the attributes of an extended attribute from its index.
 *
 * \param p_objecthandle Handle of the object you want to get attribute for.
 * \param p_context pointer to the current security context.
 * \param xattr_cookie xattr's cookie (as returned by listxattrs).
 * \param p_attrs xattr's attributes.
 */
fsal_status_t FSAL_GetXAttrAttrs(fsal_handle_t * p_objecthandle,        /* IN */
                                 fsal_op_context_t * p_context, /* IN */
                                 unsigned int xattr_id, /* IN */
                                 fsal_attrib_list_t * p_attrs
                                          /**< IN/OUT xattr attributes (if supported) */
    )
{
  int rc;
  char buff[MAXNAMLEN];
  fsal_status_t st;
  fsal_attrib_list_t file_attrs;

  /* sanity checks */
  if(!p_objecthandle || !p_context || !p_attrs)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_GetXAttrAttrs);

  /* object attributes we want to retrieve from parent */
  file_attrs.asked_attributes = FSAL_ATTR_MODE | FSAL_ATTR_FILEID | FSAL_ATTR_OWNER
      | FSAL_ATTR_GROUP | FSAL_ATTR_ATIME | FSAL_ATTR_MTIME
      | FSAL_ATTR_CTIME | FSAL_ATTR_CREATION | FSAL_ATTR_CHGTIME | FSAL_ATTR_FSID;

  /* don't retrieve attributes not asked */

  file_attrs.asked_attributes &= p_attrs->asked_attributes;

  st = FSAL_getattrs(p_objecthandle, p_context, &file_attrs);

  if(FSAL_IS_ERROR(st))
    Return(st.major, st.minor, INDEX_FSAL_GetXAttrAttrs);

  if((rc = file_attributes_to_xattr_attrs(&file_attrs, p_attrs, xattr_id)))
    {
      Return(ERR_FSAL_INVAL, rc, INDEX_FSAL_GetXAttrAttrs);
    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_GetXAttrAttrs);

}                               /* FSAL_GetXAttrAttrs */
Esempio n. 6
0
fsal_status_t FSAL_get_cookieverf(fsal_handle_t * handle,
                                  fsal_op_context_t * p_context,
                                  uint64_t * verf)
{
  fsal_status_t  rc;
  msectimer_t    timer_start, timer_end;

  timer_start = timer_get();

  if (fsal_functions.fsal_get_cookieverf)
    {
      rc = fsal_functions.fsal_get_cookieverf(handle,
                                                verf);
    }
  else
    {
      fsal_attrib_list_t attributes;

      memset(&attributes, 0, sizeof(fsal_attrib_list_t));
      attributes.asked_attributes = FSAL_ATTR_MTIME;
      rc = FSAL_getattrs(handle,
                         p_context,
                         &attributes);
      if (!FSAL_IS_ERROR(rc))
        {
          memcpy(verf, &attributes.mtime, sizeof(uint64_t));
          ReturnCode(ERR_FSAL_NO_ERROR, 0);
        }
    }

  timer_end = timer_get();

  p_context->latency += timer_end - timer_start;
  p_context->count++;

  return rc;
}
Esempio n. 7
0
/**
 * FSAL_access :
 * Tests whether the user or entity identified by the p_context structure
 * can access the object identified by object_handle,
 * as indicated by the access_type parameter.
 *
 * \param object_handle (input):
 *        The handle of the object to test permissions on.
 * \param p_context (input):
 *        Authentication context for the operation (export entry, user,...).
 * \param access_type (input):
 *        Indicates the permissions to be tested.
 *        This is an inclusive OR of the permissions
 *        to be checked for the user specified by p_context.
 *        Permissions constants are :
 *        - FSAL_R_OK : test for read permission
 *        - FSAL_W_OK : test for write permission
 *        - FSAL_X_OK : test for exec permission
 *        - FSAL_F_OK : test for file existence
 * \param object_attributes (optional input/output):
 *        The post operation attributes for the object.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        Can be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error, asked permission is granted)
 *        - ERR_FSAL_ACCESS       (object permissions doesn't fit asked access type)
 *        - ERR_FSAL_STALE        (object_handle does not address an existing object)
 *        - ERR_FSAL_FAULT        (a NULL pointer was passed as mandatory argument)
 *        - Other error codes when something anormal occurs.
 */
fsal_status_t HPSSFSAL_access(hpssfsal_handle_t * object_handle,        /* IN */
                              hpssfsal_op_context_t * p_context,        /* IN */
                              fsal_accessflags_t access_type,   /* IN */
                              fsal_attrib_list_t * object_attributes    /* [ IN/OUT ] */
                             )
{

    int hpss_test_mode = 0;
    int rc;
    fsal_status_t st;

    /* sanity checks.
     * note : object_attributes is optionnal in FSAL_getattrs.
     */
    if(!object_handle || !p_context)
        Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_access);

    /* converts fsal access type to hpss access type */

    hpss_test_mode = fsal2hpss_testperm(access_type);

    /* call to HPSS access */

    TakeTokenFSCall();

    rc = hpss_AccessHandle(&(object_handle->data.ns_handle),   /* IN - parent object handle */
                           NULL,  /* IN - path of file to check access rights */
                           hpss_test_mode,        /* IN - Type of access to be checked */
                           &p_context->credential.hpss_usercred   /* IN - user credentials */
#if HPSS_MAJOR_VERSION < 7
                           , NULL /* OUT - authorization ticket */
#endif
                          );

    ReleaseTokenFSCall();

    /* convert returned code */
    /* The HPSS_ENOENT error actually means that handle is STALE */
    if(rc == HPSS_ENOENT)
        Return(ERR_FSAL_STALE, -rc, INDEX_FSAL_access);
    else if(rc)
        Return(hpss2fsal_error(rc), -rc, INDEX_FSAL_access);

    /* get attributes if object_attributes is not null.
     * If an error occures during getattr operation,
     * it is returned, even though the access operation succeeded.
     */
    if(object_attributes)
    {
        fsal_status_t status;

        status = FSAL_getattrs(object_handle, p_context, object_attributes);

        /* on error, we set a special bit in the mask. */
        if(FSAL_IS_ERROR(status))
        {
            FSAL_CLEAR_MASK(object_attributes->asked_attributes);
            FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

    Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_access);

}
Esempio n. 8
0
/**
 *
 * cache_inode_link: hardlinks a pentry to another.
 *
 * Hard links a pentry to another. This is basically a equivalent of FSAL_link in the cache inode layer.
 *
 * @param pentry_src [IN] entry pointer the entry to be linked. This can't be a directory.
 * @param pentry_dir_dest [INOUT] entry pointer for the destination directory in which the link will be created.
 * @param plink_name [IN] pointer to the name of the object in the destination directory.
 * @param pattr [OUT] attributes for the linked attributes after the operation.
 * @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_inode_status_t cache_inode_link(cache_entry_t * pentry_src,
                                      cache_entry_t * pentry_dir_dest,
                                      fsal_name_t * plink_name,
                                      fsal_attrib_list_t * pattr,
                                      hash_table_t * ht,
                                      cache_inode_client_t * pclient,
                                      fsal_op_context_t * pcontext,
                                      cache_inode_status_t * pstatus)
{
    fsal_status_t fsal_status;
    fsal_handle_t handle_src;
    fsal_handle_t handle_dest;
    fsal_attrib_list_t link_attributes;
#ifdef _USE_MFSL
    fsal_attrib_list_t dirdest_attributes;
#endif
    cache_inode_status_t status;
    cache_entry_t *pentry_lookup = NULL;
    fsal_attrib_list_t lookup_attributes;

    fsal_size_t save_size = 0;
    fsal_size_t save_spaceused = 0;
    fsal_time_t save_mtime = {
        .seconds = 0,
        .nseconds = 0
    };

    fsal_accessflags_t access_mask = 0;

    /* 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_LINK] += 1;

    /* Is the destination a directory ? */
    if(pentry_dir_dest->internal_md.type != DIR_BEGINNING &&
            pentry_dir_dest->internal_md.type != DIR_CONTINUE)
    {
        /* Bad type .... */
        *pstatus = CACHE_INODE_BAD_TYPE;
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LINK] += 1;

        return *pstatus;
    }

    /* Check if caller is allowed to perform the operation */
    access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK) |
                  FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE);
    if((status = cache_inode_access(pentry_dir_dest,
                                    access_mask,
                                    ht, pclient, pcontext, &status)) != CACHE_INODE_SUCCESS)
    {
        *pstatus = status;

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

        /* pentry is a directory */
        return *pstatus;
    }

    /* Check if an entry of the same name doesn't exist in the destination directory */
    if((pentry_lookup = cache_inode_lookup(pentry_dir_dest,
                                           plink_name,
                                           &lookup_attributes,
                                           ht, pclient, pcontext, pstatus)) != NULL)
    {
        /* There exists such an entry... */
        *pstatus = CACHE_INODE_ENTRY_EXISTS;
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LINK] += 1;

        return *pstatus;
    }

    /* The pentry to be hardlinked can't be a DIR_BEGINNING or a DIR_CONTINUE */
    if(pentry_src->internal_md.type == DIR_BEGINNING ||
            pentry_src->internal_md.type == DIR_CONTINUE)
    {
        /* Bad type .... */
        *pstatus = CACHE_INODE_BAD_TYPE;
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LINK] += 1;

        return *pstatus;
    }

#if 0
    if( pentry_src->internal_md.type == REGULAR_FILE )
        printf( "=== link === %p | inode=%llu\n", pentry_src, pentry_src->object.file.attributes.fileid ) ;
#endif

    /* At this point, we know that the entry does not exist in destination directory, we know that the
     * destination is actually a directory and that the source is no directory */

    /* Lock the source */
    P_w(&pentry_src->lock);

    /* Lock the target dir */
    P_w(&pentry_dir_dest->lock);

    /* Get the handles */
    switch (pentry_src->internal_md.type)
    {
    case REGULAR_FILE:
        handle_src = pentry_src->object.file.handle;
        break;

    case SYMBOLIC_LINK:
        handle_src = pentry_src->object.symlink.handle;
        break;

    case FS_JUNCTION:
    case DIR_BEGINNING:
        handle_src = pentry_src->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_src->object.dir_cont.pdir_begin->lock);
        handle_src = pentry_src->object.dir_cont.pdir_begin->object.dir_begin.handle;
        V_r(&pentry_src->object.dir_cont.pdir_begin->lock);
        break;

    case CHARACTER_FILE:
    case BLOCK_FILE:
    case SOCKET_FILE:
    case FIFO_FILE:
        handle_src = pentry_src->object.special_obj.handle;
        break;

    case UNASSIGNED:
    case RECYCLED:
        LogCrit(COMPONENT_CACHE_INODE,
                "WARNING: unknown source pentry type: internal_md.type=%d, line %d in file %s",
                pentry_src->internal_md.type, __LINE__, __FILE__);
        *pstatus = CACHE_INODE_BAD_TYPE;
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LINK] += 1;
        return *pstatus;
    }

    switch (pentry_dir_dest->internal_md.type)
    {
    case FS_JUNCTION:
    case DIR_BEGINNING:
        handle_dest = pentry_dir_dest->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_dir_dest->object.dir_cont.pdir_begin->lock);
        handle_dest = pentry_src->object.dir_cont.pdir_begin->object.dir_begin.handle;
        V_r(&pentry_dir_dest->object.dir_cont.pdir_begin->lock);
        break;

    default:
        LogCrit(COMPONENT_CACHE_INODE,
                "WARNING: unknown source pentry type: internal_md.type=%d, line %d in file %s",
                pentry_src->internal_md.type, __LINE__, __FILE__);
        *pstatus = CACHE_INODE_BAD_TYPE;
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LINK] += 1;
        return *pstatus;
    }

    /* If object is a data cached regular file, keeps it mtime and size, STEP 1 */
    if((pentry_src->internal_md.type == REGULAR_FILE)
            && (pentry_src->object.file.pentry_content != NULL))
    {
        save_mtime = pentry_src->object.file.attributes.mtime;
        save_size = pentry_src->object.file.attributes.filesize;
        save_spaceused = pentry_src->object.file.attributes.spaceused;
    }

    /* Do the link at FSAL level */
    link_attributes.asked_attributes = pclient->attrmask;
#ifdef _USE_MFSL
    cache_inode_get_attributes(pentry_src, &link_attributes);
    cache_inode_get_attributes(pentry_dir_dest, &dirdest_attributes);
    fsal_status =
        MFSL_link(&pentry_src->mobject, &pentry_dir_dest->mobject, plink_name, pcontext,
                  &pclient->mfsl_context, &link_attributes, NULL);
#else
    fsal_status =
        FSAL_link(&handle_src, &handle_dest, plink_name, pcontext, &link_attributes);
#endif
    if(FSAL_IS_ERROR(fsal_status))
    {
        *pstatus = cache_inode_error_convert(fsal_status);
        V_w(&pentry_dir_dest->lock);
        V_w(&pentry_src->lock);

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

            LogEvent(COMPONENT_CACHE_INODE,
                     "cache_inode_link: Stale FSAL File Handle detected for at least one in pentry = %p and pentry = %p",
                     pentry_src, pentry_dir_dest);

            /* Use FSAL_getattrs to find which entry is staled */
            getattr_status = FSAL_getattrs(&handle_src, pcontext, &link_attributes);
            if(getattr_status.major == ERR_FSAL_ACCESS)
            {
                LogEvent(COMPONENT_CACHE_INODE,
                         "cache_inode_link: Stale FSAL File Handle detected for pentry = %p",
                         pentry_src);

                if(cache_inode_kill_entry(pentry_src, ht, pclient, &kill_status) !=
                        CACHE_INODE_SUCCESS)
                    LogCrit(COMPONENT_CACHE_INODE,
                            "cache_inode_link: Could not kill entry %p, status = %u",
                            pentry_src, kill_status);
            }

            getattr_status = FSAL_getattrs(&handle_dest, pcontext, &link_attributes);
            if(getattr_status.major == ERR_FSAL_ACCESS)
            {
                LogEvent(COMPONENT_CACHE_INODE,
                         "cache_inode_link: Stale FSAL File Handle detected for pentry = %p",
                         pentry_dir_dest);

                if(cache_inode_kill_entry(pentry_dir_dest, ht, pclient, &kill_status) !=
                        CACHE_INODE_SUCCESS)
                    LogCrit(COMPONENT_CACHE_INODE,
                            "cache_inode_link: Could not kill entry %p, status = %u",
                            pentry_dir_dest, kill_status);
            }

        }
        *pstatus = CACHE_INODE_FSAL_ESTALE;

        return *pstatus;
    }

    /* If object is a data cached regular file, keeps it mtime and size, STEP 2 */
    if((pentry_src->internal_md.type == REGULAR_FILE)
            && (pentry_src->object.file.pentry_content != NULL))
    {
        link_attributes.mtime = save_mtime;
        link_attributes.filesize = save_size;
        link_attributes.spaceused = save_spaceused;
    }

    /* Update cached attributes */
    cache_inode_set_attributes(pentry_src, &link_attributes);

    /* Add the new entry in the destination directory */
    if(cache_inode_add_cached_dirent(pentry_dir_dest,
                                     plink_name,
                                     pentry_src,
                                     NULL,
                                     ht, pclient, pcontext, &status) != CACHE_INODE_SUCCESS)
    {
        V_w(&pentry_dir_dest->lock);
        V_w(&pentry_src->lock);
        return *pstatus;
    }

    /* Regular exit */

    /* return the attributes */
    *pattr = link_attributes;

    /* Validate the entries */
    *pstatus = cache_inode_valid(pentry_src, CACHE_INODE_OP_SET, pclient);

    /* Release the target dir */
    V_w(&pentry_dir_dest->lock);

    /* Release the source */
    V_w(&pentry_src->lock);

    /* stats */
    if(*pstatus != CACHE_INODE_SUCCESS)
        pclient->stat.func_stats.nb_err_retryable[CACHE_INODE_LINK] += 1;
    else
        pclient->stat.func_stats.nb_success[CACHE_INODE_LINK] += 1;

    return *pstatus;
}
/**
 *
 * cache_inode_renew_entry: Renews the attributes for an entry.
 *
 * Sets the attributes for an entry located in the cache by its address. Attributes are provided
 * with compliance to the underlying FSAL semantics. Attributes that are set are returned in "*pattr".
 *
 * @param pentry_parent [IN] entry for the parent directory to be managed.
 * @param pattr [OUT] renewed attributes for the entry that we have found.
 * @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 Other errors shows a FSAL error.
 *
 */
cache_inode_status_t cache_inode_renew_entry(cache_entry_t * pentry,
                                             fsal_attrib_list_t * pattr,
                                             hash_table_t * ht,
                                             cache_inode_client_t * pclient,
                                             fsal_op_context_t * pcontext,
                                             cache_inode_status_t * pstatus)
{
  fsal_handle_t *pfsal_handle = NULL;
  fsal_status_t fsal_status;
  fsal_attrib_list_t object_attributes;
  fsal_path_t link_content;
  time_t current_time = time(NULL);
  time_t entry_time = pentry->internal_md.refresh_time;

  /* If we do nothing (no expiration) then everything is all right */
  *pstatus = CACHE_INODE_SUCCESS;

  if(isFullDebug(COMPONENT_CACHE_INODE))
    {
      char *type;
      char grace[20], grace2[20];
      unsigned int elapsed = (unsigned int)current_time - (unsigned int)entry_time;
      int print = 1;

      cache_inode_expire_to_str(pclient->expire_type_attr, pclient->grace_period_attr, grace);

      switch(pentry->internal_md.type)
        {
          case UNASSIGNED:
            type = "UNASSIGNED";
            break;
          case REGULAR_FILE:
            type = "REGULAR_FILE";
            break;
          case CHARACTER_FILE:
            type = "CHARACTER_FILE";
            break;
          case BLOCK_FILE:
            type = "BLOCK_FILE";
            break;
          case SYMBOLIC_LINK:
            print = 0;
            cache_inode_expire_to_str(pclient->expire_type_link, pclient->grace_period_link, grace2);
            LogDebug(COMPONENT_CACHE_INODE,
                     "Renew Entry test of %p for SYMBOLIC_LINK elapsed time=%u, grace_period_attr=%s, grace_period_link=%s",
                     pentry, elapsed, grace, grace2);
            break;
          case SOCKET_FILE:
            type = "SOCKET_FILE";
            break;
          case FIFO_FILE:
            type = "FIFO_FILE";
            break;
          case DIRECTORY:
            print = 0;
            cache_inode_expire_to_str(pclient->expire_type_dirent, pclient->grace_period_dirent, grace2);
            LogDebug(COMPONENT_CACHE_INODE,
                     "Renew Entry test of %p for DIRECTORY elapsed time=%u, grace_period_attr=%s, grace_period_dirent=%s, has_been_readdir=%u",
                     pentry, elapsed, grace, grace2,
                     pentry->object.dir.has_been_readdir);
            break;
          case FS_JUNCTION:
            type = "FS_JUNCTION";
            break;
          case RECYCLED:
            type = "RECYCLED";
            break;
          default:
            type = "UNKNOWN";
            break;
        }
      if(print)
        {
          LogDebug(COMPONENT_CACHE_INODE,
                   "Renew Entry test of %p for %s elapsed time=%u, grace_period_attr=%s",
                   pentry, type, elapsed, grace);
        }
    }

  /* An entry that is a regular file with an associated File Content Entry won't
   * expire until data exists in File Content Cache, to avoid attributes incoherency */

  /* @todo: BUGAZOMEU: I got serious doubts on the following blocks: possible trouble if using data caching */
  if(pentry->internal_md.type == REGULAR_FILE &&
     pentry->object.file.pentry_content != NULL)
    {
      /* Successfull exit without having nothing to do ... */

      LogDebug(COMPONENT_CACHE_INODE,
               "Entry %p is a REGULAR_FILE with associated data cached %p, no expiration",
               pentry, pentry->object.file.pentry_content);

      *pstatus = CACHE_INODE_SUCCESS;
      return *pstatus;
    }

  LogDebug(COMPONENT_CACHE_INODE,
           "cache_inode_renew_entry use getattr/mtime checking %d, is dir "
	   "beginning %d, has bit in mask %d, has been readdir %d state %d",
           pclient->getattr_dir_invalidation,
           pentry->internal_md.type == DIRECTORY,
           (int) FSAL_TEST_MASK(pclient->attrmask, FSAL_ATTR_MTIME),
	   pentry->object.dir.has_been_readdir,
	   pentry->internal_md.valid_state);
  /* Do we use getattr/mtime checking */
  if(pclient->getattr_dir_invalidation &&
     pentry->internal_md.type == DIRECTORY &&
     FSAL_TEST_MASK(pclient->attrmask, FSAL_ATTR_MTIME) /*&&
     pentry->object.dir.has_been_readdir == CACHE_INODE_YES*/)
    {
      /* This checking is to be done ... */
      LogDebug(COMPONENT_CACHE_INODE,
               "cache_inode_renew_entry testing directory mtime");
      pfsal_handle = &pentry->object.dir.handle;

      /* Call FSAL to get the attributes */
      object_attributes.asked_attributes = pclient->attrmask;

      fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes);

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

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

              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)",
                       pentry, __LINE__, 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_renew_entry: Could not kill entry %p, status = %u",
                         pentry, kill_status);

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }
          /* stats */
          (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++;

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_renew_entry: returning %d (%s) from FSAL_getattrs for getattr/mtime checking",
                   *pstatus, cache_inode_err_str(*pstatus));
          return *pstatus;
        }

      LogDebug(COMPONENT_CACHE_INODE,
               "cache_inode_renew_entry: Entry=%p, type=%d, Cached Time=%d, FSAL Time=%d",
               pentry, pentry->internal_md.type,
               pentry->object.dir.attributes.mtime.seconds,
               object_attributes.mtime.seconds);

      /* Compare the FSAL mtime and the cached mtime */
      if(pentry->object.dir.attributes.mtime.seconds <
         object_attributes.mtime.seconds)
        {
          /* Cached directory content is obsolete, it must be renewed */
          cache_inode_set_attributes(pentry, &object_attributes);

          /* Return the attributes as set */
          if(pattr != NULL)
            *pattr = object_attributes;

          /* Set the directory content as "to be renewed" */
          /* Next call to cache_inode_readdir will repopulate the dirent array */
          pentry->object.dir.has_been_readdir = CACHE_INODE_RENEW_NEEDED;

          /* Set the refresh time for the cache entry */
          pentry->internal_md.refresh_time = time(NULL);

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_renew_entry: cached directory content for entry %p must be renewed, due to getattr mismatch",
                   pentry);

          if(cache_inode_invalidate_all_cached_dirent(pentry, ht, pclient, pstatus)
             != CACHE_INODE_SUCCESS)
            {
              /* Should never happen */
              LogCrit(COMPONENT_CACHE_INODE,
                      "cache_inode_invalidate_all_cached_dirent returned %d (%s)",
                      *pstatus, cache_inode_err_str(*pstatus));
              return *pstatus;
            }

        }                       /* if( pentry->object.dir.attributes.mtime < object_attributes.asked_attributes.mtime ) */
    }

  /* if( pclient->getattr_dir_invalidation && ... */
  /* Check for dir content expiration and/or staleness */
  if(pentry->internal_md.type == DIRECTORY &&
     pclient->expire_type_dirent != CACHE_INODE_EXPIRE_NEVER &&
     pentry->object.dir.has_been_readdir == CACHE_INODE_YES &&
     ((current_time - entry_time >= pclient->grace_period_dirent)
      || (pentry->internal_md.valid_state == STALE)))
    {
      /* Would be better if state was a flag that we could and/or the bits but
       * in any case we need to get rid of stale so we only go through here
       * once.
       */
      if ( pentry->internal_md.valid_state == STALE )
	pentry->internal_md.valid_state = VALID;

      /* stats */
      (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++;

      /* Log */
      LogDebug(COMPONENT_CACHE_INODE,
	       "Case 1: cached directory entries for entry %p must be renewed"
	       " (has been readdir)", pentry);

      if(isFullDebug(COMPONENT_CACHE_INODE))
        {
          char name[1024];
	  struct avltree_node *d_node;
	  cache_inode_dir_entry_t *d_dirent;
	  int i = 0;
	  
	  d_node = avltree_first(&pentry->object.dir.dentries);
      	  do {
              d_dirent = avltree_container_of(d_node, cache_inode_dir_entry_t,
					      node_n);
	      if (d_dirent->pentry->internal_md.valid_state == VALID) {
	          FSAL_name2str(&(d_dirent->name), name, 1023);
                  LogDebug(COMPONENT_CACHE_INODE,
                           "cache_inode_renew_entry: Entry %d %s",
                           i, name);
	      }
	      i++;
          } while ((d_node = avltree_next(d_node)));
        }

      /* Do the getattr if it had not being done before */
      if(pfsal_handle == NULL)
        {
          pfsal_handle = &pentry->object.dir.handle;

          /* Call FSAL to get the attributes */
          object_attributes.asked_attributes = pclient->attrmask;

          fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes);

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

              /* stats */
              (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++;

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

                  LogEvent(COMPONENT_CACHE_INODE,
                           "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)",
                           pentry, __LINE__,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_renew_entry: Could not kill entry %p, status = %u",
                            pentry, kill_status);

                  *pstatus = CACHE_INODE_FSAL_ESTALE;
                }

              LogDebug(COMPONENT_CACHE_INODE,
                       "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for directory entries (1)",
                       *pstatus, cache_inode_err_str(*pstatus));
              return *pstatus;
            }
        }

      cache_inode_set_attributes(pentry, &object_attributes);

      /* Return the attributes as set */
      if(pattr != NULL)
        *pattr = object_attributes;

      /* Set the directory content as "to be renewed" */
      /* Next call to cache_inode_readdir will repopulate the dirent array */
      pentry->object.dir.has_been_readdir = CACHE_INODE_RENEW_NEEDED;

      /* Set the refresh time for the cache entry */
      pentry->internal_md.refresh_time = time(NULL);

    }

  /* if( pentry->internal_md.type == DIRECTORY && ... */
  /* if the directory has not been readdir, only update its attributes */
  else if(pentry->internal_md.type == DIRECTORY &&
          pclient->expire_type_attr != CACHE_INODE_EXPIRE_NEVER &&
          pentry->object.dir.has_been_readdir != CACHE_INODE_YES &&
	  ((current_time - entry_time >= pclient->grace_period_attr) || (pentry->internal_md.valid_state == STALE)))
    {
      /* Would be better if state was a flag that we could and/or the bits but
       * in any case we need to get rid of stale so we only go through here
       * once.
       */
      if ( pentry->internal_md.valid_state == STALE )
         pentry->internal_md.valid_state = VALID;

      /* stats */
      (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++;

      /* Log */
      LogDebug(COMPONENT_CACHE_INODE,
	       "Case 2: cached directory entries for entry %p must be renewed (has not been readdir)",
               pentry);

      if(isFullDebug(COMPONENT_CACHE_INODE))
        {
          char name[1024];
	  struct avltree_node *d_node;
	  cache_inode_dir_entry_t *d_dirent;
	  int i = 0;
	  
	  d_node = avltree_first(&pentry->object.dir.dentries);
      	  do {
              d_dirent = avltree_container_of(d_node, cache_inode_dir_entry_t,
					      node_n);
	      if (d_dirent->pentry->internal_md.valid_state == VALID) {
	          FSAL_name2str(&(d_dirent->name), name, 1023);
                  LogDebug(COMPONENT_CACHE_INODE,
                           "cache_inode_renew_entry: Entry %d %s",
                           i, name);
	      }
	      i++;
          } while ((d_node = avltree_next(d_node)));
        }

      pfsal_handle = &pentry->object.dir.handle;

      /* Call FSAL to get the attributes */
      object_attributes.asked_attributes = pclient->attrmask;

      fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes);

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

          /* stats */
          (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++;

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

              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)",
                       pentry, __LINE__,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_renew_entry: Could not kill entry %p, status = %u",
                         pentry, kill_status);

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for directory entries (2)",
                   *pstatus, cache_inode_err_str(*pstatus));
          return *pstatus;
        }

      cache_inode_set_attributes(pentry, &object_attributes);

      /* Return the attributes as set */
      if(pattr != NULL)
        *pattr = object_attributes;

      /* Set the refresh time for the cache entry */
      pentry->internal_md.refresh_time = time(NULL);

    }

  /* else if( pentry->internal_md.type == DIRECTORY && ... */
  /* Check for attributes expiration in other cases */
  else if(pentry->internal_md.type != DIRECTORY &&
          pclient->expire_type_attr != CACHE_INODE_EXPIRE_NEVER &&
	  ((current_time - entry_time >= pclient->grace_period_attr)
	   || (pentry->internal_md.valid_state == STALE)))
    {
      /* Would be better if state was a flag that we could and/or the bits but
       * in any case we need to get rid of stale so we only go through here
       * once.
       */
      if ( pentry->internal_md.valid_state == STALE )
	pentry->internal_md.valid_state = VALID;
      
      /* stats */
      (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++;

      /* Log */
      LogDebug(COMPONENT_CACHE_INODE,
               "Attributes for entry %p must be renewed", pentry);

      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 SOCKET_FILE:
        case FIFO_FILE:
        case CHARACTER_FILE:
        case BLOCK_FILE:
          pfsal_handle = &pentry->object.special_obj.handle;
          break;

        case DIRECTORY:
        case FS_JUNCTION:
        case UNASSIGNED:
        case RECYCLED:
          LogCrit(COMPONENT_CACHE_INODE,
                  "WARNING: unknown source pentry type: internal_md.type=%d, line %d in file %s",
                  pentry->internal_md.type, __LINE__, __FILE__);
          *pstatus = CACHE_INODE_BAD_TYPE;
          return *pstatus;
        }

      /* Call FSAL to get the attributes */
      object_attributes.asked_attributes = pclient->attrmask;
#ifdef _USE_MFSL
      fsal_status = FSAL_getattrs_descriptor(&(cache_inode_fd(pentry)->fsal_file), pfsal_handle, pcontext, &object_attributes);
#else
      fsal_status = FSAL_getattrs_descriptor(cache_inode_fd(pentry), pfsal_handle, pcontext, &object_attributes);
#endif
      if(FSAL_IS_ERROR(fsal_status) && fsal_status.major == ERR_FSAL_NOT_OPENED)
        {
          //TODO: LOOKATME !!!!!
          fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes);
        }
      if(FSAL_IS_ERROR(fsal_status))
        {
          *pstatus = cache_inode_error_convert(fsal_status);

          /* stats */
          (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++;

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

              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)",
                       pentry, __LINE__,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_renew_entry: Could not kill entry %p, status = %u",
                        pentry, kill_status);

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for non directories",
                   *pstatus, cache_inode_err_str(*pstatus));
          return *pstatus;
        }

      /* Keep the new attribute in cache */
      cache_inode_set_attributes(pentry, &object_attributes);

      /* Return the attributes as set */
      if(pattr != NULL)
        *pattr = object_attributes;

      /* Set the refresh time for the cache entry */
      pentry->internal_md.refresh_time = time(NULL);

    }

  /* if(  pentry->internal_md.type   != DIR_CONTINUE && ... */
  /* Check for link content expiration */
  if(pentry->internal_md.type == SYMBOLIC_LINK &&
     pclient->expire_type_link != CACHE_INODE_EXPIRE_NEVER &&
     ((current_time - entry_time >= pclient->grace_period_link)
      || (pentry->internal_md.valid_state == STALE)))
    {
      assert(pentry->object.symlink);
      pfsal_handle = &pentry->object.symlink->handle;
      /* Would be better if state was a flag that we could and/or the bits but
       * in any case we need to get rid of stale so we only go through here
       * once.
       */
      if ( pentry->internal_md.valid_state == STALE )
	pentry->internal_md.valid_state = VALID;

      assert(pentry->object.symlink);
      pfsal_handle = &pentry->object.symlink->handle;

      /* Log */
      LogDebug(COMPONENT_CACHE_INODE,
               "cached link content for entry %p must be renewed", pentry);

      FSAL_CLEAR_MASK(object_attributes.asked_attributes);
      FSAL_SET_MASK(object_attributes.asked_attributes, pclient->attrmask);

      if( CACHE_INODE_KEEP_CONTENT( pentry->policy ) )
       {
#ifdef _USE_MFSL
      fsal_status =
          MFSL_readlink(&pentry->mobject, pcontext, &pclient->mfsl_context, &link_content,
                        &object_attributes, NULL);
#else
      fsal_status =
          FSAL_readlink(pfsal_handle, pcontext, &link_content, &object_attributes);
#endif
        }
      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_RENEW_ENTRY] += 1;

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

              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)",
                       pentry, __LINE__,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_renew_entry: Could not kill entry %p, status = %u",
                       pentry, kill_status);

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }

        }
      else
        {
	  assert(pentry->object.symlink);
          fsal_status = FSAL_pathcpy(&pentry->object.symlink->content, &link_content); /* copy ctor? */
          if(FSAL_IS_ERROR(fsal_status))
            {
              *pstatus = cache_inode_error_convert(fsal_status);
              /* stats */
              pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY] += 1;
            }
        }

      /* Set the refresh time for the cache entry */
      pentry->internal_md.refresh_time = time(NULL);

    }

  /* if( pentry->internal_md.type == SYMBOLIC_LINK && ... */
  LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s)",
           *pstatus, cache_inode_err_str(*pstatus));
  return *pstatus;
}                               /* cache_inode_renew_entry */
Esempio n. 10
0
/**
 * FSAL_opendir :
 *     Opens a directory for reading its content.
 *     
 * \param dir_handle (input)
 *         the handle of the directory to be opened.
 * \param cred (input)
 *         Permission context for the operation (user,...).
 * \param dir_descriptor (output)
 *         pointer to an allocated structure that will receive
 *         directory stream informations, on successfull completion.
 * \param dir_attributes (optional output)
 *         On successfull completion,the structure pointed
 *         by dir_attributes receives the new directory attributes.
 *         May be NULL.
 * 
 */
fsal_status_t FSAL_opendir(fsal_handle_t * dir_handle,  /* IN */
                           fsal_op_context_t * p_context,       /* IN */
                           fsal_dir_t * dir_descriptor, /* OUT */
                           fsal_attrib_list_t * dir_attributes  /* [ IN/OUT ] */
    )
{
  int rc;
  dir_descriptor_t dir;

  /* For logging */
  SetFuncID(INDEX_FSAL_opendir);

  /* sanity checks
   * note : dir_attributes is optionnal.
   */
  if(!dir_handle || !p_context || !dir_descriptor)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_opendir);

  /* test access perms. For other FS than GHOST_FS,
   * this is done by the FS itself.
   */
  rc = GHOSTFS_Access((GHOSTFS_handle_t) (*dir_handle),
                      GHOSTFS_TEST_READ,
                      p_context->credential.user, p_context->credential.group);

  if(rc)
    Return(ghost2fsal_error(rc), rc, INDEX_FSAL_opendir);

  rc = GHOSTFS_Opendir((GHOSTFS_handle_t) (*dir_handle), &dir);

  if(rc)
    Return(ghost2fsal_error(rc), rc, INDEX_FSAL_opendir);

  /* building dir descriptor */
  dir_descriptor->dir_descriptor = dir;
  dir_descriptor->context = *p_context;

  /* optionaly gets the directory attributes.
   * If an error occures during getattr operation,
   * it is returned, even though the opendir operation succeeded.
   */
  if(dir_attributes)
    {

      fsal_status_t status;

      switch ((status = FSAL_getattrs(dir_handle, p_context, dir_attributes)).major)
        {
          /* change the FAULT error to appears as an internal error.
           * indeed, parameters should be null. */
        case ERR_FSAL_FAULT:
          Return(ERR_FSAL_SERVERFAULT, ERR_FSAL_FAULT, INDEX_FSAL_opendir);
          break;
        case ERR_FSAL_NO_ERROR:
          /* continue */
          break;
        default:
          Return(status.major, status.minor, INDEX_FSAL_opendir);
        }

    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_opendir);

}
Esempio n. 11
0
/**
 *
 * MFSL_getattrs : performs getattr but takes care of the asynchronous logic.
 *
 * Performs getattr but takes care of the asynchronous logic.
 *
 * @param filehandle         [IN]    mfsl object related to the object
 * @param p_context          [IN]    associated fsal context
 * @param p_mfsl_context     [INOUT] associated mfsl context
 * @param object_attributes  [INOUT] attributes for the object
 *
 * @return the same as FSAL_getattrs
 */
fsal_status_t MFSL_getattrs(mfsl_object_t * filehandle, /* IN */
                            fsal_op_context_t * p_context,      /* IN */
                            mfsl_context_t * p_mfsl_context,    /* IN */
                            fsal_attrib_list_t * object_attributes      /* [ IN/OUT ] */
    )
{
  fsal_status_t fsal_status;
  mfsl_object_specific_data_t *pasyncdata;

  if(mfsl_async_get_specdata(filehandle, &pasyncdata))
    {
      P(filehandle->lock);
      fsal_status = MFSAL_getattrs_check_perms(filehandle,
                                               pasyncdata,
                                               p_context,
                                               p_mfsl_context, object_attributes);
      V(filehandle->lock);

      if(FSAL_IS_ERROR(fsal_status))
        return fsal_status;

      /* Is the object deleted ? */
      if(pasyncdata->deleted == TRUE)
        MFSL_return(ERR_FSAL_NOENT, ENOENT);

      /* merge the attributes to the asynchronous attributes */
      if((object_attributes->asked_attributes & FSAL_ATTR_SIZE) ||
         (object_attributes->asked_attributes & FSAL_ATTR_SPACEUSED))
        {
          /* Operation on a non data cached file */
          object_attributes->filesize = pasyncdata->async_attr.filesize;
          object_attributes->spaceused = pasyncdata->async_attr.spaceused;
        }

      if(object_attributes->asked_attributes &
         (FSAL_ATTR_MODE | FSAL_ATTR_OWNER | FSAL_ATTR_GROUP))
        {
          if(object_attributes->asked_attributes & FSAL_ATTR_MODE)
            object_attributes->mode = pasyncdata->async_attr.mode;

          if(object_attributes->asked_attributes & FSAL_ATTR_OWNER)
            object_attributes->owner = pasyncdata->async_attr.owner;

          if(object_attributes->asked_attributes & FSAL_ATTR_GROUP)
            object_attributes->group = pasyncdata->async_attr.group;
        }

      if(object_attributes->asked_attributes & (FSAL_ATTR_ATIME | FSAL_ATTR_MTIME))
        {
          if(object_attributes->asked_attributes & FSAL_ATTR_ATIME)
            object_attributes->atime = pasyncdata->async_attr.atime;

          if(object_attributes->asked_attributes & FSAL_ATTR_MTIME)
            object_attributes->mtime = pasyncdata->async_attr.mtime;
        }

      /* Regular exit */
      MFSL_return(ERR_FSAL_NO_ERROR, 0);
    }
  else
    {
      return FSAL_getattrs(&filehandle->handle, p_context, object_attributes);
    }
}                               /* MFSL_getattrs */
Esempio n. 12
0
fsal_status_t FSAL_setattrs(fsal_handle_t * filehandle, /* IN */
                            fsal_op_context_t * p_context,      /* IN */
                            fsal_attrib_list_t * attrib_set,    /* IN */
                            fsal_attrib_list_t * object_attributes      /* [ IN/OUT ] */
    )
{
  GHOSTFS_setattr_mask_t set_mask = 0;
  GHOSTFS_Attrs_t ghost_attrs;
  int rc;

  memset(&ghost_attrs, 0, sizeof(GHOSTFS_Attrs_t));

  /* For logging */
  SetFuncID(INDEX_FSAL_setattrs);

#define SETTABLE_ATTRIBUTES ( FSAL_ATTR_SIZE |\
                              FSAL_ATTR_MODE |\
                              FSAL_ATTR_OWNER |\
                              FSAL_ATTR_GROUP |\
                              FSAL_ATTR_ATIME |\
                              FSAL_ATTR_MTIME )
  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!filehandle || !p_context || !attrib_set)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs);

  /* first convert attributes and mask */

  if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_SIZE))
    {
      set_mask |= SETATTR_SIZE;
      ghost_attrs.size = attrib_set->filesize;
    }
  if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_MODE))
    {
      set_mask |= SETATTR_MODE;
      ghost_attrs.mode = fsal2ghost_mode(attrib_set->mode);
    }

  /* ghostfs does not check chown restrictions,
   * so we check this for it. */

  if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_OWNER))
    {

      if(p_context->credential.user != 0)
        Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);

      set_mask |= SETATTR_UID;
      ghost_attrs.uid = attrib_set->owner;
    }

  if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_GROUP))
    {
      if(p_context->credential.user != 0)
        Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);

      set_mask |= SETATTR_GID;
      ghost_attrs.gid = attrib_set->group;
    }

  if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_ATIME))
    {
      set_mask |= SETATTR_ATIME;
      ghost_attrs.atime = attrib_set->atime.seconds;
    }
  if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_MTIME))
    {
      set_mask |= SETATTR_MTIME;
      ghost_attrs.mtime = attrib_set->mtime.seconds;
    }

  if(attrib_set->asked_attributes & ~SETTABLE_ATTRIBUTES)
    {
      LogFullDebug(COMPONENT_FSAL, "FSAL: To be set %llX, Settable %llX",
             (unsigned long long)object_attributes->asked_attributes,
             (unsigned long long)SETTABLE_ATTRIBUTES);

      Return(ERR_FSAL_ATTRNOTSUPP, 0, INDEX_FSAL_setattrs);
    }

  /* appel a setattr */
  rc = GHOSTFS_SetAttrs((GHOSTFS_handle_t) (*filehandle), set_mask, ghost_attrs);

  if(rc)
    Return(ghost2fsal_error(rc), rc, INDEX_FSAL_setattrs);

  if(object_attributes)
    {
      fsal_status_t status = FSAL_getattrs(filehandle, p_context, object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(object_attributes->asked_attributes);
          FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);

}
Esempio n. 13
0
/**
 *
 * @brief 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.
 *
 * If a cache entry is returned, its refcount is incremented by one.
 *
 * It turns out we do need cache_inode_get_located functionality for
 * cases like lookupp on an entry returning itself when it isn't a
 * root.  Therefore, if the 'associated' parameter is equal to the got
 * cache entry, a reference count is incremented but the structure
 * pointed to by attr is NOT filled in.
 *
 * @param[in]     fsdata     File system data
 * @param[out]    attr       The attributes of the got entry
 * @param[in]     context    FSAL credentials
 * @param[in]     associated Entry that may be equal to the got entry
 * @param[out]    status     Returned status
 *
 * @return If successful, the pointer to the entry; NULL otherwise
 *
 */
cache_entry_t *
cache_inode_get(cache_inode_fsal_data_t *fsdata,
                fsal_attrib_list_t *attr,
                fsal_op_context_t *context,
                cache_entry_t *associated,
                cache_inode_status_t *status)
{
    hash_buffer_t key, value;
    cache_entry_t *entry = NULL;
    fsal_status_t fsal_status = {0, 0};
    cache_inode_create_arg_t create_arg = {
        .newly_created_dir = FALSE
    };
    cache_inode_file_type_t type = UNASSIGNED;
    hash_error_t hrc = 0;
    fsal_attrib_list_t fsal_attributes;
    fsal_handle_t *file_handle;
    struct hash_latch latch;

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

    /* Turn the input to a hash key on our own.
     */
    key.pdata = fsdata->fh_desc.start;
    key.len = fsdata->fh_desc.len;

    hrc = HashTable_GetLatch(fh_to_cache_entry_ht, &key, &value,
                             FALSE,
                             &latch);

    if ((hrc != HASHTABLE_SUCCESS) &&
            (hrc != HASHTABLE_ERROR_NO_SUCH_KEY)) {
        /* This should not happened */
        *status = CACHE_INODE_HASH_TABLE_ERROR;
        LogCrit(COMPONENT_CACHE_INODE,
                "Hash access failed with code %d"
                " - this should not have happened",
                hrc);
        return NULL;
    }

    if (hrc == HASHTABLE_SUCCESS) {
        /* Entry exists in the cache and was found */
        entry = value.pdata;
        /* take an extra reference within the critical section */
        if (cache_inode_lru_ref(entry, LRU_REQ_INITIAL) !=
                CACHE_INODE_SUCCESS) {
            /* Dead entry.  Treat like a lookup failure. */
            entry = NULL;
        } else {
            if (entry == associated) {
                /* Take a quick exit so we don't invert lock
                   ordering. */
                HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch);
                return entry;
            }
        }
    }
    HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch);

    if (!context) {
        /* Upcalls have no access to fsal_op_context_t,
           so just return the entry without revalidating it or
           creating a new one. */
        if (entry == NULL) {
            *status = CACHE_INODE_NOT_FOUND;
        }
        return entry;
    }

    if (!entry) {
        /* Cache miss, allocate a new entry */
        file_handle = (fsal_handle_t *) fsdata->fh_desc.start;
        /* First, call FSAL to know what the object is */
        fsal_attributes.asked_attributes = cache_inode_params.attrmask;
        fsal_status
            = FSAL_getattrs(file_handle, context, &fsal_attributes);
        if (FSAL_IS_ERROR(fsal_status)) {
            *status = cache_inode_error_convert(fsal_status);
            LogDebug(COMPONENT_CACHE_INODE,
                     "cache_inode_get: cache_inode_status=%u "
                     "fsal_status=%u,%u ", *status,
                     fsal_status.major,
                     fsal_status.minor);
            return NULL;
        }

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

        /* Get the cache_inode file type */
        type = cache_inode_fsal_type_convert(fsal_attributes.type);
        if (type == SYMBOLIC_LINK) {
            fsal_attributes.asked_attributes = cache_inode_params.attrmask;
            fsal_status =
                FSAL_readlink(file_handle, context,
                              &create_arg.link_content,
                              &fsal_attributes);

            if (FSAL_IS_ERROR(fsal_status)) {
                *status = cache_inode_error_convert(fsal_status);
                return NULL;
            }
        }
        if ((entry
                = cache_inode_new_entry(fsdata,
                                        &fsal_attributes,
                                        type,
                                        &create_arg,
                                        status)) == NULL) {
            return NULL;
        }

    }

    *status = CACHE_INODE_SUCCESS;

    /* This is the replacement for cache_inode_renew_entry.  Rather
       than calling that function at the start of every cache_inode
       call with the inode locked, we call cache_inode_check trust to
       perform 'heavyweight' (timed expiration of cached attributes,
       getattr-based directory trust) checks the first time after
       getting an inode.  It does all of the checks read-locked and
       only acquires a write lock if there's something requiring a
       change.

       There is a second light-weight check done before use of cached
       data that checks whether the bits saying that inode attributes
       or inode content are trustworthy have been cleared by, for
       example, FSAL_CB.

       To summarize, the current implementation is that policy-based
       trust of validity is checked once per logical series of
       operations at cache_inode_get, and asynchronous trust is
       checked with use (when the attributes are locked for reading,
       for example.) */

    if ((*status = cache_inode_check_trust(entry,
                                           context))
            != CACHE_INODE_SUCCESS) {
        goto out_put;
    }

    /* Set the returned attributes */
    *status = cache_inode_lock_trust_attrs(entry, context);

    /* cache_inode_lock_trust_attrs may fail, in that case, the
       attributes are wrong and pthread_rwlock_unlock can't be called
       again */
    if(*status != CACHE_INODE_SUCCESS)
    {
        goto out_put;
    }
    *attr = entry->attributes;
    pthread_rwlock_unlock(&entry->attr_lock);

    return entry;

out_put:
    cache_inode_put(entry);
    entry = NULL;
    return entry;
} /* cache_inode_get */
Esempio n. 14
0
/**
 *
 * 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;
}
Esempio n. 15
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 */
Esempio n. 16
0
/**
 * Retrieves the list of extended attributes for an object in the filesystem.
 * 
 * \param p_objecthandle Handle of the object we want to get extended attributes.
 * \param cookie index of the next entry to be returned.
 * \param p_context pointer to the current security context.
 * \param xattrs_tab a table for storing extended attributes list to.
 * \param xattrs_tabsize the maximum number of xattr entries that xattrs_tab
 *            can contain.
 * \param p_nb_returned the number of xattr entries actually stored in xattrs_tab.
 * \param end_of_list this boolean indicates that the end of xattrs list has been reached.
 */
fsal_status_t dpmfsal_ListXAttrs(fsal_handle_t * p_objecthandle, // IN
                                 unsigned int cookie, // IN
                                 fsal_op_context_t * p_context, // IN
                                 fsal_xattrent_t * xattrs_tab, // IN/OUT
                                 unsigned int xattrs_tabsize, // IN
                                 unsigned int *p_nb_returned, // OUT
                                 int *end_of_list // OUT
)
{
    unsigned int index;
    unsigned int out_index;
    fsal_status_t st;
    fsal_attrib_list_t file_attrs;

    LogInfo(COMPONENT_FSAL, "dpmfsal_ListXAttrs: start");

    /* sanity checks */
    if (!p_objecthandle || !p_context || !xattrs_tab || !p_nb_returned || !end_of_list)
        Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_ListXAttrs);

    /* object attributes we want to retrieve from parent */
    file_attrs.asked_attributes = FSAL_ATTR_MODE | FSAL_ATTR_FILEID
            | FSAL_ATTR_OWNER | FSAL_ATTR_GROUP | FSAL_ATTR_ATIME
            | FSAL_ATTR_MTIME | FSAL_ATTR_CTIME | FSAL_ATTR_CREATION
            | FSAL_ATTR_CHGTIME | FSAL_ATTR_FSID;

    /* don't retrieve unsupported attributes */
    file_attrs.asked_attributes &= global_fs_info.supported_attrs;

    st = FSAL_getattrs(p_objecthandle, p_context, &file_attrs);

    if (FSAL_IS_ERROR(st))
        Return(st.major, st.minor, INDEX_FSAL_ListXAttrs);

    for (index = cookie, out_index = 0; index < XATTR_COUNT && out_index
            < xattrs_tabsize; index++) {
        if (do_match_type(xattr_list[index].flags,
                p_objecthandle->data.ntype)) {
            /* fills an xattr entry */
            xattrs_tab[out_index].xattr_id = index;
            FSAL_str2name(xattr_list[index].xattr_name, FSAL_MAX_NAME_LEN,
                    &xattrs_tab[out_index].xattr_name);
            xattrs_tab[out_index].xattr_cookie = index + 1;

            /* set asked attributes (all supported) */
            xattrs_tab[out_index].attributes.asked_attributes
                    = global_fs_info.supported_attrs;

            if (file_attributes_to_xattr_attrs(&file_attrs,
                    &xattrs_tab[out_index].attributes, index)) {
                /* set error flag */
                xattrs_tab[out_index].attributes.asked_attributes
                        = FSAL_ATTR_RDATTR_ERR;
            }

            /* next output slot */
            out_index++;
        }
    }

    *p_nb_returned = out_index;
    *end_of_list = (index == XATTR_COUNT);

    Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_ListXAttrs);

}
Esempio n. 17
0
fsal_status_t FSAL_readdir(fsal_dir_t * dir_descriptor, /* IN */
                           fsal_cookie_t start_position,        /* IN */
                           fsal_attrib_mask_t get_attr_mask,    /* IN */
                           fsal_mdsize_t buffersize,    /* IN */
                           fsal_dirent_t * pdirent,     /* OUT */
                           fsal_cookie_t * end_position,        /* OUT */
                           fsal_count_t * nb_entries,   /* OUT */
                           fsal_boolean_t * end_of_dir  /* OUT */
    )
{
  int rc;
  unsigned int max_entries;
  fsal_dirent_t *curr_ent;
  fsal_dirent_t *last_ent;
  GHOSTFS_cookie_t last_cookie;
  GHOSTFS_dirent_t entry;
  fsal_status_t status;

  /* For logging */
  SetFuncID(INDEX_FSAL_readdir);

  /* sanity checks */
  if(!dir_descriptor || !pdirent || !end_position || !nb_entries || !end_of_dir)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir);

  /* seeking directory position  */
  rc = GHOSTFS_Seekdir(&(dir_descriptor->dir_descriptor), start_position.cookie);

  if(rc)
    Return(ghost2fsal_error(rc), rc, INDEX_FSAL_readdir);

  /* how many entries can we get ? */
  if(buffersize < sizeof(fsal_dirent_t))
    Return(ERR_FSAL_TOOSMALL, 0, INDEX_FSAL_readdir);
  max_entries = buffersize / sizeof(fsal_dirent_t);

  /* initialize output values */
  *nb_entries = 0;
  *end_of_dir = FALSE;
  curr_ent = pdirent;
  last_ent = NULL;
  last_cookie = start_position.cookie;

  /* retrieving entries */

  while(*nb_entries < max_entries)
    {

      /* processing a readdir */
      rc = GHOSTFS_Readdir(&(dir_descriptor->dir_descriptor), &entry);

      if(rc == ERR_GHOSTFS_ENDOFDIR)
        {
          /* updates ouputs and return */
          if(last_ent)
            last_ent->nextentry = NULL;
          (*end_of_dir) = TRUE;
          end_position->cookie = last_cookie;
          Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir);
        }
      else if(rc != 0)
        {
          Return(ghost2fsal_error(rc), rc, INDEX_FSAL_readdir);
        }

      /* we have just read an entry */
      if(last_ent)
        last_ent->nextentry = curr_ent;
      curr_ent->handle = (fsal_handle_t) entry.handle;
      strncpy(curr_ent->name.name, entry.name, FSAL_MAX_NAME_LEN);
      curr_ent->name.len = strlen(curr_ent->name.name);
      curr_ent->cookie.cookie = entry.cookie;

      /* getting attributes
       * If an error occures during getattr operation,
       * it is returned, even though the readdir operation succeeded.
       */

      curr_ent->attributes.asked_attributes = get_attr_mask;
      switch ((status = FSAL_getattrs(&curr_ent->handle,
                                      &dir_descriptor->context,
                                      &curr_ent->attributes)).major)
        {
          /* change the FAULT error to appears as an internal error.
           * indeed, parameters should not be null. */
        case ERR_FSAL_FAULT:
          Return(ERR_FSAL_SERVERFAULT, ERR_FSAL_FAULT, INDEX_FSAL_readdir);
          break;
        case ERR_FSAL_NO_ERROR:
          /* ok, continue */
          break;
        default:
          Return(status.major, status.minor, INDEX_FSAL_readdir);
        }

      last_cookie = entry.cookie;       /* the cookie for the current entry */
      last_ent = curr_ent;      /* remembers last entry */
      curr_ent++;               /* the next entry to be filled */
      (*nb_entries)++;          /* numbers of entries we've read */

    }
  /* update outputs and return */
  end_position->cookie = last_cookie;
  if(last_ent)
    last_ent->nextentry = NULL;
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir);

}
Esempio n. 18
0
int main(int argc, char **argv)
{

  char localmachine[256];
  char *test;
  fsal_parameter_t init_param;
  fsal_status_t st;
  uid_t uid;
  hpssfsal_export_context_t export_ctx;
  hpssfsal_op_context_t op_ctx;
  hpssfsal_handle_t root_handle, handle;
  fsal_name_t name;
  fsal_path_t path;
  fsal_attrib_list_t attribs;
  fsal_attrib_mask_t mask;

  char tracebuff[256];

  if(argc < 2)
    {
      usage();
      exit(-1);
    }
  test = argv[1];
  /* retrieving params */

  /* init debug */
  SetDefaultLogging("TEST");
  SetNamePgm("test_fsal");
  SetNameFunction("main");
  InitLogging();

  /* Obtention du nom de la machine */
  if(gethostname(localmachine, sizeof(localmachine)) != 0)
    {
      LogError(COMPONENT_STDOUT,ERR_SYS, ERR_GETHOSTNAME, errno);
      exit(1);
    }
  else
    SetNameHost(localmachine);

  AddFamilyError(ERR_FSAL, "FSAL related Errors", tab_errstatus_FSAL);

  /* prepare fsal_init */

  /* 1 - fs specific info */

#if HPSS_MAJOR_VERSION == 5

  init_param.fs_specific_info.behaviors.PrincipalName = FSAL_INIT_FORCE_VALUE;
  strcpy(init_param.fs_specific_info.hpss_config.PrincipalName, "hpss_nfs");

  init_param.fs_specific_info.behaviors.KeytabPath = FSAL_INIT_FORCE_VALUE;
  strcpy(init_param.fs_specific_info.hpss_config.KeytabPath, "/krb5/hpssserver.keytab");

#else
  init_param.fs_specific_info.behaviors.AuthnMech = FSAL_INIT_FORCE_VALUE;
  init_param.fs_specific_info.hpss_config.AuthnMech = hpss_authn_mech_krb5;

  init_param.fs_specific_info.behaviors.Principal = FSAL_INIT_FORCE_VALUE;
  strcpy(init_param.fs_specific_info.Principal, "hpssfs");

  init_param.fs_specific_info.behaviors.KeytabPath = FSAL_INIT_FORCE_VALUE;
  strcpy(init_param.fs_specific_info.KeytabPath, "/var/hpss/etc/hpss.keytab");

#endif

  /* 2-common info (default) */
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, maxfilesize);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, maxlink);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, maxnamelen);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, maxpathlen);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, no_trunc);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, chown_restricted);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, case_insensitive);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, case_preserving);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, fh_expire_type);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, link_support);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, symlink_support);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, named_attr);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, unique_handles);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, lease_time);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, acl_support);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, cansettime);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, homogenous);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, supported_attrs);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, maxread);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, maxwrite);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, umask);
  FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, auth_exportpath_xdev);

  /* 3- fsal info */
  init_param.fsal_info.max_fs_calls = 0;

  /* Init */
  if(FSAL_IS_ERROR(st = FSAL_Init(&init_param)))
    {
      LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
    }

  /* getting creds */
  uid = getuid();
  LogTest("uid = %d", uid);

  st = FSAL_BuildExportContext(&export_ctx, NULL, NULL);
  if(FSAL_IS_ERROR(st))
    LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);

  st = FSAL_InitClientContext(&op_ctx);

  if(FSAL_IS_ERROR(st))
    LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);

  st = FSAL_GetClientContext(&op_ctx, &export_ctx, uid, -1, NULL, 0);

  if(FSAL_IS_ERROR(st))
    LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);

  /* getting root handle */

  if(FSAL_IS_ERROR(st = FSAL_lookup(NULL, NULL, &op_ctx, &root_handle, NULL)))
    {
      LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
    }

  snprintHandle(tracebuff, 256, &root_handle);
  LogTest("Root handle = %s", tracebuff);

  /* getting what are the supported attributes */

  attribs.asked_attributes = 0;
  FSAL_SET_MASK(attribs.asked_attributes, FSAL_ATTR_SUPPATTR);
  LogTest("asked attributes :");
  printmask(attribs.asked_attributes);

  if(FSAL_IS_ERROR(st = FSAL_getattrs(&root_handle, &op_ctx, &attribs)))
    {
      LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
    }

  LogTest("supported attributes :");
  printmask(attribs.supported_attributes);

  mask = attribs.supported_attributes;

/* TEST 1 */

  if(test[0] == '1')
    {

      attribs.asked_attributes = 0;
      FSAL_SET_MASK(attribs.asked_attributes, FSAL_ATTR_SUPPATTR);
      LogTest("asked attributes :");
      printmask(attribs.asked_attributes);

      if(FSAL_IS_ERROR(st = FSAL_getattrs(&root_handle, &op_ctx, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      LogTest("supported attributes :");

      /* getting all spported attributes of root */
      attribs.asked_attributes = mask;
      if(FSAL_IS_ERROR(st = FSAL_getattrs(&root_handle, &op_ctx, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      printattributes(attribs);

    }
  else
/* TEST 2 */
  if(test[0] == '2')
    {

      /* getting handle and attributes for subdirectory "OSF1_V5" */
      if(FSAL_IS_ERROR(st = FSAL_str2name("cea", 4, &name)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      attribs.asked_attributes = mask;
      if(FSAL_IS_ERROR(st = FSAL_lookup(&root_handle, &name, &op_ctx, &handle, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      snprintHandle(tracebuff, 256, &handle);
      LogTest("/cea handle = %s", tracebuff);

      /* displaying attributes */
      printattributes(attribs);

      /* getting handle and attributes for subdirectory "bin" */
      if(FSAL_IS_ERROR(st = FSAL_str2name("prot", 5, &name)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      root_handle = handle;
      attribs.asked_attributes = mask;
      if(FSAL_IS_ERROR(st = FSAL_lookup(&root_handle, &name, &op_ctx, &handle, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      snprintHandle(tracebuff, 256, &handle);
      LogTest("/cea/prot handle = %s", tracebuff);

      /* displaying attributes */
      printattributes(attribs);

      /* getting handle and attributes for symlink "AglaePwrSW" */
      if(FSAL_IS_ERROR(st = FSAL_str2name("lama", 5, &name)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      root_handle = handle;
      attribs.asked_attributes = mask;
      if(FSAL_IS_ERROR(st = FSAL_lookup(&root_handle, &name, &op_ctx, &handle, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      snprintHandle(tracebuff, 256, &handle);
      LogTest("/cea/prot/lama handle = %s", tracebuff);

      /* displaying attributes */
      printattributes(attribs);

    }
  else
/* TEST 3 */
  if(test[0] == '3')
    {

      /* lookup root */
      if(FSAL_IS_ERROR(st = FSAL_str2path("/", 30, &path)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      attribs.asked_attributes = mask;
      if(FSAL_IS_ERROR(st = FSAL_lookupPath(&path, &op_ctx, &handle, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      snprintHandle(tracebuff, 256, &handle);
      LogTest("/ handle = %s", tracebuff);

      /* displaying attributes */
      printattributes(attribs);

      /* lookup path */
      if(FSAL_IS_ERROR(st = FSAL_str2path("/cea/prot/lama", 15, &path)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      attribs.asked_attributes = mask;
      if(FSAL_IS_ERROR(st = FSAL_lookupPath(&path, &op_ctx, &handle, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      snprintHandle(tracebuff, 256, &handle);
      LogTest("/cea/prot/lama handle = %s", tracebuff);

      /* displaying attributes */
      printattributes(attribs);

    }
  else
/* TEST 4 */
  if(test[0] == '4')
    {

      /* readdir on root */
      hpssfsal_dir_t dir;
      hpssfsal_cookie_t from, to;
      fsal_dirent_t entries[READDIR_SIZE];
      fsal_count_t number;
      fsal_boolean_t eod = FALSE;
      int error = FALSE;

      attribs.asked_attributes = mask;
      if(FSAL_IS_ERROR(st = FSAL_opendir(&root_handle, &op_ctx, &dir, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      LogTest("'/' attributes :");

      /* displaying attributes */
      printattributes(attribs);

      from = FSAL_READDIR_FROM_BEGINNING;

      while(!error && !eod)
        {
          unsigned int i;
          char cookiebuff[256];

          snprintCookie(cookiebuff, 256, &from);
          LogTest("\nReaddir cookie = %s", cookiebuff);
          if(FSAL_IS_ERROR(st = FSAL_readdir(&dir, from,
                                             mask, READDIR_SIZE * sizeof(fsal_dirent_t),
                                             entries, &to, &number, &eod)))
            {
              LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
              error = TRUE;
            }

          for(i = 0; (!error) && (i < number); i++)
            {

              snprintHandle(tracebuff, 256, &entries[i].handle);

              snprintCookie(cookiebuff, 256, &entries[i].cookie);

              LogTest("\t%s : %s (cookie %s)", tracebuff,
                     entries[i].name.name, cookiebuff);
            }
          /* preparing next call */
          from = to;

        }
      LogTest("Fin de boucle : error=%d ; eod=%d", error, eod);

    }
  else
/* TEST 5 */
  if(test[0] == '5')
    {

      /* readdir on root */
      hpssfsal_dir_t dir;
      hpssfsal_cookie_t from, to;
      fsal_dirent_t entries[READDIR_SIZE];
      fsal_count_t number;
      fsal_boolean_t eod = FALSE;
      int error = FALSE;

      attribs.asked_attributes = mask;
      if(FSAL_IS_ERROR(st = FSAL_opendir(&root_handle, &op_ctx, &dir, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      LogTest("'/' attributes :");

      /* displaying attributes */
      printattributes(attribs);

      from = FSAL_READDIR_FROM_BEGINNING;

      while(!error && !eod)
        {
          fsal_dirent_t *curr;

          char cookiebuff[256];

          snprintCookie(cookiebuff, 256, &from);

          LogTest("\nReaddir cookie = %s", cookiebuff);

          if(FSAL_IS_ERROR(st = FSAL_readdir(&dir, from,
                                             mask, READDIR_SIZE * sizeof(fsal_dirent_t),
                                             entries, &to, &number, &eod)))
            {
              LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
              error = TRUE;
            }

          if(number > 0)
            {
              curr = entries;
              do
                {

                  snprintHandle(tracebuff, 256, &curr->handle);
                  snprintCookie(cookiebuff, 256, &curr->cookie);

                  LogTest("\t%s : %s (cookie %s)", tracebuff,
                         curr->name.name, cookiebuff);
                }
              while(curr = curr->nextentry);
            }
          /* preparing next call */
          from = to;

        }
      LogTest("Fin de boucle : error=%d ; eod=%d", error, eod);

    }
  else
/* TEST 6 */
  if(test[0] == '6')
    {

      /* readdir on root */
      hpssfsal_dir_t dir;
      hpssfsal_cookie_t from, to;
      fsal_dirent_t entries[READDIR_SIZE];
      fsal_count_t number;
      fsal_boolean_t eod = FALSE;
      int error = FALSE;

      attribs.asked_attributes = mask;
      if(FSAL_IS_ERROR(st = FSAL_opendir(&root_handle, &op_ctx, &dir, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      LogTest("'/' attributes :");

      /* displaying attributes */
      printattributes(attribs);

      from = FSAL_READDIR_FROM_BEGINNING;

      while(!error && !eod)
        {
          unsigned int i;

          snprintCookie(tracebuff, 256, &from);
          LogTest("\nReaddir cookie = %s", tracebuff);

          st = FSAL_readdir(&dir, from, mask,
                            READDIR_SIZE * sizeof(fsal_dirent_t),
                            entries, &to, &number, &eod);

          if(FSAL_IS_ERROR(st))
            {
              LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
              error = TRUE;
            }

          /* for each entry, we compare the result of FSAL_access
           * to FSAL_test_access. */
          for(i = 0; (!error) && (i < number); i++)
            {

              fsal_status_t st1, st2;
              char cookiebuff[256];

              snprintHandle(tracebuff, 256, &entries[i].handle);
              snprintCookie(cookiebuff, 256, &entries[i].cookie);

              LogTest("\t%s : %s (cookie %s)", tracebuff,
                     entries[i].name.name, cookiebuff);

              if(FSAL_IS_ERROR(st = FSAL_getattrs(&entries[i].handle, &op_ctx, &attribs)))
                {
                  LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
                }

              /* 1 - test R access */

              st1 = FSAL_access(&entries[i].handle, &op_ctx, FSAL_R_OK, NULL);

              st2 = FSAL_test_access(&op_ctx, FSAL_R_OK, &attribs);

              LogError(COMPONENT_STDOUT, ERR_FSAL, st1.major, st1.minor);
              LogError(COMPONENT_STDOUT, ERR_FSAL, st2.major, st2.minor);

              if(st1.major != st2.major)
                {
                  LogTest(
                      "Error : different access permissions given by FSAL_access and FSAL_test_access : %d <>%d",
                       st1.major, st2.major);
                }

              /* 2 - test W access */

              st1 = FSAL_access(&entries[i].handle, &op_ctx, FSAL_W_OK, NULL);

              st2 = FSAL_test_access(&op_ctx, FSAL_W_OK, &attribs);

              LogError(COMPONENT_STDOUT, ERR_FSAL, st1.major, st1.minor);
              LogError(COMPONENT_STDOUT, ERR_FSAL, st2.major, st2.minor);

              if(st1.major != st2.major)
                {
                  LogTest(
                      "Error : different access permissions given by FSAL_access and FSAL_test_access : %d <>%d",
                       st1.major, st2.major);
                }

              /* 3 - test X access */

              st1 = FSAL_access(&entries[i].handle, &op_ctx, FSAL_X_OK, NULL);

              st2 = FSAL_test_access(&op_ctx, FSAL_X_OK, &attribs);

              LogError(COMPONENT_STDOUT, ERR_FSAL, st1.major, st1.minor);
              LogError(COMPONENT_STDOUT, ERR_FSAL, st2.major, st2.minor);

              if(st1.major != st2.major)
                {
                  LogTest(
                      "Error : different access permissions given by FSAL_access and FSAL_test_access : %d <>%d",
                       st1.major, st2.major);
                }

            }

          /* preparing next call */
          from = to;

        }
      LogTest("Fin de boucle : error=%d ; eod=%d", error, eod);

    }
  else
/* TEST 7 */
  if(test[0] == '7')
    {

      /* test snprintmem and sscanmem */
      char test_string[] =
          "Ceci est une chaine d'essai.\nLes chiffres : 0123456789\nLes lettres : ABCDEFGHIJKLMNOPQRSTUVWXYZ";

      char buffer[256];
      char string[200];         /* 200 suffit car test_string fait <100 */

      int size1, size2, size3, i;

      /* we put bad values in string, to see if it is correctly set. */
      for(i = 0; i < 200; i++)
        string[i] = (char)i;

      LogTest("Initial data (%d Bytes) = <<%s>>", strlen(test_string), test_string);

      /* Write test_string to a buffer. */
      /* We don't give the final '\0'.  */
      snprintmem(buffer, 256, test_string, strlen(test_string));

      LogTest("Dest_Buffer (%d Bytes) = <<%s>>", strlen(buffer), buffer);

      /* read the value from the buffer */
      sscanmem(string, strlen(test_string), buffer);

      /* sets the final 0 to print the content of the buffer */
      LogTest("Retrieved string : following byte = %d",
             (int)string[strlen(test_string)]);
      string[strlen(test_string)] = '\0';

      LogTest("Retrieved string (%d Bytes) = <<%s>>", strlen(string), string);

      /* Automatic tests : */
      size1 = strlen(test_string);
      size2 = strlen(buffer);
      size3 = strlen(string);

      LogTest("-------------------------------------");

      if(size1 <= 0)
        LogTest("***** ERROR: source size=0 !!!");

      if(size1 != size3)
        LogTest("***** ERROR: source size <> target size");
      else
        LogTest("OK: source size = target size");

      if((size1 * 2) != size2)
        LogTest("***** ERROR: hexa size <> 2 * source size");
      else
        LogTest("OK: hexa size = 2 * source size");

      if(strcmp(test_string, string))
        LogTest("***** ERROR: source string <> target string");
      else
        LogTest("OK: source string = target string");

    }
  else
/* TEST 8 */
  if(test[0] == '8')
    {

      hpssfsal_handle_t dir_hdl, subdir_hdl;
      fsal_name_t subdir_name;

      /* lookup on /cea/prot/S/lama/s8/leibovic */

      if(FSAL_IS_ERROR(st = FSAL_str2path("/cea/prot/S/lama/s8/leibovic", 40, &path)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      attribs.asked_attributes = mask;
      if(FSAL_IS_ERROR(st = FSAL_lookupPath(&path, &op_ctx, &handle, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      snprintHandle(tracebuff, 256, &handle);
      LogTest("/cea/prot/S/lama/s8/leibovic: handle = %s", tracebuff);

      sleep(1);

      /* creates a directory */
      LogTest("------- Create a directory -------");

      if(FSAL_IS_ERROR(st = FSAL_str2name("tests_GANESHA", 30, &name)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      attribs.asked_attributes = mask;

      if(FSAL_IS_ERROR(st = FSAL_mkdir(&handle, &name, &op_ctx,
                                       FSAL_MODE_RUSR | FSAL_MODE_WUSR
                                       | FSAL_MODE_XUSR | FSAL_MODE_RGRP
                                       | FSAL_MODE_WGRP, &dir_hdl, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      else
        {

          snprintHandle(tracebuff, 256, &dir_hdl);
          LogTest("newly created dir handle = %s", tracebuff);

          printattributes(attribs);

        }

      sleep(1);

      /* Try to create it again */
      LogTest("------- Try to create it again -------");

      if(FSAL_IS_ERROR(st = FSAL_mkdir(&handle, &name, &op_ctx,
                                       FSAL_MODE_RUSR | FSAL_MODE_WUSR
                                       | FSAL_MODE_XUSR | FSAL_MODE_RGRP
                                       | FSAL_MODE_WGRP, &dir_hdl, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      else
        {

          LogTest("**** Error: FSAL should have returned ERR_FSAL_EXIST");

        }

      sleep(1);

      /* creates a subdirectory */
      LogTest("------- Create a subdirectory -------");

      if(FSAL_IS_ERROR(st = FSAL_str2name("subdir_GANESHA", 30, &subdir_name)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      if(FSAL_IS_ERROR(st = FSAL_mkdir(&dir_hdl, &subdir_name, &op_ctx,
                                       FSAL_MODE_RUSR | FSAL_MODE_WUSR
                                       | FSAL_MODE_XUSR | FSAL_MODE_RGRP
                                       | FSAL_MODE_WGRP, &subdir_hdl, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      else
        {

          snprintHandle(tracebuff, 256, &subdir_hdl);
          LogTest("newly created subdir handle = %s", tracebuff);

          printattributes(attribs);

        }

      /* try to removes the parent directory */
      LogTest("------- Try to removes the parent directory -------");

      if(FSAL_IS_ERROR(st = FSAL_unlink(&handle, &name, &op_ctx, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      else
        {

          LogTest("FSAL should not have unlinked %s because it is not empty", name.name);

        }

      sleep(1);

      /* removes the subdirectory */
      LogTest("------- Removes the subdirectory -------");

      if(FSAL_IS_ERROR(st = FSAL_unlink(&dir_hdl, &subdir_name, &op_ctx, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      else
        {

          LogTest("New attributes for parent directory:");
          printattributes(attribs);

        }

      /* removes the parent directory */
      LogTest("------- Removes the parent directory -------");

      if(FSAL_IS_ERROR(st = FSAL_unlink(&handle, &name, &op_ctx, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      else
        {

          LogTest("Unlink %s OK", name.name);

        }

    }
/* TEST 9 */
  else if(test[0] == '9')
    {

      hpssfsal_handle_t dir_hdl, subdir_hdl;
      fsal_name_t subdir_name;
      fsal_attrib_list_t attr_set;

      fsal_fsid_t set_fsid = { 1LL, 2LL };

#ifdef _LINUX
      struct tm jour_heure = { 56, 34, 12, 31, 12, 110, 0, 0, 0, 0, 0 };
#else
      struct tm jour_heure = { 56, 34, 12, 31, 12, 110, 0, 0, 0 };
#endif

      /* lookup on /cea/prot/S/lama/s8/leibovic */

      if(FSAL_IS_ERROR(st = FSAL_str2path("/cea/prot/S/lama/s8/leibovic", 40, &path)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      attribs.asked_attributes = mask;
      if(FSAL_IS_ERROR(st = FSAL_lookupPath(&path, &op_ctx, &handle, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      snprintHandle(tracebuff, 256, &handle);
      LogTest("/cea/prot/S/lama/s8/leibovic: handle = %s", tracebuff);

      sleep(1);

      /* creates a file */
      LogTest("------- Create a file -------");

      if(FSAL_IS_ERROR(st = FSAL_str2name("tests_GANESHA_setattrs", 30, &name)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      attribs.asked_attributes = mask;

      if(FSAL_IS_ERROR(st = FSAL_create(&handle, &name, &op_ctx,
                                        FSAL_MODE_RUSR | FSAL_MODE_WUSR
                                        | FSAL_MODE_XUSR | FSAL_MODE_RGRP
                                        | FSAL_MODE_WGRP, &dir_hdl, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      else
        {

          snprintHandle(tracebuff, 256, &dir_hdl);
          LogTest("newly created file handle = %s", tracebuff);

          printattributes(attribs);

        }

      sleep(1);

      LogTest("------- Try to change its attributes -------");

      /* Macro that try to change the value for an attribute */

#define CHANGE_ATTRS( str_nom, nom, flag, new_val ) do {\
  memset(&attr_set, 0, sizeof(fsal_attrib_list_t) );    \
  LogTest("\nTry to change '%s' :",str_nom);           \
  FSAL_SET_MASK( attr_set.asked_attributes , flag );    \
  attr_set.nom = new_val;                               \
  attribs.asked_attributes = attr_set.asked_attributes; \
/*  attribs.asked_attributes = mask;                      */\
  st = FSAL_setattrs( &dir_hdl, &op_ctx, &attr_set, &attribs );\
  if ( FSAL_IS_ERROR(st) )                              \
    LogError(COMPONENT_STDOUT,ERR_FSAL,st.major,st.minor);\
  else                                                  \
    printattributes( attribs );                         \
  } while(0)

      CHANGE_ATTRS("supported_attributes", supported_attributes,
                   FSAL_ATTR_SUPPATTR, FSAL_ATTRS_MANDATORY);

      CHANGE_ATTRS("type", type, FSAL_ATTR_TYPE, FSAL_TYPE_LNK);

      sleep(1);                 /* to see mtime modification by truncate */

      CHANGE_ATTRS("filesize", filesize, FSAL_ATTR_SIZE, (fsal_size_t) 12);

      sleep(1);                 /* to see mtime modification by truncate */

      CHANGE_ATTRS("fsid", fsid, FSAL_ATTR_FSID, set_fsid);

      /* @todo : ACLs */

      CHANGE_ATTRS("fileid", fileid, FSAL_ATTR_FILEID, (fsal_u64_t) 1234);

      CHANGE_ATTRS("mode", mode, FSAL_ATTR_MODE,
                   (FSAL_MODE_RUSR | FSAL_MODE_WUSR | FSAL_MODE_RGRP));

      CHANGE_ATTRS("numlinks", numlinks, FSAL_ATTR_NUMLINKS, 7);

      /* FSAL_ATTR_RAWDEV */

      CHANGE_ATTRS("atime", atime.seconds, FSAL_ATTR_ATIME, mktime(&jour_heure));

      jour_heure.tm_min++;

      CHANGE_ATTRS("creation", creation.seconds, FSAL_ATTR_CREATION, mktime(&jour_heure));

      jour_heure.tm_min++;

      CHANGE_ATTRS("mtime", mtime.seconds, FSAL_ATTR_MTIME, mktime(&jour_heure));

      jour_heure.tm_min++;

      CHANGE_ATTRS("ctime", ctime.seconds, FSAL_ATTR_CTIME, mktime(&jour_heure));

      CHANGE_ATTRS("spaceused", spaceused, FSAL_ATTR_SPACEUSED, (fsal_size_t) 12345);

      CHANGE_ATTRS("mounted_on_fileid", mounted_on_fileid,
                   FSAL_ATTR_MOUNTFILEID, (fsal_u64_t) 3210);

      CHANGE_ATTRS("owner", owner, FSAL_ATTR_OWNER, 3051);      /* deniel */

      CHANGE_ATTRS("group", group, FSAL_ATTR_GROUP, 5953);      /* sr */

      sleep(1);

      /* removes the parent directory */
      LogTest("------- Removes the directory -------");

      if(FSAL_IS_ERROR(st = FSAL_unlink(&handle, &name, &op_ctx, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      else
        {

          LogTest("Unlink %s OK", name.name);

        }

    }
  else if(test[0] == 'A')
    {

      char digest_buff[FSAL_DIGEST_SIZE_HDLV3];

      /* lookup on /cea/prot/S/lama/s8/leibovic */

      if(FSAL_IS_ERROR(st = FSAL_str2path("/cea/prot/S/lama/s8/leibovic", 40, &path)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      attribs.asked_attributes = mask;
      if(FSAL_IS_ERROR(st = FSAL_lookupPath(&path, &op_ctx, &handle, &attribs)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }

      snprintHandle(tracebuff, 256, &handle);
      LogTest("/cea/prot/S/lama/s8/leibovic: handle = %s", tracebuff);

      /* building digest */

      st = FSAL_DigestHandle(&export_ctx, FSAL_DIGEST_NFSV3, &handle, digest_buff);

      if(FSAL_IS_ERROR(st))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      else
        {
          /* print digest */
          snprintmem(tracebuff, 256, digest_buff, FSAL_DIGEST_SIZE_HDLV3);
          LogTest("/cea/prot/S/lama/s8/leibovic: handle_digest = %s", tracebuff);
        }

      memset(&handle, 0, sizeof(hpssfsal_handle_t));

      /* expend digest */

      st = FSAL_ExpandHandle(&export_ctx, FSAL_DIGEST_NFSV3, digest_buff, &handle);

      if(FSAL_IS_ERROR(st))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
        }
      else
        {
          /* print expended handle */
          snprintHandle(tracebuff, 256, &handle);
          LogTest("/cea/prot/S/lama/s8/leibovic: handle expended = %s", tracebuff);
        }

    }
  else if(test[0] == 'B')
    {

      fsal_dynamicfsinfo_t dyninfo;

      if(FSAL_IS_ERROR(st = FSAL_dynamic_fsinfo(&root_handle, &op_ctx, &dyninfo)))
        {
          LogError(COMPONENT_STDOUT, ERR_FSAL, st.major, st.minor);
          exit(st.major);
        }

      LogTest("total_bytes = %llu", dyninfo.total_bytes);
      LogTest("free_bytes = %llu", dyninfo.free_bytes);
      LogTest("avail_bytes = %llu", dyninfo.avail_bytes);
      LogTest("total_files = %llu", dyninfo.total_files);
      LogTest("free_files = %llu", dyninfo.free_files);
      LogTest("avail_files = %llu", dyninfo.avail_files);
      LogTest("time_delta = %u.%u", dyninfo.time_delta.seconds,
             dyninfo.time_delta.nseconds);

    }
  else
    LogTest("%s : test inconnu", test);

  return 0;

}
Esempio n. 19
0
cache_inode_status_t cache_inode_rdwr(cache_entry_t * pentry,
                                      cache_inode_io_direction_t read_or_write,
                                      fsal_seek_t * seek_descriptor,
                                      fsal_size_t buffer_size,
                                      fsal_size_t * pio_size,
                                      fsal_attrib_list_t * pfsal_attr,
                                      caddr_t buffer,
                                      fsal_boolean_t * p_fsal_eof,
                                      hash_table_t * ht,
                                      cache_inode_client_t * pclient,
                                      fsal_op_context_t * pcontext,
                                      uint64_t stable, 
				      cache_inode_status_t * pstatus)
{
  int statindex = 0;
  cache_content_io_direction_t io_direction;
  cache_content_status_t cache_content_status;
  fsal_status_t fsal_status;
  fsal_openflags_t openflags;
  fsal_size_t io_size;
  fsal_attrib_list_t post_write_attr;
  fsal_status_t fsal_status_getattr;
  struct stat buffstat;

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

  /* For now, only FSAL_SEEK_SET is supported */
  if(seek_descriptor->whence != FSAL_SEEK_SET)
    {
      LogCrit(COMPONENT_CACHE_INODE,
              "Implementation trouble: seek_descriptor was not a 'FSAL_SEEK_SET' cursor");
      *pstatus = CACHE_INODE_INVALID_ARGUMENT;
      return *pstatus;
    }

  io_size = buffer_size;

  LogDebug(COMPONENT_CACHE_INODE,
           "cache_inode_rdwr: INODE : IO Size = %llu fdsize =%zu seeksize=%zu",
           buffer_size, sizeof(fsal_file_t), sizeof(fsal_seek_t));

  /* stat */
  pclient->stat.nb_call_total += 1;
  if(read_or_write == CACHE_INODE_READ)
    {
      statindex = CACHE_INODE_READ_DATA;
      io_direction = CACHE_CONTENT_READ;
      openflags = FSAL_O_RDONLY;
      pclient->stat.func_stats.nb_call[CACHE_INODE_READ_DATA] += 1;
    }
  else
    {
      statindex = CACHE_INODE_WRITE_DATA;
      io_direction = CACHE_CONTENT_WRITE;
      openflags = FSAL_O_WRONLY;
      pclient->stat.func_stats.nb_call[CACHE_INODE_WRITE_DATA] += 1;
    }

  P_w(&pentry->lock);

  /* IO are done only on REGULAR_FILEs */
  if(pentry->internal_md.type != REGULAR_FILE)
    {
      *pstatus = CACHE_INODE_BAD_TYPE;
      V_w(&pentry->lock);

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

      return *pstatus;
    }

  /* Non absolute address within the file are not supported (we act only like pread/pwrite) */
  if(seek_descriptor->whence != FSAL_SEEK_SET)
    {
      *pstatus = CACHE_INODE_INVALID_ARGUMENT;
      V_w(&pentry->lock);

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

      return *pstatus;
    }

  /* Do we use stable or unstable storage ? */
  if(stable == FSAL_UNSAFE_WRITE_TO_GANESHA_BUFFER)
    {
      /* Data will be stored in memory and not flush to FSAL */

      /* If the unstable_data buffer allocated ? */
      if(pentry->object.file.unstable_data.buffer == NULL)
        {
          if((pentry->object.file.unstable_data.buffer =
              Mem_Alloc_Label(CACHE_INODE_UNSTABLE_BUFFERSIZE,
                              "Cache_Inode Unstable Buffer")) == NULL)
            {
              *pstatus = CACHE_INODE_MALLOC_ERROR;
              V_w(&pentry->lock);

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

              return *pstatus;
            }

          pentry->object.file.unstable_data.offset = seek_descriptor->offset;
          pentry->object.file.unstable_data.length = buffer_size;

          memcpy(pentry->object.file.unstable_data.buffer, buffer, buffer_size);

          /* Set mtime and ctime */
          cache_inode_set_time_current( &pentry->attributes.mtime ) ;  

          /* BUGAZOMEU : write operation must NOT modify file's ctime */
          pentry->attributes.ctime = pentry->attributes.mtime;

          *pio_size = buffer_size;
        }                       /* if( pentry->object.file.unstable_data.buffer == NULL ) */
      else
        {
          if((pentry->object.file.unstable_data.offset < seek_descriptor->offset) &&
             (buffer_size + seek_descriptor->offset < CACHE_INODE_UNSTABLE_BUFFERSIZE))
            {
              pentry->object.file.unstable_data.length =
                  buffer_size + seek_descriptor->offset;
              memcpy((char *)(pentry->object.file.unstable_data.buffer +
                              seek_descriptor->offset), buffer, buffer_size);

              /* Set mtime and ctime */
              cache_inode_set_time_current( &pentry->attributes.mtime ) ;

              /* BUGAZOMEU : write operation must NOT modify file's ctime */
              pentry->attributes.ctime = pentry->attributes.mtime;

              *pio_size = buffer_size;
            }
          else
            {
              /* Go back to regular situation */
              stable = FSAL_SAFE_WRITE_TO_FS;
            }
        }

    }
  /* if( stable == FALSE ) */
  if(stable == FSAL_SAFE_WRITE_TO_FS ||
     stable == FSAL_UNSAFE_WRITE_TO_FS_BUFFER)
    {
      /* Calls file content cache to operate on the cache */
      if(pentry->object.file.pentry_content != NULL)
        {
          /* Entry is data cached */
          cache_content_rdwr(pentry->object.file.pentry_content,
                             io_direction,
                             seek_descriptor,
                             &io_size,
                             pio_size,
                             buffer,
                             p_fsal_eof,
                             &buffstat,
                             (cache_content_client_t *) pclient->pcontent_client,
                             pcontext, &cache_content_status);

          /* If the entry under resync */
          if(cache_content_status == CACHE_CONTENT_LOCAL_CACHE_NOT_FOUND)
            {
              /* Data cache gc has removed this entry */
              if(cache_content_new_entry(pentry,
                                         NULL,
                                         (cache_content_client_t *)pclient->pcontent_client, 
                                         RENEW_ENTRY, pcontext,
                                         &cache_content_status) == NULL)
                {
                  /* Entry could not be recoverd, cache_content_status contains an error, let it be managed by the next block */
                  LogCrit(COMPONENT_CACHE_INODE,
                          "Read/Write Operation through cache failed with status %d (renew process failed)",
                          cache_content_status);

		  /* Will go to the end of the function on the error clause with cache_content_status describing the error */
                }
              else
                {
                  /* Entry was successfully renewed */
                  LogInfo(COMPONENT_CACHE_INODE,
                          "----> File Content Entry %p was successfully renewed",
                          pentry);

                  /* Try to access the content of the file again */
                  cache_content_rdwr(pentry->object.file.pentry_content,
                                     io_direction,
                                     seek_descriptor,
                                     &io_size,
                                     pio_size,
                                     buffer,
                                     p_fsal_eof,
                                     &buffstat,
                                     (cache_content_client_t *) pclient->pcontent_client,
                                     pcontext, &cache_content_status);

                  /* No management of cache_content_status in case of failure, this will be done
                   * within the next block */
                }

            }

          if(cache_content_status != CACHE_CONTENT_SUCCESS)
            {
              *pstatus = cache_content_error_convert(cache_content_status);

              V_w(&pentry->lock);

              LogCrit(COMPONENT_CACHE_INODE,
                      "Read/Write Operation through cache failed with status %d",
                      cache_content_status);

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

              return *pstatus;
            }

          LogFullDebug(COMPONENT_CACHE_INODE,
                       "cache_inode_rdwr: inode/dc: io_size=%llu, pio_size=%llu,  eof=%d, seek=%d.%"PRIu64,
                       io_size, *pio_size, *p_fsal_eof, seek_descriptor->whence,
                       seek_descriptor->offset);

          LogMidDebug(COMPONENT_CACHE_INODE,
                       "cache_inode_rdwr: INODE  AFTER : IO Size = %llu %llu",
                       io_size, *pio_size);

          /* Use information from the buffstat to update the file metadata */
          pentry->attributes.filesize = buffstat.st_size;
          pentry->attributes.spaceused =
              buffstat.st_blksize * buffstat.st_blocks;

        }
      else
        {
          /* No data cache entry, we operated directly on FSAL */
          pentry->attributes.asked_attributes = pclient->attrmask;

          /* We need to open if we don't have a cached
           * descriptor or our open flags differs.
           */
          if(cache_inode_open(pentry,
                              pclient,
                              openflags, pcontext, pstatus) != CACHE_INODE_SUCCESS)
            {
              V_w(&pentry->lock);

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

              return *pstatus;
            }

          /* Call FSAL_read or FSAL_write */

          if(read_or_write == CACHE_INODE_READ)
            {
#ifdef _USE_MFSL
              fsal_status = MFSL_read(&(pentry->object.file.open_fd.mfsl_fd),
                                      seek_descriptor,
                                      io_size,
                                      buffer,
                                      pio_size, p_fsal_eof, &pclient->mfsl_context, NULL);
#else
              fsal_status = FSAL_read(&(pentry->object.file.open_fd.fd),
                                      seek_descriptor,
                                      io_size, buffer, pio_size, p_fsal_eof);
#endif
            }
          else
            {
#ifdef _USE_MFSL
              fsal_status = MFSL_write(&(pentry->object.file.open_fd.mfsl_fd),
                                       seek_descriptor,
                                       io_size, buffer, pio_size, &pclient->mfsl_context, NULL);
#else
              fsal_status = FSAL_write(&(pentry->object.file.open_fd.fd),
                                       seek_descriptor, io_size, buffer, pio_size);
#endif

#if 0
              /* Alright, the unstable write is complete. Now if it was supposed to be a stable write
               * we can sync to the hard drive. */
              if(stable == FSAL_SAFE_WRITE_TO_FS)
                {
#ifdef _USE_MFSL
                  fsal_status = MFSL_commit(&(pentry->object.file.open_fd.mfsl_fd), NULL);
#else
                  fsal_status = FSAL_commit(&(pentry->object.file.open_fd.fd));
#endif
#endif

            }

          LogFullDebug(COMPONENT_FSAL,
                       "cache_inode_rdwr: FSAL IO operation returned %d, asked_size=%llu, effective_size=%llu",
                       fsal_status.major, (unsigned long long)io_size,
                       (unsigned long long)*pio_size);

          if(FSAL_IS_ERROR(fsal_status))
            {

              if(fsal_status.major == ERR_FSAL_DELAY)
                LogEvent(COMPONENT_CACHE_INODE,
                         "cache_inode_rdwr: FSAL_write returned EBUSY");
              else
                LogDebug(COMPONENT_CACHE_INODE,
                         "cache_inode_rdwr: fsal_status.major = %d",
                         fsal_status.major);

              if((fsal_status.major != ERR_FSAL_NOT_OPENED)
                 && (pentry->object.file.open_fd.fileno != 0))
                {

                  LogDebug(COMPONENT_CACHE_INODE,
                               "cache_inode_rdwr: CLOSING pentry %p: fd=%d",
                               pentry, pentry->object.file.open_fd.fileno);

#ifdef _USE_MFSL
                  MFSL_close(&(pentry->object.file.open_fd.mfsl_fd), &pclient->mfsl_context, NULL);
#else
                  FSAL_close(&(pentry->object.file.open_fd.fd));
#endif

                  *pstatus = cache_inode_error_convert(fsal_status);
                }
              else
                {
                  /* the fd has been close by another thread.
                   * return CACHE_INODE_FSAL_DELAY so the client will
                   * retry with a new fd.
                   */
                  *pstatus = CACHE_INODE_FSAL_DELAY;
                }

              pentry->object.file.open_fd.last_op = 0;
              pentry->object.file.open_fd.fileno = 0;

              V_w(&pentry->lock);

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

              return *pstatus;
            }

          LogFullDebug(COMPONENT_CACHE_INODE,
                       "cache_inode_rdwr: inode/direct: io_size=%llu, pio_size=%llu, eof=%d, seek=%d.%"PRIu64,
                       io_size, *pio_size, *p_fsal_eof, seek_descriptor->whence,
                       seek_descriptor->offset);

          if(cache_inode_close(pentry, pclient, pstatus) != CACHE_INODE_SUCCESS)
            {
              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_rdwr: cache_inode_close = %d", *pstatus);

              V_w(&pentry->lock);

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

              return *pstatus;
            }

          if(read_or_write == CACHE_INODE_WRITE)
            {
              /* Do a getattr in order to have update information on filesize
               * This query is done directly on FSAL (object is not data cached), and result
               * will be propagated to cache Inode */

              /* WARNING: This operation is to be done AFTER FSAL_close (some FSAL, like POSIX,
               * may not flush data until the file is closed */

              /*post_write_attr.asked_attributes =  pclient->attrmask ; */
              post_write_attr.asked_attributes = FSAL_ATTR_SIZE | FSAL_ATTR_SPACEUSED;
              fsal_status_getattr =
                  FSAL_getattrs(&(pentry->handle), pcontext,
                                &post_write_attr);

              /* if failed, the next block will handle the error */
              if(FSAL_IS_ERROR(fsal_status_getattr))
                fsal_status = fsal_status_getattr;
              else
                {
                  /* Update Cache Inode attributes */
                  pentry->attributes.filesize = post_write_attr.filesize;
                  pentry->attributes.spaceused = post_write_attr.spaceused;
                }
            }

        }

      /* IO was successfull (through cache content or not), we manually update the times in the attributes */

      switch (read_or_write)
        {
        case CACHE_INODE_READ:
          /* Set the atime */
          cache_inode_set_time_current( & pentry->attributes.atime ) ;
          break;

        case CACHE_INODE_WRITE:
          /* Set mtime and ctime */
          cache_inode_set_time_current( & pentry->attributes.mtime ) ;

          /* BUGAZOMEU : write operation must NOT modify file's ctime */
          pentry->attributes.ctime = pentry->attributes.mtime;

          break;
        }
    }

  /* if(stable == TRUE ) */
  /* Return attributes to caller */
  if(pfsal_attr != NULL)
    *pfsal_attr = pentry->attributes;

  *pstatus = CACHE_INODE_SUCCESS;

  /* stat */
  if(read_or_write == CACHE_INODE_READ)
    {
      *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient);

      if(*pstatus != CACHE_INODE_SUCCESS)
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_READ] += 1;
      else
        pclient->stat.func_stats.nb_success[CACHE_INODE_READ] += 1;
    }
  else
    {
      *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_SET, pclient);

      if(*pstatus != CACHE_INODE_SUCCESS)
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_WRITE] += 1;
      else
        pclient->stat.func_stats.nb_success[CACHE_INODE_WRITE] += 1;
    }

  V_w(&pentry->lock);

  return *pstatus;
}                               /* cache_inode_rdwr */
Esempio n. 20
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 */