예제 #1
0
/**
 *
 * cache_inode_lookup_sw: looks up for a name in a directory indicated by a
 * cached entry.
 * 
 * Looks up for a name in a directory indicated by a cached entry. The directory
 * should have been cached before.
 *
 * @param pentry_parent [IN]    entry for the parent directory to be managed.
 * @param name          [IN]    name of the entry that we are looking for in the
 *        cache.
 * @param pattr         [OUT]   attributes for the entry that we have found.
 * @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.
 * @param use_mutex     [IN]    if TRUE, mutex management is done, not if equal
 * to FALSE.
 * 
 * @return CACHE_INODE_SUCCESS if operation is a success \n
 * @return CACHE_INODE_LRU_ERROR if allocation error occured when validating the
 *  entry
 *
 */
cache_entry_t *cache_inode_lookup_sw(cache_entry_t        * pentry_parent,
                                     fsal_name_t          * pname,
                                     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, 
                                     int use_mutex)
{

  cache_inode_dir_entry_t dirent_key[1], *dirent;
  struct avltree_node *dirent_node;
  cache_inode_dir_entry_t *new_dir_entry;
  cache_entry_t *pentry = NULL;
  fsal_status_t fsal_status;
#ifdef _USE_MFSL
  mfsl_object_t object_handle;
#else
  fsal_handle_t object_handle;
#endif
  fsal_handle_t dir_handle;
  fsal_attrib_list_t object_attributes;
  cache_inode_create_arg_t create_arg;
  cache_inode_file_type_t type;
  cache_inode_status_t cache_status;
  cache_inode_fsal_data_t new_entry_fsdata;
  fsal_accessflags_t access_mask = 0;

  memset(&create_arg, 0, sizeof(create_arg));
  memset( (char *)&new_entry_fsdata, 0, sizeof( new_entry_fsdata ) ) ; 

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

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

  /* We should not renew entries when !use_mutex (because unless we
   * make the flag explicit (shared vs. exclusive), we don't know
   * whether a mutating operation is safe--and, the caller should have
   * already renewed the entry */
  if(use_mutex == TRUE) {
      P_w(&pentry_parent->lock);

      cache_status = cache_inode_renew_entry(pentry_parent, pattr, ht,
                                             pclient, pcontext, pstatus);
      if(cache_status != CACHE_INODE_SUCCESS)
      {
          V_w(&pentry_parent->lock);
          inc_func_err_retryable(pclient, CACHE_INODE_GETATTR);
          LogDebug(COMPONENT_CACHE_INODE,
                       "cache_inode_lookup: returning %d(%s) from cache_inode_renew_entry",
                       *pstatus, cache_inode_err_str(*pstatus));
          return NULL;
      }

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

  if(pentry_parent->internal_md.type != DIRECTORY)
    {
      /* Parent is no directory base, return NULL */
      *pstatus = CACHE_INODE_NOT_A_DIRECTORY;

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

      if(use_mutex == TRUE)
        V_r(&pentry_parent->lock);

      return NULL;
    }

  /* if name is ".", use the input value */
  if(!FSAL_namecmp(pname, (fsal_name_t *) & FSAL_DOT))
    {
      pentry = pentry_parent;
    }
  else if(!FSAL_namecmp(pname, (fsal_name_t *) & FSAL_DOT_DOT))
    {
      /* Directory do only have exactly one parent. This a limitation in all FS,
       * which implies that hard link are forbidden on directories (so that
       * they exists only in one dir).  Because of this, the parent list is
       * always limited to one element for a dir.  Clients SHOULD never 
       * 'lookup( .. )' in something that is no dir. */
      pentry =
          cache_inode_lookupp_no_mutex(pentry_parent, ht, pclient, pcontext,
                                       pstatus);
    }
  else
    {
      /* This is a "regular lookup" (not on "." or "..") */

      /* Check is user (as specified by the credentials) is authorized to 
       * lookup the directory or not */
      access_mask = FSAL_MODE_MASK_SET(FSAL_X_OK) |
                    FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_LIST_DIR);
      if(cache_inode_access_no_mutex(pentry_parent,
                                     access_mask,
                                     ht,
                                     pclient,
                                     pcontext,
                                     pstatus) != CACHE_INODE_SUCCESS)
        {
          if(use_mutex == TRUE)
            V_r(&pentry_parent->lock);

          (pclient->stat.func_stats.nb_err_retryable[CACHE_INODE_GETATTR])++;
          return NULL;
        }

      /* We first try avltree_lookup by name.  If that fails, we dispatch to
       * the fsal. */

      FSAL_namecpy(&dirent_key->name, pname);
      dirent_node = avltree_lookup(&dirent_key->node_n,
				   &pentry_parent->object.dir.dentries);
      if (dirent_node) {
      	  dirent = avltree_container_of(dirent_node, cache_inode_dir_entry_t,
					node_n);
	  pentry = dirent->pentry;
      }

      if(pentry == NULL)
        {
          LogDebug(COMPONENT_CACHE_INODE, "Cache Miss detected");

          dir_handle = pentry_parent->handle;
          object_attributes.asked_attributes = pclient->attrmask;
#ifdef _USE_MFSL

#ifdef _USE_MFSL_ASYNC
          if(!mfsl_async_is_object_asynchronous(&pentry_parent->mobject))
            {
              /* If the parent is asynchronous, rely on the content of the cache
               * inode parent entry.
               *
               * /!\ If the fs behind the FSAL is touched in a non-nfs way,
               * there will be huge incoherencies.
               */
#endif                          /* _USE_MFSL_ASYNC */

              fsal_status = MFSL_lookup(&pentry_parent->mobject,
                                        pname,
                                        pcontext,
                                        &pclient->mfsl_context,
                                        &object_handle, &object_attributes, NULL);
#ifdef _USE_MFSL_ASYNC
            }
          else
            {
              LogMidDebug(COMPONENT_CACHE_INODE,
                       "cache_inode_lookup chose to bypass FSAL and trusted his cache for name=%s",
                       pname->name);
              fsal_status.major = ERR_FSAL_NOENT;
              fsal_status.minor = ENOENT;
            }
#endif                          /* _USE_MFSL_ASYNC */

#else
          fsal_status =
              FSAL_lookup(&dir_handle, pname, pcontext, &object_handle,
                          &object_attributes);
#endif                          /* _USE_MFSL */

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

              if(use_mutex == TRUE)
                V_r(&pentry_parent->lock);

              /* Stale File Handle to be detected and managed */
              if(fsal_status.major == ERR_FSAL_STALE)
                {
                  cache_inode_status_t kill_status;

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

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

                  *pstatus = CACHE_INODE_FSAL_ESTALE;
                }

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

              return NULL;
            }

          type = cache_inode_fsal_type_convert(object_attributes.type);

          /* If entry is a symlink, this value for be cached */
          if(type == SYMBOLIC_LINK)
            {
              if( CACHE_INODE_KEEP_CONTENT( policy ) )
#ifdef _USE_MFSL
               {
                fsal_status =
                    MFSL_readlink(&object_handle, pcontext, &pclient->mfsl_context,
                                  &create_arg.link_content, &object_attributes, NULL);
               }
#else
               {
                fsal_status =
                    FSAL_readlink(&object_handle, pcontext, &create_arg.link_content,
                                  &object_attributes);
               }
             else
              { 
                 fsal_status.major = ERR_FSAL_NO_ERROR ;
                 fsal_status.minor = 0 ;
              }
#endif
              if(FSAL_IS_ERROR(fsal_status))
                {
                  *pstatus = cache_inode_error_convert(fsal_status);
                  if(use_mutex == TRUE)
                    V_r(&pentry_parent->lock);

                  /* Stale File Handle to be detected and managed */
                  if(fsal_status.major == ERR_FSAL_STALE)
                    {
                      cache_inode_status_t kill_status;

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

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

                      *pstatus = CACHE_INODE_FSAL_ESTALE;
                    }

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

                  return NULL;
                }
            }

          /* Allocation of a new entry in the cache */
#ifdef _USE_MFSL
          new_entry_fsdata.handle = object_handle.handle;
#else
          new_entry_fsdata.handle = object_handle;
#endif
          new_entry_fsdata.cookie = 0;

          if((pentry = cache_inode_new_entry( &new_entry_fsdata, 
                                              &object_attributes,
                                              type, 
                                              policy,
                                              &create_arg, 
                                              NULL, 
                                              ht, 
                                              pclient, 
                                              pcontext, 
                                              FALSE,      /* This is a population and not a creation */
                                              pstatus ) ) == NULL )
            {
              if(use_mutex == TRUE)
                V_r(&pentry_parent->lock);

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

              return NULL;
            }

          /* Entry was found in the FSAL, add this entry to the parent
           * directory */
          cache_status = cache_inode_add_cached_dirent(pentry_parent,
                                                       pname,
                                                       pentry,
                                                       ht,
						       &new_dir_entry,
						       pclient,
						       pcontext,
						       pstatus);

          if(cache_status != CACHE_INODE_SUCCESS
             && cache_status != CACHE_INODE_ENTRY_EXISTS)
            {
              if(use_mutex == TRUE)
                V_r(&pentry_parent->lock);

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

              return NULL;
            }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            return NULL;
            break;
        }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

       return pentry;
}
예제 #3
0
/**
 *
 * cache_inode_readdir_populate: fully reads a directory in FSAL and caches
 * the related entries.
 *
 * fully reads a directory in FSAL and caches the related entries. No MT
 * safety managed here !!
 *
 * @param pentry [IN]  entry for the parent directory to be read. This must be
 * a DIRECTORY
 * @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.
 *
 */
cache_inode_status_t cache_inode_readdir_populate(
    cache_entry_t * pentry_dir,
    cache_inode_policy_t policy,
    hash_table_t * ht,
    cache_inode_client_t * pclient,
    fsal_op_context_t * pcontext,
    cache_inode_status_t * pstatus)
{
  fsal_dir_t fsal_dirhandle;
  fsal_status_t fsal_status;
  fsal_attrib_list_t dir_attributes;

  fsal_cookie_t begin_cookie;
  fsal_cookie_t end_cookie;
  fsal_count_t nbfound;
  fsal_count_t iter;
  fsal_boolean_t fsal_eod;

  cache_entry_t *pentry = NULL;
  cache_entry_t *pentry_parent = pentry_dir;
  fsal_attrib_list_t object_attributes;

  cache_inode_create_arg_t create_arg;
  cache_inode_file_type_t type;
  cache_inode_status_t cache_status;
  fsal_dirent_t array_dirent[FSAL_READDIR_SIZE + 20];
  cache_inode_fsal_data_t new_entry_fsdata;
  cache_inode_dir_entry_t *new_dir_entry = NULL;
  uint64_t i = 0;

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

  /* Only DIRECTORY entries are concerned */
  if(pentry_dir->internal_md.type != DIRECTORY)
    {
      *pstatus = CACHE_INODE_BAD_TYPE;
      return *pstatus;
    }
#ifdef _USE_MFSL_ASYNC
  /* If entry is asynchronous (via MFSL), it should not be repopulated until
     it is synced */
  if(MFSL_ASYNC_is_synced(&pentry_dir->mobject) == FALSE)
    {
      /* Directory is asynchronous, do not repopulate it and let it
       * in the state 'has_been_readdir == FALSE' */
      *pstatus = CACHE_INODE_SUCCESS;
      return *pstatus;
    }
#endif

  /* If directory is already populated , there is no job to do */
  if(pentry_dir->object.dir.has_been_readdir == CACHE_INODE_YES)
    {
      *pstatus = CACHE_INODE_SUCCESS;
      return *pstatus;
    }

  /* Invalidate all the dirents */
  if(cache_inode_invalidate_all_cached_dirent(pentry_dir,
                                              ht,
                                              pclient,
					      pstatus) != CACHE_INODE_SUCCESS)
    return *pstatus;

  /* Open the directory */
  dir_attributes.asked_attributes = pclient->attrmask;
#ifdef _USE_MFSL
  fsal_status = MFSL_opendir(&pentry_dir->mobject,
                             pcontext,
                             &pclient->mfsl_context, &fsal_dirhandle, &dir_attributes, NULL);
#else
  fsal_status = FSAL_opendir(&pentry_dir->object.dir.handle,
                             pcontext, &fsal_dirhandle, &dir_attributes);
#endif
  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_readdir: Stale FSAL File Handle detected for pentry = %p, fsal_status=(%u,%u)",
                   pentry_dir, fsal_status.major, fsal_status.minor);

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

          *pstatus = CACHE_INODE_FSAL_ESTALE;
        }
      return *pstatus;
    }

  /* Loop for readding the directory */
  FSAL_SET_COOKIE_BEGINNING(begin_cookie);
  FSAL_SET_COOKIE_BEGINNING(end_cookie);
  fsal_eod = FALSE;

  do
    {
#ifdef _USE_MFSL
      fsal_status = MFSL_readdir(&fsal_dirhandle,
                                 begin_cookie,
                                 pclient->attrmask,
                                 FSAL_READDIR_SIZE * sizeof(fsal_dirent_t),
                                 array_dirent,
                                 &end_cookie,
                                 &nbfound, &fsal_eod, &pclient->mfsl_context, NULL);
#else
      fsal_status = FSAL_readdir(&fsal_dirhandle,
                                 begin_cookie,
                                 pclient->attrmask,
                                 FSAL_READDIR_SIZE * sizeof(fsal_dirent_t),
                                 array_dirent, &end_cookie, &nbfound, &fsal_eod);
#endif

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

      for(iter = 0; iter < nbfound; iter++)
        {
          LogFullDebug(COMPONENT_NFS_READDIR,
                       "cache readdir populate found entry %s",
                       array_dirent[iter].name.name);

          /* It is not needed to cache '.' and '..' */
          if(!FSAL_namecmp(&(array_dirent[iter].name), (fsal_name_t *) & FSAL_DOT) ||
             !FSAL_namecmp(&(array_dirent[iter].name), (fsal_name_t *) & FSAL_DOT_DOT))
            {
              LogFullDebug(COMPONENT_NFS_READDIR,
                           "cache readdir populate : do not cache . and ..");
              continue;
            }

          /* If dir entry is a symbolic link, its content has to be read */
          if((type =
              cache_inode_fsal_type_convert(array_dirent[iter].attributes.type)) ==
             SYMBOLIC_LINK)
            {
#ifdef _USE_MFSL
              mfsl_object_t tmp_mfsl;
#endif
              /* Let's read the link for caching its value */
              object_attributes.asked_attributes = pclient->attrmask;
              if( CACHE_INODE_KEEP_CONTENT( pentry_dir->policy ) )
                {
#ifdef _USE_MFSL
                  tmp_mfsl.handle = array_dirent[iter].handle;
                  fsal_status = MFSL_readlink(&tmp_mfsl,
                                              pcontext,
                                              &pclient->mfsl_context,
                                              &create_arg.link_content, &object_attributes, NULL);
#else
                  fsal_status = FSAL_readlink(&array_dirent[iter].handle,
                                              pcontext,
                                              &create_arg.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);

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

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

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

                      *pstatus = CACHE_INODE_FSAL_ESTALE;
                    }

                  return *pstatus;
                }
            }

          /* Try adding the entry, if it exists then this existing entry is
             returned */
          new_entry_fsdata.handle = array_dirent[iter].handle;
	  new_entry_fsdata.cookie = 0; /* XXX needed? */

          if((pentry = cache_inode_new_entry( &new_entry_fsdata,
		                              &array_dirent[iter].attributes,
		                              type, 
                                              policy,
		                              &create_arg,
		                              NULL, 
		                              ht, 
		                              pclient, 
		                              pcontext, 
		                              FALSE,  /* This is population and no creation */
		                              pstatus)) == NULL)
            return *pstatus;

          cache_status = cache_inode_add_cached_dirent(
	      pentry_parent,
	      &(array_dirent[iter].name),
	      pentry,
	      ht,
	      &new_dir_entry,
	      pclient,
	      pcontext,
	      pstatus);

          if(cache_status != CACHE_INODE_SUCCESS
             && cache_status != CACHE_INODE_ENTRY_EXISTS)
            return *pstatus;

          /*
           * Remember the FSAL readdir cookie associated with this dirent.  This
           * is needed for partial directory reads.
           * 
           * to_uint64 should be a lightweight operation--it is in the current
           * default implementation.  We think the right thing -should- happen
           * therefore with if _USE_MFSL. 
           *
           * I'm ignoring the status because the default operation is a memcmp--
           * we lready -have- the cookie. */

          if (cache_status != CACHE_INODE_ENTRY_EXISTS) {

              (void) FSAL_cookie_to_uint64(&array_dirent[iter].handle,
                                           pcontext, &array_dirent[iter].cookie,
                                           &new_dir_entry->fsal_cookie);

              /* we are filling in all entries, and the cookie avl was
               * cleared before adding dirents */
              new_dir_entry->cookie = i; /* still an offset */
              (void) avltree_insert(&new_dir_entry->node_c,
                                    &pentry_parent->object.dir.cookies);
          } /* !exist */

        } /* iter */
      
      /* Get prepared for next step */
      begin_cookie = end_cookie;

      /* next offset */
      i++;
    }
  while(fsal_eod != TRUE);

  /* Close the directory */
#ifdef _USE_MFSL
  fsal_status = MFSL_closedir(&fsal_dirhandle, &pclient->mfsl_context, NULL);
#else
  fsal_status = FSAL_closedir(&fsal_dirhandle);
#endif
  if(FSAL_IS_ERROR(fsal_status))
    {
      *pstatus = cache_inode_error_convert(fsal_status);
      return *pstatus;
    }

  /* End of work */
  pentry_dir->object.dir.has_been_readdir = CACHE_INODE_YES;
  *pstatus = CACHE_INODE_SUCCESS;
  return *pstatus;
}                               /* cache_inode_readdir_populate */
예제 #4
0
cache_entry_t *
cache_inode_create(cache_entry_t *parent,
                   fsal_name_t *name,
                   cache_inode_file_type_t type,
                   fsal_accessmode_t mode,
                   cache_inode_create_arg_t *create_arg,
                   fsal_attrib_list_t *attr,
                   fsal_op_context_t *context,
                   cache_inode_status_t *status)
{
     cache_entry_t *entry = NULL;
     fsal_status_t fsal_status = {0, 0};
     fsal_handle_t object_handle;
     fsal_attrib_list_t object_attributes;
     cache_inode_fsal_data_t fsal_data;
     cache_inode_create_arg_t zero_create_arg;

     memset(&zero_create_arg, 0, sizeof(zero_create_arg));
     memset(&fsal_data, 0, sizeof(fsal_data));
     memset(&object_handle, 0, sizeof(object_handle));

     if (create_arg == NULL) {
          create_arg = &zero_create_arg;
     }

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

     if ((type != REGULAR_FILE) && (type != DIRECTORY) &&
         (type != SYMBOLIC_LINK) && (type != SOCKET_FILE) &&
         (type != FIFO_FILE) && (type != CHARACTER_FILE) &&
         (type != BLOCK_FILE)) {
          *status = CACHE_INODE_BAD_TYPE;

          entry = NULL;
          goto out;
        }

     /* Check if an entry of the same name exists */
     entry = cache_inode_lookup(parent,
                                name,
                                attr,
                                context,
                                status);
     if (entry != NULL) {
          *status = CACHE_INODE_ENTRY_EXISTS;
          if (entry->type != type) {
               /* Incompatible types, returns NULL */
               cache_inode_lru_unref(entry, LRU_FLAG_NONE);
               entry = NULL;
               goto out;
          } else {
               goto out;
          }
     }

     /* The entry doesn't exist, so we can create it. */

     object_attributes.asked_attributes = cache_inode_params.attrmask;
     switch (type) {
     case REGULAR_FILE:
          fsal_status = FSAL_create(&parent->handle,
                                    name, context, mode,
                                    &object_handle, &object_attributes);
          break;

     case DIRECTORY:
          fsal_status = FSAL_mkdir(&parent->handle,
                                   name, context, mode,
                                   &object_handle, &object_attributes);
          break;

     case SYMBOLIC_LINK:
          fsal_status = FSAL_symlink(&parent->handle,
                                     name, &create_arg->link_content,
                                     context, mode, &object_handle,
                                     &object_attributes);
          break;

     case SOCKET_FILE:
          fsal_status = FSAL_mknode(&parent->handle, name, context,
                                    mode, FSAL_TYPE_SOCK, NULL,
                                    &object_handle, &object_attributes);
          break;

     case FIFO_FILE:
          fsal_status = FSAL_mknode(&parent->handle, name, context,
                                    mode, FSAL_TYPE_FIFO, NULL,
                                    &object_handle, &object_attributes);
          break;

     case BLOCK_FILE:
          fsal_status = FSAL_mknode(&parent->handle,
                                    name, context,
                                    mode, FSAL_TYPE_BLK,
                                    &create_arg->dev_spec,
                                    &object_handle, &object_attributes);
             break;

     case CHARACTER_FILE:
          fsal_status = FSAL_mknode(&parent->handle,
                                    name, context,
                                    mode, FSAL_TYPE_CHR,
                                    &create_arg->dev_spec,
                                    &object_handle,
                                    &object_attributes);
          break;

     default:
          /* we should never go there */
          *status = CACHE_INODE_INCONSISTENT_ENTRY;
          entry = NULL;
          goto out;
          break;
        }

     /* Check for the result */
     if (FSAL_IS_ERROR(fsal_status)) {
          if (fsal_status.major == ERR_FSAL_STALE) {
               LogEvent(COMPONENT_CACHE_INODE,
                        "FSAL returned STALE on create type %d",
                        type);
               cache_inode_kill_entry(parent);
          }
          *status = cache_inode_error_convert(fsal_status);
          entry = NULL;
          goto out;
     }
     fsal_data.fh_desc.start = (caddr_t) &object_handle;
     fsal_data.fh_desc.len = 0;
     FSAL_ExpandHandle(context->export_context,
                       FSAL_DIGEST_SIZEOF,
                       &fsal_data.fh_desc);

     entry = cache_inode_new_entry(&fsal_data,
                                   &object_attributes,
                                   type,
                                   create_arg,
                                   status);
     if (entry == NULL) {
          *status = CACHE_INODE_INSERT_ERROR;

          return NULL;
     }

     PTHREAD_RWLOCK_WRLOCK(&parent->content_lock);
     /* Add this entry to the directory (also takes an internal ref) */
     cache_inode_add_cached_dirent(parent,
                                   name, entry,
                                   NULL,
                                   status);
     PTHREAD_RWLOCK_UNLOCK(&parent->content_lock);
     if (*status != CACHE_INODE_SUCCESS) {
          cache_inode_lru_unref(entry, LRU_FLAG_NONE);
          entry = NULL;
          goto out;
     }

     PTHREAD_RWLOCK_WRLOCK(&parent->attr_lock);
     /* Update the parent cached attributes */
     cache_inode_set_time_current(&parent->attributes.mtime);
     parent->attributes.ctime = parent->attributes.mtime;
     /* if the created object is a directory, it contains a link
        to its parent : '..'. Thus the numlink attr must be increased. */
     if (type == DIRECTORY) {
          ++(parent->attributes.numlinks);
     }
     PTHREAD_RWLOCK_UNLOCK(&parent->attr_lock);

     /* Copy up the child attributes */
     *attr = object_attributes;

     *status = CACHE_INODE_SUCCESS;

out:

     return entry;
}
예제 #5
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 */
cache_inode_status_t
cache_inode_create(cache_entry_t *parent,
                   const char *name,
                   object_file_type_t type,
                   uint32_t mode,
                   cache_inode_create_arg_t *create_arg,
                   struct req_op_context *req_ctx,
                   cache_entry_t **entry)
{
     cache_inode_status_t status = CACHE_INODE_SUCCESS;
     fsal_status_t fsal_status = {0, 0};
     struct fsal_obj_handle *object_handle;
     struct attrlist object_attributes;
     struct fsal_obj_handle *dir_handle;
     cache_inode_create_arg_t zero_create_arg;
     fsal_accessflags_t access_mask = 0;

     memset(&zero_create_arg, 0, sizeof(zero_create_arg));
     memset(&object_attributes, 0, sizeof(object_attributes));

     if (create_arg == NULL) {
          create_arg = &zero_create_arg;
     }

     if ((type != REGULAR_FILE) && (type != DIRECTORY) &&
         (type != SYMBOLIC_LINK) && (type != SOCKET_FILE) &&
         (type != FIFO_FILE) && (type != CHARACTER_FILE) &&
         (type != BLOCK_FILE)) {
          status = CACHE_INODE_BAD_TYPE;

          *entry = NULL;
          goto out;
        }

    /*
     * 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 |
                                     FSAL_ACE_PERM_ADD_SUBDIRECTORY);
    status = cache_inode_access(parent,
                                access_mask,
                                req_ctx);
    if (status != CACHE_INODE_SUCCESS)
        {
          *entry = NULL;
          goto out;
        }

    /* Try to create it first */

    dir_handle = parent->obj_handle;
/* we pass in attributes to the create.  We will get them back below */
    FSAL_SET_MASK(object_attributes.mask, ATTR_MODE|ATTR_OWNER|ATTR_GROUP);
    object_attributes.owner = req_ctx->creds->caller_uid;
    object_attributes.group = req_ctx->creds->caller_gid; /* be more selective? */
    object_attributes.mode = mode;

    switch (type) {
    case REGULAR_FILE:
            fsal_status = dir_handle->ops->create(dir_handle, req_ctx,
                                                  name,
                                                  &object_attributes,
                                                  &object_handle);
            break;

    case DIRECTORY:
            fsal_status = dir_handle->ops->mkdir(dir_handle, req_ctx,
                                                 name,
                                                 &object_attributes,
                                                 &object_handle);
            break;

    case SYMBOLIC_LINK:
            fsal_status = dir_handle->ops->symlink(dir_handle, req_ctx,
                                                   name,
                                                   create_arg->link_content,
                                                   &object_attributes,
                                                   &object_handle);
            break;

        case SOCKET_FILE:
        case FIFO_FILE:
            fsal_status = dir_handle->ops->mknode(dir_handle, req_ctx,
                                                  name,
                                                  type,
                                                  NULL, /* no dev_t needed */
                                                  &object_attributes,
                                                  &object_handle);
            break;

        case BLOCK_FILE:
        case CHARACTER_FILE:
            fsal_status = dir_handle->ops->mknode(dir_handle, req_ctx,
                                                  name,
                                                  type,
                                                  &create_arg->dev_spec,
                                                  &object_attributes,
                                                  &object_handle);
            break;

    default:
            /* we should never go there */
            status = CACHE_INODE_INCONSISTENT_ENTRY;
            *entry = NULL;
            goto out;
            break;
    }

     cache_inode_refresh_attrs_locked(parent, req_ctx);

     /* Check for the result */
     if (FSAL_IS_ERROR(fsal_status)) {
          if (fsal_status.major == ERR_FSAL_STALE) {
               LogEvent(COMPONENT_CACHE_INODE,
                        "FSAL returned STALE on create type %d", type);
               cache_inode_kill_entry(parent);
          } else if (fsal_status.major == ERR_FSAL_EXIST) {
               /* Already exists. Check if type if correct */
               status = cache_inode_lookup(parent,
                                           name,
                                           req_ctx,
                                           entry);
               if (*entry != NULL) {
                    status = CACHE_INODE_ENTRY_EXISTS;
                    if ((*entry)->type != type) {
                         /* Incompatible types, returns NULL */
                         cache_inode_put(*entry);
                         *entry = NULL;
                    }
                    goto out;
               }

               if (status == CACHE_INODE_NOT_FOUND) {
                    /* Too bad, FSAL insist the file exists when we try to
                     * create it, but lookup couldn't find it, retry. */
                    status = CACHE_INODE_INCONSISTENT_ENTRY;
                    goto out;
               }
          }

          status = cache_inode_error_convert(fsal_status);
          *entry = NULL;
          goto out;
     }
     status = cache_inode_new_entry(object_handle,
				    CACHE_INODE_FLAG_CREATE,
				    entry);
     if (*entry == NULL) {
          goto out;
     }

     PTHREAD_RWLOCK_wrlock(&parent->content_lock);
     /* Add this entry to the directory (also takes an internal ref) */
     status = cache_inode_add_cached_dirent(parent,
					    name,
					    *entry,
					    NULL);
     PTHREAD_RWLOCK_unlock(&parent->content_lock);
     if (status != CACHE_INODE_SUCCESS) {
          cache_inode_put(*entry);
          *entry = NULL;
          goto out;
     }

out:
     return status;
}
예제 #7
0
static bool
populate_dirent(const char *name, void *dir_state,
		fsal_cookie_t cookie)
{
	struct cache_inode_populate_cb_state *state =
	    (struct cache_inode_populate_cb_state *)dir_state;
	struct fsal_obj_handle *entry_hdl;
	cache_inode_dir_entry_t *new_dir_entry = NULL;
	cache_entry_t *cache_entry = NULL;
	fsal_status_t fsal_status = { 0, 0 };
	struct fsal_obj_handle *dir_hdl = state->directory->obj_handle;

	fsal_status = dir_hdl->obj_ops.lookup(dir_hdl, name, &entry_hdl);
	if (FSAL_IS_ERROR(fsal_status)) {
		*state->status = cache_inode_error_convert(fsal_status);
		if (*state->status == CACHE_INODE_FSAL_XDEV) {
			LogInfo(COMPONENT_NFS_READDIR,
				"Ignoring XDEV entry %s",
				name);
			*state->status = CACHE_INODE_SUCCESS;
			return true;
		}
		LogInfo(COMPONENT_CACHE_INODE,
			"Lookup failed on %s in dir %p with %s",
			name, dir_hdl, cache_inode_err_str(*state->status));
		return !cache_param.retry_readdir;
	}

	LogFullDebug(COMPONENT_NFS_READDIR, "Creating entry for %s", name);

	*state->status =
	    cache_inode_new_entry(entry_hdl, CACHE_INODE_FLAG_NONE,
				  &cache_entry);

	if (cache_entry == NULL) {
		*state->status = CACHE_INODE_NOT_FOUND;
		/* we do not free entry_hdl because it is consumed by
		   cache_inode_new_entry */
		LogEvent(COMPONENT_NFS_READDIR,
			 "cache_inode_new_entry failed with %s",
			 cache_inode_err_str(*state->status));
		return false;
	}

	if (cache_entry->type == DIRECTORY) {
		/* Insert Parent's key */
		cache_inode_key_dup(&cache_entry->object.dir.parent,
				    &state->directory->fh_hk.key);
	}

	*state->status =
	    cache_inode_add_cached_dirent(state->directory, name, cache_entry,
					  &new_dir_entry);
	/* return initial ref */
	cache_inode_put(cache_entry);

	if ((*state->status != CACHE_INODE_SUCCESS) &&
	    (*state->status != CACHE_INODE_ENTRY_EXISTS)) {
		LogEvent(COMPONENT_NFS_READDIR,
			 "cache_inode_add_cached_dirent failed with %s",
			 cache_inode_err_str(*state->status));
		return false;
	}

	return true;
}
예제 #8
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 */
예제 #9
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 */