/* * 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 */
/** * * 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; }
/** * @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; }
/** * * 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 */