Esempio n. 1
0
/**
 * 
 * HashTable_Del: Remove a (key,val) couple from the hashtable.
 *
 * Remove a (key,val) couple from the hashtable. The parameter buffkey contains the key which describes the object to be removed
 * from the hash table. 
 *
 * @param ht the hashtable to be used.
 * @param buffkey a pointeur to an object of type hash_buffer_t which describe the key location in memory.
 * @param pusedbuffkeydata the key data buffer that was associated with this entry. Not considered if equal to NULL.
 *
 * @return HASHTABLE_SUCCESS if successfull\n.
 * @return HASHTABLE_ERROR_NO_SUCH_KEY is the key was not found.
 *
 * @see HashTable_Set
 * @see HashTable_Init
 * @see HashTable_Get
 */
int HashTable_Del(hash_table_t * ht, hash_buffer_t * buffkey,
                  hash_buffer_t * p_usedbuffkey, hash_buffer_t * p_usedbuffdata)
{
  unsigned int hashval;
  struct rbt_node *pn;
  int rbt_value = 0;
  struct rbt_head *tete_rbt;
  hash_data_t *pdata = NULL;
  int rc = 0;

  /* Sanity check */
  if(ht == NULL || buffkey == NULL)
    return HASHTABLE_ERROR_INVALID_ARGUMENT;

  /* Find the RB Tree to be processed */
  hashval = (*(ht->parameter.hash_func_key)) (&ht->parameter, buffkey);

  /* Find the entry to be deleted */
  rbt_value = (*(ht->parameter.hash_func_rbt)) (&ht->parameter, buffkey);

  /* acquire mutex */
  P_w(&(ht->array_lock[hashval]));

  /* We didn't find anything */
  if((rc = Key_Locate(ht, buffkey, hashval, rbt_value, &pn)) != HASHTABLE_SUCCESS)
    {
      ht->stat_dynamic[hashval].notfound.nb_del += 1;
      V_w(&(ht->array_lock[hashval]));
      return rc;
    }

  pdata = (hash_data_t *) RBT_OPAQ(pn);

  /* Return the key buffer back to the end user if pusedbuffkey isn't NULL */
  if(p_usedbuffkey != NULL)
    *p_usedbuffkey = pdata->buffkey;

  if(p_usedbuffdata != NULL)
    *p_usedbuffdata = pdata->buffval;

  /* Key was found */
  tete_rbt = &(ht->array_rbt[hashval]);
  RBT_UNLINK(tete_rbt, pn);

  /* the key was located, the deletion is done */
  ht->stat_dynamic[hashval].nb_entries -= 1;

  /* put back the pdata buffer to pool */
  RELEASE_PREALLOC(pdata, ht->pdata_prealloc[hashval], next_alloc);

  /* Put the node back in the table of preallocated nodes (it could be reused) */
  RELEASE_PREALLOC(pn, ht->node_prealloc[hashval], next);

  ht->stat_dynamic[hashval].ok.nb_del += 1;

  /* release mutex */
  V_w(&(ht->array_lock[hashval]));

  return HASHTABLE_SUCCESS;
}                               /*  HashTable_Del */
Esempio n. 2
0
int cache_inode_gc_fd_func(LRU_entry_t * plru_entry, void *addparam)
{
  cache_entry_t *pentry = NULL;
  cache_inode_param_gc_t *pgcparam = (cache_inode_param_gc_t *) addparam;
  cache_inode_status_t status;

  /* Get the entry */
  pentry = (cache_entry_t *) (plru_entry->buffdata.pdata);

  /* check if a file descriptor is opened on the file for a long time */

  if((pentry->internal_md.type == REGULAR_FILE)
     && (pentry->object.file.open_fd.fileno != 0)
     && (time(NULL) - pentry->object.file.open_fd.last_op > pgcparam->pclient->retention))
    {
      P_w(&pentry->lock);
      cache_inode_close(pentry, pgcparam->pclient, &status);
      V_w(&pentry->lock);

      pgcparam->nb_to_be_purged--;
    }

  /* return true for continuing */
  if(pgcparam->nb_to_be_purged == 0)
    return FALSE;
  else
    return TRUE;
}
Esempio n. 3
0
/**
 *
 * cache_inode_gc_suppress_file: suppress a file entry from the cache inode.
 *
 * Suppress a file entry from the cache inode.
 *
 * @param pentry [IN] pointer to the entry to be suppressed.
 *
 * @return LRU_LIST_SET_INVALID if entry is successfully suppressed, LRU_LIST_DO_NOT_SET_INVALID otherwise
 *
 * @see LRU_invalidate_by_function
 * @see LRU_gc_invalid
 *
 */
int cache_inode_gc_suppress_file(cache_entry_t * pentry,
                                 cache_inode_param_gc_t * pgcparam)
{
  P_w(&pentry->lock);

  LogFullDebug(COMPONENT_CACHE_INODE_GC,
               "Entry %p (REGULAR_FILE/SYMBOLIC_LINK) will be garbaged",
               pentry);

  /* Set the entry as invalid */
  pentry->internal_md.valid_state = INVALID;

  LogFullDebug(COMPONENT_CACHE_INODE_GC,
               "****> cache_inode_gc_suppress_file on %p",
               pentry);

  /* Remove refences in the parent entries */
  if(cache_inode_gc_invalidate_related_dirent(pentry, pgcparam) != LRU_LIST_SET_INVALID)
    {
      V_w(&pentry->lock);
      return LRU_LIST_DO_NOT_SET_INVALID;
    }

  /* Clean the entry */
  if(cache_inode_gc_clean_entry(pentry, pgcparam) != LRU_LIST_SET_INVALID)
    return LRU_LIST_DO_NOT_SET_INVALID;

  /* Mutex has already been freed at destruction time */

  return LRU_LIST_SET_INVALID;
}                               /* cache_inode_gc_suppress_file */
int ___cache_content_invalidate_flushed(LRU_entry_t * plru_entry, void *addparam)
{
  cache_content_entry_t *pentry = NULL;
  cache_content_client_t *pclient = NULL;

  pentry = (cache_content_entry_t *) plru_entry->buffdata.pdata;
  pclient = (cache_content_client_t *) addparam;

  if(pentry->local_fs_entry.sync_state != SYNC_OK)
    {
      /* Entry is not to be set invalid */
      return LRU_LIST_DO_NOT_SET_INVALID;
    }

  /* Clean up and set the entry invalid */
  P_w(&pentry->pentry_inode->lock);
  pentry->pentry_inode->object.file.pentry_content = NULL;
  V_w(&pentry->pentry_inode->lock);

  /* Release the entry */
  ReleaseToPool(pentry, &pclient->content_pool);

  /* Retour de la pentry dans le pool */
  return LRU_LIST_SET_INVALID;
}                               /* cache_content_invalidate_flushed */
/* set/update informations about a handle */
int fsal_posixdb_UpdateInodeCache(posixfsal_handle_t * p_handle)        /* IN */
{
#ifdef _ENABLE_CACHE_PATH

  unsigned int i;

  LogDebug(COMPONENT_FSAL, "UpdateInodeCache: inode_id=%llu", p_handle->info.inode);

  i = hash_cache_path(p_handle->id, p_handle->ts);

  /* in the handle in cache ? */
  P_w(&cache_array[i].entry_lock);

  if(cache_array[i].is_set
     && cache_array[i].handle.id == p_handle->id
     && cache_array[i].handle.ts == p_handle->ts)
    {
      /* update its inode info */
      cache_array[i].handle.info = p_handle->info;
      cache_array[i].info_is_set = TRUE;

      LogDebug(COMPONENT_FSAL, "fsal_posixdb_UpdateInodeCache: %u, %u (existing entry)",
               (unsigned int)(p_handle->id), (unsigned int)(p_handle->ts));

      V_w(&cache_array[i].entry_lock);

      return TRUE;
    }
  LogDebug(COMPONENT_FSAL, "fsal_posixdb_UpdateInodeCache: %u, %u (new entry)",
           (unsigned int)(p_handle->id), (unsigned int)(p_handle->ts));

  /* add it (replace previous handle) */
  cache_array[i].is_set = TRUE;
  cache_array[i].path_is_set = FALSE;
  cache_array[i].info_is_set = TRUE;
  cache_array[i].handle = *p_handle;
  memset(&cache_array[i].path, 0, sizeof(fsal_path_t));

  V_w(&cache_array[i].entry_lock);
#endif
  return FALSE;

}
Esempio n. 6
0
/* Remove a child entry */
int NamespaceRemove(ino_t parent_ino, dev_t parent_dev, unsigned int gen, char *name)
{
  int rc;

  /* lock the namespace for modification */
  P_w(&ns_lock);
  rc = NamespaceRemove_nl(parent_ino, parent_dev, gen, name);
  V_w(&ns_lock);

  return rc;
}
Esempio n. 7
0
void nfs4_acl_entry_inc_ref(fsal_acl_t *pacl)
{
  if(!pacl)
    return;

  /* Increase ref counter */
  P_w(&pacl->lock);
  pacl->ref++;
  LogDebug(COMPONENT_NFS_V4_ACL, "nfs4_acl_entry_inc_ref: (acl, ref) = (%p, %u)", pacl, pacl->ref);
  V_w(&pacl->lock);
}
void fsal_posixdb_CachePath(posixfsal_handle_t * p_handle,      /* IN */
                            fsal_path_t * p_path /* IN */ )
{

#ifdef _ENABLE_CACHE_PATH

  unsigned int i;

  LogDebug(COMPONENT_FSAL, "fsal_posixdb_CachePath: %u, %u = %s", (unsigned int)(p_handle->id),
           (unsigned int)(p_handle->ts), p_path->path);

  i = hash_cache_path(p_handle->id, p_handle->ts);

  /* in the handle already in cache ? */
  P_w(&cache_array[i].entry_lock);

  if(cache_array[i].is_set
     && cache_array[i].handle.id == p_handle->id
     && cache_array[i].handle.ts == p_handle->ts)
    {
      cache_array[i].path_is_set = TRUE;

      /* override it */
      cache_array[i].path = *p_path;

      V_w(&cache_array[i].entry_lock);
      return;
    }

  /* add it (replace previous handle) */
  cache_array[i].is_set = TRUE;
  cache_array[i].path_is_set = TRUE;
  cache_array[i].info_is_set = FALSE;
  cache_array[i].handle = *p_handle;
  cache_array[i].path = *p_path;
  V_w(&cache_array[i].entry_lock);

#endif
  return;
}
Esempio n. 9
0
/* Add a child entry */
int NamespaceAdd(ino_t parent_ino, dev_t parent_dev, unsigned int gen,
                 char *name, ino_t entry_ino, dev_t entry_dev, unsigned int *p_new_gen)
{
  int rc;

  /* lock the namespace for modification */
  P_w(&ns_lock);
  rc = NamespaceAdd_nl(parent_ino, parent_dev, gen, name,
                       entry_ino, entry_dev, p_new_gen);
  V_w(&ns_lock);

  return rc;
}
Esempio n. 10
0
void *thread_writter(void *arg)
{
  int duree_sleep = 1;
  int nb_iter = NB_ITER;

  while(nb_iter > 0)
    {
      P_w(&lock);
      sleep(duree_sleep);
      V_w(&lock);
      nb_iter -= 1;
    }
  OkWrite = 1;                  /* Ecriture concurrente ici, mais on s'en fout (pas d'impact) */
  return NULL;
}                               /* thread_writter */
Esempio n. 11
0
/**
 *
 * cache_inode_kill_entry: force removing an entry from the cache_inode. This is used in case of a 'stale' entry.
 *
 * Force removing an entry from the cache_inode. This is used in case of a 'stale' entry.
 *
 * @param pentry  [IN] the input pentry (supposed to be staled).
 * @param locked  [IN] tells in the entry was previously locked and how it was locked
 * @param ht      [INOUT] the related hash table for the cache_inode cache.
 * @param pclient [INOUT] related cache_inode client.
 * @param pstatus [OUT] status for the operation.
 *
 * @return CACHE_INODE_BAD_TYPE if pentry is not related a REGULAR_FILE or
 * DIRECTORY
 * @return CACHE_INODE_SUCCESS if operation succeded.
 *
 */
static void free_lock( cache_entry_t          * pentry,
                       cache_inode_lock_how_t   lock_how )
{
  switch( lock_how )
    {
      case RD_LOCK:
        V_r( &pentry->lock ) ;
        break ;
 
      case WT_LOCK:
        V_w( &pentry->lock ) ;
        break ;

      case NO_LOCK:
      default:
        break ;
    }
}
Esempio n. 12
0
fsal_status_t dumb_fsal_up_invalidate(fsal_up_event_data_t * pevdata)
{
  cache_inode_status_t cache_status;
  cache_entry_t *pentry = NULL;
  fsal_attrib_list_t attr;

  memset(&attr, 0, sizeof(fsal_attrib_list_t));

  /* Avoid dir cont check in cache_inode_get() */
  pevdata->event_context.fsal_data.cookie = DIR_START;
      LogDebug(COMPONENT_FSAL_UP,
               "FSAL_UP_DUMB: calling cache_inode_get()");
  pentry = cache_inode_get(&pevdata->event_context.fsal_data, cachepol,
                           &attr, pevdata->event_context.ht, NULL, NULL,
                           &cache_status);
  if(pentry == NULL)
    {
      LogDebug(COMPONENT_FSAL_UP,
               "FSAL_UP_DUMB: cache inode get failed.");
      /* Not an error. Expecting some nodes will not have it in cache in
       * a cluster. */
      ReturnCode(ERR_FSAL_NO_ERROR, 0);
    }

  LogDebug(COMPONENT_FSAL_UP,
          "FSAL_UP_DUMB: Invalidate cache found entry %p type %u",
          pentry, pentry->internal_md.type);

  /* Lock the entry */
  P_w(&pentry->lock);
      LogDebug(COMPONENT_FSAL_UP,
               "FSAL_UP_DUMB: setting state to STALE");
  pentry->internal_md.valid_state = STALE;
  if(pentry->internal_md.type == DIRECTORY)
    {
      pentry->object.dir.has_been_readdir = CACHE_INODE_RENEW_NEEDED;
      LogDebug(COMPONENT_FSAL_UP,
              "FSAL_CB_DUMB: Invalidate reset directory.");
    }
  V_w(&pentry->lock);

  ReturnCode(ERR_FSAL_NO_ERROR, 0);
}
Esempio n. 13
0
void fsal_posixdb_InvalidateCache()
{
#ifdef _ENABLE_CACHE_PATH
  unsigned int i;

  LogDebug(COMPONENT_FSAL, "fsal_posixdb_InvalidateCache");

  for(i = 0; i < CACHE_PATH_SIZE; i++)
    {
      P_w(&cache_array[i].entry_lock);
      cache_array[i].is_set = FALSE;
      cache_array[i].path_is_set = FALSE;
      cache_array[i].info_is_set = FALSE;
      cache_array[i].handle.id = 0;
      cache_array[i].handle.ts = 0;
      V_w(&cache_array[i].entry_lock);
    }

#endif
}
Esempio n. 14
0
cache_inode_status_t cache_inode_readlink(cache_entry_t * pentry, fsal_path_t * plink_content, 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)
{
  fsal_status_t fsal_status;
  fsal_attrib_list_t attr ;

  /* 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_READLINK])++;

  /* Lock the entry */
  P_w(&pentry->lock);
  if(cache_inode_renew_entry(pentry, NULL, ht, pclient, pcontext, pstatus) !=
     CACHE_INODE_SUCCESS)
    {
      (pclient->stat.func_stats.nb_err_retryable[CACHE_INODE_READLINK])++;
      V_w(&pentry->lock);
      return *pstatus;
    }
  /* RW_Lock obtained as writer turns to reader */
  rw_lock_downgrade(&pentry->lock);

  switch (pentry->internal_md.type)
    {
    case REGULAR_FILE:
    case DIRECTORY:
    case CHARACTER_FILE:
    case BLOCK_FILE:
    case SOCKET_FILE:
    case FIFO_FILE:
    case UNASSIGNED:
    case FS_JUNCTION:
    case RECYCLED:
      *pstatus = CACHE_INODE_BAD_TYPE;
      V_r(&pentry->lock);

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

      return *pstatus;
      break;

    case SYMBOLIC_LINK:
      assert(pentry->object.symlink);
      if( CACHE_INODE_KEEP_CONTENT( pentry->policy ) )
        {
          fsal_status = FSAL_pathcpy(plink_content, &(pentry->object.symlink->content)); /* need copy ctor? */
        }
      else
        {
           /* Content is not cached, call FSAL_readlink here */
           fsal_status = FSAL_readlink( &pentry->handle, pcontext, plink_content, &attr ) ; 
        }

      if(FSAL_IS_ERROR(fsal_status))
        {
          *pstatus = cache_inode_error_convert(fsal_status);
          V_r(&pentry->lock);

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

              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_readlink: 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_readlink: 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_READLINK] += 1;

          return *pstatus;
        }

      break;
    }

  /* Release the entry */
  *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient);
  V_r(&pentry->lock);

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

  return *pstatus;
}                               /* cache_inode_readlink */
Esempio n. 15
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;
}
Esempio n. 16
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 */
Esempio n. 17
0
/**
 * 
 * HashTable_Test_And_Set: set a pair (key,value) into the Hash Table.
 *
 * Set a (key,val) couple in the hashtable .
 *
 * @param ht the hashtable to be used.
 * @param buffkey a pointeur to an object of type hash_buffer_t which describe the key location in memory.
 * @param buffval a pointeur to an object of type hash_buffer_t which describe the value location in memory.
 * @param how a switch to tell if the entry is to be tested or overwritten or not
 *
 * @return HASHTABLE_SUCCESS if successfull\n.
 * @return HASHTABLE_INSERT_MALLOC_ERROR if an error occured during the insertion process.
 *
 * @see HashTable_Get
 * @see HashTable_Init
 * @see HashTable_Del
 */
int HashTable_Test_And_Set(hash_table_t * ht, hash_buffer_t * buffkey,
                           hash_buffer_t * buffval, hashtable_set_how_t how)
{
  unsigned int hashval = 0;
  int rbt_value = 0;
  struct rbt_head *tete_rbt = NULL;
  struct rbt_node *qn = NULL;
  struct rbt_node *pn = NULL;
  hash_data_t *pdata = NULL;

  /* Sanity check */
  if(ht == NULL)
    return HASHTABLE_ERROR_INVALID_ARGUMENT;
  else if(buffkey == NULL)
    return HASHTABLE_ERROR_INVALID_ARGUMENT;
  else if(buffval == NULL)
    return HASHTABLE_ERROR_INVALID_ARGUMENT;

  /* Find the RB Tree to be used */
  hashval = (*(ht->parameter.hash_func_key)) (&ht->parameter, buffkey);
  tete_rbt = &(ht->array_rbt[hashval]);
  rbt_value = (*(ht->parameter.hash_func_rbt)) (&ht->parameter, buffkey);

  LogFullDebug(COMPONENT_HASHTABLE,"Key = %p   Value = %p  hashval = %u  rbt_value = %x\n", buffkey->pdata,
         buffval->pdata, hashval, rbt_value);

  /* acquire mutex for protection */
  P_w(&(ht->array_lock[hashval]));

  if(Key_Locate(ht, buffkey, hashval, rbt_value, &pn) == HASHTABLE_SUCCESS)
    {
      /* An entry of that key already exists */
      if(how == HASHTABLE_SET_HOW_TEST_ONLY)
        {
          ht->stat_dynamic[hashval].ok.nb_test += 1;
          V_w(&(ht->array_lock[hashval]));
          return HASHTABLE_SUCCESS;
        }

      if(how == HASHTABLE_SET_HOW_SET_NO_OVERWRITE)
        {
          ht->stat_dynamic[hashval].err.nb_test += 1;
          V_w(&(ht->array_lock[hashval]));
          return HASHTABLE_ERROR_KEY_ALREADY_EXISTS;
        }
      qn = pn;
      pdata = RBT_OPAQ(qn);

      LogFullDebug(COMPONENT_HASHTABLE,"Ecrasement d'une ancienne entree (k=%p,v=%p)\n", buffkey->pdata,
             buffval->pdata);

    }
  else
    {
      /* No entry of that key, add it to the trees */
      if(how == HASHTABLE_SET_HOW_TEST_ONLY)
        {
          ht->stat_dynamic[hashval].notfound.nb_test += 1;
          V_w(&(ht->array_lock[hashval]));
          return HASHTABLE_ERROR_NO_SUCH_KEY;
        }

      /* Insert a new node in the table */
      RBT_FIND(tete_rbt, pn, rbt_value);

#ifdef _DEBUG_MEMLEAKS
      /* For debugging memory leaks */
      BuddySetDebugLabel("rbt_node_t");
#endif
      /* This entry does not exist, create it */
      /* First get a new entry in the preallocated node array */
      GET_PREALLOC(qn, ht->node_prealloc[hashval], ht->parameter.nb_node_prealloc,
                   rbt_node_t, next);
      if(qn == NULL)
        {
          ht->stat_dynamic[hashval].err.nb_set += 1;
          V_w(&(ht->array_lock[hashval]));
          return HASHTABLE_INSERT_MALLOC_ERROR;
        }
#ifdef _DEBUG_MEMLEAKS
      /* For debugging memory leaks */
      BuddySetDebugLabel("hash_data_t");
#endif
      GET_PREALLOC(pdata, ht->pdata_prealloc[hashval], ht->parameter.nb_node_prealloc,
                   hash_data_t, next_alloc);
      if(pdata == NULL)
        {
          ht->stat_dynamic[hashval].err.nb_set += 1;
          V_w(&(ht->array_lock[hashval]));
          return HASHTABLE_INSERT_MALLOC_ERROR;
        }
#ifdef _DEBUG_MEMLEAKS
      /* For debugging memory leaks */
      BuddySetDebugLabel("N/A");
#endif
      RBT_OPAQ(qn) = pdata;
      RBT_VALUE(qn) = rbt_value;
      RBT_INSERT(tete_rbt, qn, pn);

      LogFullDebug(COMPONENT_HASHTABLE,"Creation d'une nouvelle entree (k=%p,v=%p), qn=%p, pdata=%p\n",
             buffkey->pdata, buffval->pdata, qn, RBT_OPAQ(qn));
    }

  pdata->buffval.pdata = buffval->pdata;
  pdata->buffval.len = buffval->len;

  pdata->buffkey.pdata = buffkey->pdata;
  pdata->buffkey.len = buffkey->len;

  ht->stat_dynamic[hashval].nb_entries += 1;
  ht->stat_dynamic[hashval].ok.nb_set += 1;

  /* Release mutex */
  V_w(&(ht->array_lock[hashval]));

  return HASHTABLE_SUCCESS;
}                               /* HashTable_Set */
Esempio n. 18
0
/**
 *
 * cache_inode_gc_invalidate_related_dirent: sets the related directory entries as invalid.
 *
 * sets the related directory entries as invalid. /!\ the parent entry is supposed to be locked.
 *
 * @param pentry [INOUT] entry to be managed
 * @param addparam [IN] additional parameter used for cleaning.
 *
 * @return  LRU_LIST_SET_INVALID if ok,  LRU_LIST_DO_NOT_SET_INVALID otherwise
 *
 */
static int cache_inode_gc_invalidate_related_dirent(cache_entry_t * pentry,
                                                    cache_inode_param_gc_t * pgcparam)
{
  cache_inode_parent_entry_t *parent_iter = NULL;

  /* Set the cache status as INVALID in the directory entries */
  for(parent_iter = pentry->parent_list; parent_iter != NULL;
      parent_iter = parent_iter->next_parent)
    {
      if(parent_iter->parent == NULL)
        {
          LogDebug(COMPONENT_CACHE_INODE_GC,
                   "cache_inode_gc_invalidate_related_dirent: pentry %p has no parent, no dirent to be removed...",
                   pentry);
          continue;
        }

      /* If I reached this point, then parent_iter->parent is not null and is a valid cache_inode pentry */
      P_w(&parent_iter->parent->lock);

      /* Check for type of the parent */
      if(parent_iter->parent->internal_md.type != DIR_BEGINNING &&
         parent_iter->parent->internal_md.type != DIR_CONTINUE)
        {
          V_w(&parent_iter->parent->lock);
          /* Major parent incoherency: parent is no directory */
          LogDebug(COMPONENT_CACHE_INODE_GC,
                   "cache_inode_gc_invalidate_related_dirent: major inconcistency. Found an entry whose parent is not a directory");
          return LRU_LIST_DO_NOT_SET_INVALID;
        }

      /* Set the entry as invalid in the dirent array */
      if(parent_iter->parent->internal_md.type == DIR_BEGINNING)
        {
          if(parent_iter->subdirpos > CHILDREN_ARRAY_SIZE)
            {
              V_w(&parent_iter->parent->lock);
              LogCrit(COMPONENT_CACHE_INODE_GC,
                      "A known bug occured line %d file %s: pentry=%p type=%u parent_iter->subdirpos=%d, should never exceed %d, entry not removed",
                      __LINE__, __FILE__, pentry, pentry->internal_md.type,
                      parent_iter->subdirpos, CHILDREN_ARRAY_SIZE);
              return LRU_LIST_DO_NOT_SET_INVALID;
            }
          else
            {
              parent_iter->parent->object.dir_begin.pdir_data->dir_entries[parent_iter->
                                                                           subdirpos].
                  active = INVALID;
              /* Garbage invalidates the effet of the readdir previously made */
              parent_iter->parent->object.dir_begin.has_been_readdir = CACHE_INODE_NO;
              parent_iter->parent->object.dir_begin.nbactive -= 1;
            }
        }
      else
        {
          if(parent_iter->subdirpos > CHILDREN_ARRAY_SIZE)
            {
              V_w(&parent_iter->parent->lock);
              LogCrit(COMPONENT_CACHE_INODE_GC,
                      "A known bug occured line %d file %s: pentry=%p type=%u parent_iter->subdirpos=%d, should never exceed %d, entry not removed",
                      __LINE__, __FILE__, pentry, pentry->internal_md.type,
                      parent_iter->subdirpos, CHILDREN_ARRAY_SIZE);
              return LRU_LIST_DO_NOT_SET_INVALID;
            }
          else
            {
              parent_iter->parent->object.dir_cont.pdir_data->dir_entries[parent_iter->
                                                                          subdirpos].
                  active = INVALID;
              parent_iter->parent->object.dir_cont.nbactive -= 1;
            }
        }

      V_w(&parent_iter->parent->lock);
    }

  return LRU_LIST_SET_INVALID;
}                               /* cache_inode_gc_invalidate_related_dirent */
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_remove_sw: removes a pentry addressed by its parent pentry and
 * its FSAL name.  Mutex management is switched.
 *
 * Removes a pentry addressed by its parent pentry and its FSAL name.  Mutex
 * management is switched.
 *
 * @param pentry  [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.
 *
 * @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_remove_sw(cache_entry_t * pentry,             /**< Parent entry */
                                           fsal_name_t * pnode_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, int use_mutex)
{
  fsal_status_t fsal_status;
  cache_entry_t *to_remove_entry;
  fsal_handle_t fsal_handle_parent;
  fsal_attrib_list_t remove_attr;
  fsal_attrib_list_t after_attr;
  cache_inode_status_t status;
  cache_content_status_t cache_content_status;
  int to_remove_numlinks = 0;
  fsal_accessflags_t access_mask = 0;

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

  /* pentry is a directory */
  if(use_mutex)
    P_w(&pentry->lock);

  /* 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_DELETE_CHILD);
  if((status = cache_inode_access_sw(pentry,
                                     access_mask,
                                     ht,
                                     pclient,
                                     pcontext, &status, FALSE)) != CACHE_INODE_SUCCESS)
    {
      *pstatus = status;

      /* pentry is a directory */
      if(use_mutex)
        V_w(&pentry->lock);

      return *pstatus;
    }

  /* Looks up for the entry to remove */
  if((to_remove_entry = cache_inode_lookup_sw( pentry,
                                               pnode_name,
                                               CACHE_INODE_JOKER_POLICY,
                                               &remove_attr,
                                               ht,
                                               pclient, 
                                               pcontext, 
                                               &status, 
                                               FALSE)) == NULL)
    {
      *pstatus = status;

      /* pentry is a directory */
      if(use_mutex)
        V_w(&pentry->lock);

      return *pstatus;
    }

  /* lock it */
  if(use_mutex)
    P_w(&to_remove_entry->lock);

  if(pentry->internal_md.type != DIRECTORY)
    {
      if(use_mutex)
        {
          V_w(&to_remove_entry->lock);
          V_w(&pentry->lock);
        }

      *pstatus = CACHE_INODE_BAD_TYPE;
      return *pstatus;
    }
  
  LogDebug(COMPONENT_CACHE_INODE,
           "---> Cache_inode_remove : %s", pnode_name->name);

  /* Non-empty directories should not be removed. */
  if(to_remove_entry->internal_md.type == DIRECTORY &&
     to_remove_entry->object.dir.has_been_readdir == CACHE_INODE_YES)
    {
      if(cache_inode_is_dir_empty(to_remove_entry) != CACHE_INODE_SUCCESS)
        {
          if(use_mutex)
            {
              V_w(&to_remove_entry->lock);
              V_w(&pentry->lock);
            }

          *pstatus = CACHE_INODE_DIR_NOT_EMPTY;
          return *pstatus;
        }
    }
    
  /* pentry->internal_md.type == DIRECTORY */
  fsal_handle_parent = pentry->object.dir.handle;

  if(status == CACHE_INODE_SUCCESS)
    {
      /* Remove the file from FSAL */
      after_attr.asked_attributes = pclient->attrmask;
#ifdef _USE_MFSL
      cache_inode_get_attributes(pentry, &after_attr);
#ifdef _USE_PNFS
      after_attr.numlinks = remove_attr.numlinks ; /* Hook used to pass nlinks to MFSL_unlink */
      if( to_remove_entry->internal_md.type == REGULAR_FILE )
        fsal_status = MFSL_unlink(&pentry->mobject,
                                  pnode_name,
                                  &to_remove_entry->mobject,
                                  pcontext, &pclient->mfsl_context, &after_attr,
                                  &to_remove_entry->object.file.pnfs_file );
      else
#endif /* _USE_PNFS */
      fsal_status = MFSL_unlink(&pentry->mobject,
                                pnode_name,
                                &to_remove_entry->mobject,
                                pcontext, &pclient->mfsl_context, &after_attr,
                                NULL);

#else
      fsal_status = FSAL_unlink(&fsal_handle_parent, pnode_name, pcontext, &after_attr);
#endif

      /* Set the 'after' attr */
      if(pattr != NULL)
        *pattr = after_attr;

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

              LogDebug(COMPONENT_CACHE_INODE,
                       "cache_inode_remove: Stale FSAL FH detected for pentry %p",
                       pentry);

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

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }

          *pstatus = cache_inode_error_convert(fsal_status);
          if(use_mutex)
            {
              V_w(&to_remove_entry->lock);
              V_w(&pentry->lock);
            }
          return *pstatus;
        }
    } /* CACHE_INODE_SUCCESS */
  else
    {
      if(use_mutex)
        {
          V_w(&to_remove_entry->lock);
          V_w(&pentry->lock);
        }
      (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_REMOVE])++;
      return status;
    }

  /* Remove the entry from parent dir_entries avl */
  cache_inode_remove_cached_dirent(pentry, pnode_name, ht, pclient, &status);

  LogFullDebug(COMPONENT_CACHE_INODE,
               "cache_inode_remove_cached_dirent: status=%d", status);

  /* Update the cached attributes */
  pentry->object.dir.attributes = after_attr;

  /* Update the attributes for the removed entry */

  if(remove_attr.type != FSAL_TYPE_DIR)
    {
      if(remove_attr.numlinks > 1)
        {
          switch (to_remove_entry->internal_md.type)
            {
            case SYMBOLIC_LINK:
              assert(to_remove_entry->object.symlink);
              to_remove_entry->object.symlink->attributes.numlinks -= 1;
              cache_inode_set_time_current( &to_remove_entry->object.symlink->attributes.ctime ) ;
              to_remove_numlinks = to_remove_entry->object.symlink->attributes.numlinks;
              break;

            case REGULAR_FILE:
              to_remove_entry->object.file.attributes.numlinks -= 1;
              cache_inode_set_time_current( &to_remove_entry->object.file.attributes.ctime ) ;
              to_remove_numlinks = to_remove_entry->object.file.attributes.numlinks;
              break;

            case CHARACTER_FILE:
            case BLOCK_FILE:
            case SOCKET_FILE:
            case FIFO_FILE:
              to_remove_entry->object.special_obj.attributes.numlinks -= 1;
              cache_inode_set_time_current( &to_remove_entry->object.special_obj.attributes.ctime ) ;
              to_remove_numlinks =
                  to_remove_entry->object.special_obj.attributes.numlinks;
              break;

            default:
              /* Other objects should not be hard linked */
              if(use_mutex)
                {
                  V_w(&to_remove_entry->lock);
                  V_w(&pentry->lock);
                }
              *pstatus = CACHE_INODE_BAD_TYPE;
              return *pstatus;
              break;
            }
        }
    }
  else
    {
      /* No hardlink counter to be decremented for a directory: hardlink are not allowed for them */
    }

  /* Now, delete "to_remove_entry" from the cache inode and free its associated resources, but only if
   * numlinks == 0 */
  if(to_remove_numlinks == 0)
    {

      /* If pentry is a regular file, data cached, the related data cache entry should be removed as well */
      if(to_remove_entry->internal_md.type == REGULAR_FILE)
        {
          if(to_remove_entry->object.file.pentry_content != NULL)
            {
              /* Something is to be deleted, release the cache data entry */
              if(cache_content_release_entry
                 ((cache_content_entry_t *) to_remove_entry->object.file.pentry_content,
                  (cache_content_client_t *) pclient->pcontent_client,
                  &cache_content_status) != CACHE_CONTENT_SUCCESS)
                {
                  LogEvent(COMPONENT_CACHE_INODE,
                           "pentry %p, named %s could not be released from data cache, status=%d",
                           to_remove_entry, pnode_name->name,
                           cache_content_status);
                }
            }
        }
	
      if((*pstatus =
      	cache_inode_clean_internal(to_remove_entry, ht,
					 pclient)) != CACHE_INODE_SUCCESS)
    	{
      	  if(use_mutex)
	  {
	    V_w(&pentry->lock);
	    V_w(&to_remove_entry->lock);
	  }

      	  LogCrit(COMPONENT_CACHE_INODE,
	   	   "cache_inode_clean_internal ERROR %d", *pstatus);
      	return *pstatus;
      }

      /* Finally put the main pentry back to pool */
      if(use_mutex)
        V_w(&to_remove_entry->lock);

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

      ReleaseToPool(to_remove_entry, &pclient->pool_entry);

    } /* to_remove->numlinks == 0 */

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

  /* Regular exit */
  if(use_mutex)
    {
      if(to_remove_numlinks != 0)
        V_w(&to_remove_entry->lock);    /* This was not release yet, it should be done here */

      V_w(&pentry->lock);
    }

  if(status == CACHE_INODE_SUCCESS)
      (pclient->stat.func_stats.nb_success[CACHE_INODE_REMOVE])++;
  else
      (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_REMOVE])++;

  return status;
}                               /* cache_inode_remove */
Esempio n. 21
0
/**
 *
 * cache_inode_readdir: Reads a directory.
 *
 * Looks up for a name in a directory indicated by a cached entry. The 
 * directory should have been cached before.
 *
 * NEW: pending new (C-language) callback based dirent unpacking into caller
 * structures, we eliminate copies by returning dir entries by pointer.  To
 * permit this, we introduce lock donation.  If new int pointer argument
 * unlock is 1 on return, the calling thread holds pentry read-locked and
 * must release this lock after dirent processing.
 *
 * This is the only function in the cache_inode_readdir.c file that manages MT
 * safety on a directory cache entry.
 *
 * @param pentry [IN] entry for the parent directory to be read.
 * @param cookie [IN] cookie for the readdir operation (basically the offset).
 * @param nbwanted [IN] Maximum number of directory entries wanted.
 * @param peod_met [OUT] A flag to know if end of directory was met during this call.
 * @param dirent_array [OUT] the resulting array of found directory entries.
 * @param ht [IN] hash table used for the cache, unused in this call.
 * @param unlock [OUT] the caller shall release read-lock on pentry when done
 * @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_BAD_TYPE if entry is not related to a directory\n
 * @return CACHE_INODE_LRU_ERROR if allocation error occured when validating the entry
 *
 */
cache_inode_status_t cache_inode_readdir(cache_entry_t * dir_pentry,
                                         cache_inode_policy_t policy,
                                         uint64_t cookie,
                                         unsigned int nbwanted,
                                         unsigned int *pnbfound,
                                         uint64_t *pend_cookie,
                                         cache_inode_endofdir_t *peod_met,
                                         cache_inode_dir_entry_t **dirent_array,
                                         hash_table_t *ht,
                                         int *unlock,
                                         cache_inode_client_t *pclient,
                                         fsal_op_context_t *pcontext,
                                         cache_inode_status_t *pstatus)
{
  cache_inode_dir_entry_t dirent_key[1], *dirent;
  struct avltree_node *dirent_node;
  fsal_accessflags_t access_mask = 0;
  uint64_t inoff = cookie;
  int i = 0;

  /* Guide to parameters:
   * the first cookie is parameter 'cookie'
   * number of entries queried is set by parameter 'nbwanted'
   * number of found entries before eod is return is '*pnbfound'
   * '*peod_met' is set if end of directory is encountered */

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

  /* Set initial value of unlock */
  *unlock = FALSE;

  /* end cookie initial value is the begin cookie */
  LogFullDebug(COMPONENT_NFS_READDIR,
               "--> Cache_inode_readdir: setting pend_cookie to cookie=%"
	       PRIu64,
               cookie);
  *pend_cookie = cookie;

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

  LogFullDebug(COMPONENT_NFS_READDIR,
               "--> Cache_inode_readdir: parameters are cookie=%"PRIu64
	       "nbwanted=%u",
               cookie, nbwanted);

  /* Sanity check */
  if(nbwanted == 0)
    {
      /* Asking for nothing is not a crime !!!!!
       * build a 'dummy' return in this case */
      *pstatus = CACHE_INODE_SUCCESS;
      *pnbfound = 0;
      *peod_met = TO_BE_CONTINUED;

      /* stats */
      (pclient->stat.func_stats.nb_success[CACHE_INODE_READDIR])++;

      return *pstatus;
    }

  /* Force dir content invalidation if policy enforced no name cache */
  if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) )
    return  cache_inode_readdir_nonamecache( dir_pentry,
                                             policy,
                                             cookie, 
                                             nbwanted, 
                                             pnbfound, 
                                             pend_cookie,
                                             peod_met,
                                             dirent_array, 
                                             ht, 
                                             unlock,
                                             pclient,
                                             pcontext,
                                             pstatus ) ;    
  
  P_w(&dir_pentry->lock);

  /* Renew the entry (to avoid having it being garbagged */
  if(cache_inode_renew_entry(dir_pentry, NULL, ht, pclient, pcontext,
			     pstatus) != CACHE_INODE_SUCCESS)
    {
      (pclient->stat.func_stats.nb_err_retryable[CACHE_INODE_GETATTR])++;
      V_w(&dir_pentry->lock);
      return *pstatus;
    }

  /* readdir can be done only with a directory */
  if(dir_pentry->internal_md.type != DIRECTORY)
    {
      V_w(&dir_pentry->lock);
      *pstatus = CACHE_INODE_BAD_TYPE;

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

      return *pstatus;
    }

  /* Check is user (as specified by the credentials) is authorized to read
   * the directory or not */
  access_mask = FSAL_MODE_MASK_SET(FSAL_R_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_LIST_DIR);
  if(cache_inode_access_no_mutex(dir_pentry,
                                 access_mask,
                                 ht, pclient,
				 pcontext,
				 pstatus) != CACHE_INODE_SUCCESS)
    {
      V_w(&dir_pentry->lock);

      (pclient->stat.func_stats.nb_err_retryable[CACHE_INODE_READDIR])++;
      return *pstatus;
    }


  /* Is the directory fully cached (this is done if a readdir call is done on the directory) */
  if(dir_pentry->object.dir.has_been_readdir != CACHE_INODE_YES)
  {

    /* populate the cache */
    if(cache_inode_readdir_populate(dir_pentry,
                                    policy,
		  		    ht,
				    pclient,
				    pcontext, pstatus) != CACHE_INODE_SUCCESS)
    {
      /* stats */
      (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_READDIR])++;

      V_w(&dir_pentry->lock);
      return *pstatus;
    }
  }

  /* deal with dentry cache invalidates */
  revalidate_cookie_cache(dir_pentry, pclient);

  /* Downgrade Writer lock to a reader one. */
  rw_lock_downgrade(&dir_pentry->lock);

  /* deal with initial cookie value:
   * 1. cookie is invalid (-should- be checked by caller)
   * 2. cookie is 0 (first cookie) -- ok
   * 3. cookie is > than highest dirent position (error) 
   * 4. cookie <= highest dirent position but > highest cached cookie
   *    (currently equivalent to #2, because we pre-populate the cookie avl)
   * 5. cookie is in cached range -- ok */

  if (cookie > 0) {

      if (cookie < 3) {
	  *pstatus = CACHE_INODE_BAD_COOKIE;
	  V_r(&dir_pentry->lock);
	  return *pstatus;
      }

      if ((inoff-3) > avltree_size(&dir_pentry->object.dir.dentries)) {
          LogCrit(COMPONENT_NFS_V4, "Bad initial cookie %"PRIu64,
                  inoff);
	  *pstatus = CACHE_INODE_BAD_COOKIE;
	  V_r(&dir_pentry->lock);
	  return *pstatus;
      }

      /* we assert this can now succeed */
      dirent_key->cookie = inoff;
      dirent_node = avltree_lookup(&dirent_key->node_c,
				   &dir_pentry->object.dir.cookies);

      if (! dirent_node) {
	  LogCrit(COMPONENT_NFS_READDIR,
		  "%s: seek to cookie=%"PRIu64" fail",
		  __func__,
		  inoff);
	  *pstatus = CACHE_INODE_NOT_FOUND;
	  V_r(&dir_pentry->lock);
	  return *pstatus;
      }

      /* switch avls */
      dirent = avltree_container_of(dirent_node,
				    cache_inode_dir_entry_t, 
				    node_c);
      dirent_node = &dirent->node_n;

      /* client wants the cookie -after- the last we sent, and
       * the Linux 3.0 and 3.1.0-rc7 clients misbehave if we
       * resend the last one */
      dirent_node = avltree_next(dirent_node);

  } else {
      /* initial readdir */
      dirent_node = avltree_first(&dir_pentry->object.dir.dentries);
  }

  LogFullDebug(COMPONENT_NFS_READDIR,
               "About to readdir in  cache_inode_readdir: pentry=%p "
	       "cookie=%"PRIu64,
               dir_pentry,
	       cookie);

  /* Now satisfy the request from the cached readdir--stop when either
   * the requested sequence or dirent sequence is exhausted */
  *pnbfound = 0;
  *peod_met = TO_BE_CONTINUED;

  for(i = 0; i < nbwanted; ++i)
  {
      if (!dirent_node)
	  break;

      dirent = avltree_container_of(dirent_node,
				    cache_inode_dir_entry_t, 
				    node_n);

      dirent_array[i] = dirent;
      (*pnbfound)++;

      dirent_node = avltree_next(dirent_node);
  }

  if (*pnbfound > 0)
  {
      if (!dirent)
      {
         LogCrit(COMPONENT_CACHE_INODE, "cache_inode_readdir: "
                 "UNEXPECTED CASE: dirent is NULL whereas nbfound>0");
         *pstatus = CACHE_INODE_INCONSISTENT_ENTRY;
         return CACHE_INODE_INCONSISTENT_ENTRY;
      }
      *pend_cookie = dirent->cookie;
  }

  if (! dirent_node)
      *peod_met = END_OF_DIR;

  *pstatus = cache_inode_valid(dir_pentry, CACHE_INODE_OP_GET, pclient);

  /* stats */
  if(*pstatus != CACHE_INODE_SUCCESS) {
      (pclient->stat.func_stats.nb_err_retryable[CACHE_INODE_READDIR])++;
      V_r(&dir_pentry->lock);
  }
  else {
      (pclient->stat.func_stats.nb_success[CACHE_INODE_READDIR])++;
      *unlock = TRUE;
  }

  return *pstatus;
}                               /* cache_inode_readdir */
Esempio n. 22
0
void *reaper_thread(void *unused)
{
        hash_table_t *ht = ht_client_id;
        struct rbt_head *head_rbt;
        hash_data_t *pdata = NULL;
        int i, v4;
        struct rbt_node *pn;
        nfs_client_id_t *clientp;

#ifndef _NO_BUDDY_SYSTEM
        if((i = BuddyInit(&nfs_param.buddy_param_admin)) != BUDDY_SUCCESS) {
        /* Failed init */
                LogFatal(COMPONENT_MAIN,
                    "Memory manager could not be initialized");
        }
        LogInfo(COMPONENT_MAIN, "Memory manager successfully initialized");
#endif

        SetNameFunction("reaper_thr");

        while(1) {
                /* Initial wait */
                /* TODO: should this be configurable? */
                /* sleep(nfs_param.core_param.reaper_delay); */
                sleep(reaper_delay);
                LogFullDebug(COMPONENT_MAIN,
                    "NFS reaper : now checking clients");

                /* For each bucket of the hashtable */
                for(i = 0; i < ht->parameter.index_size; i++) {
                        head_rbt = &(ht->array_rbt[i]);

restart:
                        /* acquire mutex */
                        P_w(&(ht->array_lock[i]));

                        /* go through all entries in the red-black-tree*/
                        RBT_LOOP(head_rbt, pn) {
                                pdata = RBT_OPAQ(pn);

                                clientp =
                                    (nfs_client_id_t *)pdata->buffval.pdata;
                                /*
                                 * little hack: only want to reap v4 clients
                                 * 4.1 initializess this field to '1'
                                 */
                                v4 = (clientp->create_session_sequence == 0);
                                if (clientp->confirmed != EXPIRED_CLIENT_ID &&
                                    nfs4_is_lease_expired(clientp) && v4) {
                                        V_w(&(ht->array_lock[i]));
                                        LogDebug(COMPONENT_MAIN,
                                            "NFS reaper: expire client %s",
                                            clientp->client_name);
                                        nfs_client_id_expire(clientp);
                                        goto restart;
                                }

                                if (clientp->confirmed == EXPIRED_CLIENT_ID) {
                                        LogDebug(COMPONENT_MAIN,
                                            "reaper: client %s already expired",
                                            clientp->client_name);
                                }

                                RBT_INCREMENT(pn);
                        }
                        V_w(&(ht->array_lock[i]));
                }

        }                           /* while ( 1 ) */
Esempio n. 23
0
int nfs41_op_close(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
{
  char __attribute__ ((__unused__)) funcname[] = "nfs4_op_close";
  cache_inode_state_t *pstate_found = NULL;

  cache_inode_status_t cache_status;

  memset(&res_CLOSE4, 0, sizeof(res_CLOSE4));
  resp->resop = NFS4_OP_CLOSE;

  /* If the filehandle is Empty */
  if(nfs4_Is_Fh_Empty(&(data->currentFH)))
    {
      res_CLOSE4.status = NFS4ERR_NOFILEHANDLE;
      return res_CLOSE4.status;
    }

  /* If the filehandle is invalid */
  if(nfs4_Is_Fh_Invalid(&(data->currentFH)))
    {
      res_CLOSE4.status = NFS4ERR_BADHANDLE;
      return res_CLOSE4.status;
    }

  /* Tests if the Filehandle is expired (for volatile filehandle) */
  if(nfs4_Is_Fh_Expired(&(data->currentFH)))
    {
      res_CLOSE4.status = NFS4ERR_FHEXPIRED;
      return res_CLOSE4.status;
    }

  if(data->current_entry == NULL)
    {
      res_CLOSE4.status = NFS4ERR_SERVERFAULT;
      return res_CLOSE4.status;
    }

  /* Should not operate on directories */
  if(data->current_entry->internal_md.type == DIR_BEGINNING ||
     data->current_entry->internal_md.type == DIR_CONTINUE)
    {
      res_CLOSE4.status = NFS4ERR_ISDIR;
      return res_CLOSE4.status;
    }

  /* Object should be a file */
  if(data->current_entry->internal_md.type != REGULAR_FILE)
    {
      res_CLOSE4.status = NFS4ERR_INVAL;
      return res_CLOSE4.status;
    }

  /* Get the related state */
  if(cache_inode_get_state(arg_CLOSE4.open_stateid.other,
                           &pstate_found,
                           data->pclient, &cache_status) != CACHE_INODE_SUCCESS)
    {
      if(cache_status == CACHE_INODE_NOT_FOUND)
        res_CLOSE4.status = NFS4ERR_BAD_STATEID;
      else
        res_CLOSE4.status = NFS4ERR_INVAL;

      return res_CLOSE4.status;
    }

#ifdef _TOTO
  /* Check is held locks remain */
  if(pstate_found->state_data.share.lockheld > 0)
    {
      res_CLOSE4.status = NFS4ERR_LOCKS_HELD;
      return res_CLOSE4.status;
    }
#endif

  /* Update the seqid for the open_owner */
  P(pstate_found->powner->lock);
  pstate_found->powner->seqid += 1;
  V(pstate_found->powner->lock);

  /* Prepare the result */
  res_CLOSE4.CLOSE4res_u.open_stateid.seqid = pstate_found->seqid + 1;

  /* Close the file in FSAL through the cache inode */
  P_w(&data->current_entry->lock);
  if(cache_inode_close(data->current_entry,
                       data->pclient, &cache_status) != CACHE_INODE_SUCCESS)
    {
      V_w(&data->current_entry->lock);

      res_CLOSE4.status = nfs4_Errno(cache_status);
      return res_CLOSE4.status;
    }
  V_w(&data->current_entry->lock);

  /* File is closed, release the corresponding state */
  if(cache_inode_del_state_by_key(arg_CLOSE4.open_stateid.other,
                                  data->pclient, &cache_status) != CACHE_INODE_SUCCESS)
    {
      res_CLOSE4.status = nfs4_Errno(cache_status);
      return res_CLOSE4.status;
    }

  memcpy(res_CLOSE4.CLOSE4res_u.open_stateid.other, arg_CLOSE4.open_stateid.other, 12);;

  res_CLOSE4.status = NFS4_OK;

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

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

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

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

  fsaldata.handle = *pfsal_handle;

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

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

      cache_inode_release_fsaldata_key(&key, pgcparam->pclient);

      return LRU_LIST_DO_NOT_SET_INVALID;
    }

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

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

      cache_inode_release_fsaldata_key(&key, pgcparam->pclient);

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

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

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

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

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

  cache_inode_release_fsaldata_key(&key, pgcparam->pclient);

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

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

      parent_iter = parent_iter_next;
    }

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

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

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

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

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

  cache_inode_mutex_destroy(pentry);

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

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

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

  return LRU_LIST_SET_INVALID;  /* Cleaning ok */
}
Esempio n. 25
0
/* Move an entry in the namespace */
int NamespaceRename(ino_t parent_entry_src, dev_t src_dev, unsigned int srcgen,
                    char *name_src, ino_t parent_entry_tgt, dev_t tgt_dev,
                    unsigned int tgtgen, char *name_tgt)
{

  int rc = 0;
  fsnode_t *p_node;
  unsigned int new_gen;

  /* lock the namespace for modification */
  P_w(&ns_lock);

  /* get source node info */
  p_node = h_get_lookup(parent_entry_src, src_dev, name_src, &rc);

  if(!p_node || rc != 0)
    {
      V_w(&ns_lock);
      return rc;
    }

  /* check that source != target (if so, do nothing) */
  if((parent_entry_src == parent_entry_tgt)
     && (src_dev == tgt_dev) && !strcmp(name_src, name_tgt))
    {
      V_w(&ns_lock);
      return 0;
    }

  /* try to add new path (with the same gen number) */
  new_gen = p_node->inode.generation;

  rc = NamespaceAdd_nl(parent_entry_tgt, tgt_dev, tgtgen, name_tgt, p_node->inode.inum,
                       p_node->inode.dev, &new_gen);

  if(rc == EEXIST)
    {
      /* remove previous entry */
      rc = NamespaceRemove_nl(parent_entry_tgt, tgt_dev, tgtgen, name_tgt);
      if(rc)
        {
          V_w(&ns_lock);
          return rc;
        }

      /* add the new one */
      new_gen = p_node->inode.generation;

      rc = NamespaceAdd_nl(parent_entry_tgt, tgt_dev, tgtgen, name_tgt,
                           p_node->inode.inum, p_node->inode.dev, &new_gen);
    }

  if(rc)
    {
      V_w(&ns_lock);
      return rc;
    }

  /* remove old path */
  rc = NamespaceRemove_nl(parent_entry_src, src_dev, srcgen, name_src);

  V_w(&ns_lock);

  return rc;

}
Esempio n. 26
0
/**
 *
 * cache_inode_setattrs: set the attributes for an entry located in the cache by its address. 
 * 
 * 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 [INOUT] attributes for the entry that we have found. Out: attributes set.
 * @param ht [INOUT] 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_setattr(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)
{
  fsal_handle_t *pfsal_handle = NULL;
  fsal_status_t fsal_status;
  fsal_attrib_list_t *p_object_attributes = NULL;
  fsal_attrib_list_t result_attributes;
  fsal_attrib_list_t truncate_attributes;

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

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

  /* Lock the entry */
  P_w(&pentry->lock);

  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 FS_JUNCTION:
    case DIRECTORY:
      pfsal_handle = &pentry->object.dir.handle;
      break;

    case CHARACTER_FILE:
    case BLOCK_FILE:
    case SOCKET_FILE:
    case FIFO_FILE:
      pfsal_handle = &pentry->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->internal_md.type, __LINE__, __FILE__);
      *pstatus = CACHE_INODE_BAD_TYPE;
      return *pstatus;
    }

  /* Call FSAL to set the attributes */
  /* result_attributes.asked_attributes = pattr->asked_attributes ; */

  /* mod Th.Leibovici on 2006/02/13
   * We ask back all standard attributes, in case they have been modified
   * by another program (pftp, rcpd...)
   */

  memset(&result_attributes, 0, sizeof(fsal_attrib_list_t));
  result_attributes.asked_attributes = pclient->attrmask;
  /* end of mod */

#ifdef _USE_MFSL
  fsal_status =
      MFSL_setattrs(&pentry->mobject, pcontext, &pclient->mfsl_context, pattr,
                    &result_attributes, NULL);
#else
  fsal_status = FSAL_setattrs(pfsal_handle, pcontext, pattr, &result_attributes);
#endif
  if(FSAL_IS_ERROR(fsal_status))
    {
      *pstatus = cache_inode_error_convert(fsal_status);
      V_w(&pentry->lock);

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

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

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

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

          *pstatus = CACHE_INODE_FSAL_ESTALE;
        }

      return *pstatus;
    }

  if(pattr->asked_attributes & FSAL_ATTR_SIZE)
    {
      truncate_attributes.asked_attributes = pclient->attrmask;

      fsal_status = FSAL_truncate(pfsal_handle,
                                  pcontext, pattr->filesize, NULL, &truncate_attributes);
      if(FSAL_IS_ERROR(fsal_status))
        {
          *pstatus = cache_inode_error_convert(fsal_status);
          V_w(&pentry->lock);

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

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

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

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

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }

          return *pstatus;
        }

    }

  /* Keep the new attribute in cache */
  switch (pentry->internal_md.type)
    {
    case REGULAR_FILE:
      p_object_attributes = &(pentry->object.file.attributes);
      break;

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

    case FS_JUNCTION:
    case DIRECTORY:
      p_object_attributes = &(pentry->object.dir.attributes);
      break;

    case CHARACTER_FILE:
    case BLOCK_FILE:
    case SOCKET_FILE:
    case FIFO_FILE:
      p_object_attributes = &(pentry->object.special_obj.attributes);
      break;

    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;
    }

  /* Update the cached attributes */
  if((result_attributes.asked_attributes & FSAL_ATTR_SIZE) ||
     (result_attributes.asked_attributes & FSAL_ATTR_SPACEUSED))
    {

      if(pentry->internal_md.type == REGULAR_FILE)
        {
          if(pentry->object.file.pentry_content == NULL)
            {
              /* Operation on a non data cached file */
              p_object_attributes->filesize = result_attributes.filesize;
              p_object_attributes->spaceused = result_attributes.filesize;      /* Unclear hook here. BUGAZOMEU */
            }
          else
            {
              /* Data cached file */
              /* Do not set the p_object_attributes->filesize and p_object_attributes->spaceused  in this case 
               * This will lead to a situation where (for example) untar-ing a file will produced invalid files 
               * with a size of 0 despite the fact that they are not empty */

              LogFullDebug(COMPONENT_CACHE_INODE,
                           "cache_inode_setattr with FSAL_ATTR_SIZE on data cached entry");
            }
        }
      else if(pattr->asked_attributes & FSAL_ATTR_SIZE)
        LogCrit(COMPONENT_CACHE_INODE,
                "WARNING !!! cache_inode_setattr tried to set size on a non REGULAR_FILE type=%d",
                pentry->internal_md.type);
    }

  if(result_attributes.asked_attributes &
     (FSAL_ATTR_MODE | FSAL_ATTR_OWNER | FSAL_ATTR_GROUP))
    {
      if(result_attributes.asked_attributes & FSAL_ATTR_MODE)
        p_object_attributes->mode = result_attributes.mode;

      if(result_attributes.asked_attributes & FSAL_ATTR_OWNER)
        p_object_attributes->owner = result_attributes.owner;

      if(result_attributes.asked_attributes & FSAL_ATTR_GROUP)
        p_object_attributes->group = result_attributes.group;
    }

  if(result_attributes.asked_attributes &
     (FSAL_ATTR_ATIME | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME))
    {
      if(result_attributes.asked_attributes & FSAL_ATTR_ATIME)
        p_object_attributes->atime = result_attributes.atime;

      if(result_attributes.asked_attributes & FSAL_ATTR_CTIME)
        p_object_attributes->ctime = result_attributes.ctime;

      if(result_attributes.asked_attributes & FSAL_ATTR_MTIME)
        p_object_attributes->mtime = result_attributes.mtime;
    }
  
#ifdef _USE_NFS4_ACL
  if(result_attributes.asked_attributes & FSAL_ATTR_ACL)
    {
      LogDebug(COMPONENT_CACHE_INODE, "cache_inode_setattr: old acl = %p, new acl = %p",
               p_object_attributes->acl, result_attributes.acl);

      /* Release previous acl entry. */
      if(p_object_attributes->acl)
        {
          fsal_acl_status_t status;
          nfs4_acl_release_entry(p_object_attributes->acl, &status);
          if(status != NFS_V4_ACL_SUCCESS)
            LogEvent(COMPONENT_CACHE_INODE, "cache_inode_setattr: Failed to release old acl:"
                     " status = %d", status);
        }

      /* Update with new acl entry. */
      p_object_attributes->acl = result_attributes.acl;
    }
#endif                          /* _USE_NFS4_ACL */

  /* Return the attributes as set */
  *pattr = *p_object_attributes;

  /* validate the entry */
  *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_SET, pclient);

  /* Release the entry */
  V_w(&pentry->lock);

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

  return *pstatus;
}                               /* cache_inode_setattr */
Esempio n. 27
0
void nfs4_acl_release_entry(fsal_acl_t *pacl, fsal_acl_status_t *pstatus)
{
  fsal_acl_data_t acldata;
  hash_buffer_t key, old_key;
  hash_buffer_t old_value;
  int rc;

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

  P_w(&pacl->lock);
  nfs4_acl_entry_dec_ref(pacl);
  if(pacl->ref)
    {
      V_w(&pacl->lock);
      return;
    }
  else
      LogDebug(COMPONENT_NFS_V4_ACL, "nfs4_acl_release_entry: free acl %p", pacl);

  /* Turn the input to a hash key */
  acldata.naces = pacl->naces;
  acldata.aces = pacl->aces;

  if(nfs4_acldata_2_key(&key, &acldata))
  {
    *pstatus = NFS_V4_ACL_UNAPPROPRIATED_KEY;

    nfs4_release_acldata_key(&key);

    V_w(&pacl->lock);

    return;
  }

  /* use the key to delete the entry */
  if((rc = HashTable_Del(fsal_acl_hash, &key, &old_key, &old_value)) != HASHTABLE_SUCCESS)
    {
      LogCrit(COMPONENT_NFS_V4_ACL,
              "nfs4_acl_release_entry: entry could not be deleted, status = %d",
              rc);

      nfs4_release_acldata_key(&key);

      *pstatus = NFS_V4_ACL_NOT_FOUND;

      V_w(&pacl->lock);

      return;
    }

  /* Release the hash key data */
  nfs4_release_acldata_key(&old_key);

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

  /* Release the current key */
  nfs4_release_acldata_key(&key);

  V_w(&pacl->lock);

  /* Release acl */
  nfs4_acl_free(pacl);
}
Esempio n. 28
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) */
Esempio n. 29
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;
}
Esempio n. 30
0
/**
 *
 * cache_inode_gc_suppress_directory: suppress a directory entry from the cache inode.
 *
 * Suppress a file entry from the cache inode.
 *
 * @param pentry [IN] pointer to the entry to be suppressed.
 *
 * @return 1 if entry is successfully suppressed, 0 otherwise
 *
 * @see LRU_invalidate_by_function
 * @see LRU_gc_invalid
 *
 */
int cache_inode_gc_suppress_directory(cache_entry_t * pentry,
                                      cache_inode_param_gc_t * pgcparam)
{
  cache_entry_t *pentry_iter = NULL;
  cache_entry_t *pentry_iter_save = NULL;

  P_w(&pentry->lock);
  pentry->internal_md.valid_state = INVALID;

  if(cache_inode_is_dir_empty(pentry) != CACHE_INODE_SUCCESS)
    {
      V_w(&pentry->lock);

      LogFullDebug(COMPONENT_CACHE_INODE_GC,
                   "Entry %p (DIR_BEGINNING) is not empty. The dir_chain will not be garbaged now",
                   pentry);

      return LRU_LIST_DO_NOT_SET_INVALID;       /* entry is not to be suppressed */
    }

  /* If we reached this point, the directory contains no active entry, it should be removed from the cache */
  LogFullDebug(COMPONENT_CACHE_INODE_GC,
               "Entry %p (DIR_BEGINNING) and its associated dir_chain will be garbaged",
               pentry);

  LogFullDebug(COMPONENT_CACHE_INODE_GC,
               "****> cache_inode_gc_suppress_directory on %p",
               pentry);

  /* Remove refences in the parent entries */
  if(cache_inode_gc_invalidate_related_dirent(pentry, pgcparam) != LRU_LIST_SET_INVALID)
    {
      V_w(&pentry->lock);
      return LRU_LIST_DO_NOT_SET_INVALID;
    }

  /* Remove the whole dir_chain from the cache */
  pentry_iter = pentry->object.dir_begin.pdir_cont;
  while(pentry_iter != NULL)
    {
      pentry_iter_save = pentry_iter->object.dir_cont.pdir_cont;

      if(cache_inode_gc_clean_entry(pentry_iter, pgcparam) != LRU_LIST_SET_INVALID)
        {
          V_w(&pentry->lock);
          return LRU_LIST_DO_NOT_SET_INVALID;
        }

      pentry_iter = pentry_iter_save;
    }

  if(cache_inode_gc_clean_entry(pentry, pgcparam) != LRU_LIST_SET_INVALID)
    {
      V_w(&pentry->lock);
      return LRU_LIST_DO_NOT_SET_INVALID;
    }

  /* Mutex has already been freed at destruction time */

  return LRU_LIST_SET_INVALID;
}                               /* cache_inode_gc_suppress_directory */