Exemplo n.º 1
0
/*
 * cache_inode_invalidate_all_cached_dirent: Invalidates all the entries for a
 * cached directory.
 *
 * Invalidates all the entries for a cached directory.  No MT Safety managed
 * here !!
 *
 * @param pentry_parent [INOUT] cache entry representing the directory to be
 * managed.
 * @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 pstatus [OUT] returned status.
 *
 * @return the same as *pstatus
 *
 */
cache_inode_status_t cache_inode_invalidate_all_cached_dirent(
    cache_entry_t *pentry,
    hash_table_t *ht,
    cache_inode_client_t *pclient,
    cache_inode_status_t *pstatus)
{
  /* Set the return default to CACHE_INODE_SUCCESS */
  *pstatus = CACHE_INODE_SUCCESS;

  /* Only DIRECTORY entries are concerned */
  if(pentry->internal_md.type != DIRECTORY)
    {
      *pstatus = CACHE_INODE_BAD_TYPE;
      return *pstatus;
    }

  /* Get ride of entries cached in the DIRECTORY */
  cache_inode_release_dirents(pentry, pclient, CACHE_INODE_AVL_BOTH);

  /* Reinit the fields */
  pentry->object.dir.has_been_readdir = CACHE_INODE_NO;
  *pstatus = CACHE_INODE_SUCCESS;

  return *pstatus;
}                               /* cache_inode_invalidate_all_cached_dirent */
Exemplo n.º 2
0
/**
 *
 * revalidate_cookie_cache:  sync cookie avl offsets with the dentry name avl.
 *
 * If no cookies are cached, add those of any dirents in the name avl.  The
 * entry is assumed to be write locked.
 *
 * @param pentry [IN] entry for the parent directory to be read.
 *
 * @return void
 *
 */
static void revalidate_cookie_cache(cache_entry_t *dir_pentry,
                                    cache_inode_client_t *pclient)
{
  struct avltree_node *dirent_node;
  cache_inode_dir_entry_t *dirent;
  int size_n, size_c, ix;

  /* we'll try to add entries to any directory whose cookie
   * avl cache is currently empty (mutating dirent operations
   * clear it) */
#if 0
  if (avltree_size(&dir_pentry->object.dir.cookies) > 0)
      return;
#else
  size_c = avltree_size(&dir_pentry->object.dir.cookies);
  size_n = avltree_size(&dir_pentry->object.dir.dentries);
  if (size_c == size_n)
      return;
  /* the following is safe to call arbitrarily many times, with
   * CACHE_INODE_AVL_COOKIES -only-. */
      cache_inode_release_dirents(dir_pentry,
                                  pclient,
                                  CACHE_INODE_AVL_COOKIES);      
#endif

  dirent_node = avltree_first(&dir_pentry->object.dir.dentries);
  dirent = avltree_container_of(dirent_node,
				cache_inode_dir_entry_t, 
				node_n);

  ix = 3; /* first non-reserved cookie value */
  dirent_node = &dirent->node_n;
  while (dirent_node) {
      dirent = avltree_container_of(dirent_node,
				    cache_inode_dir_entry_t, 
				    node_n);
      dirent->cookie = ix;
      /* XXX we could optimize this somewhat (saving an internal
       * lookup in avltree_insert), by adding an avl append
       * operation */
      (void) avltree_insert(&dirent->node_c,
			    &dir_pentry->object.dir.cookies);
      dirent_node = avltree_next(dirent_node);
      ++ix;
  }

  return;
}
Exemplo n.º 3
0
/**
 * @brief Invalidates all cached entries for a directory
 *
 * Invalidates all the entries for a cached directory.  The content
 * lock must be held when this function is called.
 *
 * @param[in,out] entry  The directory to be managed
 *
 * @return CACHE_INODE_SUCCESS or errors.
 *
 */
cache_inode_status_t
cache_inode_invalidate_all_cached_dirent(cache_entry_t *entry)
{
	cache_inode_status_t status = CACHE_INODE_SUCCESS;

	/* Only DIRECTORY entries are concerned */
	if (entry->type != DIRECTORY) {
		status = CACHE_INODE_NOT_A_DIRECTORY;
		return status;
	}

	/* Get rid of entries cached in the DIRECTORY */
	cache_inode_release_dirents(entry, CACHE_INODE_AVL_BOTH);

	/* Now we can trust the content */
	atomic_set_uint32_t_bits(&entry->flags, CACHE_INODE_TRUST_CONTENT);

	status = CACHE_INODE_SUCCESS;

	return status;
}
Exemplo n.º 4
0
/**
 *
 * cache_inode_operate_cached_dirent: locates a dirent in the cached dirent,
 * and perform an operation on it.
 *
 * Looks up for an dirent in the cached dirent. Thus function searches only in
 * the entries listed in the dir_entries array. Some entries may be missing but
 * existing and not be cached (if no readdir was ever performed on the entry for
 * example. This function provides a way to operate on the dirent.
 *
 * @param pentry_parent [IN] directory entry to be searched.
 * @param name [IN] name for the searched entry.
 * @param newname [IN] newname if function is used to rename a dirent
 * @param pclient [INOUT] resource allocated by the client for the nfs management.
 * @param dirent_op [IN] operation (ADD, LOOKUP or REMOVE) to do on the dirent
 *        if found.
 * @pstatus [OUT] returned status.
 *
 * @return the found entry if its exists and NULL if it is not in the dirent
 *         cache. REMOVE always returns NULL.
 *
 */
cache_entry_t *cache_inode_operate_cached_dirent(cache_entry_t * pentry_parent,
                                                 fsal_name_t * pname,
                                                 fsal_name_t * newname,
						 cache_inode_client_t * pclient,
                                                 cache_inode_dirent_op_t dirent_op,
                                                 cache_inode_status_t * pstatus)
{
  cache_entry_t *pentry = NULL;
  cache_inode_dir_entry_t dirent_key[1], *dirent;
  struct avltree_node *dirent_node, *tmpnode;
  LRU_List_state_t vstate;

  /* Directory mutation generally invalidates outstanding 
   * readdirs, hence any cached cookies, so in these cases we 
   * clear the cookie avl */

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

  /* Sanity check */
  if(pentry_parent->internal_md.type != DIRECTORY)
    {
      *pstatus = CACHE_INODE_BAD_TYPE;
      return NULL;
    }

  /* If no active entry, do nothing */
  if (pentry_parent->object.dir.nbactive == 0) {
      *pstatus = CACHE_INODE_NOT_FOUND;
      return NULL;
  }

  FSAL_namecpy(&dirent_key->name, pname);
  dirent_node = avltree_lookup(&dirent_key->node_n,
			       &pentry_parent->object.dir.dentries);
  if (! dirent_node) {
      *pstatus = CACHE_INODE_NOT_FOUND; /* Right error code (see above)? */
      return NULL;
  }

  /* unpack avl node */
  dirent = avltree_container_of(dirent_node, cache_inode_dir_entry_t,
				node_n);

  /* check state of cached dirent */
  vstate = dirent->pentry->internal_md.valid_state;
  if (vstate == VALID || vstate == STALE) {
  
      if (vstate == STALE)
      	LogDebug(COMPONENT_NFS_READDIR,
		"DIRECTORY: found STALE cache entry");

	/* Entry was found */
        pentry = dirent->pentry;
        *pstatus = CACHE_INODE_SUCCESS;
  }

  /* Did we find something */
  if(pentry != NULL)
    {
      /* Yes, we did ! */
      switch (dirent_op)
        {
        case CACHE_INODE_DIRENT_OP_REMOVE:
	    avltree_remove(&dirent->node_n,
                           &pentry_parent->object.dir.dentries);
	    /* release to pool */
	    ReleaseToPool(dirent, &pclient->pool_dir_entry);
	    pentry_parent->object.dir.nbactive--;
	    *pstatus = CACHE_INODE_SUCCESS;
          break;

        case CACHE_INODE_DIRENT_OP_RENAME:
	  /* change the installed inode only the rename can succeed */
	  FSAL_namecpy(&dirent_key->name, newname);
  	  tmpnode = avltree_lookup(&dirent_key->node_n,
				   &pentry_parent->object.dir.dentries);
	  if (tmpnode) {
	    /* rename would cause a collision */
	    *pstatus = CACHE_INODE_ENTRY_EXISTS;

	  } else {
	      /* remove, rename, and re-insert the object with new keys */
	      avltree_remove(&dirent->node_n,
                             &pentry_parent->object.dir.dentries);

	      FSAL_namecpy(&dirent->name, newname);
	      tmpnode = avltree_insert(&dirent->node_n,
				       &pentry_parent->object.dir.dentries);
	      if (tmpnode) {
		  /* collision, tree state unchanged--this won't happen */
		  *pstatus = CACHE_INODE_ENTRY_EXISTS;

		  /* still, try to revert the change in place */
		  FSAL_namecpy(&dirent->name, pname);
		  tmpnode = avltree_insert(&dirent->node_n,
					   &pentry_parent->object.dir.dentries);
	      } else {
		  *pstatus = CACHE_INODE_SUCCESS;
	      }
	  } /* !found */
          break;

        default:
          /* Should never occurs, in any case, it cost nothing to handle
	   * this situation */
          *pstatus = CACHE_INODE_INVALID_ARGUMENT;
          break;

        }                       /* switch */
    }

  if (*pstatus == CACHE_INODE_SUCCESS) {
      /* As noted, if a mutating operation was performed, we must
       * invalidate cached cookies. */
      cache_inode_release_dirents(
          pentry_parent, pclient, CACHE_INODE_AVL_COOKIES);

      /* Someone has to repopulate the avl cookie cache.  Populating it
       * lazily is ok, but the logic to do it makes supporting simultaneous
       * readers more involved.  Another approach would be to do it in the
       * background, scheduled from here. */
  }

  return pentry;
}                               /* cache_inode_operate_cached_dirent */